Das Kontrollkästchen in RecyclerView überprüft weiterhin verschiedene Elemente


86

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?


Versuchen Sie, diese Bibliothek zu verwenden , siehe ViewStates. Es hilft, beim Scrollen einen Status zu speichern.
Vitaly

Antworten:


161

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:

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));

        //in some cases, it will prevent unwanted situations
        holder.cbSelect.setOnCheckedChangeListener(null);

        //if true, your checkbox will be selected, else unselected
        holder.cbSelect.setChecked(objIncome.isSelected());

        holder.cbSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    //set your object's last status
                    objIncome.setSelected(isChecked);
            }
        });

    }
}

17
Es hat nicht funktioniert. Sie müssen holder.cbSelect.setOnCheckedChangeListener(null);vorher schreibenholder.cbSelect.setChecked(objIncome.isSelected())
Jemshit Iskenderov

2
Gibt es einen Grund, warum Inhaber.cbSelect.setOnCheckedChangeListener (null) gesetzt wird? funktioniert?
Deb

4
@oguzhand Hallo, ich habe Ihre Lösung ausprobiert, aber sie funktioniert in keiner Weise: mit oder ohne Setzen des Listeners auf Null.
Abbas

3
@oguzhand Hier ist der Code von 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); } });
Abbas

1
@Suisse Sie müssen den Kontrollkästchenstatus in einem Objekt beibehalten, da ViewHolder nur ein Inhaber ist. Wenn Sie 100 Elemente haben, haben Sie nur etwa 6-7 (abhängig von Bildschirm- und Layoutgröße) ViewHolders und verwenden diese alle Objekte in einem Zyklus.
Oğuzhan Döngül

21

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 setzen

if (...)
    holder.cbSelect.setChecked(true);
else
    holder.cbSelect.setChecked(false);
  1. Aktivieren Sie das Kontrollkästchen Listener! Wenn sich die überprüften Statuen geändert haben, aktualisieren Sie auch das entsprechende Objekt in Ihrem myItemsArray! Wenn also eine neue Ansicht angezeigt wird, wird die neueste Statue des Objekts gelesen.

Ihr zweiter Punkt war der Schlüssel. Obwohl es in einer Situation am besten funktioniert, wenn der ursprüngliche Datensatz auch Informationen über den überprüften Zustand enthält (was bei mir der Fall ist)
Attila Orosz

1
Dies ist die direktere und korrektere Antwort. SetCheck für BEIDE wahr und falsch in onBindViewHolder ist der Schlüssel
Beeing Jk

In meinem Fall muss ich die Daten im Datenmodell mit dem Standardwert isChecked falsefür alle Datensätze beim Start speichern, dann habe onCheckChangedich nur die aktualisiertisChecked Wert auf trueoderfalse und, wie in der Antwortimplementierung angegeben, diese Prüfung entweder aktiviert oder nicht.
Ali Tamoor

20

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);

public class ComponentViewHolder extends RecyclerView.ViewHolder {
    public MyViewHolder(View itemView) {
        super(itemView);
        ....
        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.


Können Sie uns bitte erklären, wie man es benutzt?
UserName_Untold

43
Ist es nicht eine Verschwendung der Logik hinter recyclerView?
eren130

3
Ich habe dies mit einer langen Liste versucht, wodurch das Problem der zufälligen Überprüfung behoben wurde. Wenn ich jedoch nach unten
scrolle

2
Es ist keine gute Idee, die Ansicht nicht wiederverwertbar zu machen, da dadurch der Speicher entladen wird und Sie die meisten Vorteile der Recycler-Ansicht verlieren.
Arthur

Ich stimme euch zu, @ eren130 und Arthur. Ich habe den Beitrag bearbeitet und würde mich sehr freuen, wenn wir einen Weg finden könnten, setIsRecyclable (true / false) zu verwenden. richtig.
Rana Ranvijay Singh

11

Fügen Sie einfach zwei Überschreibungsmethoden von hinzu RecyclerView

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

2
Tu das nicht !! Es wird den recyclerView-Recyclingmechanismus umgehen und den Sinn der Verwendung verlieren.
Hanoch Moreno

1
Nein, wird es nicht, es gibt nur die genaue Position jeder recycelten Ansicht im Ansichtshalter zurück.
Harish Reddy

1
Harish, vielleicht fehlt mir etwas, aber soweit ich weiß, teilen Sie dem Adapter damit tatsächlich mit, dass die Anzahl der Elementtypen die Anzahl der Elemente ist. Die Bedeutung ist, dass kein Artikel recycelt werden kann, da er keine ähnliche Ansicht hat. Es ist jedoch leicht zu testen. Protokollieren Sie einfach die viewHolder.itemView-Referenz in onBindViewHolder und prüfen Sie, ob zwei viewHolders dieselbe view-Referenz enthalten. Der Test sollte auf einer langen Liste stehen, damit das Recyclingsystem ausgeführt wird.
Hanoch Moreno

3
Es erwachte einwandfrei, es rettete meinen Tag.
Kundan

5
Wenn Sie mehr als 100 Artikel in Ihrer Recycling-Ansicht haben, lädt diese Lösung alle Artikel auf einmal. Dies kann zu OutOfMemoryException führen, wenn Sie Bilder haben. Andernfalls ist diese Lösung perfekt. @Kundan
Harish Reddy

10

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

public class Model {

    private boolean isSelected;
    private String animal;

    public String getAnimal() {
        return animal;
    }

    public void setAnimal(String animal) {
        this.animal = animal;
    }

    public boolean getSelected() {
        return isSelected;
    }

    public void setSelected(boolean selected) {
        isSelected = selected;
    }
}

Erstellen Sie integer.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="btnplusview">1</integer>
    <integer name="btnpluspos">2</integer>
</resources>

Schließlich sieht der Adapter so aus:

 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
    import android.view.View;
 import android.view.ViewGroup;
 import android.widget.CheckBox;
 import android.widget.TextView;
 import android.widget.Toast;

 import java.util.ArrayList;


  public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {

private LayoutInflater inflater;
public static ArrayList<Model> imageModelArrayList;
private Context ctx;

public CustomAdapter(Context ctx, ArrayList<Model> imageModelArrayList) {

    inflater = LayoutInflater.from(ctx);
    this.imageModelArrayList = imageModelArrayList;
    this.ctx = ctx;
}

@Override
public CustomAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = inflater.inflate(R.layout.rv_item, parent, false);
    MyViewHolder holder = new MyViewHolder(view);

    return holder;
}

@Override
public void onBindViewHolder(final CustomAdapter.MyViewHolder holder, int position) {

    holder.checkBox.setText("Checkbox " + position);
    holder.checkBox.setChecked(imageModelArrayList.get(position).getSelected());
    holder.tvAnimal.setText(imageModelArrayList.get(position).getAnimal());

   // holder.checkBox.setTag(R.integer.btnplusview, convertView);
    holder.checkBox.setTag(position);
    holder.checkBox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Integer pos = (Integer) holder.checkBox.getTag();
            Toast.makeText(ctx, imageModelArrayList.get(pos).getAnimal() + " clicked!", Toast.LENGTH_SHORT).show();

            if (imageModelArrayList.get(pos).getSelected()) {
                imageModelArrayList.get(pos).setSelected(false);
            } else {
                imageModelArrayList.get(pos).setSelected(true);
            }
        }
    });


}

@Override
public int getItemCount() {
    return imageModelArrayList.size();
}

class MyViewHolder extends RecyclerView.ViewHolder {

    protected CheckBox checkBox;
    private TextView tvAnimal;

    public MyViewHolder(View itemView) {
        super(itemView);

        checkBox = (CheckBox) itemView.findViewById(R.id.cb);
        tvAnimal = (TextView) itemView.findViewById(R.id.animal);
    }

}

}}


3

Mit Kotlin das einzige , was dieses Problem für mich gelöst war klar , OnCheckedChangeListenerbevor die variable Einstellung und erstellen dann eine neue OnCheckedChangeListenernach checkedeingestellt wurde.

Ich mache folgendes in meinem RecyclerView.ViewHolder

task.setOnCheckedChangeListener(null)
task.isChecked = item.status
task.setOnCheckedChangeListener { _: CompoundButton, checked: Boolean ->
    item.status = checked
    ...
    do more stuff
    ...
}

Das funktioniert perfekt. Ich weiß nicht warum, aber das funktioniert nur, wenn jemand KOTLIN benutzt!
Aditya S.

2

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.

import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class TakePicImageAdapter extends RecyclerView.Adapter<TakePicImageAdapter.ViewHolder>{
    private Context context;
    private List<Image> imageList;

    public TakePicImageAdapter(Context context, List<Image> imageList) {
        this.context = context;
        this.imageList = imageList;
    }

    @Override
    public TakePicImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(context).inflate(R.layout.image_item,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final TakePicImageAdapter.ViewHolder holder, final int position) {
        File file=new File(imageList.get(position).getPath());
        try {
            Bitmap bitmap= MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.fromFile(file));
            holder.image.setImageBitmap(bitmap
            );
        } catch (IOException e) {
            e.printStackTrace();
        }
        holder.selectImage.setOnCheckedChangeListener(null);
        holder.selectImage.setChecked(imageList.get(position).isSelected());
        holder.selectImage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                holder.selectImage.setChecked(isChecked);
                imageList.get(position).setSelected(isChecked);
            }
        });
        holder.image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (imageList.get(position).isSelected())
                {
                    imageList.get(position).setSelected(false);
                    holder.selectImage.setChecked(false);
                }else
                {
                    imageList.get(position).setSelected(true);
                    holder.selectImage.setChecked(true);
                }
            }
        });

    }

    @Override
    public int getItemCount() {
        return imageList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView image;public CheckBox selectImage;
        public ViewHolder(View itemView) {
            super(itemView);
            image=(ImageView)itemView.findViewById(R.id.image);
            selectImage=(CheckBox) itemView.findViewById(R.id.ch);

        }
    }
}


2

In meinem Fall hat das funktioniert.

@Override
public void onViewRecycled(MyViewHolder holder) {
    holder.checkbox.setChecked(false); // - this line do the trick
    super.onViewRecycled(holder);
}

2

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

// sparse boolean array for checking the state of the items

    private SparseBooleanArray itemStateArray= new SparseBooleanArray();

onClick()Verwenden Sie dann im Elementklick- Handler den Status der Elemente im itemStateArray, um vor dem Umschalten zu überprüfen. Hier ein Beispiel

        @Override
        public void onClick(View v) {
            int adapterPosition = getAdapterPosition();
            if (!itemStateArray.get(adapterPosition, false)) {
                mCheckedTextView.setChecked(true);
                itemStateArray.put(adapterPosition, true);
            }
            else  {
                mCheckedTextView.setChecked(false);
                itemStateArray.put(adapterPosition, false);
            }
        }

Verwenden Sie außerdem ein spärliches boolesches Array, um den aktivierten Status festzulegen, wenn die Ansicht gebunden ist

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(position);
}

@Override
public int getItemCount() {
    if (items == null) {
        return 0;
    }
    return items.size();
}

 void loadItems(List<Model> tournaments) {
    this.items = tournaments;
    notifyDataSetChanged();
}


class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    CheckedTextView mCheckedTextView;

    ViewHolder(View itemView) {
        super(itemView);
        mCheckedTextView = (CheckedTextView) itemView.findViewById(R.id.checked_text_view);
        itemView.setOnClickListener(this);
    }

    void bind(int position) {
        // use the sparse boolean array to check
        if (!itemStateArray.get(position, false)) {
            mCheckedTextView.setChecked(false);}
        else {
            mCheckedTextView.setChecked(true);
        }
    }

und letzter Adapter wird wie seine diese


1

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.

boolean[] checkedStatus = new boolean[numberOfRows];

@Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
        final ViewHolderItem itemHolder = (ViewHolderItem) holder;

        //holder.bind should not trigger onCheckedChanged, it should just update UI
        itemHolder.checkBox.setOnCheckedChangeListener(null);

        itemHolder.bind(position);

        itemHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    checkedStatus[holder.getAdapterPosition()] = true;
                    performCheckedActions(); //your logic here
                } else {
                    checkedStatus[holder.getAdapterPosition()] = false;
                    performUncheckedActions(); //your logic here
                }
            }
        });
    }

public void bind(int position) {
            boolean checked = checkedStatus[position];
            if (checked) {
                checkBox.setChecked(false);
            } else {
                checkBox.setChecked(true);
            }
        }

1

Ich empfehle , dass nicht verwenden checkBox.setOnCheckedChangeListenerin recyclerViewAdapter. Denn beim Scrollen wird recyclerView checkBox.setOnCheckedChangeListenerper Adapter ausgelöst. Es ist nicht sicher . Verwenden Sie stattdessencheckBox.setOnClickListener mit Benutzereingaben zu interagieren.

Beispielsweise:

     public void onBindViewHolder(final ViewHolder holder, int position) {
        /*
         .
         .
         .
         .
         .
         .
        */

        holder.checkBoxAdapterTasks.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean isChecked =  holder.checkBoxAdapterTasks.isChecked();
                if(isChecked){
                    //checkBox clicked and checked
                }else{
                    //checkBox clicked and unchecked
                }

            }
        });

    }

1

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.

public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
private Context context;
public static class PersonViewHolder extends RecyclerView.ViewHolder {

    CardView cv;
    TextView question,category;
    TextView personAge;
    ImageView upvote;
    Button b1;
    public static int k;
    private int visibleThreshold = 5;
    public static int i=0;
     static int  check[]; //Static array
    PersonViewHolder(View itemView,int i) {
        super(itemView);
        if(i==PersonViewHolder.k)
        {
            b1=(Button)itemView.findViewById(R.id.loadmore);

        }
        else
        {
            cv = (CardView)itemView.findViewById(R.id.cv);
            question = (TextView)itemView.findViewById(R.id.question);
            category = (TextView)itemView.findViewById(R.id.text_categ);
            personAge = (TextView)itemView.findViewById(R.id.text1);
            upvote = (ImageView)itemView.findViewById(R.id.upvote);

        }

    }

}

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

List<Person> persons;

RVAdapter(List<Person> persons){
    this.persons = persons;
    PersonViewHolder.check=new int[persons.size()];
    PersonViewHolder.k=persons.size();
}

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.

@Override
public void onBindViewHolder(final PersonViewHolder personViewHolder, final int i) {
    if(i==PersonViewHolder.k) {
        personViewHolder.b1.setText("load more");

    }
    else
     {
        personViewHolder.question.setText(persons.get(i).name);
        personViewHolder.personAge.setText(persons.get(i).age);

         if(personViewHolder.check[i]==0)
         {personViewHolder.upvote.setBackgroundResource(R.drawable.noupvote);
         }
         else
         {
             personViewHolder.upvote.setBackgroundResource(R.drawable.upvote);

         }

         personViewHolder.upvote.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 if(personViewHolder.check[i]==0)
                 {personViewHolder.check[i]=1;
                     personViewHolder.upvote.setBackgroundResource(R.drawable.upvote);


                 }
                 else
                 {personViewHolder.check[i]=0;
                     personViewHolder.upvote.setBackgroundResource(R.drawable.noupvote);

                 }


             }
         });
        // personViewHolder.personPhoto.setImageResource(persons.get(i).photoId);
    }

}

1

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:

if (newsItems.get(position).getBookmark() == 1) {
            holder.getToggleButtonBookmark().setChecked(true);
        }

Aber dann habe ich eine andere Aussage hinzugefügt

if (newsItems.get(position).getBookmark() == 1) {
            holder.getToggleButtonBookmark().setChecked(true);
//else statement prevents auto toggling
        } else{
            holder.getToggleButtonBookmark().setChecked(false);
        }

Und das Problem wurde gelöst


Danke dir. Andernfalls wird das Kontrollkästchen deaktiviert, wenn beim Recycling standardmäßig dieselbe Ansicht angezeigt wird.
Adarsh ​​Vijayan P

0

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:

if (buttonView.isPressed()) {
    if (isChecked) {
        group.setSelected(true);
    } else {
        group.setSelected(false);
    }
}else{
    if (isChecked) {
        buttonView.setChecked(false);
    } else {
        buttonView.setChecked(true);
    }
}

(Wobei 'Gruppe' die Entität ist, die ich auswählen / abwählen möchte)


0

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, die CheckBoxund so RadioButtonetwas hat:

Geben Sie hier die Bildbeschreibung ein 2- Modellklasse

public class ModelClass {
private String time;
private boolean checked;
private boolean free;
private boolean paid;

public TherapistScheduleModel(String time, boolean checked, boolean free, boolean paid) {
    this.time = time;
    this.checked = checked;
    this.free = free;
    this.paid = paid;
}

public boolean isFree() {
    return free;
}

public void setFree(boolean free) {
    this.free = free;
}

public boolean isPaid() {
    return paid;
}

public void setPaid(boolean paid) {
    this.paid = paid;
}

public String getTime() {
    return time;
}

public void setTime(String time) {
    this.time = time;
}

public boolean getChecked() {
    return checked;
}

public void setChecked(boolean checked) {
    this.checked= checked;
}
}

3-Mein erstaunlicher Adapter

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
private ListAllListeners listAllListeners;
private ArrayList<ModelClass> mDataList;

public MyAdapter(Context context, ArrayList<ModelClass> mDataList,
                             ListAllListeners listAllListeners) {
    this.mDataList = mDataList;
    this.listAllListeners = listAllListeners;
    this.context = context;
}

@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View view = inflater.inflate(R.layout.single_view, parent, false);
    return new MyViewHolder(view);
}

@Override
public int getItemCount() {
    if (mDataList != null)
        return mDataList.size();
    else
        return 0;
}

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
     //important to:
    //setOnCheckedChangeListener to 'null'
    holder.checkBoxTime.setOnCheckedChangeListener(null);
    holder.freeRB.setOnCheckedChangeListener(null);
    holder.paidRB.setOnCheckedChangeListener(null);

    //Check Box
            holder.checkBoxTime.setText(mDataList.get(holder.getAdapterPosition()).getTime());
    //here we check if the item is checked or not from the model.
    if(mDataList.get(holder.getAdapterPosition()).getChecked())
        holder.checkBoxTime.setChecked(true);
    else
        holder.checkBoxTime.setChecked(false);

    holder.checkBoxTime.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            if (b) {
                mDataList.get(holder.getAdapterPosition()).setChecked(true);
                listAllListeners.onItemCheck(holder.checkBoxTime.getText().toString(), holder.getAdapterPosition());
            }
            else {
                mDataList.get(holder.getAdapterPosition()).setChecked(false);
                listAllListeners.onItemUncheck(holder.checkBoxTime.getText().toString(), holder.getAdapterPosition());
            }
        }
    });

    //Radio Buttons

    if(mDataList.get(holder.getAdapterPosition()).isFree())
        holder.freeRB.setChecked(true);
    else
        holder.freeRB.setChecked(false);
    holder.freeRB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            if (b) {
                mDataList.get(holder.getAdapterPosition()).setFree(true);
                listAllListeners.onFreeCheck(holder.freeRB.getText().toString(), holder.getAdapterPosition());
            } else {
                mDataList.get(holder.getAdapterPosition()).setFree(false);
                listAllListeners.onFreeUncheck(holder.freeRB.getText().toString(), holder.getAdapterPosition());
            }
        }
    });

   //***and so on to paidRB***

}//end onBindViewHolder()

public interface ListAllListeners {
//here is a list of clicked listeners to use them as you want ;).
//you can get a list of checked or unChecked of all 
        void onItemCheck(String checkBoxName, int position);
        void onItemUncheck(String checkBoxName, int position);
        void onFreeCheck(String name, int pos);
        void onFreeUncheck(String name, int pos);
        void onPaidCheck(String name, int pos);
        void onPaidUncheck(String name, int pos);
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        CheckBox checkBoxTime;
        RadioButton freeRB, paidRB;

        MyViewHolder(View itemView) {
            super(itemView);
            checkBoxTime = itemView.findViewById(R.id.timeCheckBox);
            freeRB = itemView.findViewById(R.id.freeRadioBtn);
            paidRB = itemView.findViewById(R.id.paidRadioBtn);
        }
    }//end class MyViewHolder

    }//end class

3- In Aktivität erhalten Sie sie ungefähr so:

myAdapter= new MyAdapter(getActivity().getApplicationContext(), mDataList,
                new MyAdapter.ListAllListeners() {

                    @Override
                    public void onItemCheck(String checkBoxName, int position) {
                        Toast.makeText(getActivity(), "" + checkBoxName + "  " + position, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onItemUncheck(String checkBoxName, int position) {
                        Toast.makeText(getActivity(), "" + checkBoxName + "  " + position, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFreeCheck(String name, int position) {

                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFreeUncheck(String name, int position) {

                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onPaidCheck(String name, int position) {

                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onPaidUncheck(String name, int position) {

                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                    }
                });

0

öffentliche Klasse TagYourDiseaseAdapter erweitert RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; privater Kontext mContext;

List<Datum> deviceList = Collections.emptyList();

/**
 * Initialize the values
 *
 * @param context : context reference
 * @param devices : data
 */

public TagYourDiseaseAdapter(Context context, List<Datum> devices,
                             ReCyclerViewItemClickListener mreCyclerViewItemClickListener) {
    this.mContext = context;
    this.deviceList = devices;
    this.mRecyclerViewItemClickListener = mreCyclerViewItemClickListener;
}


/**
 * @param parent   : parent ViewPgroup
 * @param viewType : viewType
 * @return ViewHolder
 * <p>
 * Inflate the Views
 * Create the each views and Hold for Reuse
 */
@Override
public TagYourDiseaseAdapter.OrderHistoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tag_disease, parent, false);
    TagYourDiseaseAdapter.OrderHistoryViewHolder myViewHolder = new TagYourDiseaseAdapter.OrderHistoryViewHolder(view);
    return myViewHolder;
}


/**
 * @param holder   :view Holder
 * @param position : position of each Row
 *                 set the values to the views
 */
@Override
public void onBindViewHolder(final TagYourDiseaseAdapter.OrderHistoryViewHolder holder, final int position) {
    Picasso.with(mContext).load(deviceList.get(position).getIconUrl()).into(holder.document);
    holder.name.setText(deviceList.get(position).getDiseaseName());

    holder.radioButton.setOnCheckedChangeListener(null);
    holder.radioButton.setChecked(deviceList.get(position).isChecked());

    //if true, your checkbox will be selected, else unselected
    //holder.radioButton.setChecked(objIncome.isSelected());

    holder.radioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            deviceList.get(position).setChecked(isChecked);
        }
    });


}

@Override
public int getItemCount() {
    return deviceList.size();
}


/**
 * Create The view First Time and hold for reuse
 * View Holder for Create and Hold the view for ReUse the views instead of create again
 * Initialize the views
 */

public class OrderHistoryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    ImageView document;
    TextView name;
    CheckBox radioButton;

    public OrderHistoryViewHolder(View itemView) {
        super(itemView);
        document = itemView.findViewById(R.id.img_tag);
        name = itemView.findViewById(R.id.text_tag_name);
        radioButton = itemView.findViewById(R.id.rdBtn_tag_disease);
        radioButton.setOnClickListener(this);
        //this.setIsRecyclable(false);
    }


    @Override
    public void onClick(View view) {
        mRecyclerViewItemClickListener.onItemClickListener(this.getAdapterPosition(), view);
    }
}

}}


0

Dies geschieht, wenn die Verwendung setOnCheckedChangeListeneranstelle dieser Verwendung erfolgt setObClickListenerund im Inneren nur dieser einfache Griff ausgeführt wird:

   if (list.get(position).isCheck())
            {
                list.get(position).setCheck(false);
            }
            else
            {
                list.get(position).setCheck(true);
            }

HINWEIS: checkFügen Sie in Ihrem Listenmodell eine boolesche Variable mit dem Namen hinzu und setzen Sie dafür Getter und Setter. In dem obigen Fall ist meine setCheck und isCheck

hoffe es hilft jemandem wenn ja + stimme auf diese Antwort ab



-1

Was für mich funktioniert hat, ist, die Listener auf dem viewHolder zu annullieren, wenn die Ansicht recycelt werden soll ( onViewRecycled):

 override fun onViewRecycled(holder: AttendeeViewHolder) {
            super.onViewRecycled(holder)
            holder.itemView.hasArrived.setOnCheckedChangeListener(null);
            holder.itemView.edit.setOnClickListener { null }
        }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.