Hier ist das XML für meine Artikel in RecyclerView
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cvItems"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_margin="2dp"
card_view:cardElevation="0dp"
card_view:contentPadding="0dp"
card_view:cardBackgroundColor="#FFFFFF"
>
<LinearLayout
android:orientation="horizontal"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<TextView
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:id="@+id/tvContent"
android:textSize="15dp"
android:paddingLeft="5dp"
android:paddingRight="5dp" />
<CheckBox
android:id="@+id/cbSelect"
android:layout_width="0dip"
android:layout_weight="0.2"
android:layout_height="match_parent"
android:button="@drawable/cb_checked"
android:gravity="center_horizontal"
android:textAlignment="center"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</android.support.v7.widget.CardView>
Und hier ist der RecyclerView-Adapter, der das obige Layout für jedes seiner Elemente aufbläst:
public class AdapterTrashIncome extends RecyclerView.Adapter<AdapterTrashIncome.ViewHolder> {
private ArrayList<ObjectIncome> myItems = new ArrayList<>();
public AdapterTrashIncome(ArrayList<ObjectIncome> getItems, Context context){
try {
mContext = context;
myItems = getItems;
}catch (Exception e){
Log.e(FILE_NAME, "51: " + e.toString());
e.printStackTrace();
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvContent;
public CheckBox cbSelect;
public ViewHolder(View v) {
super(v);
tvContent = (TextView) v.findViewById(R.id.tvContent);
cbSelect = (CheckBox) v.findViewById(R.id.cbSelect);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final ObjectIncome objIncome = myItems.get(position);
String content = "<b>lalalla</b>";
holder.tvContent.setText(Html.fromHtml(content));
}
}
Das Problem ist, nehmen wir an, ich habe 10 Elemente in der RecyclerView. Wenn ich das Kontrollkästchen für Punkt 1,2,3 aktiviert habe, scrolle ich in der RecyclerView nach unten. Plötzlich sind einige der anderen Punkte, z. B. Punkt 8,9, aktiviert. Und wenn ich wieder nach oben scrolle, werden Punkt 1 und 3 aktiviert, aber nicht Punkt 2. Irgendeine Idee, warum dies passiert?
android
android-recyclerview
ich bin dabei
quelle
quelle
Antworten:
Das ist ein erwartetes Verhalten. Sie setzen Ihr Kontrollkästchen nicht aktiviert oder nicht. Sie wählen eine aus und der Ansichtsinhaber behält sie ausgewählt. Sie können Ihrem ObjectIncome-Objekt eine boolesche Variable hinzufügen und den Auswahlstatus Ihres Elements beibehalten.
Sie können sich mein Beispiel ansehen. Sie können so etwas tun:
quelle
holder.cbSelect.setOnCheckedChangeListener(null);
vorher schreibenholder.cbSelect.setChecked(objIncome.isSelected())
onBindViewHolder
.@Override public void onBindViewHolder(final ItemHolder holder, int position) { holder.checkBox.setOnCheckedChangeListener(null); holder.checkBox.setSelected(list.get(position).isSelected()); holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { list.get(holder.getAdapterPosition()).setSelected(isChecked); } });
Kurz gesagt, es liegt daran, die Ansichten zu recyceln und wieder zu verwenden!
Wie können Sie das vermeiden:
1.Überprüfen Sie
onBindViewHolder
, ob Sie die Kontrollkästchen aktivieren oder deaktivieren sollten. Vergessen Sie nicht, sowohl wenn als auch sonst zu setzenmyItems
Array! Wenn also eine neue Ansicht angezeigt wird, wird die neueste Statue des Objekts gelesen.quelle
isChecked
false
für alle Datensätze beim Start speichern, dann habeonCheckChanged
ich nur die aktualisiertisChecked
Wert auftrue
oderfalse
und, wie in der Antwortimplementierung angegeben, diese Prüfung entweder aktiviert oder nicht.VERWENDEN SIE DIES NUR, WENN SIE DIE BEGRENZTE ANZAHL DER EINZELTEILE IN IHRER RECYCLER-ANSICHT HABEN.
Ich habe versucht, einen booleschen Wert im Modell zu verwenden und den Kontrollkästchenstatus beizubehalten, aber in meinem Fall hat dies nicht geholfen. Was für mich funktioniert hat, ist this.setIsRecyclable (false);
Weitere Erklärungen hierzu finden Sie hier https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable ()
HINWEIS: Dies ist eine Problemumgehung. Um es richtig zu verwenden, können Sie auf das Dokument verweisen, in dem es heißt: "Aufrufe von setIsRecyclable () sollten immer gepaart sein (ein Aufruf von setIsRecyclabe (false) sollte immer mit einem späteren Aufruf von setIsRecyclable (true) abgeglichen werden). Aufrufpaare können verschachtelt sein , da der Zustand intern referenzgezählt wird. " Ich weiß nicht, wie ich das im Code machen soll, wenn jemand mehr Code dazu bereitstellen kann.
quelle
Fügen Sie einfach zwei Überschreibungsmethoden von hinzu
RecyclerView
quelle
Mit der Modellklasse können Sie das Kontrollkästchen jedes recyclerView-Elements verfolgen. Die vollständige Referenz stammt von: RecyclerView Checkbox Android
setTag und getTag werden verwendet, um den Status des Kontrollkästchens zu verfolgen. Weitere Informationen finden Sie unter dem vollständigen Referenzlink. Außerdem erfahren Sie, wie Sie markierte Elemente an NEXTACTIVITY senden .
Modell erstellen
Erstellen Sie integer.xml
Schließlich sieht der Adapter so aus:
}}
quelle
Mit Kotlin das einzige , was dieses Problem für mich gelöst war klar ,
OnCheckedChangeListener
bevor die variable Einstellung und erstellen dann eine neueOnCheckedChangeListener
nachchecked
eingestellt wurde.Ich mache folgendes in meinem
RecyclerView.ViewHolder
quelle
Wie oben angegeben, sollte der überprüfte Status des Objekts in den Objekteigenschaften enthalten sein. In einigen Fällen müssen Sie möglicherweise auch den Objektauswahlstatus ändern, indem Sie auf das Objekt selbst klicken und das Kontrollkästchen über den tatsächlichen Status informieren (entweder ausgewählt oder nicht ausgewählt). Das Kontrollkästchen verwendet dann den Status des Objekts an der tatsächlichen Position des angegebenen Adapters, die (standardmäßig / in den meisten Fällen) die Position des Elements in der Liste ist.
Überprüfen Sie das folgende Snippet, es kann nützlich sein.
quelle
In meinem Fall hat das funktioniert.
quelle
Verwenden Sie ein Array, um den Status der Elemente zu speichern
Verwenden Sie im Adapter eine Map oder ein SparseBooleanArray (ähnlich einer Map, aber ein Schlüssel-Wert-Paar aus int und boolean), um den Status aller Elemente in unserer zu speichern, und verwenden Sie dann die Schlüssel und Werte zum Vergleichen beim Umschalten des aktivierten Zustands
Erstellen Sie im Adapter eine
SparseBooleanArray
onClick()
Verwenden Sie dann im Elementklick- Handler den Status der Elemente im itemStateArray, um vor dem Umschalten zu überprüfen. Hier ein BeispielVerwenden Sie außerdem ein spärliches boolesches Array, um den aktivierten Status festzulegen, wenn die Ansicht gebunden ist
und letzter Adapter wird wie seine diese
quelle
Sie müssen die Interaktionen von onBindViewHolder (Logik) mit CheckBox und Benutzerinteraktionen mit Checkbox trennen. Ich habe OnCheckedChangeListener für Benutzerinteraktionen (offensichtlich) und ViewHolder.bind () für Logik verwendet. Deshalb müssen Sie den aktivierten Listener vor dem Einrichten des Inhabers auf Null setzen und nachdem der Inhaber bereit ist - konfigurieren Sie den aktivierten Listener für Benutzerinteraktionen.
quelle
Ich empfehle , dass nicht verwenden
checkBox.setOnCheckedChangeListener
inrecyclerViewAdapter
. Denn beim Scrollen wird recyclerViewcheckBox.setOnCheckedChangeListener
per Adapter ausgelöst. Es ist nicht sicher . Verwenden Sie stattdessencheckBox.setOnClickListener
mit Benutzereingaben zu interagieren.Beispielsweise:
quelle
Das Problem dieser Lösung, die ich gefunden habe, besteht darin, ein statisches globales Array zu erstellen und es in der ADAPER-KLASSE "onBindViewHolder" zu verwenden, in der ich alle benötigten globalen Variablen / Objekte erstellt habe.
Hier (IN CONSTRUCTOR of RVADAPTER CLASS) habe ich dem Array eine Größe gegeben, die der Größe / Anzahl der Elemente entspricht, die in der Recycler-Ansicht angezeigt werden sollen
BindViewHolder, I, Dieses Konzept wurde auf eine Schaltfläche angewendet. Wenn ich auf eine Schaltfläche klicke, ändert sich das Hintergrundbild der Schaltfläche. Das Objekt der Schaltfläche, die ich verwendet habe, sind Namen wie "Upvote", da "i" die Position jedes Elements in der Recycler-Ansicht enthält. Ich habe es als Index des Arrays verwendet, das als Flag fungiert und den Status der Elemente verfolgt.
quelle
Ich hatte das gleiche Problem. Wenn ich in meiner recyclerView auf die Umschaltfläche des Elements geklickt habe, wurde in jedem zehnten Element die Umschalttaste angezeigt (wenn beispielsweise in einem Element mit 0 Index geklickt wurde, wurden auch Elemente mit 9, 18, 27 Indizes angeklickt). Erstens war mein Code in onBindViewHolder:
Aber dann habe ich eine andere Aussage hinzugefügt
Und das Problem wurde gelöst
quelle
Ich hatte das gleiche Problem in einer RecyclerView-Liste mit Schaltern und löste es mit der Antwort @oguzhand, aber mit diesem Code im checkedChangeListener:
(Wobei 'Gruppe' die Entität ist, die ich auswählen / abwählen möchte)
quelle
okay , es gibt eine Menge Antworten hier ich meinen Code schreiben und ich werde einfach erklären , was ich getan habe ... es vielleicht Hilfe Junioren wie ich: D.
1- Ziel:
Wir werden eine Liste erstellen
RecyclerView
, dieCheckBox
und soRadioButton
etwas hat:2- Modellklasse
3-Mein erstaunlicher Adapter
3- In Aktivität erhalten Sie sie ungefähr so:
quelle
öffentliche Klasse TagYourDiseaseAdapter erweitert RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; privater Kontext mContext;
}}
quelle
Dies geschieht, wenn die Verwendung
setOnCheckedChangeListener
anstelle dieser Verwendung erfolgtsetObClickListener
und im Inneren nur dieser einfache Griff ausgeführt wird:hoffe es hilft jemandem wenn ja + stimme auf diese Antwort ab
quelle
Hinzufügen von setItemViewCacheSize (int size) zu recyclerview und das Übergeben der löste mein Problem.
Mycode:
Quelle: https://stackoverflow.com/a/46951440/10459907
quelle
Was für mich funktioniert hat, ist, die Listener auf dem viewHolder zu annullieren, wenn die Ansicht recycelt werden soll (
onViewRecycled
):quelle