RecyclerView onClick


583

Qualcuno che sta usando ha RecyclerViewtrovato un modo per impostare un onClickListenerelemento in RecyclerView? Ho pensato di impostare un ascoltatore per ciascuno dei layout per ogni elemento, ma sembra un po 'troppo fastidioso Sono sicuro che c'è un modo per RecyclerViewascoltare l' onClickevento ma non riesco a capirlo.



4
RecyclerViewDemo Ho trovato fantastico questo progetto, usando le interfacce per fornire più azioni gratuite.
MewX,


Semplice e facile da usare - github.com/rahulkapoor1/ClickableAdapter
Rahul

stackoverflow.com/a/31199564/5788247
Shomu,

Risposte:


477

Poiché le API sono cambiate radicalmente, non mi sorprenderebbe se dovessi crearne uno OnClickListenerper ogni elemento. Non è poi una seccatura. Nella tua implementazione di RecyclerView.Adapter<MyViewHolder>, dovresti avere:

private final OnClickListener mOnClickListener = new MyOnClickListener();

@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
    view.setOnClickListener(mOnClickListener);
    return new MyViewHolder(view);
}

Il onClickmetodo:

@Override
public void onClick(final View view) {
    int itemPosition = mRecyclerView.getChildLayoutPosition(view);
    String item = mList.get(itemPosition);
    Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}

32
cosa succede se desidero eliminare una riga al suo clic?
Piyush Kukadiya,

20
Mi piace questa risposta meglio di quella che hai collegato. Chi vuole scrivere un ascoltatore di gesti e colpire il rilevamento della casella per gestire questo. Google--
Lo-Tan,

17
getChildPosition (view) è un metodo obsoleto
Jigar

45
Ti dispiace dire in quali classi sono i tuoi frammenti? onClick(), appartenenti a OnClickListenerpossono essere collegati a QUALSIASI vista. L'intera domanda qui è quale! Si prega di fare uno sforzo, un metodo non è solo identificato da un nome, ma almeno da una classe. Se non dici che il tuo codice deve essere aggiunto all'adattatore, la tua risposta non aiuta davvero.
Vince il

16
Il metodo onClick dovrebbe trovarsi nel frammento che contiene RecyclerView? Perché fai riferimento a mRecyclerView nella tua classe MyOnClickListener. Dove hai preso il riferimento a quell'oggetto?
Ced

606

Ecco un modo migliore e meno accoppiato per implementare un OnClickListenerper a RecyclerView.

Snippet di utilizzo:

RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
    new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
      @Override public void onItemClick(View view, int position) {
        // do whatever
      }

      @Override public void onLongItemClick(View view, int position) {
        // do whatever
      }
    })
);

RecyclerItemClickListener implementazione:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;


public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
  private OnItemClickListener mListener;

  public interface OnItemClickListener {
    public void onItemClick(View view, int position);

    public void onLongItemClick(View view, int position);
  }

  GestureDetector mGestureDetector;

  public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null && mListener != null) {
                mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
            }
        }
    });
}

  @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
      mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
      return true;
    }
    return false;
  }

  @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }

  @Override
  public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}

85
Questo non fornirà alcun indizio su quale pulsante o vista (all'interno dell'elemento) è stato cliccato. Ma per il clic complessivo sull'elemento, va bene.
Niranjan,

27
Il commento di ngen è corretto: se si desidera associare un listener onClick a un elemento specifico nella vista elemento, è probabile che sia necessario farlo nell'adattatore, in onBindViewHolder o nel proprio viewholder stesso.
Jacob Tabak,

16
Un problema con questo metodo è quando stai facendo qualcosa che richiede alcune centinaia di millisecondi come l'avvio di un'attività. Quando si fa clic sull'elemento e si fa clic su un'animazione, si verifica un notevole ritardo tra il clic e la visualizzazione dell'animazione.
Gak2,

20
Questa soluzione sembra estremamente goffa, c'è qualche ritardo nell'elaborazione del 'clic' e la sensazione non è solo ok
wasyl

6
Qualcuno potrebbe spiegarmi perché questa soluzione con GestureDetector dovrebbe essere una soluzione migliore del semplice utilizzo di "setOnClickListener" all'interno di onBindViewHolder () nell'adattatore per l'elemento corrispondente? In questo modo almeno ho bisogno di meno codice rispetto alla soluzione GestureDetector. Grazie per una spiegazione
e-nature

115

Lo faccio in questo modo, senza classi indebite, rilevatori ecc. Codice semplice all'interno del nostro adattatore. Soluzione particolarmente migliore per longClick rispetto a quella presentata in precedenza.

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private static ClickListener clickListener;

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
        TextView name;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(this);
            name = (TextView) itemView.findViewById(R.id.card_name);
        }

        @Override
        public void onClick(View v) {
            clickListener.onItemClick(getAdapterPosition(), v);
        }

        @Override
        public boolean onLongClick(View v) {
            clickListener.onItemLongClick(getAdapterPosition(), v);
            return false;
        }
    }

    public void setOnItemClickListener(ClickListener clickListener) {
        PasswordAdapter.clickListener = clickListener;
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

Quindi all'interno del frammento o dell'attività, premi:

PasswordAdapter mAdapter = ...;

mAdapter.setOnItemClickListener(new PasswordAdapter.ClickListener() {
    @Override
    public void onItemClick(int position, View v) {
        Log.d(TAG, "onItemClick position: " + position);
    }

    @Override
    public void onItemLongClick(int position, View v) {
        Log.d(TAG, "onItemLongClick pos = " + position);
    }
});

invece di OurAdapter.clickListener penso che Marurban significhi PasswordAdapter.clickListener e invece di TrainingAdapter.ClickListener (), dovrebbe essere PasswordAdapter.ClickListener (). A parte questo, ottima soluzione Marurban! ha lavorato per me
nommer il

Il listener onItemClick viene attivato anche con un clic lungo.
Rashad.Z,

10
ViewHolder deve essere statico per le migliori prestazioni. questa non è una buona risposta.
Gilberto Ibarra,

10
ClickListener statico crea una perdita di memoria. Dichiarare il listener come non statico e invece collegarlo a ViewHolder.
BladeCoder

1
@AJW Il modo più semplice è inizializzare il listener in anticipo e passarlo come argomento al costruttore dell'adattatore e quindi al costruttore ViewHolder.
BladeCoder

97

Dai un'occhiata a una domanda simile : il commento di @ CommonsWare si collega a questo , che implementa l' OnClickListenerinterfaccia in viewHolder.

Ecco un semplice esempio di ViewHolder:

    TextView textView;//declare global with in adapter class

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

      private ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            textView = (TextView)view.findViewById(android.R.id.text1);

      }

      @Override
      public void onClick(View view) {
            Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();

         //go through each item if you have few items within recycler view
        if(getLayoutPosition()==0){
           //Do whatever you want here

        }else if(getLayoutPosition()==1){ 
           //Do whatever you want here         

        }else if(getLayoutPosition()==2){

        }else if(getLayoutPosition()==3){

        }else if(getLayoutPosition()==4){

        }else if(getLayoutPosition()==5){

        }

        //or you can use For loop if you have long list of items. Use its length or size of the list as 
        for(int i = 0; i<exampleList.size(); i++){

        }


      }
  }

L' Adapterallora assomiglia a questo:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);

        return new ViewHolder(view);
    }

14
Questo sembra andare nella direzione sbagliata però. Se è necessario riutilizzare una vista recyclerview in un altro frammento / attività, l'adattatore / viewholder ora sta definendo la logica dei clic anziché qualsiasi cosa li contenga. I clic dovrebbero davvero essere gestiti direttamente o indirettamente dall'istanza contenente. Sembra che un ascoltatore di tocchi sia l'unico modo efficace per farlo.
ian.shaun.thomas,

18
@tencent Non vedo come sia questo il problema. Se ViewHolder stesso contiene tutte le informazioni relative a quali dati vengono selezionati quando si fa clic sull'elemento stesso, l'unica responsabilità del contenitore è la visualizzazione di N elementi, piuttosto che quella di gestire la selezione di uno specifico i-esimo elemento degli elementi N L' ListViewera già problematico se si dovesse creare un elenco di oggetti più complicato che solo semplici righe. Cosa succede se è necessario gestire eventi diversi a seconda di dove si fa clic sull'elemento in ListView? Sei fregato. Qui, hai tutti gli ascoltatori.
EpicPandaForce,

2
Sono d'accordo con @EpicPandaForce su questo. Sono anche venuto a votare questa risposta dopo aver letto la sezione del libro di Commonsware sulla gestione dei clic in RecyclerViews. Finora ha funzionato benissimo per me.
AdamMc331,

1
findViewById viene utilizzato solo per la creazione del view view qui (quindi onCreateViewHolder). Il titolare della vista ha lo scopo di impedire di trovare la vista ogni volta che un elemento è associato al titolare, non alla creazione iniziale.
Stuckj,

2
getPosition()è obsoleto, utilizzare getAdapterPosition()o getLayoutPosition()invece.
K Neeraj Lal,

94

Sulla base della risposta di Jacob Tabak (+1 per lui), sono stato in grado di aggiungere il listener di LongClick:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
        mListener = listener;

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                if (childView != null && mListener != null) {
                    mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());

        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        }

        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }
}

Quindi puoi usarlo in questo modo:

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        // ...
    }

    @Override
    public void onItemLongClick(View view, int position) {
        // ...
    }
}));

1
Mi ci è voluto un po 'per adattarmi alla mia app e allineare e formattare il codice secondo gli standard Java / Android, ma alla fine ha funzionato bene.
milosmns,

Come si aggiunge un'animazione per il clic lungo?
Jon,

1
@ Eng.Fouad l'effetto clic non funziona utilizzando questo, sebbene se impostiamo il listener di clic nell'effetto clic dell'adattatore funziona qualsiasi soluzione a questo
ingsaurabh

4
Dovresti anche scavalcarepublic void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
Paolo Rotolo,

Per qualche motivo non restituisce una vista cliccata. Nel mio caso, faccio clic su una casella di controllo ma la visualizzazione fornita è diversa. Il modo in cui controllo:view.getId() == R.id.selection
dVaffection il

63

Questo è ciò che ha funzionato per me. Allegare OnClickListeneral onBindView. Non so davvero se questo avrà un impatto sulle prestazioni, ma sembra funzionare bene con poco codice.

public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
    });
}

5
nel mio caso holder.itemView.setOnClickListener (..)
D4rWiNS

18
nel mio caso si chiama 'itemView' invece di 'view', dicendo solo per i principianti, alcuni di loro non capiscono cosa stanno copiando e non riescono a capire perché non funziona
D4rWiNS

3
È la posizione del layout
Bubunyo Nyavor,

1
per me questo sembra valere solo per l'ultimo oggetto visibile, non per quello cliccato
Nasz Njoka Sr.

2
Questa soluzione mi sembra la migliore, ma in cosa differisce dalla risposta di @bolot in termini di prestazioni? Ha implementato View.OnClickListener direttamente sulla classe ViewHolder, che sputa separatamente il metodo onClick. Quale sarebbe la soluzione migliore?
Edmond Tamas,

46

È stato così difficile per me avere un listener di clic sull'elemento nell'attività e anche avere un listener di clic per la visualizzazione singola dell'elemento che non si attiverà sul listener di clic dell'elemento. Dopo aver giocato con la risposta di Jacob Tabak, rispetto la sua risposta per il clic sull'oggetto se non vengono presentate altre azioni di tocco all'interno dell'oggetto.

Ho un'usanza OnClickListener un'interfaccia che ha un evento clic sull'elemento che contiene la vista dell'oggetto cliccato e la posizione dell'articolo dall'adattatore. Ne presento un'istanza nel costruttore (o può essere con setter) e lo allego al listener di clic del contenitore del titolare della vista.

Ho anche un altro listener di clic nell'adattatore (può essere nel supporto della vista) che gestirà il clic della vista corrente dal contenitore.

 public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {

private ArrayList<String> mData;
private OnItemClickListener mOnItemClickListener;

public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}

public MyRecyclerAdapter(ArrayList<String> itemsData,
        OnItemClickListener onItemClickListener) {
    mOnItemClickListener = onItemClickListener;
    this.mData = itemsData;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
        int viewType) {

    View layoutView = LayoutInflater.from(mContext).inflate(
            R.layout.list_item, parent, false);

    final MyViewHolder viewHolder = new MyViewHolder(layoutView);

    viewHolder.container.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition());
        }
    });

    viewHоlder.button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //do button click work here with
            // mData.get( viewHolder.getAdapterPosition() );
        }
    });

    return viewHolder;
}

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

Nell'attività è necessario inizializzare l'adattatore passando l'istanza di OnItemClickListener

public class FeedActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

    .....

    MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList<String>(), new OnItemClickListener() {

        @Override
        public void onItemClick(View view, int position) {

            ///list item was clicked
        }
    });

    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(mFeedsAdapter);
}

E il mio ViewHolder

public class MyViewHolder extends RecyclerView.ViewHolder {

public Button button;
public View container;

public MyViewHolder(View itemLayoutView) {
    super(itemLayoutView);

    container = itemLayoutView;
    button = (Button) itemLayoutView.findViewById(R.id.button);
}}

Questo approccio ha funzionato bene per me - significa che puoi gestire i clic nell'attività anziché all'interno della vista griglia
leafcutter

3
Dove posso darti soldi. 4 ore di ricerca e poi ho letto il tuo post. Grazie per il tempo che hai impiegato per pubblicare questo.
Brandon,

3
Sembra stupido, ma ha qualche problema di memoria o efficienza? Perché stiamo assegnando il listener di clic ogni volta che viene disegnata una vista, giusto?
RGV

1
@Raghav yes ogni volta che si associa la visualizzazione, viene assegnato un nuovo listener di clic, ma questo è il flusso standard. Ma mOnItemClickListener viene creato una sola volta per l'adattatore, solo la vista e la sua posizione sono diverse su ogni clic dell'elemento;)
Sir NIkolay Cesar The First

3
Ottimo esempio per eliminare le prestazioni delle app e creare un uso eccessivo della memoria! Con questo esempio è sufficiente scorrere per creare centinaia di oggetti inutili, che in un attimo saranno inutili e devono essere accessibili come garbige. @NoobDogg ha ragione. Nessun elenco di clic non deve essere creato su onBindView. Un listener di clic deve essere creato una volta in onCreateView (o costruttore del supporto) ed esiste mentre è necessario lo schermo con questo adattatore.
Mykola Tychyna,

36

Questo è ciò di cui ho avuto bisogno, nel caso qualcuno lo trovasse utile:

public static class ViewHolder extends RecyclerView.ViewHolder {

    public ViewHolder(View item) {

        super(item);
        item.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("RecyclerView", "onClick:" + getAdapterPosition());
            }
        });

    }
}

Fonte: http://blog.csdn.net/jwzhangjie/article/details/36868515


Di tutte le versioni che ho provato, questa è quella su cui ho lavorato. Ma va bene farlo in quel modo? O c'è un modo migliore, come le migliori pratiche?
Matthias Loibl,

1
Per quanto ne sapevo, questo era l'unico modo. Dai un'occhiata a questo per maggiori dettagli! stackoverflow.com/a/24933117/1508887
Fifer Sheep

Come posso aprire un nuovo frammento dall'interno del metodo onclick?
hash

5
getAdapterPosition () sostituisce getPosition ()
Kennedy Nyaga il

27

Ho bella soluzione per RecyclerViews'onItemClickListener per le voci e sottovoci

Passaggio 1- Creare un'interfaccia

public interface OnRecyclerViewItemClickListener
{
    /**
     * Called when any item with in recyclerview or any item with in item
     * clicked
     * 
     * @param position
     *            The position of the item
     * @param id
     *            The id of the view which is clicked with in the item or
     *            -1 if the item itself clicked
     */
    public void onRecyclerViewItemClicked(int position, int id);
}

Passaggio 2: quindi utilizzarlo nel onBindViewHoldermetodo dell'adattatore nel modo seguente

/**
     * Custom created method for Setting the item click listener for the items and items with in items
     * @param listener OnRecyclerViewItemClickListener 
     */
    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
    {
        this.listener = listener;
    }

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

        // viewHolder.albumBg.setBackgroundResource(_itemData[position]
        // .getImageUrl());

        viewHolder.albumName.setText(arrayList.get(position).getName());
        viewHolder.artistName.setText(arrayList.get(position).getArtistName());
        String imgUrl = arrayList.get(position).getThumbImageUrl();

        makeImageRequest(imgUrl, viewHolder);
        viewHolder.parentView.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, -1);
            }
        });
        viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, v.getId());
            }
        });

    }

    // class to hold a reference to each item of RecyclerView
    public static class ViewHolder extends RecyclerView.ViewHolder
    {

        public TextView albumName, artistName;
        public ImageView albumIcon, settingButton;
        public LinearLayout parentView;

        public ViewHolder(View itemLayoutView)
        {
            super(itemLayoutView);
            // albumBg = (LinearLayout) itemLayoutView
            // .findViewById(R.id.albumDlbg);
            albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
            artistName = (TextView) itemLayoutView
                    .findViewById(R.id.artistName);
            albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
            parentView = (LinearLayout) itemLayoutView
                    .findViewById(R.id.albumDlbg);
            settingButton = (ImageView) itemLayoutView
                    .findViewById(R.id.settingBtn);
        }

    }

Passaggio 3: trova e configura la vista del riciclatore nell'attività o nel frammento in cui lo stai utilizzando

recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);

        lm = new LinearLayoutManager(mActivity);
        lm.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(lm);
        recyclerView.addItemDecoration(
                new HorizontalDividerItemDecoration.Builder(getActivity())
                        .paint(Utils.getPaint()).build());
        PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
                mActivity, true);
        // set adapter
        recyclerView.setAdapter(mAdapter);
        mAdapter.setOnItemClickListener(this);
        // set item animator to DefaultAnimator
        recyclerView.setItemAnimator(new DefaultItemAnimator());

Passaggio 4: infine implementare l'interfaccia in attività o frammento in cui si sta utilizzando la vista recyclerview

@Override
    public void onRecyclerViewItemClicked(int position, int id)
    {
        if(id==-1){
            Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
        }
    }

2
Questa è la soluzione migliore perché di solito abbiamo bisogno di molte proprietà dall'attività / frammento sul nostro onItemClickListener e non ha senso chiamarlo direttamente dal viewholder (dovrei creare un costruttore personalizzato per ogni adattatore). A proposito, il tuo codice è un po 'esteso, ti suggerisco di tagliarlo nella parte più importante (setOnItemClickListener).
sagits

questo è un buon approccio semplice per differenziare la riga / oggetto dai sotto-elementi
Nigel Savage

17

Ecco cosa ho fatto. Questa soluzione supporta sia onClick che onLongClick su RecyclerView Items e Views all'interno di RecyclerView Items (visualizzazioni interne).

Taggo viewHolder sulle viste di mia scelta:

public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
    ViewHolder viewHolder = new ViewHolder(itemView);

    itemView.setOnClickListener( this);
    itemView.setOnLongClickListener(this);
    viewHolder.imageIV.setOnClickListener(this);
    viewHolder.imageIV.setOnLongClickListener(this);

    viewHolder.imageIV.setTag(viewHolder);
    itemView.setTag(viewHolder);

    return viewHolder;
}

E io uso holder.getPosition () per recuperare la posizione nel metodo onClick () (onLongClick è simile):

public void onClick(View view) {
    ViewHolder holder = (ViewHolder) view.getTag();
    int position = holder.getPosition();

    if (view.getId() == holder.imageIV.getId()){
        Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show();
    }
}

Una variante con getChildPosition funziona anche. Per le viste interne, in onClick () utilizzare:

int position = recyclerView.getChildPosition((View)view.getParent());

A mio avviso, l'avantage di questa soluzione è che quando si fa clic sull'immagine, viene chiamato solo l'ascoltatore di immagini onclick () mentre quando ho combinato la soluzione di Jacob per una vista degli oggetti RecyclerView e la mia soluzione per le viste interne, la vista degli articoli di RecyclerView onclick ( ) viene anche chiamato (quando si fa clic sull'immagine).


11

C'è un modo molto più semplice per farlo. Basta applicare facendo clic suonBindViewHolder su vista principale.

Considera che questa è la tua visione per l'adattatore,

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

        <TextView
            android:id="@+id/textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1dp"
            android:textSize="15sp" />
</LinearLayout>

Quindi seguire la procedura nell'adattatore

//get the layout and make view holder
@Override
public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null);
    ViewHolder1 viewHolder = new ViewHolder1(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) {

    //apply on click on your root view
    holder.linearlayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Do on click stuff
        }
    });
}

//make references to views in layout including root view
public class ViewHolder1 extends RecyclerView.ViewHolder {

    protected LinearLayout linearlayout = null
    protected TextView textview = null;

    public CareerLinksViewHolder(View itemView) {
        super(itemView);

        this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
        this.tvCompName = (TextView) itemView.findViewById(R.id.textview);
    }
}

9

Puoi passare un clickListenera Adapter.

Nel tuo Activity:

private View.OnClickListener mItemClick = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent intent = null;
        int position = list.getChildPosition(v);
        switch (position) {
            case 0:
                intent = new Intent(MainActivity.this, LeakCanaryActivity.class);
                break;
            case 1:
                intent = new Intent(MainActivity.this, ButterKnifeFragmentActivity.class);
                break;
        }
        if (intent != null) {
            MainActivity.this.startActivity(intent);
        }
    }
};

quindi passalo a Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

In Adapter's onCreateViewHolder:

 @Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
    View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false);
    ViewHolder holder = new ViewHolder(itemView);
    itemView.setOnClickListener(mItemClick);
    return holder;
}

Come si passano i holdervalori attraverso l'intento?
RoCk RoCk

8

Ho sviluppato una libreria leggera per Android, puoi visitare https://github.com/ChathuraHettiarachchi/RecycleClick

e seguire per il seguente esempio

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });

Posso confermare, questa libreria è fantastica! Molto facile da usare, buon lavoro!
peterkodermac,

7

Puoi implementare OnClickListener nella tua classe ViewHolder

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public Item item
        @InjectView(R.id.tv_title)
        public TextView tvTitle;
        @InjectView(R.id.rl_row)
        public RelativeLayout rlRow;

        public ViewHolder(View v) {
            super(v);
            ButterKnife.inject(this, v);
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            Log.e("item title",item.getTitle());
        }
    }

E onBindViewHolder imposta l'elemento del titolare della vista

public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tvTitle.setText(objects.get(position).getTitle());
        holder.item = objects.get(position);
        }

7

Troppo semplice ed efficace.

Invece di implementare l'interfaccia View.OnClickListenerall'interno del view view o creare e interfacciare e implementare l'interfaccia nella tua attività, ho usato questo codice per una semplice OnClickListenerimplementazione.

public static class SimpleStringRecyclerViewAdapter
            extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {

        // Your initializations goes here...
        private List<String> mValues;

        public static class ViewHolder extends RecyclerView.ViewHolder {

            //create a variable mView
            public final View mView;

            /*All your row widgets goes here
            public final ImageView mImageView;
            public final TextView mTextView;*/

            public ViewHolder(View view) {
                super(view);
                //Initialize it here
                mView = view;

                /* your row widgets initializations goes here
                mImageView = (ImageView) view.findViewById(R.id.avatar);
                mTextView = (TextView) view.findViewById(android.R.id.text1);*/
            }
        }

        public String getValueAt(int position) {
            return mValues.get(position);
        }

        public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {

            mBackground = mTypedValue.resourceId;
            mValues = items;
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item, parent, false);
            view.setBackgroundResource(mBackground);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(final ViewHolder holder, int position) {
            holder.mBoundString = mValues.get(position);
            holder.mTextView.setText(mValues.get(position));

            //Here it is simply write onItemClick listener here
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Context context = v.getContext();
                    Intent intent = new Intent(context, ExampleActivity.class);

                    context.startActivity(intent);
                }
            });
        }

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

3
Questa è una cattiva pratica comune perché sembra troppo facile. Stai creando un nuovo ascoltatore interno ogni volta che un oggetto viene associato (e ogni elemento in un riciclatore può essere rilegato molte volte), il che è negativo per a) prestazioni b) garbage collection. Invece dovresti creare UN listener da qualche parte (nel viewholder, nell'adattatore, nel frammento o attività superiore) e aggiungerlo agli elementi nel costruttore del viewholder su onCreateViewHolder. Ciò ha l'ulteriore complessità di dover capire quale elemento era clicker, ma può essere risolto facilmente tramite tag o aggiungendo ulteriori informazioni al titolare.
GuillermoMP,

6

Tutte le risposte pubblicate finora sono ottime soluzioni, tuttavia se non si desidera gestire troppi dettagli di implementazione e si desidera solo che funzioni in modo simile a come funziona ListView, si consiglia di utilizzare TwoWay-View, come mostrato qui:

https://github.com/lucasr/twoway-view

Si noti che questa implementazione supporta anche una lunga pressione sugli oggetti, nonché il supporto per gli stati urgenti (che è qualcosa di importante che mancano altre soluzioni a questa domanda).

Se non desideri utilizzare l'intera libreria, dai un'occhiata alla classe ClickItemTouchListener , che può essere utilizzata come standalone se necessario. L'unico problema che ho riscontrato al momento è con una pressione prolungata + scorrimento, sembra avere un comportamento errato.


6

Se desideri catturare l'evento click su singoli elementi, implementalo OnClickListenerin ViewHolderclasse e imposta i listener di clic su viste singole o intere itemView.

L'esempio seguente mostra lo stesso

public  class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener
    {
        TextView txt_title,txt_name,txt_email;

        public ContactViewHolder(View itemView) 
        {
            super(itemView);
            txt_title = (TextView)itemView.findViewById(R.id.txt_title);
            txt_name  = (TextView)itemView.findViewById(R.id.txt_name);
            txt_email = (TextView)itemView.findViewById(R.id.txt_email);

            txt_name.setOnClickListener(this);
            txt_email.setOnClickListener(this);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            if(v == itemView)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Visiting Card Clicked is ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_name)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Name ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_email)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Email ==>"+txt_email.getText(), Toast.LENGTH_SHORT).show();
            }
        }

    }
} 

5

Per me, questo è il modo migliore:

class YourRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> implements View.OnClickListener { 
  ...
  @Override
  public void onClick(View view) {
        int itemPosition = vRecycle.getChildPosition(view);
        //And use itemPosition to get the item from your collection. This way you dont restrain the ViewHolder with a OnClick callback
    }
  ...
}

3
getChildPosition () è decapitato
Nasz Njoka Sr.

5

Il RecyclerViewnon ha unOnClickListener e dovrà implementare noi stessi.

Mi piace aggiungere OnItemClickListenerun'interfaccia Adaptercon un onClickmetodo invocato quando si fa clic sulla vista elemento dal ViewHolder. Pertanto, la responsabilità di gestire il clic su un elemento è esterna a ViewHoldereAdapter . Sarà l'attività o il frammento che deciderà cosa fare

Aggiungi un'interfaccia al listener e all'oggetto listener.

public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> {

  ...

  private static OnItemClickListener onItemClickListener;

  ...

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  ...
}

Catturiamo il clic della vista principale dell'elemento e quando viene attivato il callback, la chiamata del onClicklistener sull'adattatore.

public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> {

  ...

  private static OnItemClickListener onItemClickListener;

  ...

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  ...

  public static class ViewHolder extends RecyclerView.ViewHolder {
      public ImageView imageView;

      public ViewHolder(View itemRootView) {
          super(itemRootView);
          imageView = (ImageView) itemRootView.findViewById(R.id.itemImage);

          itemRootView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  int position  = ViewHolder.super.getAdapterPosition();
                  onItemClickListener.onItemClick(view,position);
              }
          });
      }
  }
}

Poiché l'attività o il frammento, frammento nel nostro caso, assegniamo un listener all'adattatore e il callback onClick otterremo l'oggetto selezionato per posizione e apriremo un'attività dettagliata dell'articolo.

public class ItemsFragment extends Fragment {
    ...
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       ...    
        ((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                //Do something when an item has been clicked
            }
        });
        ...
    }
...
}

5

Purtroppo RecyclerViewmancano un paio di funzionalità ListViewintegrate. Ad esempio la possibilità di aggiungere OnItemClickListenerun elemento che si innesca quando si fa clic su un elemento. RecyclerViewti permette di impostare un OnClickListenernel tuo adattatore, ma passare quel listener di clic dal tuo codice chiamante, all'adattatore e al ViewHolder, è complicato per catturare un semplice clic dell'elemento.

public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mOnItemClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
    }
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        if (mOnItemLongClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
        return false;
    }
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
        = new RecyclerView.OnChildAttachStateChangeListener() {
    @Override
    public void onChildViewAttachedToWindow(View view) {
        if (mOnItemClickListener != null) {
            view.setOnClickListener(mOnClickListener);
        }
        if (mOnItemLongClickListener != null) {
            view.setOnLongClickListener(mOnLongClickListener);
        }
    }

    @Override
    public void onChildViewDetachedFromWindow(View view) {

    }
};

private ItemClickSupport(RecyclerView recyclerView) {
    mRecyclerView = recyclerView;
    mRecyclerView.setTag(R.id.item_click_support, this);
    mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}

public static ItemClickSupport addTo(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support == null) {
        support = new ItemClickSupport(view);
    }
    return support;
}

public static ItemClickSupport removeFrom(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support != null) {
        support.detach(view);
    }
    return support;
}

public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
    mOnItemClickListener = listener;
    return this;
}

public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
    mOnItemLongClickListener = listener;
    return this;
}

private void detach(RecyclerView view) {
    view.removeOnChildAttachStateChangeListener(mAttachListener);
    view.setTag(R.id.item_click_support, null);
}

public interface OnItemClickListener {

    void onItemClicked(RecyclerView recyclerView, int position, View v);
}

public interface OnItemLongClickListener {

    boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}

È inoltre necessario definire R.id.item_click_supportutilizzando ids.xml:

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
  <item name="item_click_support" type="id" />
 </resources>

Il listener di clic di codice risultante ora appare così:

ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
    // do it
}
});

Per una breve spiegazione sui clic di recyclerview, dai un'occhiata a questo littlerobots_blog


5

puoi facilmente definire setOnClickListener nella tua classe ViewHolder come segue:

public class ViewHolder extends RecyclerView.ViewHolder {
    TextView product_name;

    ViewHolder(View itemView) {
        super(itemView);
        product_name = (TextView) itemView.findViewById(R.id.product_name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int itemPosition = getLayoutPosition();
                Toast.makeText(getApplicationContext(), itemPosition + ":" + String.valueOf(product_name.getText()), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

5

Ecco cosa ho fatto Per saperne di più e scaricare l'essenza qui

Aggiungendo lo stesso qui

CustomItemClickListener.java

public interface CustomItemClickListener {
 public void onItemClick(View v, int position);
}

ItemsListAdapter.java

public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> {
ArrayList<ItemListSingleItem> data;

Context mContext;
CustomItemClickListener listener;

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false);
    final ViewHolder mViewHolder = new ViewHolder(mView);
    mView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            listener.onItemClick(v, mViewHolder.getAdapterPosition());
        }
    });
    return mViewHolder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.itemTitle.setText(Html.fromHtml(data.get(position).getTitle()));
    if (!TextUtils.isEmpty(data.get(position).getThumbnailURL())) {
      // I Love picasso library :) http://square.github.io/picasso/
        Picasso.with(mContext).load(data.get(position).getThumbnailURL()).error(R.drawable.ic_no_image).
                placeholder(R.drawable.ic_no_image).
                transform(new RoundedCornersTransformation(5, 0)).
                into(holder.thumbnailImage);
    } else {
        holder.thumbnailImage.setImageResource(R.drawable.ic_no_image);
    }
}


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

public ItemsListAdapter(Context mContext, ArrayList<ItemsListSingleItem> data, CustomItemClickListener listener) {
    this.data = data;
    this.mContext = mContext;
    this.listener = listener;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView itemTitle;
    public ImageView thumbnailImage;

    ViewHolder(View v) {
        super(v);
        itemTitle = (TextView) v
                .findViewById(R.id.post_title);
        thumbnailImage = (ImageView) v.findViewById(R.id.post_thumb_image);
    }
 }
}

4

Dalla maggior parte delle risposte sopra, sembra che stiano impostando i loro onclicklistener su singoli elementi. Tuttavia, la soluzione che sto per offrire è molto semplice ma non intuitiva per molti. Molti dimenticano che gli altri componenti si trovano sempre in un componente padre che viene utilizzato per visualizzare gli elementi nelle viste Elenco o Riciclatore. Questa soluzione consiste semplicemente nell'impostare un singolo ascoltatore onclick a questa vista principale e il turno viene giocato. La soluzione include anche un modo per passare la posizione dell'elemento su cui si fa clic dall'elenco o dalla vista del riciclatore. Qui, il nostro rootview principale è un CardView dalla libreria di supporto Android. Ecco un codice di esempio

public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {

public static final String LOG_TAG = ListAdapter.class.getSimpleName();
private Cursor mDataset;
private Context mContext;
private ViewHolder mViewHolder;

// Provide a suitable constructor (depends on the kind of dataset)
public ListAdapter(Context context, Cursor Dataset) {
    mDataset = Dataset;
    mContext = context;
}

// Create new views (invoked by the layout manager)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // create a new view
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.list_business_view, parent, false);

    mViewHolder = new ViewHolder(v);
    return mViewHolder;
}

public void setData(Cursor newdata) {
    this.mDataset = newdata;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Bind data to other items here. To save time, i have ommited that.
           //here is where we attach a click listerner for an item in the recycler list rather than for each element of a given item.
            holder.card.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext, " Just cliked item at position " + itemPosition, Toast.LENGTH_LONG).show();

            }
        });

    }
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    if (null != mDataset) {
        return mDataset.getCount();
    }
    return 0;

}


// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder{
    // each data item is just a string in this case
    public final TextView mBusinesssName; // View for the business name
    public final TextView mBusinessCategory; //View for the category name
    public final ImageView businessImage; // View for the business category image Image
    public final TextView mBusinessDistance; // View for the distance
    public final CardView card;

    public ViewHolder(View view) {
        super(view);
        mBusinesssName = (TextView) view.findViewById(R.id.list_item_name_textview);
        mBusinessCategory = (TextView) view.findViewById(R.id.list_item_category_textview);
        mBusinessDistance = (TextView) view.findViewById(R.id.list_item_dist_textview);
        businessImage = (ImageView) view.findViewById(R.id.list_item_icon);
        card = (CardView) view.findViewById(R.id.card_view);

    }
}
}

4

Implementazione di Kotlin della risposta di nhaarman :

mRecyclerView.addOnItemTouchListener(object  : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
            override fun onItemClick(view: View, position: Int) {

            }

            override fun onLongItemClick(view: View?, position: Int) {

            }
}){})

RecyclerItemClickListener.java:

import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View


open class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener {

    private var mGestureDetector: GestureDetector

    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int)

        fun onLongItemClick(view: View?, position: Int)
    }

    init {
        mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent): Boolean {
                return true
            }

            override fun onLongPress(e: MotionEvent) {
                val child = recyclerView.findChildViewUnder(e.x, e.y)
                if (child != null && mListener != null) {
                    mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
                }
            }
        })
    }

    override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
        val childView = view.findChildViewUnder(e.x, e.y)
        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
            return true
        }
        return false
    }

    override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {}

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}

3
public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, year, genre;

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            genre = (TextView) view.findViewById(R.id.genre);
            year = (TextView) view.findViewById(R.id.year);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, ""+getAdapterPosition(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

3

ecco il codice completo per il mio adattatore personalizzato, questo codice gonfia le righe con gli elementi dell'elenco definiti nel file xml denominato "list_item", inoltre eseguirà un evento clic su tutte le righe degli elementi dell'elenco con le rispettive posizioni.

public class MyCustomAdapter extends RecyclerView.Adapter`<`AdapterMyCustomAdapter.ViewHolder> {

    public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
        public onItemClickListener mListener;
        public ViewHolder(View v, onItemClickListener listener) {
            super(v);
            mListener =listener;
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            mListener.onRecyclerItemClick(v, getPosition());
        }

        public static interface onItemClickListener {
            public void onRecyclerItemClick(View view , int position);
        }
    }

    @Override
    public int getItemCount() {
        return 5;
    }

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

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item, parent, false);

    /* here list_item is an xml file we want to inflate ...it is same as we do in case of listview for customization.*/

        MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() {

            @Override
            public void onRecyclerItemClick(View view, int position) {
                System.out.println("clicked on list item at position " +position);
            } 
        });
        return vh;
    }
}

2

Possiamo farlo usando riferimenti deboli Java. Semanticamente, il titolare della vista è quello che dovrebbe rispondere all'evento clic o delegarlo al risponditore corretto.

I nostri obiettivi:

  1. Il Viewholder non dovrebbe sapere nulla della classe che risponde agli eventi, tranne che implementa una certa interfaccia.
  2. Il gestore di clic dovrebbe ottenere la posizione in RecyclerView della vista selezionata.
  3. Dovremmo essere in grado di discernere quale vista è stata cliccata nel supporto della vista.
  4. Mantenere un accoppiamento lento tra tutti i componenti e non provocare alcun ciclo di ritenzione.

passi:

  1. Crea un'interfaccia per gestire le risposte ai clic.

  2. Implementare questa interfaccia nell'attività che gestirà il clic.

  3. Aggiungi una variabile membro nell'adattatore RecyclerView per contenere il riferimento debole e un costruttore che lo imposta.

  4. Fai lo stesso in RecyclerView ViewHolder e aggiungi una variabile membro per tenere traccia della posizione.

  5. Imposta i tuoi ascoltatori al clic su qualsiasi vista desideri in ViewHolder, quindi richiama il risponditore per gestirli.

  6. Modifica il metodo onBindViewHolder per impostare la posizione durante l'associazione.

  7. Passa il risponditore verso il basso su ViewHolder.

  8. Nel risponditore, ora puoi usare getId () nella vista per capire quale vista è stata cliccata.

Ed ecco un Gist in modo da poter vedere come va tutto bene insieme: gestione dei clic di RecyclerView


2

Sono consapevole che ci sono molte risposte, ma ho pensato che potrei anche fornire la mia implementazione. (I dettagli completi sono disponibili su un'altra domanda a cui ho risposto ).

Pertanto, per aggiungere un listener di clic, ViewHolderè necessario implementare la classe interna View.OnClickListener. Questo è perché si impostare un OnClickListeneral itemViewparametro del ViewHoldercostruttore di 's. Lascia che ti mostri cosa intendo:

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

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

        // we do this because we want to check when an item has been clicked:
        itemView.setOnClickListener(this);

        // now, like before, we assign our View variables
        title = (TextView) itemView.findViewById(R.id.text1);
        subtitle = (TextView) itemView.findViewById(R.id.text2);
    }

    @Override
    public void onClick(View v) {
        // The user may not set a click listener for list items, in which case our listener
        // will be null, so we need to check for this
        if (mOnEntryClickListener != null) {
            mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
        }
    }
}

Le uniche altre cose che devi aggiungere sono un'interfaccia personalizzata per il tuo Adaptere un metodo setter:

private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}

Quindi il tuo nuovo supporto per i clic Adapterè completo.

Ora usiamolo ...

    ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects);
    clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() {
        @Override
        public void onEntryClick(View view, int position) {
            // stuff that will happen when a list item is clicked
        }
    });

Fondamentalmente è come impostare un normale Adapter, tranne per il fatto che usi il tuo metodo setter che hai creato per controllare cosa farai quando il tuo utente fa clic su un particolare elemento dell'elenco.

Puoi anche consultare una serie di esempi che ho fatto su questo Gist su GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07


Dovresti usare getAdapterPosition () invece di getLayoutPosition ()
BladeCoder il

2

Questo è quello che faccio per riutilizzare OnClickListener

  public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyviewHolder>
                                         implements View.OnClickListener

in ViewHoder Prendi il genitore di itemlayout

  public class MyviewHolder extends RecyclerView.ViewHolder {

       LinearLayout linearLayout_item;

        public MyviewHolder(View itemView) {
            super(itemView);
            linearLayout_item=itemView.findViewById(R.id.linearLayout_item);
        }
    }

in onBindViewHolder imposta il tag come posizione

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

       holder.linearLayout_item.setTag(position);
       holder.linearLayout_item.setOnClickListener(this);
    }

e in Onclick

 @Override
public void onClick(View v) {

    int position = (int) v.getTag();
    switch (v.getId()) {
        case R.id.linearLayout_item:

            // do some thing with position 

            break;
    }
}

2

Per me il modo pulito per farlo è questo.

Costruttore dell'adattatore

private class EnvironmentTypeRecyclerViewAdapter extends RecyclerView.Adapter<EnvironmentTypeRecyclerViewAdapter.ViewHolder>
{
     private final EnvironmentTypeRecyclerViewAdapterListener mEnvironmentTypeRecyclerViewAdapterListener;
     private List<Environment> mEnvironmentsData;

     public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
     {
         public ViewHolder(View v)
         {
             super(v);
             v.setOnClickListener(this);

         }

         @Override
         public void onClick(View v)
         {
              Environment environment = mEnvironmentsData.get(getAdapterPosition());
              if (mEnvironmentTypeRecyclerViewAdapterListener != null && environment != null) {
                      mEnvironmentTypeRecyclerViewAdapterListener.onListItemSelected(environment);      
              }
        }

        public EnvironmentTypeRecyclerViewAdapter(List<SmallCellEnvironment> environments, EnvironmentTypeRecyclerViewAdapterListener environmentTypeRecyclerViewAdapterListener)
        {
            mEnvironmentTypeRecyclerViewAdapterListener = environmentTypeRecyclerViewAdapterListener;
            mEnvironmentsData = environments;
        }
}

L'interfaccia collegata

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
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.