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

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는 확인되지 않습니다. 왜 이런 일이 발생하는지 아십니까?



답변

그것은 예상되는 행동입니다. 확인란을 선택하거나 설정하지 않았습니다. 하나를 선택하고 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);
            }
        });

    }
}


답변

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

어떻게 피할 수 있습니까?

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

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


답변

리사이클보기에 제한된 수의 항목이있는 경우에만 이것을 사용하십시오.
모델에서 부울 값을 사용하고 확인란 상태를 유지했지만 제 경우에는 도움이되지 않았습니다. 나를 위해 일한 것은 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) 호출과 일치해야 함). 호출 쌍은 중첩 될 수 있습니다. , 상태가 내부적으로 참조 계산되기 때문입니다. ” 누군가가 더 많은 코드를 제공 할 수 있다면 코드에서이 작업을 수행하는 방법을 모르겠습니다.


답변

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

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

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


답변

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

}

}


답변

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

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

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


답변

위에서 언급했듯이 객체의 확인 된 상태는 객체 속성에 포함되어야합니다. 어떤 경우에는 개체 자체를 클릭하여 개체 선택 상태를 변경하고 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);

        }
    }
}