Hat jemand, der RecyclerView
verwendet, einen Weg gefunden, um einen onClickListener
für Elemente im RecyclerView
festzulegen? Ich dachte daran, für jedes Element einen Listener für jedes Layout festzulegen, aber das scheint etwas zu umständlich zu sein. Ich bin sicher, dass es eine Möglichkeit gibt, dass der RecyclerView
auf das onClick
-Ereignis hört, aber ich kann es nicht ganz herausfinden.
Antworten
Zu viele Anzeigen?Erfinden Sie das Rad nicht neu! Der Code für diesen speziellen Anwendungsfall ist im Master/Detail Flow Starterprojekt enthalten, das mit Android Studio geliefert wird.
Wählen Sie in Android Studio aus:
- Datei > Neu > Neues Projekt....
- Wählen Sie im Tab Telefon und Tablet <strong>Master/Detail Flow</strong> wie unten dargestellt.
- Erstellen Sie das Projekt entweder in Kotlin oder Java.
- Profitieren Sie.
Ich werde hier nicht den Code aus Googles Out-of-the-Box-Demo-Projekt einbeziehen, aber ich werde die Hauptentwurfsansätze in der von Google bereitgestellten Beispiel anreißen:
- Der Element-OnClickListener wird NUR EINMAL erstellt und einem Feld in Ihrer
RecyclerView.Adapter
-Implementierung zugewiesen. - In der
onBindViewHolder()
sollten Sie derselben, vorher erstellten onClickListener-Objekt auf Ihrer ViewHolder-Instanz mitholder.itemView.setOnClickListener(mOnClickListener)
setzen (Vermeiden Sie das Erstellen einer neuen Instanz bei jedem Methodenaufruf!); wenn Sie Klicks auf bestimmte Elemente innerhalb des ViewHolders erfassen müssen, erweitern Sie ViewHolder und machen Sie die benötigten Elemente als Felder zugänglich, damit Sie die erforderlichen Listener inonBindViewHolder()
anhängen können— und nochmals, erstellen Sie die Listener nicht bei jedem Methodenaufruf neu—initialisieren Sie sie als Instanzfelder und fügen Sie sie nach Bedarf an. - Sie können
.setTag()
verwenden, um Zustand an Ihren ViewHolder zu übergeben, z.B.holder.itemView.setTag(mValues.get(position));
wie in der Demo verwendet.
Hier ist eine einfache und klare Möglichkeit, sie innerhalb Ihres ReacyclerView
ViewHolder
hinzuzufügen
public static class MyViewholder extends RecyclerView.ViewHolder {
public MyViewholder(View itemView) {
super(itemView);
itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Tag", "onClick" + getAdapterPosition());
}
});
}
}
getAdapterPosition()
gibt die aktuelle Position des angeklickten Elements zurück
Leider fehlen dem RecyclerView
einige Funktionen, die im ListView
eingebaut waren. Zum Beispiel die Möglichkeit, einen OnItemClickListener
hinzuzufügen, der ausgelöst wird, wenn ein Element angeklickt wird. Das RecyclerView
ermöglicht es Ihnen, einen OnClickListener
in Ihrem Adapter festzulegen, aber das Weiterleiten dieses Klicks Listeners von Ihrem Aufrufcode über den Adapter bis zum ViewHolder
ist kompliziert, um einen einfachen Elementklick zu erfassen.
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_support
in der Datei ids.xml definieren:
Der resultierende Code für den Klick-Listener sieht jetzt 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 im RecyclerView finden Sie in diesem littlerobots_blog
hier ist der vollständige Code für meinen benutzerdefinierten Adapter. Dieser Code wird die Zeilen mit den in der XML-Datei "list_item" definierten Listenelementen aufblähen und auf alle Listenelemente Zeilen mit den entsprechenden Positionen Klickereignisse ausführen.
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);
/* hier wird list_item eine XML-Datei sein, die wir aufblähen möchten ... es ist dasselbe wie bei ListView für die Anpassung. */
MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() {
@Override
public void onRecyclerItemClick(View view, int position) {
System.out.println("Klick auf Listenelement an Position " +position);
}
});
return vh;
}
}
Ich bin mir bewusst, dass es viele Antworten gibt, aber ich dachte, ich könnte auch meine Implementierung davon bereitstellen. (Weitere Details finden Sie in einer weiteren Frage, die ich beantwortet habe).
Also, um einen Klick-Listener hinzuzufügen, muss Ihre innere ViewHolder
-Klasse View.OnClickListener
implementieren. Das liegt daran, dass Sie einen OnClickListener
auf den itemView
-Parameter des Konstruktors der ViewHolder
setzen. Lassen Sie mich Ihnen zeigen, was ich meine:
public class BeispielClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView text1, text2;
BeispielClickViewHolder(View itemView) {
super(itemView);
// Wir tun dies, weil wir überprüfen möchten, wann ein Element angeklickt wurde:
itemView.setOnClickListener(this);
// Jetzt, wie zuvor, weisen wir unsere View-Variablen zu
text1 = (TextView) itemView.findViewById(R.id.text1);
text2 = (TextView) itemView.findViewById(R.id.text2);
}
@Override
public void onClick(View v) {
// Der Benutzer hat möglicherweise keinen Klick-Listener für Listenelemente festgelegt, in diesem Fall wird unser Listener null sein, daher müssen wir das überprüfen
if (mOnEntryClickListener != null) {
mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
}
}
}
Das Einzige, was Sie noch hinzufügen müssen, ist eine benutzerdefinierte Schnittstelle für Ihren Adapter
und eine Setter-Methode:
private OnEntryClickListener mOnEntryClickListener;
public interface OnEntryClickListener {
void onEntryClick(View view, int position);
}
public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
mOnEntryClickListener = onEntryClickListener;
}
Ihr neuer, klickunterstützender Adapter
ist also komplett.
Nun, lassen Sie uns ihn benutzen...
BeispielClickAdapter clickAdapter = new BeispielClickAdapter(ihreObjekte);
clickAdapter.setOnEntryClickListener(new BeispielClickAdapter.OnEntryClickListener() {
@Override
public void onEntryClick(View view, int position) {
// Dinge, die passieren werden, wenn auf ein Listenelement geklickt wird
}
});
Es ist im Grunde genommen, wie Sie einen normalen Adapter
einrichten würden, außer dass Sie Ihre Setter-Methode verwenden, um zu kontrollieren, was passiert, wenn der Benutzer auf ein bestimmtes Listenelement klickt.
Sie können auch durch eine Reihe von Beispielen blättern, die ich in diesem Gist auf GitHub gemacht habe:
https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07