Ключом к представлению переработчика или любого представления адаптера в Android является то, что адаптер адаптирует ваши модели к представлению. В вашем случае ваш вид - TextView
плюс Switch
, поэтому ваш адаптер должен адаптировать некоторую модель к этому виду. В этом случае я бы выбрал простую модель, подобную этой:
class ItemModel {
String text;
boolean on;
}
Я упустил геттеры и сеттеры для простоты
Эта модель содержит строку text
, которая отражает текст в вашем текстовом представлении, и логическое значение on
, которое отражает состояние переключателя. Когда true, переключатель проверен, а когда false, он не проверен.
Существует множество способов представить эту модель. Я выбрал этот, вы можете выбрать другой. Дело в том, что вам нужно где-то сохранить состояние, и это то, что я имею в виду под моделью - модель представления.
Теперь давайте создадим адаптер, который может выполнять 2 действия: обновлять модели при нажатии переключателя и сообщать операции, что состояние переключателя изменилось. Вот один из способов сделать это:
public class ItemsAdapter extends
RecyclerView.Adapter<ItemsAdapter.ViewHolder> {
@NonNull
private final List<ItemModel> itemModels;
@Nullable
private OnItemCheckedChangeListener onItemCheckedChangeListener;
ItemsAdapter(@NonNull List<ItemModel> itemModels) {
this.itemModels = itemModels;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
ItemModel item = itemModels.get(position);
holder.text.setText(item.text);
holder.switchCompat.setChecked(item.on);
// Make sure we update the model if the user taps the switch
holder.switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int adapterPosition = holder.getAdapterPosition();
ItemModel tapped = itemModels.get(adapterPosition);
itemModels.set(adapterPosition, new ItemModel(tapped.text, isChecked));
if (onItemCheckedChangeListener != null) {
onItemCheckedChangeListener.onItemCheckedChanged(adapterPosition, isChecked);
}
}
});
}
@Override
public void onViewRecycled(@NonNull ViewHolder holder) {
super.onViewRecycled(holder);
holder.switchCompat.setOnCheckedChangeListener(null);
}
@Override
public int getItemCount() {
return itemModels.size();
}
public void setOnItemCheckedChangeListener(@Nullable OnItemCheckedChangeListener onItemCheckedChangeListener) {
this.onItemCheckedChangeListener = onItemCheckedChangeListener;
}
interface OnItemCheckedChangeListener {
/**
* Fired when the item check state is changed
*/
void onItemCheckedChanged(int position, boolean isChecked);
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView text;
SwitchCompat switchCompat;
ViewHolder(View itemView) {
super(itemView);
text = itemView.findViewById(R.id.item_text);
switchCompat = itemView.findViewById(R.id.item_switch);
}
}
}
Есть много чего переварить, но давайте сосредоточимся на важных битах - метод onBindViewHolder
. Первые 3 строки - это классическая переработка вида. Мы берем модель в правильном положении и устанавливаем элементы в представлении, которые соответствуют атрибутам модели.
Тогда становится интереснее. Мы устанавливаем OnCheckedChangeListener
для обновления модели и активности каждый раз, когда коммутатор меняет состояние. Первые 3 строки изменяют модель в адаптере, а остальные используют пользовательский интерфейс OnItemCheckedChangeListener
, чтобы уведомить слушателя об изменении коммутатора. Важно отметить, что внутри метода OnCheckedChangeListener
вы больше не должны использовать position
, а вместо этого использовать holder.getAdapterPosition
. Это даст вам правильное положение в списке данных адаптера.
Поскольку у адаптера всегда есть правильные модели в списке данных, каждый раз, когда вызывается метод onBindViewHolder
, адаптер точно знает, как настроить представление. Это означает, что при прокрутке и переработке представлений будет сохраняться состояние каждого элемента в моделях в списке data
.
Важно удалить OnCheckedChangeListener
, когда представление будет переработано - onViewRecycled
. Это позволяет избежать путаницы в подсчете, когда адаптер устанавливает значение switchCompat
в onBindViewHolder
.
Вот пример того, как может выглядеть упражнение:
public class MainActivity extends AppCompatActivity {
private int count = 0;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<ItemModel> data = new ArrayList<>();
for (int i = 1; i <= 100; i++)
data.add(new ItemModel("Item " + i, false));
ItemsAdapter adapter = new ItemsAdapter(data);
((RecyclerView) findViewById(R.id.recyclerview)).setAdapter(adapter);
final TextView countTextView = findViewById(R.id.count);
drawCount(countTextView);
adapter.setOnItemCheckedChangeListener(new ItemsAdapter.OnItemCheckedChangeListener() {
@Override
public void onItemCheckedChanged(int position, boolean isChecked) {
if (isChecked)
count++;
else
count--;
drawCount(countTextView);
}
});
}
private void drawCount(TextView countTextView) {
countTextView.setText(String.valueOf(count));
}
}
Этот код предназначен для демонстрации идеи, а не для следования :) В любом случае, мы настраиваем все начальное состояние, а затем настраиваем настраиваемый прослушиватель OnItemCheckedChangeListener
для обновления представления текста в действии.
Файлы макетов здесь не должны быть релевантными, но, как вы можете себе представить, у действия есть текстовое представление с идентификатором count
, и есть представление переработчика с идентификатором recyclerview
.
Надеюсь, это поможет