Выберите элементы в RecyclerView

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

Я хочу выбрать элемент в RecyclerView, изменить фон этого вида элемента и сохранить позицию выбранного элемента.

Основная проблема заключается в том, что у вас есть onCreateViewHolder (в адаптере), onBindViewHolder (в адаптере) и конструктор ViewHolder, и все работают с разными методами. Теперь я даже не знаю, где положить onClickListener (в предыдущих проектах я поместил его в ViewHolder), потому что люди также предлагают другие два метода.

Моя идея состояла в том, чтобы хранить каждый список ViewHolder (или View) в списке, поэтому я могу ссылаться на каждую строку и менять фон. Но это не сработало для меня, потому что, когда я пытаюсь добавить в список View (или ViewHolders), из любого из трех мест (onCreateVH, onBindVH, VH-класс), мое приложение сбой по какой-либо причине (null pointer ex).

Любые предложения? Где и как его реализовать?

Ответ 1

Смотрите как часть 1, так и часть 2. Отличные уроки по RecyclerView. В части 2 четко объясняется, как реализовать RecyclerView с помощью элемента select, onclick и всех других материалов списка. Исходный код также указан на github. Надеюсь, что это поможет.

http://www.bignerdranch.com/blog/recyclerview-part-2-choice-modes/

Ответ 2

Сделать глобальную переменную для хранения позиции и обработчика кликов в ViewHolder. Onclick элемента, измените значение глобальной позиции, например

textView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        globalPosition=getAdapterPosition();
        notifyDataSetChanged();
    }
});

то в onBindViewHolder

if(postion==globalPosition)
{
    //change color like
    textview.setTextColor(Color.RED);
}
else
{
    //revert back to regular color 
    textview.setTextColor(Color.WHITE);
}

с этим кодом, элемент, который вы нажали, получит красный цвет, а все остальные будут в белом цвете.

Ответ 3

Прежде всего, вы спросили, где положить onClickListener - вы должны поместить его в onBindViewHolder. Вы также можете подключить onClickListener в классе ViewHolder вашего элемента так:

public class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                }
            });
        }
    }

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

Ссылка, предоставленная Rafiduzzaman Sonnet, является хорошим учебным пособием, чтобы понять многое о настройке RecyclerView, но я думаю, что это делает одно поведение выбора сложным. Я собираюсь ответить всесторонне, давая все, что может потребоваться, чтобы заставить его работать. Здесь, как я реализовал единое поведение выбора:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    final YourItemViewHolder itemViewHolder = (YourItemViewHolder) holder;
    //This will remember which one was selected
    itemViewHolder.getItemSelectionIndicator()
            .setSelected(position == mSelectedPosition);
        itemViewHolder.getItemWrapperView()
            .setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(mLogTag, "Tapped on " + position);
                    //This is the previous selection
                    notifyItemChanged(mSelectedPosition);
                    itemViewHolder.getItemSelectionIndicator().setSelected(true);
                    mSelectedPosition = position;
                    //This is the new selection
                    notifyItemChanged(position);
                }
            });

getItemSelectionIndicator() и getItemWrapperView() - методы внутри элемента ViewHolder, которые возвращают определенные представления из макета элемента. Элемент ItemWrapperView может быть самым верхним линеаром /RelativeLayout, который обертывает весь элемент. Настройка прослушивателя кликов на нем гарантирует, что клики будут работать, если пользователь закроет в любом месте просмотра элемента.

ItemSelectionIndicator может представлять собой Linear или RelativeLayout, для которого был установлен фон списка, отображаемый в списке состояний. Это означает, что, когда он установлен как выбранный, он автоматически отображает фигуру, которая автоматически отображает выделение. Когда он будет выбран как невыбранный, извлекаемый будет удален автоматически. Это выглядит так:

<RelativeLayout
        android:id="@+id/selection_indicator"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/selection_indicator_state_list"/>

Это selection_indicator_state_list.xml в res/drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Selected background -->
    <item android:state_selected="true"
          android:drawable="@drawable/item_selection_shape"/>
    <!-- Unselected background -->
    <item android:state_selected="false"
        android:drawable="@color/transparent"/>
</selector>

И это item_selection_shape.xml в res/drawable:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    //22 is value of transparency, BDBDBD is the color
    <solid android:color="#22BDBDBD"/>
    <stroke android:width="2dp" android:color="@color/md_blue_600"/>
    <corners
        android:radius="3dp"/>
</shape>