RecyclerView onClick

583

Hat jemand, der verwendet RecyclerView, einen Weg gefunden, um onClickListenerElemente in der zu setzen RecyclerView? Ich habe darüber nachgedacht, für jedes Element einen Listener für jedes Layout festzulegen, aber das scheint ein wenig zu mühsam zu sein. Ich bin mir sicher, dass es eine Möglichkeit gibt RecyclerView, auf das onClickEreignis zu hören , aber ich kann es nicht ganz herausfinden.

CurtJRees
quelle
4
RecyclerViewDemo Ich fand dieses Projekt großartig und verwendete Schnittstellen, um mehr kostenlose Aktionen bereitzustellen.
MewX
2
Überprüfen Sie dieses Tutorial wiki.workassis.com/android-recyclerview-example
Bikesh M
Einfach und leicht zu bedienen - github.com/rahulkapoor1/ClickableAdapter
Rahul
stackoverflow.com/a/31199564/5788247
Shomu

Antworten:

477

Da sich die APIs radikal geändert haben, würde es mich nicht überraschen, wenn Sie OnClickListenerfür jedes Element eine erstellen würden. Es ist allerdings kein so großer Aufwand. Bei Ihrer Implementierung von RecyclerView.Adapter<MyViewHolder>sollten Sie Folgendes haben:

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

Die onClickMethode:

@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();
}
Nhaarman
quelle
32
Was ist, wenn ich eine Zeile beim Klicken löschen möchte?
Piyush Kukadiya
20
Diese Antwort gefällt mir besser als die, die Sie verlinkt haben. Wer möchte einen Gesten-Listener schreiben und die Box-Erkennung treffen, um dies zu handhaben. Google
Lo-Tan
17
getChildPosition (Ansicht) ist veraltete Methode
Jigar
45
Haben Sie etwas dagegen zu sagen, in welchen Klassen sich Ihre Schnipsel befinden? onClick(), gehört zu OnClickListenerkann an jede Ansicht angehängt werden. Die ganze Frage hier ist welche! Bitte bemühen Sie sich, eine Methode wird nicht nur durch einen Namen, sondern zumindest durch eine Klasse identifiziert. Wenn Sie nicht sagen, dass Ihr Code zum Adapter hinzugefügt werden soll, hilft Ihre Antwort nicht wirklich.
Vince
16
Sollte sich die onClick-Methode in dem Fragment befinden, das die RecyclerView enthält? Weil Sie in Ihrer MyOnClickListener-Klasse auf mRecyclerView verweisen. Woher haben Sie den Verweis auf dieses Objekt?
Ced
606

Hier ist eine bessere und weniger eng gekoppelte Möglichkeit, ein OnClickListenerfor a zu implementieren RecyclerView.

Nutzungsausschnitt:

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 Implementierung:

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){}
}
Jacob Tabak
quelle
85
Dies gibt keinen Hinweis darauf, auf welche Schaltfläche oder Ansicht (innerhalb des Elements) geklickt wurde. Für den gesamten Artikelklick ist dies jedoch in Ordnung.
Niranjan
27
Der Kommentar von ngen ist korrekt. Wenn Sie einen onClick-Listener an ein bestimmtes Element in der Elementansicht anhängen möchten, sollten Sie dies wahrscheinlich in Ihrem Adapter, in onBindViewHolder oder in Ihrem Ansichtsinhaber selbst tun.
Jacob Tabak
16
Ein Problem bei dieser Methode besteht darin, dass Sie etwas tun, das einige hundert Millisekunden dauert, wie das Starten einer Aktivität. Wenn auf das Element geklickt wird und eine angeklickte Animation vorhanden ist, tritt eine merkliche Verzögerung zwischen dem Klicken und dem Anzeigen der Animation auf.
Gak2
20
Diese Lösung fühlt sich extrem klobig an, es gibt einige Verzögerungen bei der Verarbeitung des "Klicks" und das Gefühl ist nicht nur in
Ordnung
6
Kann mir jemand erklären, warum diese Lösung mit dem GestureDetector eine bessere Lösung sein soll, als nur "setOnClickListener" in onBindViewHolder () im Adapter für das entsprechende Element zu verwenden? Auf diese Weise benötige ich zumindest weniger Code als mit der GestureDetector-Lösung. Danke für eine Erklärung.
E-Natur
115

Ich mache es auf diese Weise, ohne übermäßige Klassen, Detektoren usw. Einfacher Code in unserem Adapter. Besonders bessere Lösung für longClick als zuvor.

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

Dann innerhalb eines Fragments oder einer Aktivität einfach drücken:

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);
    }
});
Marurban
quelle
Anstelle von OurAdapter.clickListener bedeutet Marurban PasswordAdapter.clickListener und anstelle von TrainingAdapter.ClickListener () sollte PasswordAdapter.ClickListener () sein. Davon abgesehen tolle Lösung Marurban! arbeitete für mich
Nommer
Der onItemClick-Listener wird auch bei langem Klicken aktiviert.
Rashad.Z
10
ViewHolder muss statisch sein, um die beste Leistung zu erzielen. Das ist keine gute Antwort.
Gilberto Ibarra
10
Der statische clickListener erzeugt einen Speicherverlust. Deklarieren Sie den Listener als nicht statisch und binden Sie ihn stattdessen an den ViewHolder.
BladeCoder
1
@AJW Der einfachste Weg besteht darin, den Listener frühzeitig zu initialisieren und als Argument an den Adapterkonstruktor und dann an den ViewHolder-Konstruktor zu übergeben.
BladeCoder
97

Schauen Sie sich eine ähnliche Frage an. @ CommonsWares Kommentar verlinkt darauf , wodurch die OnClickListenerSchnittstelle in der implementiert wird viewHolder.

Hier ist ein einfaches Beispiel für 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++){

        }


      }
  }

Das Adaptersieht dann so aus:

    @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);
    }
Bolot
quelle
14
Dies scheint jedoch in die falsche Richtung zu gehen. Wenn Sie eine Recycling-Ansicht in einem anderen Fragment / einer anderen Aktivität wiederverwenden müssen, definiert der Adapter / Ansichtsinhaber jetzt die Logik der Klicks anstelle dessen, was sie enthält. Die Klicks sollten wirklich direkt oder indirekt von der enthaltenden Instanz verarbeitet werden. Es scheint, dass ein Touch-Listener der einzig effektive Weg ist, dies zu tun.
ian.shaun.thomas
18
@tencent Ich sehe nicht, wie das das Problem ist. Wenn der ViewHolder selbst alle Informationen darüber enthält, welche Daten beim Klicken auf das Element selbst ausgewählt werden, liegt die einzige Verantwortung des Containers in der Anzeige von N Elementen und nicht in der Auswahl eines bestimmten i-ten Elements der N Elemente. Das ListViewwar schon problematisch, wenn man eine Liste komplizierterer Objekte als nur einfacher Zeilen erstellen musste. Was ist, wenn Sie unterschiedliche Ereignisse behandeln müssen, je nachdem, wo Sie auf das Element in der ListView klicken? Du bist beschissen. Hier haben Sie jeweils Zuhörer.
EpicPandaForce
2
Ich stimme @EpicPandaForce in diesem Punkt zu. Ich habe diese Antwort auch positiv bewertet, nachdem ich den Abschnitt in Commonswares Buch über den Umgang mit Klicks in RecyclerViews gelesen hatte. Bisher hat es für mich hervorragend funktioniert.
AdamMc331
1
findViewById wird hier nur bei der Erstellung von Ansichtshaltern verwendet (daher onCreateViewHolder). Der Ansichtsinhaber soll verhindern, dass die Ansicht jedes Mal gefunden wird, wenn ein Element an den Inhaber gebunden wird, und nicht bei der erstmaligen Erstellung.
Stuckj
2
getPosition()ist veraltet, verwenden getAdapterPosition()oder getLayoutPosition()stattdessen.
K Neeraj Lal
94

Basierend auf der Antwort von Jacob Tabak (+1 für ihn) konnte ich onLongClick Listener hinzufügen:

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

Dann können Sie es so verwenden:

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) {
        // ...
    }
}));
Eng.Fouad
quelle
1
Ich habe eine Weile gebraucht, um mich an meine App anzupassen und Code an Java / Android-Standards auszurichten und zu formatieren, aber schließlich hat es gut funktioniert.
Milosmns
Wie fügt man eine Animation für den langen Klick hinzu?
Jon
1
@ Eng.Fouad Klickeffekt funktioniert nicht mit diesem, obwohl, wenn wir Klick Listener im Adapter setzen, Klick-Effekt funktioniert jede Lösung für dieses
ingsaurabh
4
Sie sollten auch überschreibenpublic void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
Paolo Rotolo
Aus irgendeinem Grund wird keine angeklickte Ansicht zurückgegeben. In meinem Fall klicke ich auf ein Kontrollkästchen, aber die angegebene Ansicht ist etwas anderes. Die Art und Weise, wie ich überprüfe:view.getId() == R.id.selection
dVaffection
63

Das hat bei mir funktioniert. Befestigen Sie die OnClickListeneran der onBindView. Ich weiß nicht wirklich, ob sich dies auf die Leistung auswirkt, aber es scheint mit wenig Code gut zu funktionieren.

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();
            }
    });
}
Bubunyo Nyavor
quelle
5
in meinem Fall Inhaber.itemView.setOnClickListener (..)
D4rWiNS
18
In meinem Fall heißt es 'itemView' anstelle von 'view' und sagt nur für Anfänger, einige von ihnen verstehen nicht, was sie kopieren, und können nicht herausfinden, warum es nicht funktioniert
D4rWiNS
3
Es ist die Layout-Position
Bubunyo Nyavor
1
Für mich scheint dies nur für das letzte sichtbare Element zu gelten, nicht für das angeklickte Element
Nasz Njoka Sr.
2
Diese Lösung scheint mir die beste zu sein, aber wie unterscheidet sich diese von der Antwort von @bolot in Bezug auf die Leistungsthermie? Er hat View.OnClickListener direkt in der ViewHolder-Klasse implementiert, die dann die onClick-Methode separat ausspuckt. Welches wäre die beste Lösung?
Edmond Tamas
46

Dies war so schwierig für mich, einen Listener für Artikelklicks in der Aktivität zu haben und auch einen Klicklistener für eine einzelne Ansicht des Artikels zu haben, der beim Listener für Artikelklicks nicht ausgelöst wird. Nachdem ich mit Jacob Tabaks Antwort herumgespielt habe, respektiere ich seine Antwort für das Klicken auf einen Gegenstand, wenn keine anderen Berührungsaktionen innerhalb des Gegenstands angezeigt werden.

Ich habe einen Brauch OnClickListener Oberfläche Ereignis-Klickereignis, das die Ansicht des angeklickten Elements und die Elementposition vom Adapter enthält. Ich präsentiere eine Instanz davon im Konstruktor (oder es kann mit Setter sein) und hänge sie an den View Listener Container Click Listener an.

Ich habe auch einen anderen Klick-Listener im Adapter (kann sich im Ansichtshalter befinden), der den aktuellen Ansichts-Klick aus dem Container verarbeitet.

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

In der Aktivität müssen Sie den Adapter initialisieren, indem Sie die Instanz von übergeben 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);
}

Und mein 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);
}}
Sir NIkolay Cesar der Erste
quelle
Dieser Ansatz hat für mich gut funktioniert - es bedeutet, dass Sie Klicks in der Aktivität und nicht in der Rasteransicht verarbeiten können
Leafcutter
3
Wo kann ich dir Geld geben? 4 Stunden suchen und dann habe ich Ihren Beitrag gelesen. Vielen Dank für die Zeit, die Sie für die Veröffentlichung benötigt haben.
Brandon
3
Das klingt dumm, aber hat dies ein Problem mit Speicher oder Effizienz? Weil wir den Klick-Listener jedes Mal zuweisen, wenn eine Ansicht gezeichnet wird, oder?
RGV
1
@Raghav Ja, jedes Mal, wenn die Ansicht gebunden wird, wird ein neuer Klick-Listener zugewiesen, aber dies ist der Standardablauf. Aber der mOnItemClickListener wird nur einmal für den Adapter erstellt, nur die Ansicht und seine Position sind bei jedem
Elementklick
3
Ein großartiges Beispiel, um die App-Leistung zu beeinträchtigen und Speicherüberlastung zu verursachen! In diesem Beispiel müssen Sie nur scrollen, um Hunderte von nutzlosen Objekten zu erstellen, die in einem Moment nutzlos sind und als garbige abgerufen werden müssen. @ NoobDogg ist richtig. Bei onBindView müssen keine ClickListener erstellt werden. Ein Klick-Listener muss einmal in onCreateView (oder Holder-Konstruktor) erstellt werden und ist vorhanden, während der Bildschirm mit diesem Adapter benötigt wird.
Mykola Tychyna
36

Dies ist, was ich am Ende brauchte, falls jemand es nützlich findet:

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

    }
}

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

Fifer Schafe
quelle
Von allen Versionen, die ich ausprobiert habe, ist dies die, die ich zum Arbeiten gebracht habe. Aber ist es in Ordnung, das so zu machen? Oder gibt es einen besseren Weg, wie Best Practice?
Matthias Loibl
1
Soweit ich das beurteilen konnte, war dies der einzige Weg. Überprüfen Sie dies für weitere Details! stackoverflow.com/a/24933117/1508887
Fifer Sheep
Wie kann ich ein neues Fragment innerhalb der onclick-Methode öffnen?
Hash
5
getAdapterPosition () ersetzt getPosition ()
Kennedy Nyaga
27

Ich habe eine schöne Lösung für RecyclerView'sonItemClickListener für die Elemente und Subitems

Schritt 1- Erstellen Sie eine Schnittstelle

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

Schritt 2: Verwenden Sie es dann wie onBindViewHolderfolgt in der Adaptermethode

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

    }

Schritt 3: Suchen und Einrichten der Recycler-Ansicht in Aktivität oder Fragment, in der Sie diese verwenden

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

Schritt 4: Implementieren Sie abschließend die Schnittstelle in Aktivität oder Fragment, in der Sie die Recycling-Ansicht verwenden

@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();
        }
    }
Gopal Singh Sirvi
quelle
2
Dies ist die beste Lösung, da wir normalerweise viele Eigenschaften von Aktivität / Fragment in unserem onItemClickListener benötigen und es keinen Sinn macht, sie direkt vom Ansichtsinhaber aus aufzurufen (ich müsste für jeden Adapter einen benutzerdefinierten Konstruktor erstellen). Ihr Code ist übrigens etwas intensiv, ich empfehle Ihnen, ihn auf den wichtigsten Teil (setOnItemClickListener) zu schneiden.
Sagits
Dies ist ein guter einfacher Ansatz, um die Zeile / das Element von den Unterelementen zu unterscheiden
Nigel Savage
17

Hier ist was ich getan habe. Diese Lösung unterstützt sowohl onClick als auch onLongClick sowohl für RecyclerView-Elemente als auch für Ansichten innerhalb von RecyclerView-Elementen (interne Ansichten).

Ich tagge viewHolder in den Ansichten meiner Wahl:

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

Und ich benutze Inhaber.getPosition (), um die Position in der onClick () -Methode abzurufen (onLongClick ist ähnlich):

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

Eine Variante mit getChildPosition funktioniert ebenfalls. Bitte beachten Sie, dass für die internen Ansichten in onClick () Folgendes verwendet wird:

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

Meiner Meinung nach besteht der Vorteil dieser Lösung darin, dass beim Klicken auf das Bild nur der Bild-Listener onclick () aufgerufen wird, während bei der Kombination von Jacobs Lösung für eine RecyclerView-Elementansicht und meiner Lösung für interne Ansichten die RecyclerView-Elementansicht onclick ( ) wird auch aufgerufen (wenn Sie auf das Bild klicken).

u2gilles
quelle
11

Es gibt einen viel einfacheren Weg, dies zu tun. Bewerben Sie sich einfach beim Klicken in der onBindViewHolderStammansicht.

Bedenken Sie, dass dies Ihre Ansicht für den Adapter ist.

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

Folgen Sie dann Ihrem Adapter

//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);
    }
}
Sushant
quelle
9

Sie können ein clickListeneran übergeben Adapter.

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

dann weitergeben an 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;
}
Francis Shi
quelle
Wie geben Sie die holderWerte absichtlich weiter?
RoCk RoCk
8

Ich habe eine leichte Bibliothek für Android entwickelt, die Sie unter https://github.com/ChathuraHettiarachchi/RecycleClick besuchen können

und folgen Sie für das folgende Beispiel

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });
Chathura Jayanath
quelle
Kann bestätigen, diese Bibliothek ist großartig! Sehr einfach zu bedienen, gute Arbeit!
Peterkodermac
7

Sie können OnClickListener in Ihre ViewHolder-Klasse implementieren

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

Und onBindViewHolder legt den Artikel Ihres Ansichtsinhabers fest

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

Viel zu einfach und effektiv.

Anstatt die Schnittstelle View.OnClickListenerin View View zu implementieren oder eine Schnittstelle in Ihrer Aktivität zu erstellen und eine Schnittstelle zu erstellen und zu implementieren, habe ich diesen Code zur einfachen OnClickListenerImplementierung verwendet.

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();
        }
    }
Manikanta
quelle
3
Dies ist eine weit verbreitete schlechte Praxis, da sie viel zu einfach aussieht. Sie erstellen jedes Mal einen neuen inneren Listener, wenn ein Objekt gebunden wird (und jedes Element in einem Recycler kann viele Male gebunden werden), was sich negativ auf a) Leistung b) Speicherbereinigung auswirkt. Stattdessen sollten Sie EINEN Listener irgendwo erstellen (im Viewholder, im Adapter, im oberen Fragment oder in der Aktivität) und ihn einfach zu den Elementen im Viewholder-Konstruktor in onCreateViewHolder hinzufügen. Dies hat die zusätzliche Komplexität, herausfinden zu müssen, welcher Artikel ein Klicker war, kann jedoch einfach über Tags oder das Hinzufügen weiterer Informationen zum Halter gelöst werden.
GuillermoMP
6

Alle bisher veröffentlichten Antworten sind großartige Lösungen. Wenn Sie jedoch nicht mit zu vielen Implementierungsdetails umgehen möchten und möchten, dass diese ähnlich wie ListView funktionieren, würde ich die Verwendung von TwoWay-View empfehlen, wie hier dargestellt:

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

Beachten Sie, dass diese Implementierung auch langes Drücken auf Elemente sowie die Unterstützung für gedrückte Zustände unterstützt (was wichtig ist, dass andere Lösungen für diese Frage fehlen).

Wenn Sie nicht die gesamte Bibliothek verwenden möchten, sehen Sie sich die ClickItemTouchListener- Klasse an, die bei Bedarf als eigenständige Klasse verwendet werden kann. Das einzige Problem, das ich im Moment dabei gefunden habe, ist das lange Drücken + Scrollen. Es scheint ein falsches Verhalten zu haben.

Jawnnypoo
quelle
6

Wenn Sie das Klickereignis für einzelne Elemente abfangen möchten, implementieren Sie es einfach OnClickListenerin der ViewHolderKlasse und legen Sie dann die Klick-Listener für einzelne oder ganze Ansichten festitemView .

Das folgende Beispiel zeigt dasselbe

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

    }
} 
HemangNirmal
quelle
5

Für mich ist das der beste Weg:

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
    }
  ...
}
4gus71n
quelle
3
getChildPosition () wird enthauptet
Nasz Njoka Sr.
5

Das RecyclerViewhat keineOnClickListener und muss es selbst umsetzen.

Ich möchte eine OnItemClickListenerSchnittstelle Adaptermit einer onClickMethode hinzufügen , die aufgerufen wird, wenn Sie in der Elementansicht auf klicken ViewHolder. Daher liegt die Verantwortung für die Verwaltung des Klicks auf ein Element außerhalb des ViewHolderundAdapter . Wird die Aktivität oder das Fragment entscheiden, was zu tun ist

Fügen Sie dem Listener und dem Listener-Objekt eine Schnittstelle hinzu.

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...
}

Wir erfassen den Klick der Stammansicht des Elements und wenn der Rückruf ausgelöst wird, onClickrufen Listener den Adapter an.

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

Da die Aktivität oder das Fragment, in unserem Fall das Fragment, dem Adapter und dem onClick-Rückruf einen Listener zuweist, erhalten wir das ausgewählte Element nach Position und öffnen eine detaillierte Aktivität des Elements.

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
            }
        });
        ...
    }
...
}
xurxodev
quelle
5

Leider RecyclerViewfehlen einige Funktionen, ListViewdie eingebaut waren. Zum Beispiel die Möglichkeit, eine hinzuzufügen OnItemClickListener, die ausgelöst wird, wenn auf ein Element geklickt wird. RecyclerViewSie können einen OnClickListenerin Ihrem Adapter festlegen , aber die Weitergabe dieses Klick-Listeners von Ihrem Aufrufcode an den Adapter und an den Adapter ViewHolderist kompliziert, um einen einfachen Elementklick zu erhalten.

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

Sie müssen auch R.id.item_click_supportmit ids.xml definieren :

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

Der resultierende Code-Klick-Listener sieht nun folgendermaßen aus:

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

Eine kurze Erklärung zu den Klicks auf die Recyclingansicht finden Sie in diesem littlerobots_blog

anand krish
quelle
5

Sie können setOnClickListener in Ihrer ViewHolder-Klasse wie folgt definieren:

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();
            }
        });
    }
}
Arash Hatami
quelle
5

Hier ist was ich getan habe Lesen Sie mehr und laden Sie das Wesentliche hier herunter

Fügen Sie das gleiche hier hinzu

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);
    }
 }
}
Muhammad Riyaz
quelle
4

Aus den meisten der obigen Antworten geht hervor, dass sie ihre Onclicklistener auf einzelne Elemente einstellen. Die Lösung, die ich anbieten werde, ist jedoch sehr einfach, aber für viele nicht intuitiv. Viele vergessen, dass sich die anderen Komponenten immer in einer übergeordneten Komponente befinden, mit der Elemente in den Listen- oder Recycler-Ansichten angezeigt werden. Bei dieser Lösung geht es nur darum, einen einzelnen On-Click-Listener auf diese übergeordnete Ansicht zu setzen, und der Zug wird gespielt. Die Lösung bietet auch eine Möglichkeit, die Position des Elements, auf das geklickt wird, in der Listen- oder Recycler-Ansicht zu übergeben. Hier ist unsere Hauptansicht eine CardView aus der Android-Support-Bibliothek. Hier ist ein Beispielcode

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

    }
}
}
larrytech
quelle
4

Kotlin Umsetzung von Nhaarmans Antwort :

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) {}
}
Nilesh Deokar
quelle
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();
                }
            });
        }
    }
Nullzeiger-Ausnahme
quelle
3

Hier ist der vollständige Code für meinen benutzerdefinierten Adapter. Dieser Code füllt die Zeilen mit Listenelementen auf, die in der XML-Datei mit dem Namen "list_item" definiert sind. Er führt auch ein Klickereignis für alle Listenelementzeilen mit entsprechenden Positionen durch.

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;
    }
}
Lone_iqbal
quelle
2

Wir können dies mit schwachen Java-Referenzen tun. Semantisch ist der Ansichtsinhaber derjenige, der auf das Klickereignis reagieren oder es an den richtigen Antwortenden delegieren soll.

Unsere Ziele:

  1. Der Viewholder sollte nichts über die Klasse wissen, die auf die Ereignisse reagiert, außer dass sie eine bestimmte Schnittstelle implementiert.
  2. Der Klick-Handler sollte die Position der angeklickten Ansicht in der RecyclerView erhalten.
  3. Wir sollten erkennen können, auf welche Ansicht im Ansichtshalter geklickt wurde.
  4. Sorgen Sie für eine lose Kopplung zwischen allen Komponenten und verursachen Sie keine Haltezyklen.

Schritte:

  1. Erstellen Sie eine Schnittstelle für Klickantworten.

  2. Implementieren Sie diese Schnittstelle in der Aktivität, die den Klick verarbeitet.

  3. Fügen Sie dem RecyclerView-Adapter eine Mitgliedsvariable hinzu, die die schwache Referenz und einen Konstruktor enthält, der sie festlegt.

  4. Machen Sie dasselbe im RecyclerView ViewHolder und fügen Sie eine Mitgliedsvariable hinzu, um die Position zu verfolgen.

  5. Stellen Sie Ihre On-Click-Listener auf eine beliebige Ansicht im ViewHolder ein und rufen Sie dann den Responder zurück, um sie zu verarbeiten.

  6. Ändern Sie Ihre onBindViewHolder-Methode, um die Position beim Binden festzulegen.

  7. Geben Sie den Responder an den ViewHolder weiter.

  8. Im Responder können Sie jetzt getId () für die Ansicht verwenden, um herauszufinden, auf welche Ansicht geklickt wurde.

Und hier ist eine Zusammenfassung, damit Sie sehen können, wie alles zusammenpasst: RecyclerView-Klickbehandlung

Rajiev Timal
quelle
2

Ich bin mir bewusst, dass es viele Antworten gibt, aber ich dachte, ich könnte auch nur meine Implementierung bereitstellen. (Ausführliche Informationen finden Sie auf einer anderen Frage, die ich beantwortet habe ).

Um einen Klick-Listener hinzuzufügen, muss Ihre innere ViewHolderKlasse implementiert werden View.OnClickListener. Dies liegt daran, dass Sie einen OnClickListenerauf den itemViewParameter des ViewHolderKonstruktors des Konstruktors setzen. Lassen Sie mich Ihnen zeigen, was ich meine:

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

Die einzigen anderen Dinge, die Sie hinzufügen müssen, sind eine benutzerdefinierte Schnittstelle für Ihre Adapterund eine Setter-Methode:

private OnEntryClickListener mOnEntryClickListener;

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

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

Also dein neues, klickunterstützendes Adapter abgeschlossen.

Jetzt lass es uns benutzen ...

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

Es ist im Grunde, wie Sie eine normale einrichten würden Adapter Methode , außer dass Sie Ihre von Ihnen erstellte Setter-Methode verwenden, um zu steuern, was Sie tun, wenn Ihr Benutzer auf ein bestimmtes Listenelement klickt.

Sie können sich auch eine Reihe von Beispielen ansehen, die ich in diesem Gist auf GitHub erstellt habe:

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

Farbod Salamat-Zadeh
quelle
Sie sollten getAdapterPosition () anstelle von getLayoutPosition ()
BladeCoder
2

Dies ist, was ich tue, um wiederzuverwenden OnClickListener

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

in ViewHoder Nehmen Sie das übergeordnete Element des Elementlayouts

  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 wird das Tag als Position festgelegt

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

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

und 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;
    }
}
Manohar Reddy
quelle
2

Für mich ist der saubere Weg, dies zu tun, dieser.

Adapterkonstruktor

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

Die verknüpfte Schnittstelle

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
Jeremie Petitjean
quelle