CheckBox di RecyclerView terus memeriksa item yang berbeda

93

Inilah XML untuk item saya di dalam 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>

Dan inilah adaptor RecyclerView yang memekarkan tata letak di atas untuk setiap itemnya:

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

Masalahnya adalah, katakanlah saya memiliki 10 item di dalam RecyclerView. Ketika saya mencentang kotak centang pada item 1,2,3 lalu saya scroll ke bawah RecyclerView, tiba-tiba beberapa item lain misalnya item 8,9 dicentang. Dan ketika saya menggulir ke atas lagi, item 1 dan 3 dicentang tetapi bukan item 2. Anda tahu mengapa ini terjadi?

imin
sumber
Coba gunakan perpustakaan ini , lihat Kondisi Tampilan. Ini membantu untuk menyimpan keadaan saat menggulir.
Vitaly

Jawaban:

167

Itu adalah perilaku yang diharapkan. Anda tidak menyetel kotak centang Anda dipilih atau tidak. Anda memilih satu dan View holder tetap memilihnya. Anda dapat menambahkan variabel boolean ke dalam objek ObjectIncome Anda dan mempertahankan status pemilihan item Anda.

Anda dapat melihat contoh saya. Anda bisa melakukan sesuatu seperti itu:

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

    }
}
Oğuzhan Döngül
sumber
19
Tidak berhasil. Anda harus menulis holder.cbSelect.setOnCheckedChangeListener(null);sebelumnyaholder.cbSelect.setChecked(objIncome.isSelected())
Jemshit Iskenderov
2
apakah ada alasan mengapa pengaturan holder.cbSelect.setOnCheckedChangeListener (null); bekerja?
Deb
4
@oguzhand hai Saya mencoba solusi Anda tetapi tidak berhasil: dengan atau tanpa pengaturan pendengar ke null.
Abbas
3
@oguzhand Berikut kode dari 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 Anda perlu mempertahankan status kotak centang dalam sebuah objek, karena ViewHolder hanyalah sebuah pemegang. Jika Anda memiliki 100 item, Anda hanya memiliki sekitar 6-7 (bergantung pada layar dan ukuran tata letak) ViewHolders dan menggunakan semua objek ini dalam satu siklus.
Oğuzhan Döngül
22

Singkatnya, ini karena mendaur ulang tampilan dan menggunakannya lagi!

bagaimana Anda bisa menghindari itu:

1. Di onBindViewHoldercentang apakah Anda harus mencentang atau menghapus centang pada kotak. jangan lupa untuk meletakkan keduanya jika dan lainnya

if (...)
    holder.cbSelect.setChecked(true);
else
    holder.cbSelect.setChecked(false);
  1. Letakkan pendengar untuk kotak centang! setiap kali patung yang dicentang berubah, perbarui juga objek yang sesuai dalam myItemslarik Anda ! jadi setiap kali tampilan baru ditampilkan, itu membaca patung terbaru dari objek tersebut.
Omid Heshmatinia
sumber
Poin kedua Anda adalah kuncinya. Meskipun berfungsi paling baik dalam suatu situasi, ketika set data awal juga memiliki informasi tentang status yang diperiksa (yang saya
alami
1
ini adalah jawaban yang lebih lugas dan tepat. SetCheck untuk KEDUA benar dan salah di onBindViewHolder adalah kuncinya
Beeing Jk
Dalam kasus saya, saya harus menyimpan data dalam model data dengan nilai default isChecked falseuntuk semua kumpulan data di awal, lalu onCheckChangedsaya baru saja memperbarui isCheckednilainya ke trueatau falsedan seperti yang diceritakan dalam implementasi jawaban yang centangnya dicentang atau tidak.
Ali Tamoor
20

GUNAKAN INI HANYA JIKA ANDA MEMILIKI JUMLAH BARANG TERBATAS DALAM TAMPILAN DAUR ULANG.
Saya mencoba menggunakan nilai boolean dalam model dan mempertahankan status kotak centang, tetapi tidak membantu dalam kasus saya. Apa yang berhasil bagi saya adalah this.setIsRecyclable (false);

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

Penjelasan lebih lanjut tentang ini dapat ditemukan di sini https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable ()

CATATAN: Ini adalah solusi. Untuk menggunakannya dengan benar, Anda dapat merujuk dokumen yang menyatakan "Panggilan ke setIsRecyclable () harus selalu dipasangkan (satu panggilan ke setIsRecyclabe (false) harus selalu dicocokkan dengan panggilan selanjutnya ke setIsRecyclable (true)). Pasangan panggilan dapat disarangkan , karena negara bagian dihitung referensi secara internal. " Saya tidak tahu bagaimana melakukan ini dalam kode, jika seseorang dapat memberikan kode lebih lanjut tentang ini.

Rana Ranvijay Singh
sumber
tolong jelaskan bagaimana cara menggunakannya?
UserName_Untold
44
bukankah itu menyia-nyiakan logika di balik recyclerView?
Eren
3
Saya mencoba ini dengan daftar panjang yang menyelesaikan masalah pemeriksaan acak tetapi ketika saya menggulir ke bawah dan menggulir ulang ke atas dengan daftar panjang, kotak centang yang dicentang menghilang :(
SonDang
2
Bukan ide yang baik untuk membuat tampilan tidak dapat didaur ulang karena akan menguras memori dan Anda akan kehilangan sebagian besar manfaat tampilan pendaur ulang.
Arthur
Saya setuju dengan kalian, @ eren130 dan Arthur. Saya telah mengedit postingan tersebut, dan akan sangat menghargai jika kita dapat menemukan cara untuk menggunakan setIsRecyclable (true / false); tepat.
Rana Ranvijay Singh
13

Cukup tambahkan dua metode penggantian RecyclerView

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

@Override
public int getItemViewType(int position) {
    return position;
}
Harish Reddy
sumber
2
Jangan lakukan itu !! Ini akan melewati mekanisme daur ulang recyclerView dan kehilangan seluruh tujuan penggunaannya.
Hanoch Moreno
1
Tidak, tidak akan, itu hanya mengembalikan posisi persis dari setiap tampilan daur ulang di view holder.
Harish Reddy
1
Harish, mungkin saya melewatkan sesuatu, tetapi sejauh yang saya tahu, dengan melakukan ini Anda benar-benar memberi tahu adaptor bahwa jumlah jenis item adalah jumlah item. Artinya tidak ada barang yang dapat didaur ulang karena tidak memiliki kesamaan pandangan. Ini mudah untuk diuji. cukup catat referensi viewHolder.itemView di dalam onBindViewHolder dan lihat apakah ada dua viewHolders yang memegang referensi tampilan yang sama. Tes harus dalam daftar panjang sehingga sistem daur ulang akan dijalankan.
Hanoch Moreno
3
Itu terbangun dengan sempurna, Ini menyelamatkan hari saya.
Kundan
5
jika Anda memiliki lebih dari 100 item di recycview Anda, solusi ini akan memuat semua item sekaligus, ini dapat menyebabkan OutOfMemoryException jika Anda memiliki gambar berarti jika tidak, solusi ini sempurna @Kundan
Harish Reddy
11

Anda bisa menggunakan kelas Model untuk melacak setiap kotak centang item recyclerView. Referensi lengkap berasal dari: RecyclerView Checkbox Android

setTag dan getTag digunakan untuk melacak status kotak centang. Lihat tautan referensi lengkap untuk informasi lebih lanjut. Ini juga mengajarkan cara mengirim item yang dicentang ke NEXTACTIVITY .

Membuat model

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

buat integer.xml

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

Akhirnya adaptor terlihat seperti ini:

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

}

}

pengguna6435056
sumber
3

Menggunakan Kotlin, satu-satunya hal yang memecahkan masalah ini bagi saya adalah menghapus OnCheckedChangeListenersebelum mengatur variabel dan kemudian membuat yang baru OnCheckedChangeListenersetelah checkedditetapkan.

Saya melakukan hal berikut di saya RecyclerView.ViewHolder

task.setOnCheckedChangeListener(null)
task.isChecked = item.status
task.setOnCheckedChangeListener { _: CompoundButton, checked: Boolean ->
    item.status = checked
    ...
    do more stuff
    ...
}
just_user
sumber
Ini bekerja dengan sempurna. Saya tidak tahu mengapa tetapi ini hanya berfungsi ketika seseorang menggunakan KOTLIN!
Aditya S.
2

Seperti yang dinyatakan di atas, status objek yang diperiksa harus dimasukkan dalam properti objek. Dalam beberapa kasus, Anda mungkin juga perlu mengubah status pemilihan objek dengan mengklik objek itu sendiri dan membiarkan Kotak Centang menginformasikan tentang keadaan sebenarnya (baik dipilih atau tidak). Kotak centang kemudian akan menggunakan status objek pada posisi sebenarnya dari adaptor yang diberikan, yaitu (secara default / dalam banyak kasus) posisi elemen dalam daftar.

Cek potongan dibawah ini, semoga bermanfaat.

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

        }
    }
}

Gratien Asimbahwe
sumber
2

Dalam kasus saya ini berhasil.

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

Gunakan larik untuk menampung status item

Dalam adaptor, gunakan Map atau SparseBooleanArray (yang mirip dengan map tetapi merupakan pasangan nilai kunci int dan boolean) untuk menyimpan status semua item dalam daftar item kami dan kemudian gunakan kunci dan nilai untuk membandingkan saat mengubah status yang dicentang

Di Adapter, buat file SparseBooleanArray

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

    private SparseBooleanArray itemStateArray= new SparseBooleanArray();

lalu di item click handler onClick()gunakan status item di itemStateArray untuk memeriksa sebelum toggling, berikut ini contohnya

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

juga, gunakan larik boolean renggang untuk menyetel status yang dicentang saat tampilan terikat

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

dan adaptor terakhir akan seperti ini

Basi
sumber
1

Anda perlu memisahkan interaksi onBindViewHolder (logika) dengan CheckBox dan interaksi pengguna dengan checkbox. Saya menggunakan OnCheckedChangeListener untuk interaksi pengguna (jelas) dan ViewHolder.bind () untuk logika, itulah mengapa Anda perlu mengatur pendengar yang dicentang ke null sebelum menyiapkan pemegang dan setelah pemegang siap - konfigurasikan pendengar yang diperiksa untuk interaksi pengguna.

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);
            }
        }
Levor
sumber
1

Saya merekomendasikan agar tidak digunakan checkBox.setOnCheckedChangeListenerdalam recyclerViewAdapter. Karena saat menggulir recyclerView, checkBox.setOnCheckedChangeListenerakan diaktifkan oleh adaptor. Tidak aman . Sebaliknya, gunakan checkBox.setOnClickListeneruntuk berinteraksi dengan input pengguna.

Sebagai contoh:

     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
                }

            }
        });

    }
Eren
sumber
1

Masalah dari solusi ini yang saya temukan adalah, dengan membuat array global statis dan menggunakannya dalam "onBindViewHolder" ADAPER CLASS, di mana saya membuat semua varaibles global / objek yang dibutuhkan.

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

        }

    }

}

Di sini (DALAM PEMBANGUN RVADAPTER CLASS) saya memberi ukuran pada array sama dengan ukuran / tidak item yang akan saya tampilkan di tampilan pendaur ulang

List<Person> persons;

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

BindViewHolder, I, Menerapkan konsep ini pada tombol, ketika saya mengklik tombol, gambar latar belakang tombol berubah. Objek tombol yang saya gunakan adalah nama sebagai "upvote", karena "i" memegang posisi setiap item dalam tampilan recycler, saya menggunakannya sebagai indeks array yang berfungsi sebagai bendera dan yang melacak status elemen.

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

}
Vishal kharb
sumber
1

Saya pernah mengalami masalah yang sama. Ketika saya mengklik tombol sakelar item di recyclerView saya, tombol Toggle dicentang muncul di setiap item ke-10 (misalnya jika diklik di item dengan indeks 0, item dengan indeks 9, 18, 27 juga diklik). Pertama, kode saya di onBindViewHolder adalah:

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

Tapi kemudian saya menambahkan pernyataan Else

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

Dan masalahnya terpecahkan

LA_Homie
sumber
Terima kasih. Bagian lain akan mengosongkan kotak centang jika dicentang secara default saat mendaur ulang melihat tampilan yang sama.
Adarsh ​​Vijayan P
1

oke ada banyak jawaban di sini saya akan memposting kode saya dan saya hanya akan menjelaskan apa yang saya lakukan ... itu mungkin membantu junior seperti saya: D.

1- Tujuan:

kami akan membuat daftar RecyclerViewyang memiliki CheckBoxdan RadioButton, sesuatu seperti ini:

masukkan deskripsi gambar di sini 2- Kelas Model

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-Adaptor Luar Biasa Saya

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- Dalam Aktivitas Anda mendapatkan mereka sesuatu seperti ini:

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();
                    }
                });
Mahmoud Ayman
sumber
0

Saya memiliki masalah yang sama dalam daftar RecyclerView dengan sakelar, dan menyelesaikannya menggunakan jawaban @oguzhand, tetapi dengan kode ini di dalam checkChangeListener:

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

(Di mana 'grup' adalah entitas yang ingin saya pilih / batalkan pilihan)

Granjero
sumber
0

kelas publik TagYourDiseaseAdapter extends RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; Konteks pribadi 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);
    }
}

}

velraj
sumber
0

ini akan terjadi ketika digunakan setOnCheckedChangeListenersebagai pengganti penggunaan itu setObClickListenerdan di dalamnya hanya melakukan pegangan mudah ini:

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

CATATAN: dalam model daftar Anda tambahkan satu variabel boolean dengan nama checkdan set getter dan setter untuk itu, dalam kasus di atas saya adalah setCheck dan isCheck

semoga membantu seseorang jika demikian + pilih jawaban ini

E-zad
sumber
0

Menambahkan setItemViewCacheSize (int size) ke recyclerview dan meneruskan ukuran daftar memecahkan masalah saya.

kode saya:

mrecyclerview.setItemViewCacheSize(mOrderList.size());
mBinding.mrecyclerview.setAdapter(mAdapter);

Sumber: https://stackoverflow.com/a/46951440/10459907

Pravin Yadav
sumber
0

Hal ini karena berulang kali membuat tampilan, opsi terbaik adalah menghapus cache sebelum mengatur adaptor

recyclerview.setItemViewCacheSize(your array.size());
Mrutyunjay Swain
sumber
0

Contoh lengkap
kelas publik ChildAddressAdapter memperluas 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);
    }
}

}

Mudassar Ashraf
sumber
-1

Apa yang berhasil bagi saya adalah membatalkan listener di viewHolder saat tampilan akan didaur ulang ( onViewRecycled):

 override fun onViewRecycled(holder: AttendeeViewHolder) {
            super.onViewRecycled(holder)
            holder.itemView.hasArrived.setOnCheckedChangeListener(null);
            holder.itemView.edit.setOnClickListener { null }
        }
shannoga.dll
sumber