RecyclerView索引中的复选框被单击了两次

时间:2019-03-06 00:10:31

标签: android checkbox android-recyclerview

我有一个RecyclerView列表,其中的CheckBox中的CardView使用了简单的onClickListener。但是,当单击索引0时,索引10也显示为单击。如果单击了索引1,则同样,单击11,单击索引2,也单击12,依此类推。我该如何解决这个问题?

4 个答案:

答案 0 :(得分:0)

这是因为您的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);

希望有帮助!

答案 1 :(得分:0)

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;
        }
    });
}

答案 2 :(得分:0)

解决此问题的三个步骤,可以在任何具有复选框小部件的地方使用,然后将继续使用它。

首先,每个适配器都有一个对应的“ bean”绑定到它。例如List,T是bean。

第二,在'bean'类中添加一个'ischecked'布尔字段。

最后,使用此字段可在recycleview重用复选框时重置复选框的状态,并在更改复选框状态时进行更新。

答案 3 :(得分:0)

问题是因为您没有保持每个项目的点击状态。您可以修改pojo并添加检查状态属性,也可以简单地使用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中的复选框时,保存状态:

    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);
            }

        });
    }
}