Wie kann ich ausgewählte Elemente in RecyclerView richtig hervorheben?
Lesezeit: 13 Minuten
Benutzer65721
Ich versuche, a zu verwenden RecyclerView als Horizontale ListView. Ich versuche herauszufinden, wie ich das ausgewählte Element hervorheben kann. Wenn ich auf eines der Elemente klicke, wird es ausgewählt und richtig hervorgehoben, aber wenn ich auf ein anderes klicke, wird das zweite mit dem älteren hervorgehoben.
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.setItem(fruitsData[position]);
if(selectedPosition == position)
viewHolder.itemView.setBackgroundColor(Color.CYAN);
else
viewHolder.itemView.setBackgroundColor(Color.RED);
}
Die Verwendung von fokussierbaren Ansichten ist keine gute Idee, um zu versuchen, ausgewählte Elemente zu verfolgen. Überprüfen Sie meine Antwort auf eine vollständige Lösung
Dies ist schwer nachzuvollziehen, wenn Sie noch nichts haben Arbeitenwas schlecht ist, da die Antworten mitlaufen und nicht viel darüber sagen, was wohin gehört.
– Erster
27. April 2018 um 18:08 Uhr
zIronManBox
Dies ist ein sehr einfacher Weg, dies zu tun.
Habe einen private int selectedPos = RecyclerView.NO_POSITION; in der Klasse RecyclerView Adapter und unter der Methode onBindViewHolder Folgendes versuchen:
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.itemView.setSelected(selectedPos == position);
}
Andernfalls wird setSelected(..) nichts tun, wodurch diese Lösung unbrauchbar wird.
Ich habe diese Lösung mit einem Drawable/Selector-Set im Hintergrund in meiner Zeilenansicht verwendet: <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/pressed_color" android:state_pressed="true"/> <item android:drawable="@color/selected_color" android:state_selected="true"/> <item android:drawable="@color/focused_color" android:state_focused="true"/> </selector>
– Colabug
18. Januar 2016 um 12:42 Uhr
@zIronManBox: netter, einfacher Weg! Soll “s selectedPosition ” in der onClick-Methode “s selectedPos ” sein?
– AJW
8. August 2016 um 1:33 Uhr
getLayoutPosition() ist bei mir nicht verfügbar.
– ka3ak
17. März 2017 um 5:43 Uhr
Verwenden Sie nicht nur -1, verwenden Sie RecyclerView.NO_POSITION; (was -1 ist)
– Martin Marconcini
13. April 2017 um 0:45 Uhr
@ka3ak: getLayoutPosition ist eine Methode der ViewHolder-Klasse, deren Objekt als erster Parameter in der Bind-View-Methode übergeben wird. So kann darauf zugegriffen werden vieHolder.getLayoutPosition
– Tushar Kathuria
25. Mai 2017 um 16:19 Uhr
Triff Vora
AKTUALISIEREN [26/Jul/2017]:
Wie der Pawan im Kommentar zu dieser IDE-Warnung erwähnt hat, diese feste Position nicht zu verwenden, habe ich meinen Code gerade wie folgt geändert. Der Klick-Listener wird verschoben ViewHolderund dort bekomme ich die Position mit getAdapterPosition() Methode
int selected_position = 0; // You have to set this globally in the Adapter class
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Item item = items.get(position);
// Here I am just highlighting the background
holder.itemView.setBackgroundColor(selected_position == position ? Color.GREEN : Color.TRANSPARENT);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// Below line is just like a safety check, because sometimes holder could be null,
// in that case, getAdapterPosition() will return RecyclerView.NO_POSITION
if (getAdapterPosition() == RecyclerView.NO_POSITION) return;
// Updating old as well as new positions
notifyItemChanged(selected_position);
selected_position = getAdapterPosition();
notifyItemChanged(selected_position);
// Do your another stuff for your onClick
}
}
hoffe das hilft.
Das ist großartig! Ich bin jedoch etwas verwirrt. Können Sie mir helfen, eine Möglichkeit zu implementieren und diese Antwort zu erweitern, wie Sie das tun, was Sie in der Else-Anweisung tun, wenn Sie auf ein bereits ausgewähltes Element klicken, damit Sie es abwählen: sonst { holder.itemView.setBackgroundColor(Color.TRANSPARENT); }
– iBobb
27. Februar 2016 um 14:20 Uhr
Natürlich ja. @iBobb. Für NICHT AUSGEWÄHLTE Elemente, dh deren Position nicht gleich unserer ‘ausgewählten_position’-Variablen ist, wird KEIN Hintergrund angezeigt. Ich habe dies verwendet, weil RecyclerView, wie der Name schon sagt, jedes Element recycelt, also einen GRÜNEN Hintergrund für zufällige Zeilen setzt, während wir SCROLLEN, deshalb habe ich diesen ELSE-Teil platziert. (Sie können es einfach ausprobieren, indem Sie diesen ELSE-Teil auskommentieren und dann in Ihrer Recycler-Ansicht scrollen.)
– Treffen Sie Vora
28. Februar 2016 um 11:57 Uhr
Ich glaube du hast meine Frage nicht verstanden. Sie wissen in jeder App, wenn Sie etwas auswählen, wird es hervorgehoben. Wenn Sie es erneut halten, wird es deaktiviert. Wie würden wir das umsetzen? Im Moment können wir nur mit Ihrem Code auswählen und das Berühren und Halten desselben Elements bewirkt nichts.
– iBobb
28. Februar 2016 um 14:17 Uhr
Es kann möglich sein, aber dafür müssen Sie onLongClickListener anstelle von onClickListener überschreiben, im Moment bin ich beschäftigt, also kann ich keinen vollständigen Code bereitstellen, aber Sie sollten es im Grunde so tun.
– Treffen Sie Vora
1. März 2016 um 12:42 Uhr
Gute Arbeit Treffen. Für NICHT AUSGEWÄHLT hier die Codes unten, es funktioniert für mich, int previouss selectedPosition = -2; // global gesetzt. dann kommen nach diesen Zeilen notificationItemChanged(s selected_position); Fügen Sie die folgenden Zeilen hinzu, wenn (vorherige ausgewählte Position == ausgewählte_position) { ausgewählte_position = -1; benachrichtigenItemChanged (ausgewählte_position); } Else {vorherigeausgewähltePosition = ausgewählte_Position; } Probieren Sie dieses aus, es wird funktionieren.
– GNSRIDHAR
27. April 2020 um 9:26 Uhr
Gregor Ennis
Ich habe eine Basisadapterklasse geschrieben, um die Elementauswahl automatisch mit einer RecyclerView zu handhaben. Leiten Sie einfach Ihren Adapter davon ab und verwenden Sie darstellbare Zustandslisten mit state_selected, wie Sie es mit einer Listenansicht tun würden.
public abstract class TrackSelectionAdapter<VH extends TrackSelectionAdapter.ViewHolder> extends RecyclerView.Adapter<VH> {
// Start with first item selected
private int focusedItem = 0;
@Override
public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
// Handle key up and key down and attempt to move selection
recyclerView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
// Return false if scrolled to the bounds and allow focus to move off the list
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
return tryMoveSelection(lm, 1);
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
return tryMoveSelection(lm, -1);
}
}
return false;
}
});
}
private boolean tryMoveSelection(RecyclerView.LayoutManager lm, int direction) {
int tryFocusItem = focusedItem + direction;
// If still within valid bounds, move the selection, notify to redraw, and scroll
if (tryFocusItem >= 0 && tryFocusItem < getItemCount()) {
notifyItemChanged(focusedItem);
focusedItem = tryFocusItem;
notifyItemChanged(focusedItem);
lm.scrollToPosition(focusedItem);
return true;
}
return false;
}
@Override
public void onBindViewHolder(VH viewHolder, int i) {
// Set selected state; use a state list drawable to style the view
viewHolder.itemView.setSelected(focusedItem == i);
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
// Handle item click and set the selection
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Redraw the old selection and the new
notifyItemChanged(focusedItem);
focusedItem = getLayoutPosition();
notifyItemChanged(focusedItem);
}
});
}
}
}
mRecyclerView ist nirgendwo deklariert. Sollen wir es einfach als Parameter im Konstruktor übergeben und in einem Feld speichern?
– Pedro
26. März 2015 um 0:13 Uhr
Das tut mir leid. Mein Adapter ist eine innere Klasse meines Fragments, sodass er Zugriff auf das Recycler-Ansichtsfeld hat. Ansonsten ja, Sie könnten es als Parameter übergeben. Oder noch besser Griff onRecyclerViewAttached und dort in einer Member-Variablen speichern.
Es tut mir leid, meinst du, ich muss nur deine importieren TrackSelectionAdapter Klasse und in meiner Liste verwenden? Wie leite ich meinen Adapter von Ihrer Klasse ab? Könnten Sie bitte auf meine Frage antworten? Ich stecke so tief fest: stackoverflow.com/questions/29695811/…
– Kris
17. April 2015 um 18:22 Uhr
Ich habe dies ausprobiert und festgestellt, dass die beiden aufeinanderfolgenden Aufrufe von NotifyItemChanged() jeden Anschein von reibungslosem Scrollen auf langsamerer Hardware zunichte gemacht haben. War auf dem Fire TV vor dem Lollipop-Update besonders schlimm
– Rotes Shirt
18. April 2016 um 17:30 Uhr
Entitäten
Wie in dieser verknüpften Frage erwähnt, sollte das Festlegen von Listenern für viewHolders in onCreateViewHolder erfolgen. Allerdings zielte die folgende Implementierung ursprünglich auf Mehrfachauswahl ab, aber ich habe einen Hack in das Snippet geworfen, um eine Einzelauswahl zu erzwingen.(*1)
// an array of selected items (Integer indices)
private final ArrayList<Integer> selected = new ArrayList<>();
// items coming into view
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// each time an item comes into view, its position is checked
// against "selected" indices
if (!selected.contains(position)){
// view not selected
holder.parent.setBackgroundColor(Color.LTGRAY);
}
else
// view is selected
holder.parent.setBackgroundColor(Color.CYAN);
}
// selecting items
@Override
public boolean onLongClick(View v) {
// select (set color) immediately.
v.setBackgroundColor(Color.CYAN);
// (*1)
// forcing single selection here...
if (selected.isEmpty()){
selected.add(position); // (done - see note)
}else {
int oldSelected = selected.get(0);
selected.clear(); // (*1)... and here.
selected.add(position);
// note: We do not notify that an item has been selected
// because that work is done here. We instead send
// notifications for items which have been deselected.
notifyItemChanged(oldSelected);
}
return false;
}
Davideas
Ich denke, ich habe das beste Tutorial zur Verwendung von RecyclerView mit allen grundlegenden Funktionen gefunden, die wir benötigen (Einzel- und Mehrfachauswahl, Hervorheben, Ripple, Klicken und Entfernen in Mehrfachauswahl usw.).
Darauf aufbauend konnte ich eine Bibliothek „FlexibleAdapter“ erstellen, die einen SelectableAdapter erweitert. Ich denke, dies muss in der Verantwortung des Adapters liegen, eigentlich müssen Sie die grundlegenden Funktionen des Adapters nicht jedes Mal neu schreiben, sondern eine Bibliothek dies tun lassen, sodass Sie einfach dieselbe Implementierung wiederverwenden können.
Dieser Adapter ist sehr schnell, er funktioniert sofort nach dem Auspacken (Sie müssen ihn nicht verlängern); Sie passen die Elemente für alle Ansichtstypen an, die Sie benötigen. ViewHolder sind vordefiniert: allgemeine Ereignisse sind bereits implementiert: einfacher und langer Klick; es behält den Zustand nach der Rotation bei und viel viel mehr.
Bitte schauen Sie es sich an und setzen Sie es gerne in Ihren Projekten ein.
Tolle Arbeit, diesen Adapter zu schreiben, er scheint sehr nützlich zu sein. Die einzige Sache ist, dass es wirklich einige grundlegende Beispiele und Dokumentation braucht, ich finde es ein wenig verwirrend, es überhaupt zum Laufen zu bringen. Potenziell großartig!
– Voy
20. Juni 2016 um 10:17 Uhr
Ja, ich habe dort nicht genügend Informationen gefunden, um loszulegen. API-Referenz konnte nicht gefunden werden, obwohl der Code in diesem Sinne kommentiert zu sein scheint. Die Beispiel-App scheint – obwohl breit und informativ – ohne Vorkenntnisse der Bibliothek sehr schwer zu verstehen. Alle Anwendungsfälle sind miteinander verbunden, es gibt kaum Hinweise darauf, was was demonstriert, Klassen werden in verschiedenen Szenarien wiederverwendet, was dazu führt, dass sie mit Informationen überladen werden. Ich habe hier ein neues Problem mit diesen Vorschlägen erstellt: github.com/davideas/FlexibleAdapter/issues/120
– Voy
22. Juni 2016 um 9:37 Uhr
Wiki wurde komplett neu geschrieben und steht kurz vor der Fertigstellung.
– Davideas
6. Juni 2017 um 13:23 Uhr
Schau dir meine Lösung an. Ich nehme an, dass Sie die ausgewählte Position im Halter festlegen und als Tag of View übergeben sollten. Die Ansicht sollte in der Methode onCreateViewHolder(…) gesetzt werden. Es gibt auch den richtigen Ort, um Listener für die Ansicht festzulegen, z. B. OnClickListener oder LongClickListener.
Bitte schauen Sie sich das Beispiel unten an und lesen Sie die Kommentare zum Code.
public class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder> {
//Here is current selection position
private int mSelectedPosition = 0;
private OnMyListItemClick mOnMainMenuClickListener = OnMyListItemClick.NULL;
...
// constructor, method which allow to set list yourObjectList
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//here you prepare your view
// inflate it
// set listener for it
final ViewHolder result = new ViewHolder(view);
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.your_view_layout, parent, false);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//here you set your current position from holder of clicked view
mSelectedPosition = result.getAdapterPosition();
//here you pass object from your list - item value which you clicked
mOnMainMenuClickListener.onMyListItemClick(yourObjectList.get(mSelectedPosition));
//here you inform view that something was change - view will be invalidated
notifyDataSetChanged();
}
});
return result;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final YourObject yourObject = yourObjectList.get(position);
holder.bind(yourObject);
if(mSelectedPosition == position)
holder.itemView.setBackgroundColor(Color.CYAN);
else
holder.itemView.setBackgroundColor(Color.RED);
}
// you can create your own listener which you set for adapter
public void setOnMainMenuClickListener(OnMyListItemClick onMyListItemClick) {
mOnMainMenuClickListener = onMyListItemClick == null ? OnMyListItemClick.NULL : onMyListItemClick;
}
static class ViewHolder extends RecyclerView.ViewHolder {
ViewHolder(View view) {
super(view);
}
private void bind(YourObject object){
//bind view with yourObject
}
}
public interface OnMyListItemClick {
OnMyListItemClick NULL = new OnMyListItemClick() {
@Override
public void onMyListItemClick(YourObject item) {
}
};
void onMyListItemClick(YourObject item);
}
}
Tolle Arbeit, diesen Adapter zu schreiben, er scheint sehr nützlich zu sein. Die einzige Sache ist, dass es wirklich einige grundlegende Beispiele und Dokumentation braucht, ich finde es ein wenig verwirrend, es überhaupt zum Laufen zu bringen. Potenziell großartig!
– Voy
20. Juni 2016 um 10:17 Uhr
Ja, ich habe dort nicht genügend Informationen gefunden, um loszulegen. API-Referenz konnte nicht gefunden werden, obwohl der Code in diesem Sinne kommentiert zu sein scheint. Die Beispiel-App scheint – obwohl breit und informativ – ohne Vorkenntnisse der Bibliothek sehr schwer zu verstehen. Alle Anwendungsfälle sind miteinander verbunden, es gibt kaum Hinweise darauf, was was demonstriert, Klassen werden in verschiedenen Szenarien wiederverwendet, was dazu führt, dass sie mit Informationen überladen werden. Ich habe hier ein neues Problem mit diesen Vorschlägen erstellt: github.com/davideas/FlexibleAdapter/issues/120
– Voy
22. Juni 2016 um 9:37 Uhr
Wiki wurde komplett neu geschrieben und steht kurz vor der Fertigstellung.
– Davideas
6. Juni 2017 um 13:23 Uhr
amodkanthe
Es gibt keinen Selektor in RecyclerView wie ListView und GridView, aber Sie versuchen unten, was für mich funktioniert hat
Erstellen Sie wie unten eine zeichnerische Auswahl
Die Verwendung von fokussierbaren Ansichten ist keine gute Idee, um zu versuchen, ausgewählte Elemente zu verfolgen. Überprüfen Sie meine Antwort auf eine vollständige Lösung
– Greg Ennis
3. März 2015 um 18:08 Uhr
vielleicht hilft dir das weiter amolsawant88.blogspot.in/2015/08/…
– Amol Sawant 96 Kuli
28. August 2015 um 8:48 Uhr
Recycler-Ansichtselementauswahl: stackoverflow.com/a/38501676/2648035
– Alok Omkar
18. März 2018 um 14:58 Uhr
Dies ist schwer nachzuvollziehen, wenn Sie noch nichts haben Arbeitenwas schlecht ist, da die Antworten mitlaufen und nicht viel darüber sagen, was wohin gehört.
– Erster
27. April 2018 um 18:08 Uhr