Як правильно виділити вибраний елемент у RecyclerView?


146

Я намагаюся використовувати RecyclerViewяк горизонтальну ListView. Я намагаюся розібратися, як виділити вибраний елемент. Коли я клацаю на одному з елементів, він вибирається і він правильно виділяється, але коли натискаю на інший, другий виділяється зі старшим.

Ось моя функція onClick:

@Override
public void onClick(View view) {

    if(selectedListItem!=null){
        Log.d(TAG, "selectedListItem " + getPosition() + " " + item);
        selectedListItem.setBackgroundColor(Color.RED);
    }
    Log.d(TAG, "onClick " + getPosition() + " " + item);
    viewHolderListener.onIndexChanged(getPosition());
    selectedPosition = getPosition();
    view.setBackgroundColor(Color.CYAN); 
    selectedListItem = view;
}

Ось onBindViewHolder:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {   
    viewHolder.setItem(fruitsData[position]);
    if(selectedPosition == position)
        viewHolder.itemView.setBackgroundColor(Color.CYAN);    
    else
        viewHolder.itemView.setBackgroundColor(Color.RED);

}

Використання зосереджених поглядів не є хорошою ідеєю для спроби відстежити вибраний елемент. Перевірте мою відповідь на повне рішення
Грег Енніс

можливо, це допоможе u amolsawant88.blogspot.in/2015/08/…
Amol Sawant 96 Kuli

Ресайклер вибір виду предмета: stackoverflow.com/a/38501676/2648035
Alok Omkar

Це важко прослідкувати, коли у вас вже нічого не працює , що погано, оскільки теги відповідей уздовж і не вказують багато про те, що куди йде.
ПершийOn

Відповіді:


61

Я написав базовий клас адаптера, щоб автоматично обробляти вибір предмета за допомогою RecyclerView. Просто вийміть з нього адаптер і використовуйте перелічені списки станів з state_selected, як ви б це робили з переглядом списку.

У мене тут є повідомлення в блозі , але ось код:

public abstract class TrackSelectionAdapter<VH extends TrackSelectionAdapter.ViewHolder> extends RecyclerView.Adapter<VH> {
    // Start with first item selected
    private int focusedItem = 0;

    @Override
    public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);

        // Handle key up and key down and attempt to move selection
        recyclerView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();

                // Return false if scrolled to the bounds and allow focus to move off the list
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
                        return tryMoveSelection(lm, 1);
                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
                        return tryMoveSelection(lm, -1);
                    }
                }

                return false;
            }
        });
    }

    private boolean tryMoveSelection(RecyclerView.LayoutManager lm, int direction) {
        int tryFocusItem = focusedItem + direction;

        // If still within valid bounds, move the selection, notify to redraw, and scroll
        if (tryFocusItem >= 0 && tryFocusItem < getItemCount()) {
            notifyItemChanged(focusedItem);
            focusedItem = tryFocusItem;
            notifyItemChanged(focusedItem);
            lm.scrollToPosition(focusedItem);
            return true;
        }

        return false;
    }

    @Override
    public void onBindViewHolder(VH viewHolder, int i) {
        // Set selected state; use a state list drawable to style the view
        viewHolder.itemView.setSelected(focusedItem == i);
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);

            // Handle item click and set the selection
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Redraw the old selection and the new
                    notifyItemChanged(focusedItem);
                    focusedItem = getLayoutPosition();
                    notifyItemChanged(focusedItem);
                }
            });
        }
    }
} 

mRecyclerViewніде не оголошено. Чи слід просто передати його як параметр у конструкторі та зберігати його у полі?
Педро

1
Вибач за це. Мій адаптер - це внутрішній клас мого фрагмента, тому він має доступ до поля перегляду рециркулятора. Інакше так, ви можете передати це як параметр. Або ще краще, обробляти onRecyclerViewAttachedта зберігати його в змінній члена.
Грег Енніс

1
Хороша відповідь, але навіщо використовувати getChildPosition ()? Є інший метод developer.android.com/reference/android/support/v7/widget/…
skyfishjy

Вибачте, ви маєте на увазі, що мені просто потрібно імпортувати ваш TrackSelectionAdapterклас та використовувати його у своєму списку? Як я "вивожу адаптер з вашого класу"? Чи можете ви відповісти на моє запитання? Я застряг так глибоко: stackoverflow.com/questions/29695811 / ...
Кріштіану Colacillo

2
Я спробував це, і виявив, що два зворотні звороти до NotifyItemChanged () вбили будь-яку подобу плавного прокручування на повільному апаратному забезпеченні. Особливо погано було на Fire TV перед оновленням Lollipop
Redshirt

158

Це набагато простий спосіб зробити це.

Майте private int selectedPos = RecyclerView.NO_POSITION;у класі RecyclerView Adapter і під методом onBindViewHolder спробуйте:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {   
    viewHolder.itemView.setSelected(selectedPos == position);

}

І у вашій події OnClick модифікуйте:

@Override
public void onClick(View view) {
     notifyItemChanged(selectedPos);
     selectedPos = getLayoutPosition();
     notifyItemChanged(selectedPos); 
}

Працює як шарм для навігаційного ящика та інших переробників предметів RecyclerView.

Примітка. Обов'язково використовуйте колір тла у своєму макеті, використовуючи такий вибір, як уточнений colabug:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@color/pressed_color" android:state_pressed="true"/>
  <item android:drawable="@color/selected_color" android:state_selected="true"/>
  <item android:drawable="@color/focused_color" android:state_focused="true"/>
</selector>

Інакше setSelected (..) нічого не зробить, зробивши це рішення марним.


12
Я використав це рішення з фоновим малюнком / селектором на моєму перегляді рядків: <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/pressed_color" android:state_pressed="true"/> <item android:drawable="@color/selected_color" android:state_selected="true"/> <item android:drawable="@color/focused_color" android:state_focused="true"/> </selector>
colabug

1
@zIronManBox: приємний, простий спосіб! Чи має бути "selectedPosition" у методі onClick "вибраноPos"?
AJW

3
getLayoutPosition () мені недоступний.
ka3ak

3
Не використовуйте просто -1, використовуйте RecyclerView.NO_POSITION; (а це -1)
Мартін Марконніні

8
@ ka3ak: getLayoutPosition - метод класу ViewHolder, об'єкт якого передається як перший параметр у методі перегляду прив’язки. Тож до нього можна отримати доступvieHolder.getLayoutPosition
Tushar Kathuria

129

ОНОВЛЕННЯ [26 / липень 2017]:

Як Паван згадував у коментарі до цього попередження IDE про те, що не використовувати цю фіксовану позицію, я щойно змінив свій код, як показано нижче. Слухач клацань переміщується ViewHolder, і там я отримую позицію getAdapterPosition()методом

int selected_position = 0; // You have to set this globally in the Adapter class

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    Item item = items.get(position);

    // Here I am just highlighting the background
    holder.itemView.setBackgroundColor(selected_position == position ? Color.GREEN : Color.TRANSPARENT);
}

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    public ViewHolder(View itemView) {
        super(itemView);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // Below line is just like a safety check, because sometimes holder could be null,
        // in that case, getAdapterPosition() will return RecyclerView.NO_POSITION
        if (getAdapterPosition() == RecyclerView.NO_POSITION) return;

        // Updating old as well as new positions
        notifyItemChanged(selected_position);
        selected_position = getAdapterPosition();
        notifyItemChanged(selected_position);

        // Do your another stuff for your onClick
    }
}

сподіваюся, що це допоможе.


Це круто! Я трохи розгублений, чи можете ви допомогти мені реалізувати спосіб, розширюючи цю відповідь, як робити все, що ви робите, в операторі else, коли натискаєте на вже вибраний елемент, щоб ви скасували цей вибір: else { hold.itemView.setBackgroundColor (Color.TRANSPARENT); }
iBobb

Звичайно так. @iBobb. Для НЕ ВИБРАНИХ елементів, тобто позиція яких не дорівнює нашій змінній "вибраний_позиція", не повинно бути фону. Я використовував це, тому що RecyclerView, як випливає з назви, переробляє кожен елемент, тому він встановлює ЗЕЛЕНИЙ фон для випадкових рядків, поки ми SCROLL, тому я розмістив цю частину ELSE. (Ви можете просто спробувати, прокоментувавши цю частину ELSE, а потім прокручуйте перегляд Recycler)
Зустрічайте Vora

Я не думаю, що ти зрозумів моє запитання. Ви знаєте в будь-якому додатку, коли вибираєте щось, що виділяється. Якщо утримувати його ще раз, його буде відмінено. Як би ми це здійснили? Зараз ми можемо вибрати лише за допомогою вашого коду, а торкання та утримування одного і того ж предмета нічого не робить.
iBobb

Це може бути можливим, але для цього вам доведеться перекрити onLongClickListener замість onClickListener, зараз я зайнятий, тому не можу надати повний код, але в основному ви повинні це зробити.
Зустріньтесь з Ворою

Чомусь потрібно виділити час після клацання, приблизно від 100 до 200 мілісекунд. Будь-яка ідея чому? Я відчував це на емуляторі та своєму телефоні льодяника
suku

14

Ваша реалізація, ймовірно, спрацює, якщо ви прокручуєте вміст з виду, а потім назад в режим перегляду. У мене було подібне питання, коли я прийшов до вашого запитання.

Наступний фрагмент файлу працює для мене. Моя реалізація була спрямована на багаторазовий вибір, але я кинув хак, щоб змусити один вибір (* 1)

// an array of selected items (Integer indices) 
private final ArrayList<Integer> selected = new ArrayList<>();

// items coming into view
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    // each time an item comes into view, its position is checked
    // against "selected" indices
    if (!selected.contains(position)){
        // view not selected
        holder.parent.setBackgroundColor(Color.LTGRAY);
    }
    else
        // view is selected
        holder.parent.setBackgroundColor(Color.CYAN);
}

// selecting items
@Override
public boolean onLongClick(View v) {

        // set color immediately.
        v.setBackgroundColor(Color.CYAN);

        // (*1)
        // forcing single selection here
        if (selected.isEmpty()){
            selected.add(position);
        }else {
            int oldSelected = selected.get(0);
            selected.clear();
            selected.add(position);
            // we do not notify that an item has been selected
            // because that work is done here.  we instead send
            // notifications for items to be deselected
            notifyItemChanged(oldSelected);
        }
        return false;
}

Як зазначається в цьому пов'язаному питанні , встановлення слухачів для viewHolders слід здійснювати в onCreateViewHolder. Раніше я забув згадати про це.


6

Думаю, я знайшов найкращий підручник щодо використання RecyclerView з усіма необхідними нам основними функціями (одиночний + мультиселекція, виділення, пульсація, клацання та видалення у багатоселекції тощо).

Ось це -> http://enoent.fr/blog/2015/01/18/recyclerview-basics/

На підставі цього мені вдалося створити бібліотеку "FlexibleAdapter", яка розширює SelectableAdapter. Я думаю, що це повинно бути відповідальністю адаптера, насправді вам не потрібно кожного разу переписувати основні функціональні можливості адаптера, дозвольте бібліотеці це робити, щоб ви могли просто повторно використовувати ту саму реалізацію.

Цей адаптер дуже швидкий, він працює з коробки (не потрібно його продовжувати); ви налаштовуєте елементи під кожен тип перегляду, який вам потрібен; ViewHolder заздалегідь визначені: загальні події вже реалізовані: одинарне та довге клацання; він підтримує стан після обертання та багато іншого .

Будь ласка, погляньте і не соромтеся реалізувати це у своїх проектах

https://github.com/davideas/F prilagodAdapter

Також доступний Wiki.


Чудово працювати над написанням цього адаптера, здається, дуже корисно. Єдине, що справді потрібні деякі основні приклади та документація, я вважаю це трохи заплутаним, щоб навіть почати працювати та працювати. Потенційно все-таки чудово!
Вой

Так, я не знайшов там достатньої інформації, щоб розпочати роботу. Не вдалося знайти посилання API, навіть незважаючи на те, що код, здається, прокоментований з цим на увазі. Зразок додатка здається - хоча широкий та інформативний - дуже важко зрозуміти без попереднього знання бібліотеки. Всі випадки використання пов'язані між собою, мало вказується на те, що демонструє що, класи повторно використовуються в різних сценаріях, в результаті чого вони перевантажуються інформацією. Я створив нове видання з цими пропозиціями тут: github.com/davideas/F prilagodAdapter/isissue/120
Voy

Wiki повністю переписана і вже на завершенні.
Давідеас

6

Подивіться на моє рішення. Я припускаю, що вам слід встановити вибрану позицію у власнику та передати її як Тег перегляду. Вид повинен бути встановлений у методі onCreateViewHolder (...). Також є правильне місце для установки слухача для перегляду, наприклад OnClickListener або LongClickListener.

Перегляньте приклад нижче та прочитайте коментарі до коду.

public class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder> {
    //Here is current selection position
    private int mSelectedPosition = 0;
    private OnMyListItemClick mOnMainMenuClickListener = OnMyListItemClick.NULL;

    ...

    // constructor, method which allow to set list yourObjectList

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //here you prepare your view 
        // inflate it
        // set listener for it
        final ViewHolder result = new ViewHolder(view);
        final View view =  LayoutInflater.from(parent.getContext()).inflate(R.layout.your_view_layout, parent, false);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //here you set your current position from holder of clicked view
                mSelectedPosition = result.getAdapterPosition();

                //here you pass object from your list - item value which you clicked
                mOnMainMenuClickListener.onMyListItemClick(yourObjectList.get(mSelectedPosition));

                //here you inform view that something was change - view will be invalidated
                notifyDataSetChanged();
            }
        });
        return result;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final YourObject yourObject = yourObjectList.get(position);

        holder.bind(yourObject);
        if(mSelectedPosition == position)
            holder.itemView.setBackgroundColor(Color.CYAN);
        else
            holder.itemView.setBackgroundColor(Color.RED);
    }

    // you can create your own listener which you set for adapter
    public void setOnMainMenuClickListener(OnMyListItemClick onMyListItemClick) {
        mOnMainMenuClickListener = onMyListItemClick == null ? OnMyListItemClick.NULL : onMyListItemClick;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {


        ViewHolder(View view) {
            super(view);
        }

        private void bind(YourObject object){
            //bind view with yourObject
        }
    }

    public interface OnMyListItemClick {
        OnMyListItemClick NULL = new OnMyListItemClick() {
            @Override
            public void onMyListItemClick(YourObject item) {

            }
        };

        void onMyListItemClick(YourObject item);
    }
}

Чи вважаєте ви, що mSelectedPosition можна оголосити статичним для підтримки змін у конфігурації?
Сатеш

Немає! неправильно робити це статичним, це дуже неправильно
Конрад Краков'як

Так. його небезпечно. Але для підтримки зміни конфігурації (особливо обертання екрана) ми можемо оголосити цю змінну у діяльності та отримати її звідти, правда?
Сатеш

Рішення існує багато ... Ви можете використовувати геттер і сеттер, ви можете створити власний метод saveInstanceState для адаптера і викликати його в saveInstanceState з Activity / Fragment
Konrad Krakowiak

4

у RecyclerView немає селектора, як ListView і GridView, але ви спробуйте нижче, ніж це працювало для мене

створити перемикач, який можна малювати, як показано нижче

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
<item android:state_pressed="true">
   <shape>
         <solid android:color="@color/blue" />
   </shape>
</item>

<item android:state_pressed="false">
    <shape>
       <solid android:color="@android:color/transparent" />
    </shape>
</item>
</selector>

потім встановіть цей рисунок як фон вашого макета рядка RecyclerView як

android:background="@drawable/selector"

2
Це нічого корисного не робить. Це просто змінить колір, роблячи час преси.
Лев Дродікодер

4

Рішення з інтерфейсами та зворотними дзвінками. Створіть інтерфейс із станами вибору та скасування вибору:

public interface ItemTouchHelperViewHolder {
    /**
     * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
     * Implementations should update the item view to indicate it's active state.
     */
    void onItemSelected();


    /**
     * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
     * state should be cleared.
     */
    void onItemClear();
}

Інтерфейс реалізації у ViewHolder:

   public static class ItemViewHolder extends RecyclerView.ViewHolder implements
            ItemTouchHelperViewHolder {

        public LinearLayout container;
        public PositionCardView content;

        public ItemViewHolder(View itemView) {
            super(itemView);
            container = (LinearLayout) itemView;
            content = (PositionCardView) itemView.findViewById(R.id.content);

        }

               @Override
    public void onItemSelected() {
        /**
         * Here change of item
         */
        container.setBackgroundColor(Color.LTGRAY);
    }

    @Override
    public void onItemClear() {
        /**
         * Here change of item
         */
        container.setBackgroundColor(Color.WHITE);
    }
}

Запустити зміну стану під час зворотного виклику:

public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ItemTouchHelperAdapter mAdapter;

    public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        this.mAdapter = adapter;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        ...
    }

    @Override
    public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
        ...
    }

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder instanceof ItemTouchHelperViewHolder) {
                ItemTouchHelperViewHolder itemViewHolder =
                        (ItemTouchHelperViewHolder) viewHolder;
                itemViewHolder.onItemSelected();
            }
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        if (viewHolder instanceof ItemTouchHelperViewHolder) {
            ItemTouchHelperViewHolder itemViewHolder =
                    (ItemTouchHelperViewHolder) viewHolder;
            itemViewHolder.onItemClear();
        }
    }   
}

Створіть RecyclerView за допомогою зворотного виклику (приклад):

mAdapter = new BuyItemsRecyclerListAdapter(MainActivity.this, positionsList, new ArrayList<BuyItem>());
positionsList.setAdapter(mAdapter);
positionsList.setLayoutManager(new LinearLayoutManager(this));
ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(positionsList);

Дивіться більше у статті iPaulPro: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.6gh29uaaz


3

це моє рішення, ви можете встановити елемент (або групу) та скасувати виділення його ще одним клацанням миші:

 private final ArrayList<Integer> seleccionados = new ArrayList<>();
@Override
    public void onBindViewHolder(final ViewHolder viewHolder, final int i) {
        viewHolder.san.setText(android_versions.get(i).getAndroid_version_name());
        if (!seleccionados.contains(i)){ 
            viewHolder.inside.setCardBackgroundColor(Color.LTGRAY);
        }
        else {
            viewHolder.inside.setCardBackgroundColor(Color.BLUE);
        }
        viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (seleccionados.contains(i)){
                    seleccionados.remove(seleccionados.indexOf(i)); 
                    viewHolder.inside.setCardBackgroundColor(Color.LTGRAY);
                } else { 
                    seleccionados.add(i);
                    viewHolder.inside.setCardBackgroundColor(Color.BLUE);
                }
            }
        });
    }

2

У мене був такий самий випуск, і я вирішую його наступним чином:

Файл XML, який використовується для створення рядка всередині createViewholder, просто додайте нижче рядка:

 android:clickable="true"
 android:focusableInTouchMode="true"
 android:background="?attr/selectableItemBackgroundBorderless"

АБО Якщо ви використовуєте frameLayout як батьківський елемент рядка, тоді:

android:clickable="true"
android:focusableInTouchMode="true"
android:foreground="?attr/selectableItemBackgroundBorderless"

У коді Java всередині власника перегляду, куди ви додали слухача кліків:

@Override
   public void onClick(View v) {

    //ur other code here
    v.setPressed(true);
 }

1

Я не зміг знайти в Інтернеті хорошого рішення для цієї проблеми і вирішив її самостійно. Від цієї проблеми страждає багато людей. Таким чином, я хочу поділитися своїм рішенням тут.

Під час прокрутки рядки переробляються. Таким чином, встановлені прапорці та виділені рядки не працюють належним чином. Я вирішив цю проблему, написавши нижче клас адаптерів.

Я також реалізую повний проект. У цьому проекті ви можете встановити декілька прапорців. Рядки, що включають вибрані прапорці, виділяються. І що ще важливіше, вони не втрачаються під час прокрутки. Ви можете завантажити його за посиланням:

https://www.dropbox.com/s/ssm58w62gw32i29/recyclerView_checkbox_highlight.zip?dl=0

    public class RV_Adapter extends RecyclerView.Adapter<RV_Adapter.ViewHolder> {
        public ArrayList<String> list;
        boolean[] checkBoxState;
        MainActivity mainActivity;
        MyFragment myFragment;
        View firstview;

        private Context context;

        FrameLayout framelayout;

        public RV_Adapter() {

      }

        public RV_Adapter(Context context, MyFragment m, ArrayList<String> list ) {
          this.list = list;
          myFragment = m;
          this.context = context;
          mainActivity = (MainActivity) context;
          checkBoxState = new boolean[list.size()];
          // relativeLayoutState = new boolean[list.size()];
        }

        public class ViewHolder extends RecyclerView.ViewHolder  {
            public TextView textView;
            public CheckBox checkBox;
            RelativeLayout relativeLayout;
            MainActivity mainActivity;
            MyFragment myFragment;
            public ViewHolder(View v,MainActivity mainActivity,MyFragment m) {
                super(v);
                textView = (TextView) v.findViewById(R.id.tv_foodname);
                /**/
                checkBox= (CheckBox) v.findViewById(R.id.checkBox);
                relativeLayout = (RelativeLayout)v.findViewById(R.id.relativelayout);
                this.mainActivity = mainActivity;
                this.myFragment = m;
                framelayout = (FrameLayout) v.findViewById(R.id.framelayout);
                framelayout.setOnLongClickListener(m);
            }

        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            firstview = inflater.inflate(R.layout.row, parent, false);
            return new ViewHolder(firstview,mainActivity, myFragment);
        }

        @Override
        public void onBindViewHolder( final ViewHolder holder,  final int position) {

            holder.textView.setText(list.get(position));

            holder.itemView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {

              }
            });

            // When action mode is active, checkboxes are displayed on each row, handle views(move icons) on each row are disappered.
            if(!myFragment.is_in_action_mode)
            {

              holder.checkBox.setVisibility(View.GONE);
            }
            else
            {
              holder.checkBox.setVisibility(View.VISIBLE);
              holder.checkBox.setChecked(false);
            }

              holder.checkBox.setTag(position);

              holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                  if(compoundButton.isPressed()) // ekrandan kaybolan checkbox'lar otomatik olarak state degistiriyordu ve bu listener method cagiriliyordu, bunu onlemek icin isPressed() method'u ile kullanici mi basmis diye kontrol ediyorum.
                  {
                    int getPosition = (Integer) compoundButton.getTag();  // Here we get the position that we have set for the checkbox using setTag.
                    checkBoxState[getPosition] = compoundButton.isChecked(); // Set the value of checkbox to maintain its state.
                    //relativeLayoutState[getPosition] = compoundButton.isChecked();

                  if(checkBoxState[getPosition] && getPosition == position )
                    holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view  **/
                  else
                    holder.relativeLayout.setBackgroundResource(R.color.food_unselected); /** Change background color of the selected items in list view  **/
                    myFragment.prepareselection(compoundButton, getPosition, holder.relativeLayout);

                  }
                }
              });
              holder.checkBox.setChecked(checkBoxState[position]);

              if(checkBoxState[position]  )
                holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view  **/
              else
                holder.relativeLayout.setBackgroundResource(R.color.food_unselected);
        }



        @Override
        public int getItemCount() {
            return list.size();
        }

        public void updateList(ArrayList<String> newList){
          this.list = newList;
          checkBoxState = new boolean[list.size()+1];
        }

      public void resetCheckBoxState(){
        checkBoxState = null;
        checkBoxState = new boolean[list.size()];
      }

    }

Скріншоти програми:

екран1 екран2 екран3 екран4


-1

Установіть так, private int selected_position = -1;щоб на початку не було вибрано жоден елемент.

 @Override
 public void onBindViewHolder(final OrdersHolder holder, final int position) {
    final Order order = orders.get(position);
    holder.bind(order);
    if(selected_position == position){
        //changes background color of selected item in RecyclerView
        holder.itemView.setBackgroundColor(Color.GREEN);
    } else {
        holder.itemView.setBackgroundColor(Color.TRANSPARENT);
        //this updated an order property by status in DB
        order.setProductStatus("0");
    }
    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //status switch and DB update
            if (order.getProductStatus().equals("0")) {
                order.setProductStatus("1");
                notifyItemChanged(selected_position);
                selected_position = position;
                notifyItemChanged(selected_position);
             } else {
                if (order.getProductStatus().equals("1")){
                    //calls for interface implementation in
                    //MainActivity which opens a new fragment with 
                    //selected item details 
                    listener.onOrderSelected(order);
                }
             }
         }
     });
}

-1

Просто додавання android:background="?attr/selectableItemBackgroundBorderless"Якщо у вас немає кольору фону, повинно працювати, але не забудьте використати метод setSelected. Якщо у вас різний колір фону, я просто використовував це (я використовую прив'язку даних);

Установити вибрано у функції onClick

b.setIsSelected(true);

І додайте це до xml;

android:background="@{ isSelected ? @color/{color selected} : @color/{color not selected} }"

-1

Зробити вибір:

 <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/Green_10" android:state_activated="true" />
    <item android:drawable="@color/Transparent" />
</selector>

Встановіть його як фон у макеті списку елементів

   <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:background="@drawable/selector_attentions_list_item"
        android:layout_width="match_parent"
        android:layout_height="64dp">

У своєму адаптері додайте до перегляду OnClickListener (метод onBind)

 @Suppress("UNCHECKED_CAST")
    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(item: T) {
            initItemView(itemView, item)
            itemView.tag = item
            if (isClickable) {
                itemView.setOnClickListener(onClickListener)
            }
        }
    }

У події onClick активуйте подання:

 fun onItemClicked(view: View){
        view.isActivated = true
    }

2
У цьому питанні є 2 питання: 1) Ви не надали жодного способу скасувати активацію інших елементів утилізатора. 2) Перегляди повторно використовуються. Тож можливо, що той самий активований вид буде видно вниз порядок під час прокрутки.
Anup Sharma
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.