Флажок в индексе RecyclerView нажимается дважды - PullRequest
1 голос
/ 06 марта 2019

У меня есть список RecyclerView с CheckBox в CardView, с использованием простого onClickListener.Но при нажатии на индекс 0 индекс 10 также отображается как нажатый.То же самое, если щелкнуть индекс 1, как и 11, индекс 2 - это 12 и т. Д.Как мне решить эту проблему?

Ответы [ 4 ]

0 голосов
/ 11 марта 2019

Проблема в том, что вы не сохранили состояние щелчка для каждого элемента.Вы можете изменить свое pojo и добавить свойство состояния проверки или просто использовать SparseBooleanArray для хранения состояния проверки для всех элементов.

Вот пример использования SparseBooleanArray.

Предполагая, что мы используем простое pojo пользователя:

public class User {
    private String id;
    private String name;
    // constructor, setter, getter
}

First , создайте 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();
    }

    ...
}

Второй , сохраняйте состояние всякий раз, когда вы нажимаете CheckBox в вашем 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);
            }

        });
    }

Last , устанавливаете состояние в 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);
            }

        });
    }
}
0 голосов
/ 06 марта 2019

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;
        }
    });
}
0 голосов
/ 06 марта 2019

Три шага для его решения, и его можно использовать везде, где у вас есть виджет-флажок, и он будет возобновлен.

Во-первых, каждый адаптер имеет соответствующий «боб», привязанный к нему.например, List, T - это bean-компонент.

Во-вторых, добавьте логическое поле 'ischecked' в класс 'bean'.

Наконец, используйте это поле для сброса статуса флажка, когда recycleview повторно использует флажок, и обновите его, когда статус флажка изменяется.

0 голосов
/ 06 марта 2019

Это из-за поведения вашего 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);

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...