Come evidenziare correttamente l'elemento selezionato su RecyclerView?


146

Sto provando a usare a RecyclerViewcome orizzontale ListView. Sto cercando di capire come evidenziare l'elemento selezionato. Quando faccio clic su uno degli elementi, viene selezionato e viene evidenziato correttamente, ma quando faccio clic su un altro, il secondo viene evidenziato con quello precedente.

Ecco la mia funzione 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;
}

Ecco il 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);

}

L'uso di viste focalizzabili non è una buona idea per provare a tenere traccia dell'elemento selezionato. Controlla la mia risposta per una soluzione completa
Greg Ennis


Selezione articolo vista riciclatore: stackoverflow.com/a/38501676/2648035
Alok Omkar

Questo è difficile da seguire quando non hai già qualcosa che funziona , il che è male dal momento che il tag risponde e non specifica molto su cosa va dove.
Primo

Risposte:


61

Ho scritto una classe di adattatori di base per gestire automaticamente la selezione degli articoli con un RecyclerView. Basta derivare l'adattatore da esso e utilizzare elenchi di stati disegnabili con state_selected, come si farebbe con una vista elenco.

Ho un post sul blog Qui a riguardo, ma ecco il codice:

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);
                }
            });
        }
    }
} 

mRecyclerViewnon è dichiarato da nessuna parte. Dovremmo semplicemente passarlo come parametro nel costruttore e memorizzarlo in un campo?
Pedro,

1
Mi dispiace per quello. Il mio adattatore è una classe interna del mio frammento, quindi ha accesso al campo di visualizzazione del riciclatore. Altrimenti sì, potresti passarlo come parametro. O ancora meglio, gestiscilo onRecyclerViewAttachede memorizzalo in una variabile membro lì.
Greg Ennis,

1
Bella risposta, ma perché usare getChildPosition ()? Esiste un altro metodo developer.android.com/reference/android/support/v7/widget/…
skyfishjy

Mi dispiace, vuoi dire che devo solo importare la tua TrackSelectionAdapterclasse e usarla nella mia lista? Come faccio a "derivare il mio adattatore dalla tua classe"? Per favore, potresti rispondere alla mia domanda? Sono bloccato così profondamente: stackoverflow.com/questions/29695811/...
Cristiano Colacillo

2
Ho provato questo e ho scoperto che le due chiamate back-to-back a NotifyItemChanged () hanno ucciso qualsiasi parvenza di scorrimento regolare su hardware più lento. Era particolarmente brutto su Fire TV prima dell'aggiornamento di Lollipop
Redshirt,

158

Questo è un modo molto semplice per farlo.

Avere un private int selectedPos = RecyclerView.NO_POSITION;nella classe Adapter RecyclerView e sotto il metodo onBindViewHolder provare:

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

}

E nel tuo evento OnClick modifica:

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

Funziona come un fascino per il cassetto di navigazione e altri adattatori di oggetti RecyclerView.

Nota: assicurati di utilizzare un colore di sfondo nel layout utilizzando un selettore come chiarimento 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>

Altrimenti setSelected (..) non farà nulla, rendendo inutile questa soluzione.


12
Ho usato questa soluzione con un disegnatore / selettore di sfondo impostato sulla mia vista riga: <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: bello, semplice! "SelectedPosition" nel metodo onClick dovrebbe essere "selectedPos"?
AJW

3
getLayoutPosition () non è disponibile da me.
Ka3ak

3
Non usare solo -1, usa RecyclerView.NO_POSITION; (che è -1)
Martin Marconcini

8
@ ka3ak: getLayoutPosition è il metodo della classe ViewHolder il cui oggetto viene passato come primo parametro nel metodo di visualizzazione bind. Quindi è possibile accedervi davieHolder.getLayoutPosition
Tushar Kathuria,

129

AGGIORNAMENTO [26 / lug / 2017]:

Come il Pawan ha menzionato nel commento sull'avvertimento IDE di non utilizzare quella posizione fissa, ho appena modificato il mio codice come di seguito. Il listener di clic viene spostato in ViewHoldere qui ottengo la posizione utilizzando il getAdapterPosition()metodo

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
    }
}

spero che questo ti aiuti.


È fantastico! Sono un po 'confuso, potresti aiutarmi a implementare un modo, espandendo questa risposta, come fare qualsiasi cosa tu faccia nell'istruzione else quando fai clic su un elemento già selezionato, in modo da deselezionarlo: else { holder.itemView.setBackgroundColor (Color.TRANSPARENT); }
iBobb,

Certo che si. @iBobb. Per gli elementi NON SELEZIONATI, vale a dire la cui posizione non è uguale alla nostra variabile 'selected_position' non dovrà avere sfondo. L'ho usato perché RecyclerView, come suggerisce il nome, ricicla ogni elemento, quindi imposta lo sfondo VERDE per le righe casuali mentre SCROLL, ecco perché ho inserito quella parte ELSE. (Puoi semplicemente provarlo commentando quella parte ELSE, quindi scorrere la vista del tuo riciclatore)
Incontra Vora il

Non credo che tu abbia capito la mia domanda. Sai in qualsiasi app, quando selezioni qualcosa viene evidenziato. Se lo tieni di nuovo, viene deselezionato. Come lo implementeremmo? Al momento possiamo selezionare solo usando il tuo codice e toccare e tenere premuto lo stesso oggetto non fa nulla.
iBobb,

Può essere possibile, ma per questo devi sovrascrivere onLongClickListener anziché onClickListener, in questo momento sono occupato, quindi non posso fornire il codice completo, ma dovresti sostanzialmente farlo in quel modo.
Incontra Vora

Per qualche motivo ci vuole tempo per evidenziare dopo il clic, circa 100-200 millisecondi. Qualche idea sul perché? L'ho sperimentato su un emulatore e sul mio telefono lecca-lecca
suku

14

L'implementazione probabilmente funziona se si fa scorrere il contenuto fuori dalla vista per poi tornare alla vista. Stavo riscontrando un problema simile quando ho avuto la tua domanda.

Il seguente frammento di file funziona per me. La mia implementazione era finalizzata alla selezione multipla, ma ho lanciato un hack per forzare la selezione singola. (* 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;
}

Come notato in questa domanda collegata , l'impostazione dei listener per viewHolder dovrebbe essere eseguita in onCreateViewHolder. Ho dimenticato di menzionarlo in precedenza.


6

Penso di aver trovato il miglior tutorial su come utilizzare RecyclerView con tutte le funzioni di base di cui abbiamo bisogno (singola + selezione multipla, evidenziazione, ondulazione, clic e rimozione in selezione multipla, ecc ...).

Eccolo qui:> http://enoent.fr/blog/2015/01/18/recyclerview-basics/

Sulla base di ciò, sono stato in grado di creare una libreria "FlexibleAdapter", che estende un SelectableAdapter. Penso che questo debba essere una responsabilità dell'adapter, in realtà non è necessario riscrivere le funzionalità di base dell'adattatore ogni volta, lasciare che una libreria lo faccia, quindi puoi semplicemente riutilizzare la stessa implementazione.

Questo adattatore è molto veloce, funziona subito (non è necessario estenderlo); personalizzi gli articoli per tutti i tipi di visualizzazione di cui hai bisogno; ViewHolder è predefinito: sono già implementati eventi comuni: clic singolo e lungo; mantiene lo stato dopo la rotazione e molto altro ancora .

Dai un'occhiata e sentiti libero di implementarlo nei tuoi progetti.

https://github.com/davideas/FlexibleAdapter

È disponibile anche un Wiki.


Ottimo lavoro per scrivere quell'adattatore, sembra molto utile. L'unica cosa è che ha davvero bisogno di alcuni esempi e documentazione di base, trovo un po 'confuso persino metterlo in funzione. Potenzialmente fantastico però!
Voy,

Sì, non ho trovato informazioni sufficienti per iniziare. Impossibile trovare il riferimento API anche se il codice sembra essere commentato tenendo presente questo. L'app di esempio sembra, sebbene ampia e informativa, molto difficile da capire senza una conoscenza preliminare della libreria. Tutti i casi d'uso sono legati insieme, c'è poca indicazione di ciò che dimostra cosa, le classi vengono riutilizzate in diversi scenari, il che si traduce in un sovraccarico di informazioni. Ho creato un nuovo numero con questi suggerimenti qui: github.com/davideas/FLEXAdapter/issues/120
Voy,

Wiki è stato completamente riscritto ed è in via di completamento.
Davideas,

6

Guarda la mia soluzione. Suppongo che dovresti impostare la posizione selezionata nel supporto e passarla come Tag of View. La vista deve essere impostata nel metodo onCreateViewHolder (...). C'è anche un posto corretto per impostare il listener per la visualizzazione come OnClickListener o LongClickListener.

Guarda l'esempio seguente e leggi i commenti al codice.

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);
    }
}

Pensi che mSelectedPosition possa essere dichiarato statico per mantenere le modifiche alla configurazione?
Sathesh,

No! è sbagliato renderlo statico, è molto sbagliato
Konrad Krakowiak,

Si. è pericoloso. Ma per mantenere la modifica della configurazione (in particolare rotazione dello schermo) possiamo dichiarare questa variabile in attività e ottenerla da lì, giusto?
Sathesh,

Ci sono molte soluzioni ... Puoi usare getter e setter, Puoi creare il tuo metodo saveInstanceState per l'adattatore e chiamarlo in saveInstanceState da Activity / Fragment
Konrad Krakowiak,

4

non c'è alcun selettore in RecyclerView come ListView e GridView, ma provi di seguito cosa ha funzionato per me

crea un selettore disegnabile come di seguito

<?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>

quindi imposta questo disegno come sfondo del layout di riga di RecyclerView come

android:background="@drawable/selector"

2
Questo non fa nulla di utile. Cambierà semplicemente il colore facendo il tempo di stampa.
Leo Droidcoder,

4

Decisione con interfacce e callback. Crea interfaccia con stati di selezione e deselezione:

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();
}

Implementare l'interfaccia in 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);
    }
}

Esegui cambio stato su Richiamata:

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();
        }
    }   
}

Crea RecyclerView con Callback (esempio):

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);

Vedi di più nell'articolo di iPaulPro: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.6gh29uaaz


3

questa è la mia soluzione, puoi impostare un elemento (o un gruppo) e deselezionarlo con un altro clic:

 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

Ho avuto lo stesso problema e lo risolvo nel modo seguente:

Il file XML che sta usando per creare una riga all'interno di createViewholder, basta aggiungere la riga seguente:

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

OPPURE Se si utilizza frameLayout come elemento principale dell'elemento riga, allora:

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

Nel codice java all'interno del supporto della vista in cui hai aggiunto il listener di clic:

@Override
   public void onClick(View v) {

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

1

Non sono riuscito a trovare una buona soluzione sul web per questo problema e l'ho risolto da solo. Ci sono molte persone che soffrono di questo problema. Quindi voglio condividere la mia soluzione qui.

Durante lo scorrimento, le righe vengono riciclate. Pertanto, le caselle di controllo selezionate e le righe evidenziate non funzionano correttamente. Ho risolto questo problema scrivendo la classe dell'adattatore seguente.

Realizzo anche un progetto completo. In questo progetto, è possibile selezionare più caselle di controllo. Le righe che includono le caselle di controllo selezionate sono evidenziate. E, soprattutto, questi non vengono persi durante lo scorrimento. Puoi scaricarlo dal link:

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()];
      }

    }

Schermate dell'app:

screen1 Screen2 SCREEN3 screen4


-1

Impostare private int selected_position = -1;per impedire qualsiasi elemento selezionato all'avvio.

 @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

La semplice aggiunta android:background="?attr/selectableItemBackgroundBorderless"dovrebbe funzionare se non hai il colore di sfondo, ma non dimenticare di usare il metodo setSelected. Se hai un colore di sfondo diverso, l'ho appena usato (sto usando la rilegatura dei dati);

Set isSelezionato nella funzione onClick

b.setIsSelected(true);

E aggiungi questo a xml;

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

-1

Crea selettore:

 <?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>

Impostalo come sfondo nel layout della tua voce di elenco

   <?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">

Nell'adattatore aggiungere OnClickListener alla vista (metodo 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)
            }
        }
    }

Nell'evento onClick attiva la vista:

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

2
Questo ha 2 problemi: 1) Non hai fornito alcun modo per annullare l'attivazione di altri oggetti nel riciclatore. 2) Le visualizzazioni vengono riutilizzate. Quindi è possibile che la stessa vista attivata sia visibile nell'ordine durante lo scorrimento.
Anup Sharma,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.