我在RecyclerView
有CheckBox
的CardView
列表,使用简单的onClickListener
。但是当点击索引0
时,索引10
也会显示为已点击。如果点击指数1
同样是11
,索引2
也是12
,依此类推。我该如何解决这个问题?
解决它的三个步骤,可以在任何有复选框小部件的地方使用,它将被重新启动。
首先,每个适配器都有一个相应的'bean'绑定它。例如,List,T是bean。
其次,在'bean'类中添加一个布尔字段'ischecked'。
最后,使用此字段可以在recyclelerview重新使用复选框时重置复选框的状态,并在复选框的状态更改时更新它。
RecyclerView
将在滚动时重复使用前一行的布局,因此如果您检查项目1并滚动,项目11仍将被检查,除非被告知不是。
在onBindViewHolder
中,您希望将布局设置为您正在显示的对象的当前状态。
例如,假设我们有一个Dogs
列表,我们可以标记我们是否宠爱了Dog
。
class Dog {
public boolean hasPet = false;
public String name;
}
现在,如果您要显示每个Dog
,您可以这样做。
void onBindViewHolder(MyViewHolder holde, int position) {
Dog dog = list[position];
holder.name = dog.name;
// Remove any onCheckChangeListener or else we'll change the previously rendered dog.
holder.check.setOnCheckedChangeListener(null);
// Set the checkbox to the current state of the dog.
holder.check.setChecked(dog.hasPet);
// Add a new onCheckChangeListener with the current dog.
holder.check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Logger.d("Clicked.");
dog.hasPet = isChecked;
}
});
}
这是因为你的RecyclerView
的行为。 RecyclerView
尝试回收已经生成的视图,只需对数据进行最小的更改。因此,为了在列表项中精确填充数据,您需要准确说明需要显示的内容。
在您的情况下,您需要保持复选框的轨道单击某处(可能在不同的数组中),以便您可以相应地填充视图。让我们考虑以下代码。
// Let us create an integer array having the same size of your list that is being passed to your RecyclerView
// Initially, all elements in the array is zero.
private int[] array = new int[yourList.size()];
现在在你的onBindViewHolder
,我想你已经为你的onClickListener
实施了CheckBox
。因此,当您单击CheckBox
时,将array
中的相应元素设置为1
。
public void onClick(int position) {
// Checbox click action here
if (array[position] == 0)
array[position] = 1; // Use the position of your adapter to set the value.
else array[position] = 0; // Toggle the values on check/uncheck
}
现在在填充onBindViewHolder
的CheckBox
中,检查其在array
中的位置值并相应地设置检查状态。
if(array[position] == 1) checkBox.setChecked(true);
else checkBox.setChecked(false);
希望有所帮助!
问题是因为您没有保留每个项目的点击状态。您可以修改pojo并添加check state属性,或者只需使用SparseBooleanArray来保存所有项目的检查状态。
这里是使用SparseBooleanArray的示例。
假设我们正在使用User的简单pojo:
public class User {
private String id;
private String name;
// constructor, setter, getter
}
首先,创建一个SparseBooleanArray来保存所选的标志,如下所示:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {
private List<User> mUsers;
private SparseBooleanArray mSelectedFlags;
public UserAdapter(List<User> users) {
mUsers = users;
mSelectedFlags = new SparseBooleanArray();
}
...
}
其次,每当你单击ViewHolder
中的CheckBox时保存状态:
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public TextView tvId;
public CheckBox cbxSelect;
public ViewHolder(View itemView) {
super(itemView);
...
// bind view here
cbxSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// set the state for specific item by its position.
mSelectedFlags.put(getAdapterPosition()), isChecked);
}
});
}
最后,在onBindViewHolder
中设置状态:
@Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
int itemPosition = viewHolder.getAdapterPosition();
User user = mUsers.get(itemPosition);
viewHolder.tvId.setText(user.getId());
viewHolder.tvName.setText(user.getName());
// set the check state for each item
// SparseBooleanArray will return false as default value
viewHolder.cbxSelect.setChecked(mFlagSelected.get(itemPosition));
}
完整的适配器将是这样的:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {
private List<User> mUsers;
private SparseBooleanArray mSelectedFlags;
public UserAdapter(List<User> users) {
mUsers = users;
mSelectedFlags = new SparseBooleanArray();
}
@Override
public UserAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
// inflate and return view holder.
return viewHolder;
}
@Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
int itemPosition = viewHolder.getAdapterPosition();
User user = mUsers.get(itemPosition);
viewHolder.tvId.setText(user.getId());
viewHolder.tvName.setText(user.getName());
// set the check state for each item
// SparseBooleanArray will return false as default value
viewHolder.cbxSelect.setChecked(mFlagSelected.get(itemPosition));
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public TextView tvId;
public CheckBox cbxSelect;
public ViewHolder(View itemView) {
super(itemView);
...
// bind view here
cbxSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// set the state for specific item by its position.
mSelectedFlags.put(getAdapterPosition()), isChecked);
}
});
}
}