Aqui está o XML para meus itens dentro do RecyclerView
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cvItems"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_margin="2dp"
card_view:cardElevation="0dp"
card_view:contentPadding="0dp"
card_view:cardBackgroundColor="#FFFFFF"
>
<LinearLayout
android:orientation="horizontal"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<TextView
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:id="@+id/tvContent"
android:textSize="15dp"
android:paddingLeft="5dp"
android:paddingRight="5dp" />
<CheckBox
android:id="@+id/cbSelect"
android:layout_width="0dip"
android:layout_weight="0.2"
android:layout_height="match_parent"
android:button="@drawable/cb_checked"
android:gravity="center_horizontal"
android:textAlignment="center"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</android.support.v7.widget.CardView>
E aqui está o adaptador RecyclerView que aumenta o layout acima para cada um de seus itens:
public class AdapterTrashIncome extends RecyclerView.Adapter<AdapterTrashIncome.ViewHolder> {
private ArrayList<ObjectIncome> myItems = new ArrayList<>();
public AdapterTrashIncome(ArrayList<ObjectIncome> getItems, Context context){
try {
mContext = context;
myItems = getItems;
}catch (Exception e){
Log.e(FILE_NAME, "51: " + e.toString());
e.printStackTrace();
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvContent;
public CheckBox cbSelect;
public ViewHolder(View v) {
super(v);
tvContent = (TextView) v.findViewById(R.id.tvContent);
cbSelect = (CheckBox) v.findViewById(R.id.cbSelect);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final ObjectIncome objIncome = myItems.get(position);
String content = "<b>lalalla</b>";
holder.tvContent.setText(Html.fromHtml(content));
}
}
O problema é, digamos que eu tenha 10 itens dentro do RecyclerView. Quando eu marquei a caixa de seleção no item 1,2,3, percorri o RecyclerView e, de repente, alguns dos outros itens, por exemplo, itens 8,9, estão marcados. E quando eu rolar para cima novamente, os itens 1 e 3 são verificados, mas não o item 2. Alguma idéia de por que isso aconteceu?
android
android-recyclerview
estou dentro
fonte
fonte
Respostas:
Esse é um comportamento esperado. Você não está definindo sua caixa de seleção marcada ou não. Você está selecionando um e o titular da visualização o mantém selecionado. Você pode adicionar uma variável booleana em seu objeto ObjectIncome e manter o status de seleção do seu item.
Você pode olhar meu exemplo. Você pode fazer algo assim:
public class AdapterTrashIncome extends RecyclerView.Adapter<AdapterTrashIncome.ViewHolder> { private ArrayList<ObjectIncome> myItems = new ArrayList<>(); public AdapterTrashIncome(ArrayList<ObjectIncome> getItems, Context context){ try { mContext = context; myItems = getItems; }catch (Exception e){ Log.e(FILE_NAME, "51: " + e.toString()); e.printStackTrace(); } } public class ViewHolder extends RecyclerView.ViewHolder { public TextView tvContent; public CheckBox cbSelect; public ViewHolder(View v) { super(v); tvContent = (TextView) v.findViewById(R.id.tvContent); cbSelect = (CheckBox) v.findViewById(R.id.cbSelect); } } @Override public void onBindViewHolder(ViewHolder holder, final int position) { final ObjectIncome objIncome = myItems.get(position); String content = "<b>lalalla</b>"; holder.tvContent.setText(Html.fromHtml(content)); //in some cases, it will prevent unwanted situations holder.cbSelect.setOnCheckedChangeListener(null); //if true, your checkbox will be selected, else unselected holder.cbSelect.setChecked(objIncome.isSelected()); holder.cbSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { //set your object's last status objIncome.setSelected(isChecked); } }); } }
fonte
holder.cbSelect.setOnCheckedChangeListener(null);
antesholder.cbSelect.setChecked(objIncome.isSelected())
onBindViewHolder
.@Override public void onBindViewHolder(final ItemHolder holder, int position) { holder.checkBox.setOnCheckedChangeListener(null); holder.checkBox.setSelected(list.get(position).isSelected()); holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { list.get(holder.getAdapterPosition()).setSelected(isChecked); } });
Resumindo, é porque reciclamos as visualizações e as usamos novamente!
como você pode evitar isso:
1. Em
onBindViewHolder
verificar se você deve marcar ou desmarcar as caixas. não se esqueça de colocar if e elseif (...) holder.cbSelect.setChecked(true); else holder.cbSelect.setChecked(false);
myItems
array! portanto, sempre que uma nova vista é mostrada, ele lê a estátua mais recente do objeto.fonte
isChecked
false
para todos os dados definidos no início, entãoonCheckChanged
eu apenas atualizei oisChecked
valor paratrue
oufalse
e conforme informado no implemento de resposta que verifica está marcada ou não.USE ISSO SOMENTE SE VOCÊ TIVER NÚMERO LIMITADO DE ITENS EM SUA VISUALIZAÇÃO DO RECICLADOR.
Tentei usar valor booleano no modelo e manter o status da caixa de seleção, mas não adiantou no meu caso. O que funcionou para mim é this.setIsRecyclable (false);
public class ComponentViewHolder extends RecyclerView.ViewHolder { public MyViewHolder(View itemView) { super(itemView); .... this.setIsRecyclable(false); }
Mais explicações sobre isso podem ser encontradas aqui https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable ()
NOTA: Esta é uma solução alternativa. Para usá-lo corretamente, você pode consultar o documento que afirma "As chamadas para setIsRecyclable () devem sempre ser emparelhadas (uma chamada para setIsRecyclabe (false) deve sempre ser combinada com uma chamada posterior para setIsRecyclable (true)). Pares de chamadas podem ser aninhados , já que o estado é contado por referência internamente. " Não sei como fazer isso no código, se alguém puder fornecer mais código sobre isso.
fonte
Basta adicionar dois métodos de substituição de
RecyclerView
@Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { return position; }
fonte
Você pode usar a classe Model para controlar a caixa de seleção de cada item recyclerView. A referência completa é de: RecyclerView Checkbox Android
setTag e getTag são usados para controlar o status da caixa de seleção. Verifique o link de referência completo para obter mais informações. Também ensina como enviar itens verificados para NEXTACTIVITY .
Fazer modelo
public class Model { private boolean isSelected; private String animal; public String getAnimal() { return animal; } public void setAnimal(String animal) { this.animal = animal; } public boolean getSelected() { return isSelected; } public void setSelected(boolean selected) { isSelected = selected; } }
criar integer.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="btnplusview">1</integer> <integer name="btnpluspos">2</integer> </resources>
Finalmente o adaptador se parece com isto:
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> { private LayoutInflater inflater; public static ArrayList<Model> imageModelArrayList; private Context ctx; public CustomAdapter(Context ctx, ArrayList<Model> imageModelArrayList) { inflater = LayoutInflater.from(ctx); this.imageModelArrayList = imageModelArrayList; this.ctx = ctx; } @Override public CustomAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = inflater.inflate(R.layout.rv_item, parent, false); MyViewHolder holder = new MyViewHolder(view); return holder; } @Override public void onBindViewHolder(final CustomAdapter.MyViewHolder holder, int position) { holder.checkBox.setText("Checkbox " + position); holder.checkBox.setChecked(imageModelArrayList.get(position).getSelected()); holder.tvAnimal.setText(imageModelArrayList.get(position).getAnimal()); // holder.checkBox.setTag(R.integer.btnplusview, convertView); holder.checkBox.setTag(position); holder.checkBox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Integer pos = (Integer) holder.checkBox.getTag(); Toast.makeText(ctx, imageModelArrayList.get(pos).getAnimal() + " clicked!", Toast.LENGTH_SHORT).show(); if (imageModelArrayList.get(pos).getSelected()) { imageModelArrayList.get(pos).setSelected(false); } else { imageModelArrayList.get(pos).setSelected(true); } } }); } @Override public int getItemCount() { return imageModelArrayList.size(); } class MyViewHolder extends RecyclerView.ViewHolder { protected CheckBox checkBox; private TextView tvAnimal; public MyViewHolder(View itemView) { super(itemView); checkBox = (CheckBox) itemView.findViewById(R.id.cb); tvAnimal = (TextView) itemView.findViewById(R.id.animal); } }
}
fonte
Usando Kotlin, a única coisa que resolveu esse problema para mim foi limpar o
OnCheckedChangeListener
antes de definir a variável e, em seguida, criar um novoOnCheckedChangeListener
depoischecked
ser definido.Eu faço o seguinte no meu
RecyclerView.ViewHolder
task.setOnCheckedChangeListener(null) task.isChecked = item.status task.setOnCheckedChangeListener { _: CompoundButton, checked: Boolean -> item.status = checked ... do more stuff ... }
fonte
task.setOnCheckedChangeListener(null)
apenas consideramos a caixa de seleção como nova, pois estamos interessados apenas em novos eventos. Novamente muito inteligente.Eu recomendo que não use
checkBox.setOnCheckedChangeListener
emrecyclerViewAdapter
. Porque no scrolling recyclerView,checkBox.setOnCheckedChangeListener
será disparado pelo adaptador. Não é seguro . Em vez disso, usecheckBox.setOnClickListener
para interagir com as entradas do usuário.Por exemplo:
public void onBindViewHolder(final ViewHolder holder, int position) { /* . . . . . . */ holder.checkBoxAdapterTasks.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean isChecked = holder.checkBoxAdapterTasks.isChecked(); if(isChecked){ //checkBox clicked and checked }else{ //checkBox clicked and unchecked } } }); }
fonte
Conforme declarado acima, o estado verificado do objeto deve ser incluído nas propriedades do objeto. Em alguns casos, você também pode precisar alterar o estado de seleção do objeto clicando no próprio objeto e deixar o CheckBox informar sobre o estado atual (selecionado ou não). A caixa de seleção usará então o estado do objeto na posição real do adaptador fornecido que é (por padrão / na maioria dos casos) a posição do elemento na lista.
Verifique o snippet abaixo, pode ser útil.
import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; import android.provider.MediaStore; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; import java.io.File; import java.io.IOException; import java.util.List; public class TakePicImageAdapter extends RecyclerView.Adapter<TakePicImageAdapter.ViewHolder>{ private Context context; private List<Image> imageList; public TakePicImageAdapter(Context context, List<Image> imageList) { this.context = context; this.imageList = imageList; } @Override public TakePicImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view= LayoutInflater.from(context).inflate(R.layout.image_item,parent,false); return new ViewHolder(view); } @Override public void onBindViewHolder(final TakePicImageAdapter.ViewHolder holder, final int position) { File file=new File(imageList.get(position).getPath()); try { Bitmap bitmap= MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.fromFile(file)); holder.image.setImageBitmap(bitmap ); } catch (IOException e) { e.printStackTrace(); } holder.selectImage.setOnCheckedChangeListener(null); holder.selectImage.setChecked(imageList.get(position).isSelected()); holder.selectImage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { holder.selectImage.setChecked(isChecked); imageList.get(position).setSelected(isChecked); } }); holder.image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (imageList.get(position).isSelected()) { imageList.get(position).setSelected(false); holder.selectImage.setChecked(false); }else { imageList.get(position).setSelected(true); holder.selectImage.setChecked(true); } } }); } @Override public int getItemCount() { return imageList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public ImageView image;public CheckBox selectImage; public ViewHolder(View itemView) { super(itemView); image=(ImageView)itemView.findViewById(R.id.image); selectImage=(CheckBox) itemView.findViewById(R.id.ch); } } }
fonte
No meu caso, funcionou.
@Override public void onViewRecycled(MyViewHolder holder) { holder.checkbox.setChecked(false); // - this line do the trick super.onViewRecycled(holder); }
fonte
Use uma matriz para manter o estado dos itens
No adaptador, use um Mapa ou um SparseBooleanArray (que é semelhante a um mapa, mas é um par de valores-chave int e booleano) para armazenar o estado de todos os itens em nossa lista de itens e, em seguida, use as chaves e valores para comparar ao alternar o estado verificado
No adaptador, crie um
SparseBooleanArray
// sparse boolean array for checking the state of the items private SparseBooleanArray itemStateArray= new SparseBooleanArray();
em seguida, no manipulador de clique de item,
onClick()
use o estado dos itens no itemStateArray para verificar antes de alternar, aqui está um exemplo@Override public void onClick(View v) { int adapterPosition = getAdapterPosition(); if (!itemStateArray.get(adapterPosition, false)) { mCheckedTextView.setChecked(true); itemStateArray.put(adapterPosition, true); } else { mCheckedTextView.setChecked(false); itemStateArray.put(adapterPosition, false); } }
Além disso, use uma matriz booleana esparsa para definir o estado verificado quando a visualização estiver ligada
@Override public void onBindViewHolder(ViewHolder holder, int position) { holder.bind(position); } @Override public int getItemCount() { if (items == null) { return 0; } return items.size(); } void loadItems(List<Model> tournaments) { this.items = tournaments; notifyDataSetChanged(); } class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { CheckedTextView mCheckedTextView; ViewHolder(View itemView) { super(itemView); mCheckedTextView = (CheckedTextView) itemView.findViewById(R.id.checked_text_view); itemView.setOnClickListener(this); } void bind(int position) { // use the sparse boolean array to check if (!itemStateArray.get(position, false)) { mCheckedTextView.setChecked(false);} else { mCheckedTextView.setChecked(true); } }
e adaptador final será como este
fonte
Tive o mesmo problema em uma lista de RecyclerView com switches, e resolvi usando @oguzhand answer, mas com este código dentro do CHECKChangeListener:
if (buttonView.isPressed()) { if (isChecked) { group.setSelected(true); } else { group.setSelected(false); } }else{ if (isChecked) { buttonView.setChecked(false); } else { buttonView.setChecked(true); } }
(Onde 'grupo' é a entidade que desejo selecionar / desmarcar)
fonte
Você precisa separar as interações onBindViewHolder (lógica) com CheckBox e as interações do usuário com checkbox. Usei OnCheckedChangeListener para interações do usuário (obviamente) e ViewHolder.bind () para lógica, é por isso que você precisa definir o listener verificado como nulo antes de configurar o holder e depois que o holder estiver pronto - configure o listener verificado para interações do usuário.
boolean[] checkedStatus = new boolean[numberOfRows]; @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { final ViewHolderItem itemHolder = (ViewHolderItem) holder; //holder.bind should not trigger onCheckedChanged, it should just update UI itemHolder.checkBox.setOnCheckedChangeListener(null); itemHolder.bind(position); itemHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { checkedStatus[holder.getAdapterPosition()] = true; performCheckedActions(); //your logic here } else { checkedStatus[holder.getAdapterPosition()] = false; performUncheckedActions(); //your logic here } } }); } public void bind(int position) { boolean checked = checkedStatus[position]; if (checked) { checkBox.setChecked(false); } else { checkBox.setChecked(true); } }
fonte
O problema desta solução que encontrei é, ao criar um array global estático e usá-lo no ADAPER CLASS "onBindViewHolder", no qual criei todos os objetos / objetos globais necessários.
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> { private Context context; public static class PersonViewHolder extends RecyclerView.ViewHolder { CardView cv; TextView question,category; TextView personAge; ImageView upvote; Button b1; public static int k; private int visibleThreshold = 5; public static int i=0; static int check[]; //Static array PersonViewHolder(View itemView,int i) { super(itemView); if(i==PersonViewHolder.k) { b1=(Button)itemView.findViewById(R.id.loadmore); } else { cv = (CardView)itemView.findViewById(R.id.cv); question = (TextView)itemView.findViewById(R.id.question); category = (TextView)itemView.findViewById(R.id.text_categ); personAge = (TextView)itemView.findViewById(R.id.text1); upvote = (ImageView)itemView.findViewById(R.id.upvote); } } }
Aqui (NO CONSTRUTOR de RVADAPTER CLASS), dei o tamanho ao array igual ao tamanho / número de itens que irei exibir na visualização do reciclador
List<Person> persons; RVAdapter(List<Person> persons){ this.persons = persons; PersonViewHolder.check=new int[persons.size()]; PersonViewHolder.k=persons.size(); }
BindViewHolder, I, Apliquei este conceito em um botão, quando eu clico em um botão, a imagem de fundo do botão muda. O objeto do botão que usei é nomes como "upvote", já que "i" mantém a posição de cada item na visualização do reciclador, usei-o como um índice de array que está funcionando como uma bandeira e que está acompanhando o status dos elementos.
@Override public void onBindViewHolder(final PersonViewHolder personViewHolder, final int i) { if(i==PersonViewHolder.k) { personViewHolder.b1.setText("load more"); } else { personViewHolder.question.setText(persons.get(i).name); personViewHolder.personAge.setText(persons.get(i).age); if(personViewHolder.check[i]==0) {personViewHolder.upvote.setBackgroundResource(R.drawable.noupvote); } else { personViewHolder.upvote.setBackgroundResource(R.drawable.upvote); } personViewHolder.upvote.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(personViewHolder.check[i]==0) {personViewHolder.check[i]=1; personViewHolder.upvote.setBackgroundResource(R.drawable.upvote); } else {personViewHolder.check[i]=0; personViewHolder.upvote.setBackgroundResource(R.drawable.noupvote); } } }); // personViewHolder.personPhoto.setImageResource(persons.get(i).photoId); } }
fonte
Eu tive o mesmo problema. Quando eu estava clicando no botão de alternância do item em meu recyclerView, o botão de alternância marcado aparecia a cada 10 itens (por exemplo, se ele foi clicado em um item com índice 0, itens com 9, 18, 27 índices estavam sendo clicados também). Em primeiro lugar, meu código em onBindViewHolder era:
if (newsItems.get(position).getBookmark() == 1) { holder.getToggleButtonBookmark().setChecked(true); }
Mas então eu adicionei outra declaração
if (newsItems.get(position).getBookmark() == 1) { holder.getToggleButtonBookmark().setChecked(true); //else statement prevents auto toggling } else{ holder.getToggleButtonBookmark().setChecked(false); }
E o problema foi resolvido
fonte
ok, há muitas respostas aqui , postarei meu código e simplesmente explicarei o que fiz ... talvez ajude juniores como eu: D.
1- Objetivo:
vamos criar uma lista de
RecyclerView
que temCheckBox
eRadioButton
, algo assim:2- Classe de modelo
public class ModelClass { private String time; private boolean checked; private boolean free; private boolean paid; public TherapistScheduleModel(String time, boolean checked, boolean free, boolean paid) { this.time = time; this.checked = checked; this.free = free; this.paid = paid; } public boolean isFree() { return free; } public void setFree(boolean free) { this.free = free; } public boolean isPaid() { return paid; } public void setPaid(boolean paid) { this.paid = paid; } public String getTime() { return time; } public void setTime(String time) { this.time = time; } public boolean getChecked() { return checked; } public void setChecked(boolean checked) { this.checked= checked; } }
3-My Amazing Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private Context context; private ListAllListeners listAllListeners; private ArrayList<ModelClass> mDataList; public MyAdapter(Context context, ArrayList<ModelClass> mDataList, ListAllListeners listAllListeners) { this.mDataList = mDataList; this.listAllListeners = listAllListeners; this.context = context; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.single_view, parent, false); return new MyViewHolder(view); } @Override public int getItemCount() { if (mDataList != null) return mDataList.size(); else return 0; } @Override public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) { //important to: //setOnCheckedChangeListener to 'null' holder.checkBoxTime.setOnCheckedChangeListener(null); holder.freeRB.setOnCheckedChangeListener(null); holder.paidRB.setOnCheckedChangeListener(null); //Check Box holder.checkBoxTime.setText(mDataList.get(holder.getAdapterPosition()).getTime()); //here we check if the item is checked or not from the model. if(mDataList.get(holder.getAdapterPosition()).getChecked()) holder.checkBoxTime.setChecked(true); else holder.checkBoxTime.setChecked(false); holder.checkBoxTime.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { if (b) { mDataList.get(holder.getAdapterPosition()).setChecked(true); listAllListeners.onItemCheck(holder.checkBoxTime.getText().toString(), holder.getAdapterPosition()); } else { mDataList.get(holder.getAdapterPosition()).setChecked(false); listAllListeners.onItemUncheck(holder.checkBoxTime.getText().toString(), holder.getAdapterPosition()); } } }); //Radio Buttons if(mDataList.get(holder.getAdapterPosition()).isFree()) holder.freeRB.setChecked(true); else holder.freeRB.setChecked(false); holder.freeRB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { if (b) { mDataList.get(holder.getAdapterPosition()).setFree(true); listAllListeners.onFreeCheck(holder.freeRB.getText().toString(), holder.getAdapterPosition()); } else { mDataList.get(holder.getAdapterPosition()).setFree(false); listAllListeners.onFreeUncheck(holder.freeRB.getText().toString(), holder.getAdapterPosition()); } } }); //***and so on to paidRB*** }//end onBindViewHolder() public interface ListAllListeners { //here is a list of clicked listeners to use them as you want ;). //you can get a list of checked or unChecked of all void onItemCheck(String checkBoxName, int position); void onItemUncheck(String checkBoxName, int position); void onFreeCheck(String name, int pos); void onFreeUncheck(String name, int pos); void onPaidCheck(String name, int pos); void onPaidUncheck(String name, int pos); } class MyViewHolder extends RecyclerView.ViewHolder { CheckBox checkBoxTime; RadioButton freeRB, paidRB; MyViewHolder(View itemView) { super(itemView); checkBoxTime = itemView.findViewById(R.id.timeCheckBox); freeRB = itemView.findViewById(R.id.freeRadioBtn); paidRB = itemView.findViewById(R.id.paidRadioBtn); } }//end class MyViewHolder }//end class
3- Na atividade, você obtém algo assim:
myAdapter= new MyAdapter(getActivity().getApplicationContext(), mDataList, new MyAdapter.ListAllListeners() { @Override public void onItemCheck(String checkBoxName, int position) { Toast.makeText(getActivity(), "" + checkBoxName + " " + position, Toast.LENGTH_SHORT).show(); } @Override public void onItemUncheck(String checkBoxName, int position) { Toast.makeText(getActivity(), "" + checkBoxName + " " + position, Toast.LENGTH_SHORT).show(); } @Override public void onFreeCheck(String name, int position) { Toast.makeText(getActivity(), "" + name + " " + position, Toast.LENGTH_SHORT).show(); } @Override public void onFreeUncheck(String name, int position) { Toast.makeText(getActivity(), "" + name + " " + position, Toast.LENGTH_SHORT).show(); } @Override public void onPaidCheck(String name, int position) { Toast.makeText(getActivity(), "" + name + " " + position, Toast.LENGTH_SHORT).show(); } @Override public void onPaidUncheck(String name, int position) { Toast.makeText(getActivity(), "" + name + " " + position, Toast.LENGTH_SHORT).show(); } });
fonte
public class TagYourDiseaseAdapter extends RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; contexto privado mContext;
List<Datum> deviceList = Collections.emptyList(); /** * Initialize the values * * @param context : context reference * @param devices : data */ public TagYourDiseaseAdapter(Context context, List<Datum> devices, ReCyclerViewItemClickListener mreCyclerViewItemClickListener) { this.mContext = context; this.deviceList = devices; this.mRecyclerViewItemClickListener = mreCyclerViewItemClickListener; } /** * @param parent : parent ViewPgroup * @param viewType : viewType * @return ViewHolder * <p> * Inflate the Views * Create the each views and Hold for Reuse */ @Override public TagYourDiseaseAdapter.OrderHistoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tag_disease, parent, false); TagYourDiseaseAdapter.OrderHistoryViewHolder myViewHolder = new TagYourDiseaseAdapter.OrderHistoryViewHolder(view); return myViewHolder; } /** * @param holder :view Holder * @param position : position of each Row * set the values to the views */ @Override public void onBindViewHolder(final TagYourDiseaseAdapter.OrderHistoryViewHolder holder, final int position) { Picasso.with(mContext).load(deviceList.get(position).getIconUrl()).into(holder.document); holder.name.setText(deviceList.get(position).getDiseaseName()); holder.radioButton.setOnCheckedChangeListener(null); holder.radioButton.setChecked(deviceList.get(position).isChecked()); //if true, your checkbox will be selected, else unselected //holder.radioButton.setChecked(objIncome.isSelected()); holder.radioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { deviceList.get(position).setChecked(isChecked); } }); } @Override public int getItemCount() { return deviceList.size(); } /** * Create The view First Time and hold for reuse * View Holder for Create and Hold the view for ReUse the views instead of create again * Initialize the views */ public class OrderHistoryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { ImageView document; TextView name; CheckBox radioButton; public OrderHistoryViewHolder(View itemView) { super(itemView); document = itemView.findViewById(R.id.img_tag); name = itemView.findViewById(R.id.text_tag_name); radioButton = itemView.findViewById(R.id.rdBtn_tag_disease); radioButton.setOnClickListener(this); //this.setIsRecyclable(false); } @Override public void onClick(View view) { mRecyclerViewItemClickListener.onItemClickListener(this.getAdapterPosition(), view); } }
}
fonte
isso acontecerá quando usar em
setOnCheckedChangeListener
vez desse usosetObClickListener
e dentro de fazer este manuseio fácil:if (list.get(position).isCheck()) { list.get(position).setCheck(false); } else { list.get(position).setCheck(true); }
espero que ajude alguém em caso afirmativo + vote nesta resposta
fonte
Adicionar setItemViewCacheSize (int size) para recyclerview e passar o tamanho da lista resolveu meu problema.
mycode:
mrecyclerview.setItemViewCacheSize(mOrderList.size()); mBinding.mrecyclerview.setAdapter(mAdapter);
Fonte: https://stackoverflow.com/a/46951440/10459907
fonte
isso se deve à criação repetida de visualização, a melhor opção é limpar o cache antes de configurar o adaptador
recyclerview.setItemViewCacheSize(your array.size());
fonte
Exemplo completo de
classe pública ChildAddressAdapter extends RecyclerView.Adapter <ChildAddressAdapter.CartViewHolder> {
private Activity context; private List<AddressDetail> addressDetailList; private int selectedPosition = -1; public ChildAddressAdapter(Activity context, List<AddressDetail> addressDetailList) { this.context = context; this.addressDetailList = addressDetailList; } @NonNull @Override public CartViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(context); View myView = inflater.inflate(R.layout.address_layout, parent, false); return new CartViewHolder(myView); } @Override public void onBindViewHolder(@NonNull CartViewHolder holder, int position) { holder.adress_checkbox.setOnClickListener(view -> { selectedPosition = holder.getAdapterPosition(); notifyDataSetChanged(); }); if (selectedPosition==position){ holder.adress_checkbox.setChecked(true); } else { holder.adress_checkbox.setChecked(false); } } @Override public int getItemCount() { return addressDetailList.size(); } class CartViewHolder extends RecyclerView.ViewHolder { TextView address_text,address_tag; CheckBox adress_checkbox; CartViewHolder(View itemView) { super(itemView); address_text = itemView.findViewById(R.id.address_text); address_tag = itemView.findViewById(R.id.address_tag); adress_checkbox = itemView.findViewById(R.id.adress_checkbox); } }
}
fonte
O que funcionou para mim é anular os ouvintes no viewHolder quando a visualização vai ser reciclada (
onViewRecycled
):override fun onViewRecycled(holder: AttendeeViewHolder) { super.onViewRecycled(holder) holder.itemView.hasArrived.setOnCheckedChangeListener(null); holder.itemView.edit.setOnClickListener { null } }
fonte