RecyclerView中的CheckBox继续检查不同的项目
这是RecyclerView中的项目的XML
<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>
这里是RecyclerView适配器,它扩大了上面的每个项目的布局:
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)); } }
问题是,假设我在RecyclerView中有10个项目。 当我检查1,2,3项的checkbox,然后向下滚动RecyclerView,突然其他一些项目,例如项目8,9被检查。 当我再次滚动时,项目1和3被检查,但不是项目2.任何想法,为什么发生这种情况?
这是正常的。 您没有设置您的checkboxselect或不。 您正在select一个和查看持有人保持select。 您可以添加一个布尔variables到您的ObjectIncome对象,并保持您的项目的select状态。
你可以看看我的例子。 你可以这样做:
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); } }); } }
我尝试在模型中使用布尔值,并保持checkbox的状态,但它没有帮助我的情况。 什么为我工作this.setIsRecyclable(false);
public class ComponentViewHolder extends RecyclerView.ViewHolder { public MyViewHolder(View itemView) { super(itemView); .... this.setIsRecyclable(false); }
更多的解释可以在这里findhttps://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable()
注意:这是一个解决方法。 要正确地使用它,你可以参考文档中的“调用setIsRecyclable()应该总是配对(一个调用setIsRecyclabe(false)应该总是匹配以后调用setIsRecyclable(true))。对调用可能是嵌套的,因为国家是内部参考计数的。“ 我不知道如何在代码中做到这一点,如果有人可以提供更多的代码。
总之,它是因为回收意见,并再次使用它们!
你怎么能避免:1.in onBindViewHolder检查你是否应该选中或取消选中框。 nt忘记把这两个如果和别的
if (...) holder.cbSelect.setChecked(true); else holder.cbSelect.setChecked(false);
- 把一个听众的checkbox! 每当它的检查的雕像改变,更新你的myItems数组中相应的对象! 所以每当一个新的视图显示,它读取对象的最新雕像。
您可以使用Model类来跟踪每个recyclerView项目的checkbox。 完整的参考来自: RecyclerViewcheckboxAndroid
setTag和getTag用于跟踪checkbox状态。 查看完整的参考链接了解更多信息。 它还教如何发送检查的项目NEXTACTIVITY 。
制作模型
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; } }
创buildinteger.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="btnplusview">1</integer> <integer name="btnpluspos">2</integer> </resources>
最后适配器看起来像这样:
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); } }
}
你需要分开onBindViewHolder(逻辑)与CheckBox的交互和用户与checkbox的交互。 我使用OnCheckedChangeListener进行用户交互(显然)和ViewHolder.bind()用于逻辑,这就是为什么您需要在设置持有者和持有者准备好之前将已检查的侦听器设置为null – 为用户交互configuration已检查的侦听器。
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); } }
我发现这个解决scheme的问题是,通过创build一个静态全局数组,并在“onBindViewHolder”ADAPER CLASS中使用它,在这个类中我创build了所有需要的全局variables/对象。
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); } } }
在这里(在RVADAPTER类的构造函数)我给数组的大小等于我要在回收视图中显示的项目的大小/
List<Person> persons; RVAdapter(List<Person> persons){ this.persons = persons; PersonViewHolder.check=new int[persons.size()]; PersonViewHolder.k=persons.size(); }
BindViewHolder,I,将这个概念应用到一个button上,当我点击一个button时,button的背景图像会改变。 我使用的button对象名称为“upvote”,因为“i”在回收器视图中保存了每个项目的位置,所以我将其用作标记工作的数组的索引,并且跟踪元素的状态。
@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); } }
我有一个RecyclerView列表中的开关同样的问题,并解决了它使用@oguzhand答案,但在checkedChangeListener内的代码:
if (buttonView.isPressed()) { if (isChecked) { group.setSelected(true); } else { group.setSelected(false); } }else{ if (isChecked) { buttonView.setChecked(false); } else { buttonView.setChecked(true); } }
(其中“组”是我想要select/取消select的实体)
我build议不要在recyclerViewAdapter
使用checkBox.setOnCheckedChangeListener
。 因为滚动recyclerView, checkBox.setOnCheckedChangeListener
将被适配器触发。 这是不安全的 。 相反,使用checkBox.setOnClickListener
与用户input交互。
例如:
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 } } }); }
只需添加recyclerview的两个覆盖方法
@Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { return position; }
什么对我来说是视图将被回收( onViewRecycled
)时取消viewHolder上的监听器:
override fun onViewRecycled(holder: AttendeeViewHolder) { super.onViewRecycled(holder) holder.itemView.hasArrived.setOnCheckedChangeListener(null); holder.itemView.edit.setOnClickListener { null } }