CheckBox trong RecyclerView tiếp tục kiểm tra các mục khác nhau


93

Đây là XML cho các mục của tôi bên trong 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>

Và đây là bộ điều hợp RecyclerView làm phồng bố cục ở trên cho từng mục của nó:

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

Vấn đề là, giả sử tôi có 10 mục bên trong RecyclerView. Khi tôi chọn hộp kiểm ở mục 1,2,3 rồi cuộn xuống RecyclerView, đột nhiên một số mục khác, ví dụ như mục 8,9 được chọn. Và khi tôi cuộn lên một lần nữa, mục 1 và 3 được chọn chứ không phải mục 2. Bạn có biết tại sao điều này lại xảy ra không?


Hãy thử sử dụng thư viện này , xem ViewStates. Nó giúp lưu một trạng thái khi cuộn.
Vitaly

Câu trả lời:


167

Đó là một hành vi được mong đợi. Bạn không đặt hộp kiểm của mình được chọn hay không. Bạn đang chọn một và người giữ Chế độ xem sẽ giữ nó được chọn. Bạn có thể thêm một biến boolean vào đối tượng ObjectIncome và giữ trạng thái lựa chọn của mục của bạn.

Bạn có thể nhìn vào ví dụ của tôi. Bạn có thể làm điều gì đó như vậy:

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
Nó không hoạt động. Bạn phải ghi holder.cbSelect.setOnCheckedChangeListener(null);trướcholder.cbSelect.setChecked(objIncome.isSelected())
Jemshit Iskenderov

2
có bất kỳ lý do nào giải thích tại sao thiết lập Holder.cbSelect.setOnCheckedChangeListener (null); làm?
Deb

4
@oguzhand xin chào, tôi đã thử giải pháp của bạn nhưng nó không hoạt động theo cách nào: có hoặc không đặt trình nghe thành null.
Abbas

3
@oguzhand Đây là mã từ 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 bạn cần giữ trạng thái hộp kiểm trong một đối tượng, vì ViewHolder chỉ là một người nắm giữ. Nếu bạn có 100 mục, bạn chỉ có khoảng 6-7 (phụ thuộc vào kích thước màn hình và bố cục) ViewHolders và sử dụng tất cả các đối tượng này trong một chu kỳ.
Oğuzhan Döngül

22

Trong ngắn hạn, đó là vì tái chế các khung nhìn và sử dụng chúng một lần nữa!

làm thế nào bạn có thể tránh điều đó:

1. onBindViewHolderKiểm tra xem bạn nên chọn hoặc bỏ chọn các hộp. đừng quên đặt cả if và else

if (...)
    holder.cbSelect.setChecked(true);
else
    holder.cbSelect.setChecked(false);
  1. Đặt một người nghe cho hộp kiểm! bất cứ khi nào các bức tượng được kiểm tra của nó thay đổi, hãy cập nhật đối tượng tương ứng trong myItemsmảng của bạn ! vì vậy bất cứ khi nào một dạng xem mới được hiển thị, nó sẽ đọc bức tượng mới nhất của đối tượng.

Điểm thứ hai của bạn là chìa khóa. Mặc dù nó hoạt động tốt nhất trong một tình huống, khi các tập dữ liệu ban đầu cũng có thông tin về tình trạng kiểm tra (đó là trường hợp đối với tôi)
Attila Orosz

1
đây là câu trả lời thẳng vào vấn đề và chính xác hơn. SetCheck cho cả đúng và sai trong onBindViewHolder là chìa khóa
beeing Jk

Trong trường hợp của tôi, tôi phải lưu dữ liệu trong mô hình dữ liệu với giá trị mặc định isChecked falsecho tất cả tập dữ liệu khi bắt đầu, sau đó onCheckChangedtôi chỉ cập nhật isCheckedgiá trị thành truehoặc falsevà như đã nói trong triển khai câu trả lời rằng kiểm tra được chọn hoặc không.
Ali Tamoor

21

CHỈ SỬ DỤNG ĐIỀU NÀY NẾU BẠN CÓ SỐ LƯỢNG MẶT HÀNG CÓ GIỚI HẠN TRONG XEM TỆP CỦA BẠN.
Tôi đã thử sử dụng giá trị boolean trong mô hình và giữ trạng thái hộp kiểm, nhưng nó không giúp được gì trong trường hợp của tôi. Điều làm việc cho tôi là this.setIsRecyclable (sai);

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

Giải thích thêm về điều này có thể được tìm thấy tại đây https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable ()

LƯU Ý: Đây là một cách giải quyết. Để sử dụng nó đúng cách, bạn có thể tham khảo tài liệu nêu rõ "Các lệnh gọi đến setIsRecyclable () phải luôn được ghép nối (một lệnh gọi tới setIsRecyclabe (false) phải luôn được khớp với một lệnh gọi sau đó tới setIsRecyclable (true)). Các cặp lệnh gọi có thể được lồng vào nhau , vì trạng thái được tính tham chiếu nội bộ. " Tôi không biết cách thực hiện việc này bằng mã, nếu ai đó có thể cung cấp thêm mã về việc này.


xin vui lòng bạn có thể giải thích làm thế nào để sử dụng nó?
UserName_Untold

43
nó có lãng phí logic đằng sau RecyclerView không?
Eren

3
Tôi cố gắng này với danh sách dài mà giải quyết được vấn đề kiểm tra ngẫu nhiên nhưng khi tôi di chuyển xuống và tái cuộn lên với danh sách dài, các hộp kiểm kiểm tra biến mất :(
SonDang

2
Không phải là một ý kiến ​​hay nếu bạn không thể sử dụng chế độ xem vì nó sẽ tiêu hao bộ nhớ và bạn sẽ mất hầu hết các lợi ích của chế độ xem tái chế.
Arthur

Tôi đồng ý với các bạn, @ eren130 và Arthur. Tôi đã chỉnh sửa bài đăng và sẽ đánh giá rất cao nếu chúng tôi có thể nghĩ ra cách sử dụng setIsRecyclable (true / false); đúng cách.
Rana Ranvijay Singh

13

Chỉ cần thêm hai phương pháp ghi đè của RecyclerView

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

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

2
Đừng làm vậy !! Nó sẽ bỏ qua cơ chế tái chế RecyclerView và mất toàn bộ điểm khi sử dụng.
Hanoch Moreno

1
Không, nó sẽ không, nó chỉ trả về vị trí chính xác của mọi chế độ xem được tái chế trong ngăn chứa chế độ xem.
Harish Reddy

1
Harish, có lẽ tôi đang thiếu thứ gì đó, nhưng theo như tôi biết, bằng cách làm này, bạn thực sự nói với bộ điều hợp rằng số lượng các loại mặt hàng là số lượng mặt hàng. Ý nghĩa là không có vật phẩm nào có thể được tái chế vì nó không có tầm nhìn mô phỏng. Nó rất dễ dàng để kiểm tra mặc dù. chỉ cần ghi lại tham chiếu viewHolder.itemView bên trong onBindViewHolder và xem liệu có hai viewHolder giữ cùng một tham chiếu xem hay không. Thử nghiệm phải nằm trong một danh sách dài để hệ thống tái chế sẽ được thực hiện.
Hanoch Moreno

3
Nó đã đi một cách hoàn hảo, Nó đã cứu một ngày của tôi.
Kundan

5
trong trường hợp bạn có sau đó hơn 100 mặt hàng trong recyclerview của bạn, giải pháp này sẽ được tải tất cả các mục cùng một lúc, điều này có thể gây ra OutOfMemoryException trong trường hợp bạn có hình ảnh phương tiện khác giải pháp này là hoàn hảo @Kundan
Harish Reddy

11

Bạn có thể sử dụng lớp Model để theo dõi hộp kiểm của từng mục RecyclerView. Tham khảo đầy đủ là từ: Hộp kiểm RecyclerView Android

setTaggetTag được sử dụng để theo dõi trạng thái hộp kiểm. Kiểm tra liên kết tham khảo đầy đủ để biết thêm thông tin. Nó cũng dạy cách gửi các mục đã kiểm tra tới NEXTACTIVITY .

Làm mô hình

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

tạo integer.xml

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

Cuối cùng bộ điều hợp trông như thế này:

 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

Sử dụng Kotlin, điều duy nhất giải quyết được vấn đề này đối với tôi là xóa OnCheckedChangeListenertrước khi thiết lập biến và sau đó tạo một biến mới OnCheckedChangeListenersau khi checkedđã được đặt.

Tôi làm những điều sau đây trong RecyclerView.ViewHolder

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

Điều này đang hoạt động hoàn hảo. Tôi không hiểu tại sao nhưng điều này chỉ hoạt động khi bất kỳ ai sử dụng KOTLIN!
Aditya S.

2

Như đã nêu ở trên, trạng thái đã kiểm tra của đối tượng nên được bao gồm trong các thuộc tính đối tượng. Trong một số trường hợp, bạn cũng có thể cần thay đổi trạng thái lựa chọn đối tượng bằng cách nhấp vào chính đối tượng và để CheckBox thông báo về trạng thái thực tế (được chọn hoặc không được chọn). Hộp kiểm sau đó sẽ sử dụng trạng thái của đối tượng tại vị trí thực tế của bộ điều hợp đã cho, đó là (theo mặc định / trong hầu hết các trường hợp) là vị trí của phần tử trong danh sách.

Kiểm tra đoạn mã dưới đây, nó có thể hữu ích.

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

Trong trường hợp của tôi, điều này đã hoạt động.

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

2

Sử dụng một mảng để giữ trạng thái của các mục

Trong bộ điều hợp sử dụng Bản đồ hoặc SparseBooleanArray (tương tự như bản đồ nhưng là một cặp khóa-giá trị của int và boolean) để lưu trữ trạng thái của tất cả các mục trong danh sách các mục của chúng tôi và sau đó sử dụng các khóa và giá trị để so sánh khi chuyển đổi trạng thái đã chọn

Trong Bộ điều hợp, tạo một SparseBooleanArray

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

    private SparseBooleanArray itemStateArray= new SparseBooleanArray();

sau đó trong trình xử lý nhấp chuột onClick()sử dụng trạng thái của các mục trong itemStateArray để kiểm tra trước khi chuyển đổi, đây là một ví dụ

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

ngoài ra, sử dụng mảng boolean thưa thớt để đặt trạng thái được kiểm tra khi chế độ xem bị ràng buộc

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

và bộ điều hợp cuối cùng sẽ như thế này


1

Bạn cần tách biệt các tương tác onBindViewHolder (logic) với CheckBox và các tương tác của người dùng với hộp kiểm. Tôi đã sử dụng OnCheckedChangeListener cho các tương tác của người dùng (rõ ràng) và ViewHolder.bind () cho logic, đó là lý do tại sao bạn cần đặt trình nghe đã kiểm tra thành null trước khi thiết lập trình giữ và sau khi trình giữ sẵn sàng - định cấu hình trình nghe đã kiểm tra cho các tương tác của người dùng.

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

Tôi khuyên bạn không nên sử dụng checkBox.setOnCheckedChangeListenertrong recyclerViewAdapter. Bởi vì trên RecrollingView cuộn, checkBox.setOnCheckedChangeListenersẽ được kích hoạt bởi bộ điều hợp. Nó không an toàn . Thay vào đó, hãy sử dụng checkBox.setOnClickListenerđể tương tác với đầu vào của người dùng.

Ví dụ:

     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

Vấn đề của giải pháp này mà tôi tìm thấy là, bằng cách tạo một mảng toàn cục tĩnh và sử dụng nó trong LỚP ADAPER "onBindViewHolder", trong đó tôi đã tạo tất cả các đối tượng / biến thể toàn cục cần thiết.

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

        }

    }

}

Ở đây (TRONG TRÌNH HƯỚNG DẪN CỦA LỚP RVADAPTOR) tôi đã cung cấp kích thước cho mảng bằng với kích thước của / không có mục mà tôi sẽ hiển thị trong chế độ xem trình tái chế

List<Person> persons;

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

BindViewHolder, I, Đã áp dụng khái niệm này trên một nút, khi tôi nhấp vào một nút, hình nền của nút sẽ thay đổi. đối tượng của nút tôi đã sử dụng có tên là "upvote", vì "i" giữ vị trí của từng mục trong chế độ xem tái chế, tôi đã sử dụng nó như một chỉ mục của mảng đang hoạt động như một cờ và theo dõi trạng thái của các phần tử.

@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

Tôi đã có cùng một vấn đề. Khi tôi nhấp vào nút bật tắt của mục trong bộ tái chế của tôi, nút Bật tắt đã kiểm tra của tôi sẽ xuất hiện ở mỗi mục thứ 10 (ví dụ: nếu nó được nhấp vào mục có chỉ mục 0, các mục có 9, 18, 27 chỉ mục cũng được nhấp). Đầu tiên, mã của tôi trong onBindViewHolder là:

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

Nhưng sau đó tôi đã thêm câu lệnh khác

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

Và vấn đề đã được giải quyết


Cảm ơn bạn. Phần khác sẽ xóa hộp kiểm nếu nó chọn theo mặc định khi tái chế xem cùng một chế độ xem.
Adarsh ​​Vijayan P

1

Được rồi, có rất nhiều câu trả lời ở đây tôi sẽ đăng mã của mình và tôi sẽ giải thích đơn giản những gì tôi đã làm ... nó có thể giúp ích cho những người đàn em như tôi: D.

1- Mục tiêu:

chúng tôi sẽ tạo một danh sách RecyclerViewCheckBoxRadioButton, tương tự như sau:

nhập mô tả hình ảnh ở đây 2- Lớp mẫu

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-Bộ điều hợp tuyệt vời của tôi

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- Trong Activity, bạn nhận được chúng như sau:

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

Tôi đã gặp vấn đề tương tự trong danh sách RecyclerView có công tắc và đã giải quyết nó bằng cách sử dụng câu trả lời @oguzhand, nhưng với mã này bên trong checkChangeListener:

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

(Trong đó 'nhóm' là thực thể tôi muốn chọn / bỏ chọn)


0

public class TagYourDiseaseAdapter mở rộng RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; ngữ cảnh riêng 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

điều này sẽ xảy ra khi sử dụng setOnCheckedChangeListenerthay vì sử dụng đó setObClickListenervà bên trong chỉ cần thực hiện thao tác dễ dàng này:

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

LƯU Ý: trong mô hình danh sách của bạn, hãy thêm một biến boolean có tên checkvà đặt getter và setter cho điều đó, trong trường hợp trên của tôi là setCheck và isCheck

hy vọng nó sẽ giúp một số người nếu vậy + bỏ phiếu cho câu trả lời này


0

Thêm setItemViewCacheSize (kích thước int) vào chế độ xem lại và chuyển kích thước danh sách đã giải quyết được vấn đề của tôi.

mã của tôi:

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

Nguồn: https://stackoverflow.com/a/46951440/10459907


0

điều này là do nhiều lần tạo chế độ xem, tùy chọn tốt nhất là xóa bộ nhớ cache trước khi đặt bộ điều hợp

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

0

Ví dụ hoàn chỉnh về
lớp công khai ChildAddressAdapter mở rộng 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

Điều hiệu quả đối với tôi là vô hiệu hóa người nghe trên viewHolder khi lượt xem sẽ được tái chế ( onViewRecycled):

 override fun onViewRecycled(holder: AttendeeViewHolder) {
            super.onViewRecycled(holder)
            holder.itemView.hasArrived.setOnCheckedChangeListener(null);
            holder.itemView.edit.setOnClickListener { null }
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.