Страницы

Поиск по вопросам

понедельник, 15 октября 2018 г.

RecyclerView CheckBox

Знаю, что эта тема много раз поднималась для ListView, но ни как не могу разобраться с ней на примере RecyclerView
Есть RecyclerView, в котором повторяются CardView. RecyclerView заполняется адаптером. Когда отмечаю несколько чек-боксов, при скроллинге вниз, некоторые чек-боксы сами становятся отмеченными. Понял, что нужно описать этот момент в адаптере, но не нашел, где объясняется как правильно и почему. Подскажите пожалуйста. Вот код адаптера:
public class AddFilterAdapter extends RecyclerView.Adapter {
private ArrayList mDataset;
public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public CheckBox mCheckBox;
public ViewHolder(View v) { super(v); mTextView = (TextView) v.findViewById(R.id.tv_filter_card); mCheckBox = (CheckBox) v.findViewById(R.id.mcheckBox);
} }
public AddFilterAdapter(ArrayList dataset) { mDataset = dataset; }
@Override public AddFilterAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.add_filter_card, parent, false);
ViewHolder vh = new ViewHolder(v); return vh; }
@Override public void onBindViewHolder(ViewHolder holder, int position) {
holder.mTextView.setText(mDataset.get(position)); }
@Override public int getItemCount() { return mDataset.size(); } }


Ответ

Дело в том, что айтемы переиспользуются и для корректной работы нужно принудительно сохранять изменения в чекбоксах в отдельное хранилище, а при выводе востанавливать значения из него.
Kласс RecyclerView не реализует никаких готовых методов для работы с чекбоксами, поэтому все нужно писать самому. Возможный вариант - завести отдельный массив булевых переменных и сохранять в него текущие состояния чекбоксов. На чекбоксы повешать слушатели, чтобы контролировать изменения состояний. При выводе в адаптере восстанавливать сохраненное ранее состояние.
public class AddFilterAdapter extends RecyclerView.Adapter {
private ArrayList mDataset; boolean[] checked;
public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public CheckBox mCheckBox;
public ViewHolder(View v) { super(v); mTextView = (TextView) v.findViewById(R.id.tv_filter_card); mCheckBox = (CheckBox) v.findViewById(R.id.mcheckBox);
} }
public AddFilterAdapter(ArrayList dataset) { mDataset = dataset; checked = new boolean[mDataset.size()]; }
@Override public AddFilterAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.add_filter_card, parent, false);
ViewHolder vh = new ViewHolder(v); return vh; }
@Override public void onBindViewHolder(ViewHolder holder, final int position) {
holder.mTextView.setText(mDataset.get(position)); holder.mCheckBox.setChecked(checked[position]); holder.mCheckBox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { checked[position] = !checked[position]; } }); }
public boolean[] getChecked(){ return checked;
@Override public int getItemCount() { return mDataset.size(); } }
метод getChecked() вернет полученные значения из адаптера "наружу", например в активити, где эти данные можно обработать:
// код в активити для получения чекнутых значений. boolean[] checked = filterAdapter.getChecked();
Так же вы можете не заводить отдельный массив, а создать дополнительное поле в своей модели данных и писать сохранение состояния туда, так же оттуда и восстанавливать текущее состояние для вывода. Соответственно и возвращать через геттер коллекцию самих моделей. Это может быть полезно, когда требуется связать данные самой модели и их признак чекнутости.

Комментариев нет:

Отправить комментарий