Ich habe nachgeforscht RecyclerView
und war überrascht zu sehen, dass RecyclerView
dies nicht der Fall ist onItemClickListener()
.
Ich habe zwei Fragen.
Hauptfrage
Ich möchte wissen, warum Google entfernt hat onItemClickListener()
.
Gibt es ein Leistungsproblem oder etwas anderes?
Sekundäre Frage
Ich habe mein Problem gelöst, indem ich Folgendes geschrieben onClick
habe RecyclerView.Adapter
:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
Ist das in Ordnung / gibt es einen besseren Weg?
java
android
android-recyclerview
Tarun Varshney
quelle
quelle
QUESTION
Antworten:
tl; dr 2016 Verwenden Sie RxJava und ein PublishSubject, um ein Observable für die Klicks verfügbar zu machen.
Ursprünglicher Beitrag:
Seit der Einführung von
ListView
,onItemClickListener
hat sich als problematisch gewesen. In dem Moment, in dem Sie einen Klick-Listener für eines der internen Elemente haben, wird der Rückruf nicht ausgelöst, aber er wurde nicht benachrichtigt oder (wenn überhaupt) gut dokumentiert, sodass es viel Verwirrung und SO-Fragen gab.Da
RecyclerView
dies einen Schritt weiter geht und kein Konzept für eine Zeile / Spalte, sondern eine willkürlich festgelegte Anzahl von untergeordneten Elementen enthält, haben sie den onClick an jeden von ihnen oder an die Programmiererimplementierung delegiert.Stellen Sie sich das
Recyclerview
nicht alsListView
1: 1-Ersatz vor, sondern als flexiblere Komponente für komplexe Anwendungsfälle. Und wie Sie sagen, ist Ihre Lösung genau das, was Google von Ihnen erwartet hat. Jetzt haben Sie einen Adapter, der onClick an eine Schnittstelle delegieren kann, die an den Konstruktor übergeben wird. Dies ist das richtige Muster fürListView
undRecyclerview
.und dann auf Ihrem Adapter
Schauen Sie sich nun den letzten Code an:
onCreateViewHolder(ViewGroup parent, int viewType)
Die Signatur schlägt bereits verschiedene Ansichtstypen vor. Für jeden von ihnen benötigen Sie auch einen anderen Ansichtsinhaber, und anschließend kann jeder von ihnen einen anderen Satz von Klicks haben. Oder Sie können einfach einen generischen Ansichtsinhaber erstellen, der eine beliebige Ansicht und eine Ansicht übernimmtonClickListener
und entsprechend angewendet wird . Oder delegieren Sie eine Ebene an den Orchestrator, damit mehrere Fragmente / Aktivitäten dieselbe Liste mit unterschiedlichem Klickverhalten haben. Auch hier ist jede Flexibilität auf Ihrer Seite.Es ist eine wirklich notwendige Komponente und ziemlich nah an dem, was unsere internen Implementierungen und Verbesserungen bisher
ListView
waren. Es ist gut, dass Google es endlich anerkennt.quelle
onBindViewHolder(holder, position)
, wo die Infos ausgefüllt werden sollen.getPosition()
ist veraltet "Diese Methode ist veraltet, da ihre Bedeutung aufgrund der asynchronen * Behandlung von Adapteraktualisierungen nicht eindeutig ist. Verwenden Sie je nach Anwendungsfall {@link #getLayoutPosition ()} oder * {@link #getAdapterPosition ()}. ""viewHolder.getPosition();
Warum der RecyclerView keine hat
onItemClickListener
Das
RecyclerView
ist eine Toolbox, im Gegensatz zum altenListView
hat es weniger eingebaute Funktionen und mehr Flexibilität. DasonItemClickListener
ist nicht die einzige Funktion von Listview entfernt werden. Aber es hat viele Zuhörer und Methoden, um es nach Ihren Wünschen zu erweitern, es ist in den richtigen Händen weitaus mächtiger;).Meiner Meinung nach
RecyclerView
ist die schnellste Funktion die komplexeste Funktion, die entfernt wurde . Die meisten anderen Funktionen können problemlos erneut implementiert werden.Wenn Sie wissen möchten, welche anderen coolen Funktionen
RecyclerView
hinzugefügt wurden, lesen Sie diese Antwort auf eine andere Frage.Speichereffizient - Drop-In-Lösung für onItemClickListener
Diese Lösung wurde vorgeschlagen von Hugo Visser , ein Android - GDE, direkt nach
RecyclerView
veröffentlicht wurde. Er hat Ihnen eine lizenzfreie Klasse zur Verfügung gestellt, in der Sie einfach Ihren Code eingeben und verwenden können.Es zeigt einige der Vielseitigkeit, die
RecyclerView
durch die Nutzung vonRecyclerView.OnChildAttachStateChangeListener
.Edit 2019 : Kotlin-Version von mir, Java One, von Hugo Visser, unten aufbewahrt
Kotlin / Java
Erstellen Sie eine Datei
values/ids.xml
und fügen Sie diese ein:Fügen Sie dann den folgenden Code zu Ihrer Quelle hinzu
Kotlin
Verwendungszweck:
(Es unterstützt auch lange Artikelklicks und siehe unten für eine weitere Funktion, die ich hinzugefügt habe).
Implementierung (meine Anpassung an Hugo Visser Java Code):
(siehe unten Sie müssen auch eine XML-Datei hinzufügen)
Bonusfunktion der Kotlin-Version
Manchmal möchten Sie nicht, dass alle Elemente der RecyclerView anklickbar sind.
Um dies zu handhaben, habe ich die
ItemClickSupportViewHolder
Benutzeroberfläche eingeführt, über die SieViewHolder
steuern können, auf welches Element geklickt werden kann.Beispiel:
Java
Verwendungszweck:
(Es unterstützt auch lange Artikelklicks)
Implementierung (Kommentare von mir hinzugefügt):
Wie es funktioniert (warum es effizient ist)
Diese Klasse funktioniert, indem ein
RecyclerView.OnChildAttachStateChangeListener
an das angehängt wirdRecyclerView
. Dieser Listener wird jedes Mal benachrichtigt, wenn ein Kind an das angeschlossen oder von diesem getrennt wirdRecyclerView
. Der Code verwendet dies, um einen Tap / Long Click-Listener an die Ansicht anzuhängen. Dieser Zuhörer fragtRecyclerView
nach dem,RecyclerView.ViewHolder
der die Position enthält.Dies ist effizienter als andere Lösungen, da nicht mehrere Listener für jede Ansicht erstellt werden und diese während des
RecyclerView
Bildlaufs weiterhin zerstört und erstellt werden.Sie können den Code auch anpassen, um den Halter selbst zurückzugeben, wenn Sie mehr benötigen.
Letzte Bemerkung
Denken Sie daran, dass es VOLLSTÄNDIG in Ordnung ist, dies in Ihrem Adapter zu handhaben, indem Sie in jeder Ansicht Ihrer Liste einen Klick-Listener festlegen, wie bei anderen vorgeschlagenen Antworten.
Es ist einfach nicht die effizienteste Sache (Sie erstellen jedes Mal einen neuen Listener, wenn Sie eine Ansicht wiederverwenden), aber es funktioniert und in den meisten Fällen ist es kein Problem.
Es ist auch ein bisschen gegen die Trennung von Bedenken, da es nicht wirklich die Aufgabe des Adapters ist, Klickereignisse zu delegieren.
quelle
addTo()
undremoveFrom()
. Die Instanz ist dem recyclerview-Tag zugeordnet und stirbt damit oder wenn es manuell entfernt wird.onCreateViewHolder
und das war's.RecyclerView
.Ich mag diesen Weg und ich benutze ihn
Innerhalb
Stellen
Und erstellen Sie diese Klasse, wo immer Sie möchten
Ich habe vorher gelesen, dass es einen besseren Weg gibt, aber ich mag diesen Weg ist einfach und nicht kompliziert.
quelle
MyOnClickListener
in Instanzvariable machen, weil Sie jedes Mal eine neue Instanz davon mit demnew
SchlüsselwortrecyclerView
in MyOnClickListener?Android Recyclerview With
onItemClickListener
, Warum wir es nicht versuchen können, funktioniertListView
nur so.Quelle: Link
Und setzen Sie dies auf RecyclerView:
quelle
SwipeRefreshLayout
Dank @marmor habe ich meine Antwort aktualisiert.
Ich denke, es ist eine gute Lösung, mit onClick () im ViewHolder- Klassenkonstruktor umzugehen und es über die OnItemClickListener- Schnittstelle an die übergeordnete Klasse zu übergeben .
MyAdapter.java
Verwendung des Adapters in anderen Klassen:
MyFragment.java
quelle
onBindViewHolder()
beim Scrollen auch mehrmals für dieselbe Ansicht aufgerufen. Selbst das Erstellen einer SingleOnClickListener
hilft nicht weiter, da Sie dieOnClickListener
jedes Mal zurücksetzen, wenn SieonBindViewHolder()
aufgerufen werden. Siehe stattdessen @ MLProgrammer-CiM-Lösung.MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....
erstellen, können Sie für alle Ansichten einen einzelnen Listener erstellen.Jungs verwenden diesen Code in Ihrer Hauptaktivität. Sehr effiziente Methode
Hier ist Ihre Adapterklasse.
Danach erhalten Sie diese Überschreibungsmethode in Ihrer Aktivität.
quelle
> Wie unterscheidet sich RecyclerView von Listview?
Ein Unterschied besteht darin, dass es
LayoutManager
in RecyclerView eine Klasse gibt, mit der Sie IhreRecyclerView
Like- verwalten können .Wie beim horizontalen Scrollen für RecyclerView-
quelle
Weiterverfolgung der hervorragenden RxJava-Lösung von MLProgrammer-CiM
Klicks verbrauchen / beobachten
RxJava 2. +
Ändern Sie das Original wie folgt :
PublishSubject#asObservable()
wurde entfernt. Geben Sie einfach das zurück,PublishSubject
was ein istObservable
.quelle
Wie man alles zusammensetzt Beispiel ...
ViewHolder-Typen
quelle
Soweit ich die MLProgrammer-CiM- Antwort verstehe , ist es einfach möglich, dies einfach zu tun:
quelle
Nachdem ich die Antwort von @ MLProgrammer-CiM gelesen habe , ist hier mein Code:
quelle
getAdapterPosition
Dose Rückkehr-1
für „keine Position“.Ich habe es so gemacht, es ist sehr einfach:
Fügen Sie einfach 1 Zeile für die angeklickte RecyclerView-Position hinzu :
Vollständiger Code für die ViewHolder- Klasse:
Hoffe das wird dir helfen.
quelle
getAdapterPosition
anstelle von verwendengetLayoutPosition
. Schutz vor-1
.Ich verwende diese Methode, um eine Absicht von RecyclerView aus zu starten:
quelle
onBindViewHolder(...)
nicht nachnotify()
Methoden aufgerufen wird . In einigen Situationen kann es daher zu einer falschen Klickposition kommen.RecyclerView hat keine,
onItemClickListener
da RecyclerView für das Recycling von Ansichten verantwortlich ist (Überraschung!), Daher liegt es in der Verantwortung der Ansicht, die recycelt wird, um die empfangenen Klickereignisse zu verarbeiten.Dies erleichtert die Verwendung erheblich, insbesondere wenn Sie Elemente hatten, auf die an mehreren Stellen geklickt werden kann.
Das Erkennen eines Klicks auf ein RecyclerView-Element ist jedoch sehr einfach. Sie müssen lediglich eine Schnittstelle definieren (wenn Sie Kotlin nicht verwenden, übergeben Sie in diesem Fall nur ein Lambda):
Gleicher Code in Kotlin:
Was Sie NICHT tun müssen:
1.) Sie müssen Berührungsereignisse nicht manuell abfangen
2.) Sie müssen nicht mit Listenern für untergeordnete Statusänderungen herumspielen
3.) Sie benötigen PublishSubject / PublishRelay von RxJava nicht
Verwenden Sie einfach einen Klick-Listener.
quelle
Siehe meinen Ansatz dazu:
Deklarieren Sie zuerst eine Schnittstelle wie folgt:
Dann erstellen Sie den Adapter:
Und jetzt wollen wir sehen, wie man dies aus einem Fragment integriert:
quelle
Wenn Sie der untergeordneten Ansicht von Elementen onClick () hinzufügen möchten, z. B. eine Schaltfläche in Element, habe ich festgestellt, dass Sie dies in onCreateViewHolder () Ihres eigenen RecyclerView.Adapter wie folgt problemlos tun können:
Ich weiß nicht, ob es ein guter Weg ist, aber es funktioniert gut. Wenn jemand eine bessere Idee hat, bin ich sehr froh, es mir zu sagen und meine Antwort zu korrigieren! :) :)
quelle
Hier ist eine Möglichkeit, es ganz einfach zu implementieren, wenn Sie eine Liste von POJOs haben und eine beim Klicken von außerhalb des Adapters abrufen möchten.
Erstellen Sie in Ihrem Adapter einen Listener für die Klickereignisse und eine Methode zum Festlegen:
}}
Implementieren Sie in Ihrem ViewHolder onClickListener und erstellen Sie ein Klassenmitglied, um das von der Ansicht präsentierte POJO vorübergehend auf diese Weise zu speichern (dies ist ein Beispiel, bei dem das Erstellen eines Setters besser wäre):
Setzen Sie in Ihrem Adapter das aktuelle POJO, wenn der ViewHolder gebunden ist (oder auf null, wenn die aktuelle Ansicht keine hat):
Das war's, jetzt kannst du es so aus deinem Fragment / deiner Aktivität verwenden:
quelle
mMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
Ja, du kannst
quelle
Hier können Sie mit mehreren Onclicks umgehen (siehe unten) und es ist sehr effizient
quelle
itemView
.Mein Kommentar wurde geändert ...
quelle
getAdapterPosition()
.Überprüfen Sie dieses, in dem ich alle Dinge richtig implementiert habe
RecyclerViewHolder-Klasse
Adapter
Die Schnittstelle
quelle
Das hat bei mir funktioniert:
quelle
setOnClickListener(holder)
inonBindViewHolder()
. Weil onBindViewHolder (...) nach notify () -Methoden nicht aufgerufen wird. In einigen Situationen kann es daher zu einer falschen Klickposition kommen.onCreateViewHolder
.Greifen Sie auf das
mainView
vonrowLayout(cell)
für Sie zuRecyclerView
undOnBindViewHolder
schreiben Sie in Ihren Code:quelle
Anstatt die Schnittstelle View.OnClickListener im Ansichtshalter zu implementieren oder eine Schnittstelle in Ihrer Aktivität zu erstellen und zu verbinden und zu implementieren. Ich habe diesen Code für die einfache Implementierung von OnClickListener verwendet.
quelle
Innenansichtshalter
Innerhalb von OnBindViewHolder ()
Und lassen Sie mich wissen, haben Sie Fragen zu dieser Lösung?
quelle
onCreateViewHolder
für eine bessere Leistung aktivieren , aber dann müssen Sie die Position mitgetAdapterPosition()
(und Schutz vor-1
)quelle
Verwenden Sie PlaceHolderView
quelle
Ich habe eine Bibliothek geschrieben, um das Klickereignis für Elemente des Android Recycler-Ansichts zu behandeln. Das gesamte Tutorial finden Sie unter https://github.com/ChathuraHettiarachchi/RecycleClick
oder um lange Druckvorgänge zu handhaben, die Sie verwenden können
quelle
Die Recyclerview-Animation wurde nicht getestet, die andere ist normal. Ich denke, es wurde maximal optimiert. Die Schnittstelle hat andere Verwendungszwecke, die Sie vorübergehend ignorieren können.
Dies ist die Schnittstelle
Dies ist eine abstrakte Klasse
Du brauchst es nur
quelle
Beispiel mit getTag () / setTag () und Single-Click-Listener für den gesamten Adapter:
Die in der Datei tags.xml definierte TAG_POSITION als
quelle