Элементы RecyclerView не отображаются правильно

В моем onBindViewHolder моего RecyclerView.Adapter<SearchAdapter.ViewHolder>, когда пользователь нажимает кнопку cardview, кнопка становится видимой. Но когда я прокручиваю recyclerview, некоторые другие кнопки элементов отображаются как видимые тоже. Почему это происходит?

это мой код:

@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
    viewHolder.card.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (viewHolder.content_layout.getVisibility() == View.VISIBLE) {
                viewHolder.content_layout.setVisibility(View.GONE);
                viewHolder.address.setMaxLines(2);
                viewHolder.attribute.setMaxLines(2);
            } else {
                viewHolder.content_layout.setVisibility(View.VISIBLE);
                viewHolder.address.setMaxLines(8);
                viewHolder.attribute.setMaxLines(8);
            }
        }
    });
    ...
}

Ответ 1

Как только вы начнете прокрутку списка, ваши просмотры будут переработаны. Это означает, что ранее завышенный ViewHolder (некоторые из которых создаются в onCreateViewHolder) повторно используется.
Итак, вам нужно запомнить защёщенные позиции (например, через SparseBooleanArray) и проверить onBindViewHolder, следует ли быть видимым (ранее нажатым) или нет.

Вы можете найти базовый пример использования SparseBooleanArray в fooobar.com/questions/128033/...

Ответ 2

Кнопки "других" видимых элементов - те, которые используются одним и тем же наблюдателем, который был изменен в обратном вызове. Таким образом, поскольку пользователи (и представления) переработаны:

  • Они должны хранить информацию, которая может быть получена каждый раз, когда зритель привязан к позиции.

  • Все, что может быть изменено в состоянии представлений, должно быть обновлено в onBindViewHolder()

В вашем случае вы должны сохранить 'selected' в другом месте и reset видимость и максимальные значения в onBindViewHolder() (не только в обратном вызове)

Ответ 3

Хорошей идеей является создание объекта класса со всеми данными, которые вам нужны для одного элемента в представлении recycler, а также добавить туда один логический isItemWasClicked и внутри onBindViewHolder() проверить это логическое и сделать кнопки видимыми или нет. Например:

public class OneItemOfList{
    int priceToDisplay;
    String name;
    String date;
    boolean wasClicked;
}

public class YourAdapter extends RecyclerView.Adapter<OneItemOfList.ViewHolder> {
ArrayList<OneItemOfList> items;
...
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
    viewHolder.view.setText(items.get(position).name);
    if (items.get(position).wasClicked)
        viewHolder.button.setVisible(View.VISIBLE);
    else
        viewHolder.button.setVisible(View.GONE);
    viewHolder.view2.setOnClickListener(...
        OnClick(...){
            items.get(position).wasClicked = !items.get(position).wasClicked;
        });
}
...
}

Ответ 4

создайте массив, например Boolean array, и когда каждая позиция нажата, установите true в том же положении массива. и в onBindViewHolder проверьте, установлен ли этот массив [позиция] true, чтобы этот элемент был видимым, если.