RecyclerView의 CheckBox는 다른 항목을 계속 확인합니다.


93

RecyclerView 내의 내 항목에 대한 XML은 다음과 같습니다.

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

다음은 각 항목에 대해 위의 레이아웃을 확장하는 RecyclerView 어댑터입니다.

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

문제는 RecyclerView 안에 10 개의 항목이 있다고 가정 해 보겠습니다. 항목 1,2,3의 확인란을 선택한 다음 RecyclerView를 아래로 스크롤하면 갑자기 다른 항목 (예 : 항목 8,9)이 선택됩니다. 그리고 다시 위로 스크롤하면 항목 1과 3은 확인되지만 항목 2는 확인되지 않습니다. 왜 이런 일이 발생하는지 아십니까?


이 라이브러리를 사용해보십시오 . ViewStates를 참조하십시오. 스크롤 할 때 상태를 저장하는 데 도움이됩니다.
Vitaly

답변:


167

그것은 예상되는 행동입니다. 확인란을 선택하거나 설정하지 않았습니다. 하나를 선택하고 View holder가 선택한 상태로 유지합니다. ObjectIncome 개체에 부울 변수를 추가하고 항목의 선택 상태를 유지할 수 있습니다.

내 예를 볼 수 있습니다. 다음과 같이 할 수 있습니다.

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
작동하지 않았습니다. 당신은 쓸 필요가 holder.cbSelect.setOnCheckedChangeListener(null);전에holder.cbSelect.setChecked(objIncome.isSelected())
Jemshit Iskenderov

2
holder.cbSelect.setOnCheckedChangeListener (null); 설정하는 이유에 대한 이유가 있습니까? 공장?
Deb

4
@oguzhand 안녕하세요 귀하의 솔루션을 시도했지만 리스너를 null로 설정하거나 설정하지 않고 어느 쪽이든 작동하지 않습니다.
Abbas

3
@oguzhand 다음은 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가 홀더 일 뿐이므로 개체의 확인란 상태를 유지해야합니다. 100 개의 항목이있는 경우 약 6 ~ 7 개 (화면 및 레이아웃 크기에 따라 다름) ViewHolders 만 있으며이 모든 개체를 한 번에 사용합니다.
Oğuzhan Döngül

22

요컨대, 뷰를 재활용하고 다시 사용하기 때문입니다!

어떻게 피할 수 있습니까?

1. onBindViewHolder체크 박스의 체크 / 체크 해제 여부를 체크합니다. if와 else를 모두 입력하는 것을 잊지 마십시오

if (...)
    holder.cbSelect.setChecked(true);
else
    holder.cbSelect.setChecked(false);
  1. 체크 박스에 청취자를 넣으십시오! 체크 된 조각상이 변경 될 때마다 myItems배열 에서 해당 객체도 업데이트하십시오 ! 따라서 새로운 뷰가 표시 될 때마다 객체의 최신 조각상을 읽습니다.

두 번째 요점이 핵심이었습니다. 그것은 초기 데이터 세트도 (나를 위해의 경우) 확인 상태에 대한 정보를 가지고 상황에 가장 잘 작동하지만
아틸라 Orosz

1
이것은 더 직설적이고 정답입니다. onBindViewHolder 모두 진실과 거짓에 대한 SetCheck가 핵심이다
에 beeing JK

제 경우에는 isChecked false시작시 모든 데이터 세트에 대한 기본값을 사용하여 데이터 모델에 데이터를 저장해야합니다 . 그런 다음 확인 여부를 확인하는 응답 구현에서 언급 한대로 값을 또는로 onCheckChanged업데이트했습니다 . isCheckedtruefalse
Ali Tamoor

21

리사이클보기에 제한된 수의 항목이있는 경우에만 이것을 사용하십시오.
모델에서 부울 값을 사용하고 확인란 상태를 유지했지만 제 경우에는 도움이되지 않았습니다. 나를 위해 일한 것은 this.setIsRecyclable (false);

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

이에 대한 자세한 설명은 https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable () 에서 찾을 수 있습니다.

참고 : 이것은 해결 방법입니다. 제대로 사용하려면 "setIsRecyclable () 호출은 항상 쌍을 이루어야합니다 (setIsRecyclabe (false) 호출은 항상 나중에 setIsRecyclable (true) 호출과 일치해야 함). 호출 쌍은 중첩 될 수 있습니다. , 상태가 내부적으로 참조 계산되기 때문입니다. " 누군가가 더 많은 코드를 제공 할 수 있다면 코드에서이 작업을 수행하는 방법을 모르겠습니다.


사용 방법을 설명해 주시겠습니까?
UserName_Untold

43
recyclerView의 논리를 낭비하지 않습니까?
에렌

3
무작위 검사 문제를 해결 한 긴 목록으로 시도했지만 아래로 스크롤하고 긴 목록으로 다시 스크롤하면 체크 된 확인란이 사라집니다. (
SonDang

2
뷰를 재활용 할 수 없게 만드는 것은 메모리를 소모하고 리사이클 러 뷰의 대부분의 이점을 잃게되므로 좋은 생각이 아닙니다.
아서

@ eren130과 Arthur에게 동의합니다. 나는 게시물을 편집했으며 setIsRecyclable (true / false); 사용하는 방법을 생각해 낼 수 있다면 대단히 감사하겠습니다. 정확히.
라나 Ranvijay 싱

13

두 개의 재정의 방법을 추가하십시오. RecyclerView

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

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

2
하지마 !! recyclerView 재활용 메커니즘을 우회하고 전체 사용 지점을 잃게됩니다.
Hanoch Moreno

1
아니요, 뷰 홀더에서 모든 재활용 된 뷰의 정확한 위치를 반환합니다.
Harish 레디

1
Harish, 아마도 내가 뭔가를 놓치고 있을지도 모르지만, 내가 아는 한, 이렇게하면 실제로 어댑터에 항목 유형의 수가 항목 수라는 것을 알립니다. 의미는 비슷한 관점이 없기 때문에 재활용 할 수 없다는 것입니다. 그래도 테스트하기 쉽습니다. onBindViewHolder 내부에 viewHolder.itemView 참조를 기록하고 동일한 뷰 참조를 보유하는 두 개의 viewHolder가 있는지 확인하십시오. 테스트는 긴 목록에 있어야 재활용 시스템이 실행됩니다.
Hanoch Moreno

3
흠 잡을 데없이 깨어나서 하루를 구했습니다.
Kundan

5
recyclerview에 100 개 이상의 항목이있는 경우이 솔루션은 모든 항목을 한 번에로드합니다. 이미지가있는 경우 OutOfMemoryException이 발생할 수 있습니다. 그렇지 않으면이 솔루션이 완벽합니다 @Kundan
Harish Reddy

11

Model 클래스를 사용하여 각 recyclerView 항목의 확인란을 추적 할 수 있습니다. 전체 참조 출처 : RecyclerView Checkbox Android

setTaggetTag 는 체크 박스 상태를 추적하는 데 사용됩니다. 자세한 내용은 전체 참조 링크를 확인하십시오. 또한 체크 된 항목을 NEXTACTIVITY 로 보내는 방법을 알려줍니다 .

모형을 만들다

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

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

마지막으로 어댑터는 다음과 같습니다.

 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을 사용하여이 문제를 해결 한 유일한 방법 OnCheckedChangeListener은 변수를 설정하기 전에 지운 다음 설정 한 OnCheckedChangeListener후에 새 파일을 만드는 checked것입니다.

내에서 다음을 수행합니다. RecyclerView.ViewHolder

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

이것은 완벽하게 작동합니다. 이유는 아니지만 KOTLIN을 사용하는 사람이있을 때만 작동합니다!
Aditya S.

2

위에서 언급했듯이 객체의 확인 된 상태는 객체 속성에 포함되어야합니다. 어떤 경우에는 개체 자체를 클릭하여 개체 선택 상태를 변경하고 CheckBox가 실제 상태 (선택 또는 선택 취소)에 대해 알려주도록해야 할 수도 있습니다. 그런 다음 확인란은 (기본적으로 / 대부분의 경우) 목록에있는 요소의 위치 인 지정된 어댑터의 실제 위치에있는 개체의 상태를 사용합니다.

아래 스 니펫을 확인하면 유용 할 수 있습니다.

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

제 경우에는 이것이 효과가있었습니다.

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

2

배열을 사용하여 항목 상태 유지

어댑터에서 Map 또는 SparseBooleanArray (지도와 유사하지만 int 및 boolean의 키-값 쌍)를 사용하여 항목 목록에있는 모든 항목의 상태를 저장 한 다음 키와 값을 사용하여 비교합니다. 체크 상태를 전환 할 때

어댑터에서 SparseBooleanArray

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

    private SparseBooleanArray itemStateArray= new SparseBooleanArray();

그런 다음 항목 클릭 핸들러 onClick()에서 itemStateArray의 항목 상태를 사용하여 토글하기 전에 확인합니다. 여기에 예제가 있습니다.

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

또한 희소 부울 배열을 사용하여 뷰가 바인딩 될 때 확인 된 상태를 설정합니다.

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

최종 어댑터는 다음과 같습니다.


1

CheckBox를 사용한 onBindViewHolder (logic) 상호 작용과 확인란을 사용한 사용자 상호 작용을 분리해야합니다. 사용자 상호 작용에는 OnCheckedChangeListener를 사용하고 논리에는 ViewHolder.bind ()를 사용했습니다. 그래서 홀더를 설정하기 전과 홀더가 준비된 후에 확인 된 리스너를 null로 설정해야합니다. 사용자 상호 작용을 위해 확인 된 리스너를 구성해야합니다.

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

나는 사용하지 않는 것이 좋습니다 checkBox.setOnCheckedChangeListener에서 recyclerViewAdapter. 스크롤 checkBox.setOnCheckedChangeListener할 때 recyclerView 가 어댑터에 의해 시작되기 때문입니다. 안전하지 않습니다 . 대신 checkBox.setOnClickListener사용자 입력과 상호 작용하는 데 사용하십시오.

예를 들면 :

     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

내가 찾은이 솔루션의 문제는 정적 전역 배열을 만들고 필요한 모든 전역 변수 / 객체를 만든 "onBindViewHolder"ADAPER CLASS에서 사용하는 것입니다.

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

        }

    }

}

여기 (RVADAPTER CLASS의 CONSTRUCTOR에서) 리사이클 러 뷰에 표시 할 항목의 / no 크기와 동일한 배열 크기를 지정했습니다.

List<Person> persons;

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

BindViewHolder, I, 버튼에이 개념을 적용했습니다. 버튼을 클릭하면 버튼의 배경 이미지가 변경됩니다. 내가 사용한 버튼의 객체는 "upvote"로 이름이되는데, "i"는 리사이클 러 뷰에서 각 항목의 위치를 ​​유지하므로 플래그로 작동하고 요소의 상태를 추적하는 배열의 인덱스로 사용했습니다.

@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

나는 같은 문제가 있었다. recyclerView에서 항목의 토글 버튼을 클릭했을 때 10 번째 항목마다 토글 버튼이 표시되었습니다 (예 : 인덱스가 0 인 항목에서 클릭하면 인덱스가 9, 18, 27 인 항목도 클릭 됨). 첫째, onBindViewHolder의 코드는 다음과 같습니다.

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

하지만 Else 문을 추가했습니다.

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

그리고 문제가 해결되었습니다


감사합니다. 다른 부분은 동일한보기를 재활용 할 때 기본적으로 선택하면 확인란의 선택을 취소합니다.
Adarsh ​​Vijayan P

1

좋아요 여기에 많은 답변이 있습니다. 저는 제 코드를 게시하고 제가 한 일을 간단히 설명 할 것입니다 ... 그것은 나 같은 후배들에게 도움이 될 것입니다. : D.

1- 목표 :

우리의 목록을 만들 것 RecyclerView즉 가지고 CheckBoxRadioButton, 이런 걸 :

여기에 이미지 설명 입력 2- 모델 클래스

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 어댑터

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- 활동에서 다음과 같이 얻습니다.

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

스위치가있는 RecyclerView 목록에서 동일한 문제가 발생했으며 @oguzhand 답변을 사용하여 해결했지만이 코드는 checkedChangeListener 내부에 있습니다.

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

(여기서 '그룹'은 내가 선택 / 선택 취소하려는 엔티티입니다)


0

Public class TagYourDiseaseAdapter extends RecyclerView.Adapter {private ReCyclerViewItemClickListener mRecyclerViewItemClickListener; 개인 컨텍스트 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

이것은 setOnCheckedChangeListener그 사용 대신에 사용 setObClickListener하고 내부 에서이 쉬운 핸들을 할 때 발생합니다 .

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

참고 : 목록 모델에서 이름이있는 하나의 부울 변수를 추가 check하고 getter 및 setter를 설정하십시오. 위의 경우 내 경우 setCheck 및 isCheck

이 답변에 + 투표한다면 누군가에게 도움이되기를 바랍니다.



0

이것은보기를 반복해서 생성하기 때문이며, 최상의 옵션은 어댑터를 설정하기 전에 캐시를 지우는 것입니다.

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

0

전체 예제
공용 클래스 ChildAddressAdapter extends 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

나를 위해 일한 것은 뷰가 재활용 될 때 viewHolder의 리스너를 무효화하는 것입니다 ( onViewRecycled).

 override fun onViewRecycled(holder: AttendeeViewHolder) {
            super.onViewRecycled(holder)
            holder.itemView.hasArrived.setOnCheckedChangeListener(null);
            holder.itemView.edit.setOnClickListener { null }
        }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.