tl;dr 2016 Verwenden Sie RxJava und ein PublishSubject, um ein Observable für die Klicks freizulegen.
public class ReactiveAdapter extends RecyclerView.Adapter {
String[] mDataset = { "Daten", "Im", "Adapter" };
private final PublishSubject onClickSubject = PublishSubject.create();
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final String element = mDataset[position];
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickSubject.onNext(element);
}
});
}
public Observable getPositionClicks(){
return onClickSubject.asObservable();
}
}
Ursprünglicher Post:
Seit der Einführung von ListView
war onItemClickListener
problematisch. Sobald Sie einen Klick-Listener für eines der internen Elemente hatten, würde der Rückruf nicht ausgelöst, doch dies wurde nicht benachrichtigt oder gut dokumentiert (wenn überhaupt), sodass es viele Verwirrung und SO-Fragen dazu gab.
Aufgrund der Tatsache, dass RecyclerView
einen Schritt weiter geht und kein Konzept von Zeile/Spalte hat, sondern eine beliebig angeordnete Menge von Kindern, wurde der Klick an jeden von ihnen delegiert oder zur Programmiererimplementierung.
Das Recyclerview
sollte nicht als 1:1-Ersatz für ListView
betrachtet werden, sondern eher als ein flexibleres Komponent für komplexe Anwendungsfälle. Und wie Sie sagen, ist Ihre Lösung das, was Google von Ihnen erwartet hat. Jetzt haben Sie einen Adapter, der den Klick an ein über den Konstruktor übergebenes Interface delegieren kann, was das richtige Muster sowohl für ListView
als auch für Recyclerview
ist.
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public IMyViewHolderClicks mListener;
public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
super(itemLayoutView);
mListener = listener;
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
imgViewIcon.setOnClickListener(this);
itemLayoutView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v instanceof ImageView){
mListener.onTomato((ImageView)v);
} else {
mListener.onPotato(v);
}
}
public static interface IMyViewHolderClicks {
public void onPotato(View caller);
public void onTomato(ImageView callerImage);
}
}
und dann in Ihrem Adapter:
public class MyAdapter extends RecyclerView.Adapter {
String[] mDataset = { "Daten" };
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false);
MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() {
public void onPotato(View caller) { Log.d("GEMÜSE", "Kartoffeln"); };
public void onTomato(ImageView callerImage) { Log.d("GEMÜSE", "Tomaten"); }
});
return vh;
}
// Ersetzen Sie den Inhalt einer Ansicht (aufgerufen vom Layout-Manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Element aus Ihrem Datensatz an dieser Position erhalten
// Ersetzen Sie den Inhalt der Ansicht durch dieses Element
// Löschen Sie die, die nicht verwendet werden
holder.txtViewTitle.setText(mDataset[position]);
}
// Geben Sie die Größe Ihres Datensatzes zurück (aufgerufen vom Layout-Manager)
@Override
public int getItemCount() {
return mDataset.length;
}
...
Schauen Sie sich nun diesen letzten Codeausschnitt an: onCreateViewHolder(ViewGroup parent, int viewType)
die Signatur deutet bereits auf verschiedene Ansichtstypen hin. Für jeden von ihnen benötigen Sie auch einen anderen ViewHolder, und folglich kann jeder von ihnen einen unterschiedlichen Satz von Klicks haben. Oder Sie erstellen einfach einen generischen ViewHolder, der eine beliebige Ansicht und einen onClickListener
benötigt und entsprechend anwendet. Oder delegieren Sie eine Ebene höher an den Orchestrierer, damit verschiedene Fragmente/Aktivitäten dieselbe Liste mit unterschiedlichem Klickverhalten haben. Nochmals, alle Flexibilität liegt bei Ihnen.
Es ist eine wirklich benötigte Komponente und ziemlich nah an dem, was unsere internen Implementierungen und Verbesserungen von ListView
bis jetzt waren. Es ist gut, dass Google dies endlich anerkennt.