RecyclerView'daki CheckBox farklı öğeleri kontrol etmeye devam ediyor


93

RecyclerView içindeki öğelerim için XML burada

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

Ve işte, her bir öğesi için yukarıdaki düzeni şişiren RecyclerView adaptörü:

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

Sorun şu ki, RecyclerView içinde 10 öğem var diyelim. 1,2,3 öğesindeki onay kutusunu işaretlediğimde RecyclerView'de aşağı kaydırıyorum, aniden diğer öğelerden bazıları, örneğin öğeler 8,9 kontrol ediliyor. Ve tekrar yukarı kaydırdığımda, 1. ve 3. madde kontrol edilir, ancak 2. madde değil. Bunun neden olduğu hakkında bir fikriniz var mı?


Bu kitaplığı kullanmayı deneyin , ViewStates'e bakın. Kaydırırken bir durumu kaydetmeye yardımcı olur.
Vitaly

Yanıtlar:


167

Bu beklenen bir davranış. Onay kutunuzun seçili olup olmadığını ayarlamıyorsunuz. Birini seçersiniz ve Görünüm sahibi onu seçili tutar. ObjectIncome nesnenize bir boolean değişkeni ekleyebilir ve öğenizin seçim durumunu koruyabilirsiniz.

Örneğime bakabilirsiniz. Bunun gibi bir şey yapabilirsiniz:

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

    }
}

19
Çalışmadı. Daha holder.cbSelect.setOnCheckedChangeListener(null);önce holder.cbSelect.setChecked(objIncome.isSelected())
yazmalısın

2
holder.cbSelect.setOnCheckedChangeListener (null) 'un neden ayarlanmasının herhangi bir nedeni var mı; İşler?
Deb

4
@oguzhand merhaba Çözümünüzü denedim ama iki şekilde de çalışmıyor: dinleyiciyi null olarak ayarlayarak veya ayarlamadan.
Abbas

3
@ oguzhand İşte kodu 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, ViewHolder sadece bir tutucu olduğu için bir nesnede onay kutusu durumunu tutmanız gerekir. 100 öğeniz varsa, yalnızca yaklaşık 6-7 öğeniz (ekrana ve düzen boyutuna bağlıdır) ViewHolders ve tüm bu nesneleri bir döngüde kullanın.
Oğuzhan Döngül

22

Kısacası, görünümlerin geri dönüştürülmesi ve tekrar kullanılması nedeniyle!

bundan nasıl kaçınabilirsiniz:

1. onBindViewHolderKutuları işaretlemeniz veya işaretlerini kaldırmanız gerekip gerekmediğini kontrol edin. ikisini de koymayı unutma if ve else

if (...)
    holder.cbSelect.setChecked(true);
else
    holder.cbSelect.setChecked(false);
  1. Onay kutusu için bir dinleyici koyun! kontrol edilen heykelleri her değiştiğinde, myItemsdizinizdeki ilgili nesneyi de güncelleyin ! böylece yeni bir görünüm gösterildiğinde, nesnenin en yeni heykelini okur.

İkinci noktanız anahtardı. Bir durumda en iyi şekilde çalışmasına rağmen, ilk veri kümesinin kontrol edilen durum hakkında da bilgi içerdiği durumlarda (bu benim için geçerli)
Attila Orosz

1
bu daha doğrudan ve doğru cevaptır. OnBindViewHolder'da HER İKİ doğru ve yanlış için SetCheck anahtardır
Beeing Jk

Benim durumumda, isChecked falseverileri başlangıçta tüm veri kümesi için varsayılan değerle veri modeline kaydetmem gerekiyor , ardından değeri yalnızca veya olarak onCheckChangedgüncelledim ve yanıt uygulamasında kontrol edilen ya da işaretlenmeyen yanıt uygulamasında söylendiği gibi. isCheckedtruefalse
Ali Tamoor

20

BUNU YALNIZCA GERİ DÖNÜŞÜMÜNÜZDE SINIRLI SAYIDA ÖĞE VARSA KULLANIN.
Modelde boole değerini kullanmayı ve onay kutusu durumunu korumayı denedim, ancak benim durumumda yardımcı olmadı. Benim için işe yarayan şey this.setIsRecyclable (false);

public class ComponentViewHolder extends RecyclerView.ViewHolder {
    public MyViewHolder(View itemView) {
        super(itemView);
        ....
        this.setIsRecyclable(false);
    }

Bununla ilgili daha fazla açıklama burada https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable () bulunabilir.

NOT: Bu bir çözümdür. Düzgün kullanmak için, "setIsRecyclable () çağrılarının her zaman eşleştirilmesi gerektiğini belirten belgeye başvurabilirsiniz (setIsRecyclabe (false) için bir çağrı her zaman daha sonraki bir setIsRecyclable (true) çağrısıyla eşleştirilmelidir). Çağrı çiftleri yuvalanmış olabilir , durum dahili olarak referans sayıldığından. " Birisi bununla ilgili daha fazla kod sağlayabilirse, bunu kodla nasıl yapacağımı bilmiyorum.


lütfen nasıl kullanılacağını açıklar mısınız?
UserName_Untold

44
recyclerView arkasındaki mantığın boşa gitmesi değil mi?
Eren

3
Bunu, rastgele kontrol sorununu çözen uzun bir listeyle denedim, ancak aşağı
kaydırdığımda

2
Hafızayı tüketeceğinden ve geri dönüşümlü görünümün pek çok avantajını kaybedeceğinizden, görünümü geri dönüştürülemez hale getirmek iyi bir fikir değildir.
Arthur

Size katılıyorum çocuklar, @ eren130 ve Arthur. Gönderiyi düzenledim ve setIsRecyclable'ı (doğru / yanlış) kullanmanın bir yolunu bulabilirsek çok memnun olurum; uygun şekilde.
Rana Ranvijay Singh

13

Sadece iki geçersiz kılma yöntemi ekleyin RecyclerView

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

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

2
Bunu yapma !! RecyclerView geri dönüşüm mekanizmasını atlayacak ve tüm kullanım noktasını kaybedecektir.
Hanoch Moreno

1
Hayır olmaz, sadece görüntü tutucudaki her geri dönüştürülmüş görüntünün tam konumunu döndürür.
Harish Reddy

1
Harish, belki bir şeyi kaçırıyorum, ama bildiğim kadarıyla, bunu yaparak adaptöre aslında öğe türlerinin sayısının öğe sayısı olduğunu söylüyorsun. Bunun anlamı, benzer bir görünümü olmadığı için hiçbir öğenin geri dönüştürülemeyeceğidir. Yine de test etmek kolaydır. sadece onBindViewHolder içindeki viewHolder.itemView referansını günlüğe kaydedin ve aynı görünüm referansını tutan iki viewHolders olup olmadığına bakın. Geri dönüşüm sisteminin çalıştırılması için test uzun bir listede olmalıdır.
Hanoch Moreno

3
Kusursuz uyandı, Günümü kurtardı.
Kundan

5
Geri dönüşüm görünümünüzde 100'den fazla öğe varsa, bu çözüm tüm öğeleri bir kerede yükleyecektir, bu, görüntülerin olması durumunda OutOfMemoryException'a neden olabilir, aksi takdirde bu çözüm mükemmeldir @Kundan
Harish Reddy

11

Her recyclerView öğesinin onay kutusunu takip etmek için Model sınıfını kullanabilirsiniz. Tam başvuru kaynağı: RecyclerView Checkbox Android

setTag ve getTag , onay kutusu durumunu takip etmek için kullanılır. Daha fazla bilgi için tam referans bağlantısını kontrol edin. Ayrıca, işaretli öğelerin NEXTACTIVITY'e nasıl gönderileceğini de öğretir .

Model Yap

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

integer.xml oluştur

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

Son olarak adaptör şuna benziyor:

 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

Kotlin'i kullanmak benim için bu sorunu çözen tek şey OnCheckedChangeListenerdeğişkeni ayarlamadan önce temizleyip sonra yeni bir OnCheckedChangeListenersonrasını oluşturmaktı checked.

Ben aşağıdakileri yapıyorum RecyclerView.ViewHolder

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

Bu mükemmel çalışıyor. Neden bilmiyorum ama bu sadece KOTLIN kullanan herkes için geçerli!
Aditya S.

2

Yukarıda belirtildiği gibi, nesnenin kontrol edilmiş durumu, nesne özelliklerine dahil edilmelidir. Bazı durumlarda, nesnenin kendisine tıklayarak nesne seçim durumunu değiştirmeniz ve CheckBox'ın gerçek durum (seçili veya seçilmemiş) hakkında bilgi vermesine izin vermeniz gerekebilir. Onay kutusu, daha sonra (varsayılan olarak / çoğu durumda) listedeki öğenin konumu olan, verilen bağdaştırıcının gerçek konumundaki nesnenin durumunu kullanacaktır.

Aşağıdaki parçacığı kontrol edin, yararlı olabilir.

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

Benim durumumda bu işe yaradı.

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

2

Öğelerin durumunu tutmak için bir dizi kullanın

Bağdaştırıcıda , öğeler listemizdeki tüm öğelerin durumunu saklamak için bir Map veya SparseBooleanArray (haritaya benzer, ancak int ve boolean anahtar-değer çiftidir) kullanın ve ardından karşılaştırmak için anahtarları ve değerleri kullanın kontrol edilmiş durumu değiştirirken

Bağdaştırıcıda bir SparseBooleanArray

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

    private SparseBooleanArray itemStateArray= new SparseBooleanArray();

sonra öğe tıklama işleyicisinde onClick()geçiş yapmadan önce kontrol etmek için itemStateArray'deki öğelerin durumunu kullanın, işte bir örnek

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

ayrıca, görünüm bağlandığında denetlenen durumu ayarlamak için seyrek boole dizisini kullanın

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

ve son adaptör gibi olacak bu


1

CheckBox ile onBindViewHolder (mantık) etkileşimlerini ve onay kutusu ile kullanıcı etkileşimlerini ayırmanız gerekir. Kullanıcı etkileşimleri için (tabii ki) OnCheckedChangeListener'ı ve mantık için ViewHolder.bind () 'ı kullandım, bu yüzden tutucu ayarlamadan önce ve tutucu hazır olduktan sonra denetlenen dinleyiciyi kullanıcı etkileşimleri için yapılandırın.

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

Bunu kullanmamayı tavsiye checkBox.setOnCheckedChangeListeneriçinde recyclerViewAdapter. Çünkü recyclerView kaydırıldığında checkBox.setOnCheckedChangeListeneradaptör tarafından ateşlenecektir. Güvenli değil . Bunun yerine, checkBox.setOnClickListenerkullanıcı girdileriyle etkileşim kurmak için kullanın .

Örneğin:

     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

Bulduğum bu çözümün sorunu, statik bir global dizi oluşturarak ve bunu gerekli tüm global değişkenleri / nesneleri oluşturduğum "onBindViewHolder" ADAPER SINIFI içinde kullanmaktır.

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

        }

    }

}

Burada (RVADAPTER SINIFI YAPICISINDA) diziye boyut verdim, geri dönüşümcü görünümünde göstereceğim öğelerin boyutuna eşittir / yok

List<Person> persons;

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

BindViewHolder, I, Bu kavramı bir butona uyguladım, bir butona tıkladığımda butonun arka plan görüntüsü değişiyor. Kullandığım düğmenin nesnesi "upvote" olarak adlar, "i" geri dönüşümcü görünümündeki her öğenin konumunu koruduğu için, bunu bayrak olarak çalışan ve öğelerin durumunu takip eden bir dizi dizini olarak kullandım.

@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

Ben de aynı sorunu yaşadım. RecyclerView öğemde öğenin geçiş düğmesine tıkladığımda her 10 öğede bir Değiştir düğmesi görünüyordu (örneğin 0 indeksli öğede tıklanmışsa, 9, 18, 27 indeksli öğeler de tıklanıyordu). İlk olarak, onBindViewHolder'daki kodum şuydu:

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

Ama sonra Else ifadesini ekledim

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

Ve sorun çözüldü


Teşekkür ederim. Diğer kısım, aynı görünümü geri dönüştürürken varsayılan olarak işaretlerse, onay kutusunu temizler.
Adarsh ​​Vijayan P

1

tamam burada birçok cevap var kodumu göndereceğim ve ne yaptığımı basitçe açıklayacağım ... benim gibi gençlere yardımcı olabilir: D.

1- Amaç:

biz bir listesini yaratacak RecyclerViewo vardır CheckBoxve RadioButtonböyle bir şey:

görüntü açıklamasını buraya girin 2- Model Sınıfı

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-My Amazing Adaptör

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- Aktivite'de onlara şöyle bir şey elde edersiniz:

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

Aynı sorunu bir RecyclerView listesinde anahtarlarla yaşadım ve @ oguzhand cevabını kullanarak çözdüm, ancak checkChangeListener içindeki bu kodla:

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

('Grup', seçmek / seçimi kaldırmak istediğim varlıktır)


0

public class TagYourDiseaseAdapter RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; özel Bağlam 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

bu, o kullanım setOnCheckedChangeListeneryerine kullanıldığında gerçekleşecek setObClickListenerve bunun içinde sadece bu kolay kullanımı yapın:

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

NOT: liste modelinize adla birlikte bir boole değişkeni ekleyin checkve bunun için alıcı ve ayarlayıcıyı ayarlayın, yukarıdaki durumda benimki setCheck ve isCheck

Umarım birine yardımcı olur, eğer öyleyse + bu yanıta oy verin



0

bunun nedeni tekrar tekrar görünüm oluşturmaktır, en iyi seçenek adaptörü ayarlamadan önce önbelleği temizlemektir

recyclerview.setItemViewCacheSize(your array.size());

0

Tam örnek
genel sınıf ChildAddressAdapter RecyclerView.Adapter <ChildAddressAdapter.CartViewHolder> {

private Activity context;
private List<AddressDetail> addressDetailList;
private int selectedPosition = -1;

public ChildAddressAdapter(Activity context, List<AddressDetail> addressDetailList) {
    this.context = context;
    this.addressDetailList = addressDetailList;
}

@NonNull
@Override
public CartViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    LayoutInflater inflater = LayoutInflater.from(context);
    View myView = inflater.inflate(R.layout.address_layout, parent, false);
    return new CartViewHolder(myView);
}

@Override
public void onBindViewHolder(@NonNull CartViewHolder holder, int position) {

    holder.adress_checkbox.setOnClickListener(view -> {
        selectedPosition = holder.getAdapterPosition();
        notifyDataSetChanged();
    });

    if (selectedPosition==position){
        holder.adress_checkbox.setChecked(true);
    }
    else {
        holder.adress_checkbox.setChecked(false);
    }


}

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

class CartViewHolder extends RecyclerView.ViewHolder
{
    TextView address_text,address_tag;
    CheckBox adress_checkbox;

    CartViewHolder(View itemView) {
        super(itemView);
        address_text = itemView.findViewById(R.id.address_text);
        address_tag = itemView.findViewById(R.id.address_tag);
        adress_checkbox = itemView.findViewById(R.id.adress_checkbox);
    }
}

}


-1

Benim için işe yarayan şey, görünüm geri dönüştürülürken viewHolder'daki dinleyicileri geçersiz kılmaktır ( onViewRecycled):

 override fun onViewRecycled(holder: AttendeeViewHolder) {
            super.onViewRecycled(holder)
            holder.itemView.hasArrived.setOnCheckedChangeListener(null);
            holder.itemView.edit.setOnClickListener { null }
        }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.