RecyclerView点击首个条目时末尾条目同步选中问题求助
解决RecyclerView点击第一个条目时最后一个同步选中的问题
这个问题我太熟了!根源就是RecyclerView的ViewHolder复用机制——当条目被滚出屏幕或者回收后,会被用来显示新的条目,如果没给每个条目单独维护选中状态,就会出现这种状态错乱的情况。下面给你一套完整的解决步骤:
1. 给数据模型添加选中状态字段
首先,你的兴趣数据类(比如叫Interest)里需要加一个字段来记录每个条目的选中状态,因为ViewHolder会被复用,绝对不能把状态存在ViewHolder里。
public class Interest { private String interestName; private boolean isSelected; // 专门用来存当前条目的选中状态 // 构造方法、getter和setter必须要有 public Interest(String interestName) { this.interestName = interestName; this.isSelected = false; // 默认未选中 } public String getInterestName() { return interestName; } public boolean isSelected() { return isSelected; } public void setSelected(boolean selected) { isSelected = selected; } }
2. 在ViewHolder中绑定选中状态
修改你的InterestViewHolder,添加一个bind方法,每次绑定数据时根据数据的isSelected状态来设置条目的样式(比如背景色、文字颜色,区分选中和未选中)。
public class InterestViewHolder extends RecyclerView.ViewHolder { private TextView interestTv; public InterestViewHolder(View itemView) { super(itemView); interestTv = itemView.findViewById(R.id.interests_textview); } // 绑定数据和状态的方法 public void bind(Interest interest) { interestTv.setText(interest.getInterestName()); // 根据选中状态设置样式,这里举个例子,你可以换成自己的样式逻辑 if (interest.isSelected()) { interestTv.setBackgroundColor(Color.parseColor("#E0E0E0")); // 选中时浅灰色背景 } else { interestTv.setBackgroundColor(Color.WHITE); // 未选中时白色背景 } } }
3. 修复点击事件逻辑
在onCreateViewHolder里设置点击事件时,要更新对应数据的选中状态,然后只刷新当前条目(不要全局刷新,影响性能)。同时要注意用getAdapterPosition()获取正确的位置,避免位置错乱。
@Override public InterestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { TextView v = (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.interests_textview, parent, false); InterestViewHolder holder = new InterestViewHolder(v); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int currentPosition = holder.getAdapterPosition(); // 避免无效位置(比如条目已被删除的情况) if (currentPosition != RecyclerView.NO_POSITION) { Interest currentInterest = mInterestList.get(currentPosition); // 切换选中状态 currentInterest.setSelected(!currentInterest.isSelected()); // 只刷新当前条目,精准更新 notifyItemChanged(currentPosition); } } }); return holder; } // 别忘了在onBindViewHolder里调用bind方法 @Override public void onBindViewHolder(InterestViewHolder holder, int position) { Interest interest = mInterestList.get(position); holder.bind(interest); }
额外提示
如果你的需求是单选模式(只能选一个兴趣),点击时还要先把之前选中的条目状态设为false,再设置当前条目为true,然后刷新这两个条目:
// 在点击事件里修改 int currentPosition = holder.getAdapterPosition(); if (currentPosition != RecyclerView.NO_POSITION) { // 先找到之前选中的条目 for (int i = 0; i < mInterestList.size(); i++) { if (mInterestList.get(i).isSelected()) { mInterestList.get(i).setSelected(false); notifyItemChanged(i); break; } } // 设置当前条目为选中 Interest currentInterest = mInterestList.get(currentPosition); currentInterest.setSelected(true); notifyItemChanged(currentPosition); }
这样修改后,每个条目的选中状态都存在对应的数据模型里,ViewHolder复用的时候会重新绑定正确的状态,就不会出现首尾条目同步选中的问题啦!
内容的提问来源于stack exchange,提问作者Artur Schwarz
相关产品推荐
相关产品推荐

