Aquí está el XML de mis elementos dentro de 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>
Y aquí está el adaptador RecyclerView que infla el diseño anterior para cada uno de sus elementos:
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));
}
}
El problema es, digamos que tengo 10 elementos dentro de RecyclerView. Cuando marqué la casilla de verificación en el elemento 1, 2, 3, luego me desplacé hacia abajo en RecyclerView, y de repente algunos de los otros elementos, por ejemplo, los elementos 8,9, están marcados. Y cuando vuelvo a desplazarme hacia arriba, los elementos 1 y 3 están marcados pero no el elemento 2. ¿Alguna idea de por qué sucede esto?
android
android-recyclerview
estoy dentro
fuente
fuente
Respuestas:
Ese es un comportamiento esperado. No está configurando su casilla de verificación seleccionada o no. Está seleccionando uno y Ver titular lo mantiene seleccionado. Puede agregar una variable booleana a su objeto ObjectIncome y mantener el estado de selección de su artículo.
Puedes mirar mi ejemplo. Puedes hacer algo como eso:
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); } }); } }
fuente
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); } });
En resumen, ¡es por reciclar las vistas y volver a usarlas!
¿Cómo puedes evitar eso?
1.Compruebe
onBindViewHolder
si debe marcar o desmarcar casillas. no olvides poner if y elseif (...) holder.cbSelect.setChecked(true); else holder.cbSelect.setChecked(false);
myItems
matriz. así que cada vez que se muestra una nueva vista, lee la estatua más nueva del objeto.fuente
isChecked
false
para todo el conjunto de datos en el arranque, entoncesonCheckChanged
me acaba de actualizar elisChecked
valor detrue
ofalse
, y según lo dicho en la respuesta implementar el registro de entrada, ya sea marcada o no.UTILICE ESTO SÓLO SI TIENE UN NÚMERO LIMITADO DE ARTÍCULOS EN SU VISTA DE RECICLADOR.
Intenté usar un valor booleano en el modelo y mantener el estado de la casilla de verificación, pero no ayudó en mi caso. Lo que funcionó para mí es this.setIsRecyclable (false);
public class ComponentViewHolder extends RecyclerView.ViewHolder { public MyViewHolder(View itemView) { super(itemView); .... this.setIsRecyclable(false); }
Puede encontrar más explicación sobre esto aquí https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable ()
NOTA: esta es una solución. Para usarlo correctamente, puede consultar el documento que dice "Las llamadas a setIsRecyclable () siempre deben estar emparejadas (una llamada a setIsRecyclabe (falso) siempre debe coincidir con una llamada posterior a setIsRecyclable (verdadero)). Los pares de llamadas pueden estar anidados , ya que el estado se cuenta internamente por referencia ". No sé cómo hacer esto en código, si alguien puede proporcionar más código sobre esto.
fuente
Simplemente agregue dos métodos de anulación de
RecyclerView
@Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { return position; }
fuente
Puede usar la clase Model para realizar un seguimiento de la casilla de verificación de cada elemento de recyclingView. La referencia completa es de: RecyclerView Checkbox Android
setTag y getTag se utilizan para realizar un seguimiento del estado de la casilla de verificación. Consulte el enlace de referencia completo para obtener más información. También enseña cómo enviar elementos marcados a NEXTACTIVITY .
Haz un 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; } }
crear integer.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="btnplusview">1</integer> <integer name="btnpluspos">2</integer> </resources>
Finalmente el adaptador se ve así:
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); } }
}
fuente
Usando Kotlin, lo único que resolvió este problema para mí fue borrar el
OnCheckedChangeListener
antes de configurar la variable y luego crear un nuevoOnCheckedChangeListener
después de quechecked
se haya configurado.Hago lo siguiente en mi
RecyclerView.ViewHolder
task.setOnCheckedChangeListener(null) task.isChecked = item.status task.setOnCheckedChangeListener { _: CompoundButton, checked: Boolean -> item.status = checked ... do more stuff ... }
fuente
Como se indicó anteriormente, el estado verificado del objeto debe incluirse dentro de las propiedades del objeto. En algunos casos, es posible que también deba cambiar el estado de selección del objeto haciendo clic en el objeto en sí y dejar que CheckBox le informe sobre el estado real (seleccionado o no seleccionado). La casilla de verificación usará el estado del objeto en la posición real del adaptador dado que es (por defecto / en la mayoría de los casos) la posición del elemento en la lista.
Consulte el fragmento a continuación, puede 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); } } }
fuente
En mi caso esto funcionó.
@Override public void onViewRecycled(MyViewHolder holder) { holder.checkbox.setChecked(false); // - this line do the trick super.onViewRecycled(holder); }
fuente
Use una matriz para mantener el estado de los elementos
En el adaptador, use un Map o SparseBooleanArray (que es similar a un mapa pero es un par clave-valor de int y boolean) para almacenar el estado de todos los elementos en nuestra lista de elementos y luego use las claves y valores para comparar al alternar el estado marcado
En el Adaptador, cree un
SparseBooleanArray
// sparse boolean array for checking the state of the items private SparseBooleanArray itemStateArray= new SparseBooleanArray();
luego, en el controlador de clic del elemento,
onClick()
use el estado de los elementos en itemStateArray para verificar antes de alternar, aquí hay un ejemplo@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); } }
también, use una matriz booleana dispersa para establecer el estado marcado cuando la vista está vinculada
@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); } }
y el adaptador final será como este
fuente
Debe separar las interacciones onBindViewHolder (lógica) con CheckBox y las interacciones del usuario con checkbox. Utilicé OnCheckedChangeListener para las interacciones del usuario (obviamente) y ViewHolder.bind () para la lógica, es por eso que debe configurar el oyente verificado en nulo antes de configurar el titular y después de que el titular esté listo: configure el oyente verificado para las interacciones del usuario.
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); } }
fuente
Recomiendo que no se use
checkBox.setOnCheckedChangeListener
enrecyclerViewAdapter
. Porque al desplazarse, secheckBox.setOnCheckedChangeListener
activará el adaptador. No es seguro . En su lugar, utilicecheckBox.setOnClickListener
para interactuar con las entradas del usuario.Por ejemplo:
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 } } }); }
fuente
El problema de esta solución que encontré es, mediante la creación de una matriz global estática y su uso en "onBindViewHolder" ADAPER CLASS, en la que creé todos los varaibles / objetos globales necesarios.
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); } } }
Aquí (EN CONSTRUCTOR de RVADAPTER CLASS) le di un tamaño a la matriz igual al tamaño de / no de elementos que voy a mostrar en la vista del reciclador
List<Person> persons; RVAdapter(List<Person> persons){ this.persons = persons; PersonViewHolder.check=new int[persons.size()]; PersonViewHolder.k=persons.size(); }
BindViewHolder, yo, apliqué este concepto en un botón, cuando hago clic en un botón, la imagen de fondo del botón cambia. El objeto del botón que usé son nombres como "upvote", ya que "i" mantiene la posición de cada elemento en la vista de reciclador, lo usé como un índice de matriz que funciona como una bandera y que mantiene un registro del estado de los 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); } }
fuente
Tuve el mismo problema. Cuando estaba haciendo clic en el botón de alternancia del elemento en mi reciclador, el botón de alternancia comprobado apareció en cada décimo elemento (por ejemplo, si se hizo clic en un elemento con índice 0, también se hizo clic en elementos con índices 9, 18, 27). En primer lugar, mi código en onBindViewHolder fue:
if (newsItems.get(position).getBookmark() == 1) { holder.getToggleButtonBookmark().setChecked(true); }
Pero luego agregué otra declaración
if (newsItems.get(position).getBookmark() == 1) { holder.getToggleButtonBookmark().setChecked(true); //else statement prevents auto toggling } else{ holder.getToggleButtonBookmark().setChecked(false); }
Y el problema se solucionó
fuente
está bien, hay muchas respuestas aquí voy a publicar mi código y simplemente le explicará lo que hice ... es tal vez jóvenes de ayuda como yo: D.
1- Objetivo:
crearemos una lista de lo
RecyclerView
que tieneCheckBox
yRadioButton
, algo como esto:2- Clase 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-Mi asombroso adaptador
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- En Actividad les obtienes algo como esto:
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(); } });
fuente
Tuve el mismo problema en una lista de RecyclerView con interruptores, y lo resolví usando la respuesta de @oguzhand, pero con este código dentro del checkChangeListener:
if (buttonView.isPressed()) { if (isChecked) { group.setSelected(true); } else { group.setSelected(false); } }else{ if (isChecked) { buttonView.setChecked(false); } else { buttonView.setChecked(true); } }
(Donde 'grupo' es la entidad que quiero seleccionar / deseleccionar)
fuente
La clase pública TagYourDiseaseAdapter extiende RecyclerView.Adapter {ReCyclerViewItemClickListener privado 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); } }
}
fuente
esto sucederá cuando se use en
setOnCheckedChangeListener
lugar de ese usosetObClickListener
y dentro de eso solo haga este fácil manejo:if (list.get(position).isCheck()) { list.get(position).setCheck(false); } else { list.get(position).setCheck(true); }
espero que ayude a alguien si es así + vote a esta respuesta
fuente
Agregar setItemViewCacheSize (int size) a recyclingview y pasar el tamaño de la lista resolvió mi problema.
mi código:
mrecyclerview.setItemViewCacheSize(mOrderList.size()); mBinding.mrecyclerview.setAdapter(mAdapter);
Fuente: https://stackoverflow.com/a/46951440/10459907
fuente
Esto se debe a que se crea una y otra vez la vista, la mejor opción es borrar el caché antes de configurar el adaptador
recyclerview.setItemViewCacheSize(your array.size());
fuente
Ejemplo completo de
clase pública ChildAddressAdapter extiende 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); } }
}
fuente
Lo que funcionó para mí es anular los oyentes en viewHolder cuando la vista se va a reciclar (
onViewRecycled
):override fun onViewRecycled(holder: AttendeeViewHolder) { super.onViewRecycled(holder) holder.itemView.hasArrived.setOnCheckedChangeListener(null); holder.itemView.edit.setOnClickListener { null } }
fuente