项目回顾-RecyclerView和CheckBox错乱问题

如果在item布局中引入CheckBox,而不作任何处理的话,在RecyclerView滑动的时候,选中状态都会出现错乱。

解决思路是:用map保存每一个被勾选的对象的特定信息,比如id,在onBindViewHolder中获取当前对象,判断map中是否包含当前对象的id,是则setChecked为true,否则为false

效果

 

 

废话不说,上代码

首先实体Box  一个int id   一个String name

public class Box {

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
View Code

 

item_cb.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/rl_cb"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="15dp"
    >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"/>

    <TextView
        android:id="@+id/tv_cb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/imageView"
        android:paddingLeft="10dp"
        android:text="cb"
        />

    <CheckBox
        android:id="@+id/cb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"/>

</RelativeLayout>
View Code

 

activity

首先两个重要参数   isMulChoice 判断当前是否为多选状态;selectid为保存状态的map

initView()操作  初始化recyclerView 和adapter 的点击事件

setData() 手动添加了30个数据

 

长按 item时 isMulChoice 为真,此时notifyDataSetChanged会调用adapter的 onBindViewHolder,由于isMulChoice 为真了,隐藏的CheckBox会显示出来,同时主页面隐藏的删除、撤销按钮的布局也会出现

点击撤销按钮  map会清空,isMulChoice 为假,notifyDataSetChanged隐藏CheckBox,同时按钮的布局隐藏

点击删除按钮  会遍历map,找到每一个选中对象的id,之后交给adapter操作,最后执行一下撤销按钮的操作

  1 public class CbActivity extends AppCompatActivity {
  2 
  3 
  4     public static boolean isMulChoice=false;
  5     public static Map<Integer, String> selectid = new HashMap<>();
  6 
  7     private LinearLayoutManager linearLayoutManager;
  8     public List<Box> list;
  9     private CbAdapter adapter;
 10 
 11     @Bind(R.id.rcv)
 12     RecyclerView recyclerView;
 13 
 14     @Bind(R.id.ll_btn)
 15     LinearLayout ll_btn;
 16 
 17     @OnClick(R.id.btn_cancle)
 18     void btn_cancle(){
 19         selectid.clear();
 20         ll_btn.setVisibility(View.GONE);
 21         isMulChoice = false;
 22         adapter.notifyDataSetChanged();
 23     }
 24 
 25     @OnClick(R.id.btn_del)
 26     void btn_del(){
 27         if (selectid.size()==0){
 28             Toast.makeText(this,"至少选中一条数据",Toast.LENGTH_SHORT).show();
 29         }else {
 30 
 31             Set<Integer> mapSet =  selectid.keySet();
 32             Iterator<Integer> itor=mapSet.iterator();
 33             while (itor.hasNext()){
 34                 int id = itor.next();
 35                 if (selectid.get(id).equals("true")){
 36                     Logger.e("要删除的id :"+id);
 37                     adapter.remove(id);
 38                 }
 39             }
 40             btn_cancle();
 41         }
 42     }
 43 
 44 
 45     @Override
 46     protected void onCreate(Bundle savedInstanceState) {
 47         super.onCreate(savedInstanceState);
 48         setContentView(R.layout.activity_cb);
 49         ButterKnife.bind(this);
 50 
 51         initView();
 52         setData();
 53     }
 54 
 55     private void setData() {
 56 
 57         List<Box> boxes=new ArrayList<>();
 58         for (int i=0;i<30;i++){
 59             Box box=new Box();
 60             box.setId(i);
 61             box.setName("name"+i);
 62             boxes.add(box);
 63         }
 64 
 65         adapter.addAll(boxes);
 66 
 67     }
 68 
 69     private void initView() {
 70         adapter = new CbAdapter();
 71         linearLayoutManager=new LinearLayoutManager(this);
 72         recyclerView.setLayoutManager(linearLayoutManager);
 73         recyclerView.setAdapter(adapter);
 74         recyclerView.setItemAnimator(new DefaultItemAnimator());
 75 
 76         adapter.setOnClickListener(new CbAdapter.OnClick() {
 77             @Override
 78             public void OnItemClick(View view, int position) {
 79               //  switch (view.getId()){
 80               //      case R.id.cb:
 81               //         Logger.e("cb "+position);
 82               //          break;
 83               //  }
 84             }
 85 
 86             @Override
 87             public void OnItemLongClick(View view, int position) {
 88                 switch (view.getId()){
 89                     case R.id.rl_cb:
 90                         isMulChoice=true;
 91                         ll_btn.setVisibility(View.VISIBLE);
 92                         adapter.notifyDataSetChanged();
 93                         Logger.e("rl_cb OnItemLongClick"+position);
 94                         break;
 95                 }
 96             }
 97 
 98             @Override
 99             public void OnItemChecked(View view, int position, boolean isChecked) {
100 
101             }
102         });
103     }
104 }

 

adapter

先看 onBindViewHolder

第49行 cbHolder.cb.setVisibility(CbActivity.isMulChoice?View.VISIBLE:View.INVISIBLE);   CheckBox的状态是由activity里的isMulChoice控制

设置 setOnCheckedChangeListener事件,判断是否选中

如果选中 true,再判断selectid中是否包含当前点击的对象的id,如果没有就添加进去

如果取消选中 false,再判断selectid中是否包含当前点击的对象的id,如果有就删除

而CheckBox的选中与否的状态就是selectid是否包含id 来做判断的

删除操作 根据传入的id来遍历list,remove,最后更新。当然删除可能有更好的方法

  1 public class CbAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
  2 
  3     private List<Box> list=new ArrayList<>();
  4 
  5     public List<Box> getList(){
  6         return list;
  7     }
  8 
  9     public void addAll(List<Box> boxes){
 10         list.addAll(boxes);
 11         notifyDataSetChanged();
 12     }
 13 
 14     public void remove(int id){
 15         for (int i=0;i<list.size();i++){
 16             if (id==list.get(i).getId()){
 17                 list.remove(list.get(i));
 18             }
 19         }
 20         notifyDataSetChanged();
 21     }
 22 
 23     public interface OnClick {
 24         void OnItemClick(View view,int position);
 25         void OnItemLongClick(View view,int position);
 26         void OnItemChecked(View view,int position,boolean isChecked);
 27     }
 28 
 29     private OnClick onClick;
 30 
 31     public void setOnClickListener(OnClick click){
 32         this.onClick=click;
 33     }
 34 
 35     @Override
 36     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 37         View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_cb,parent,false);
 38         return new CbHolder(view);
 39     }
 40 
 41     @Override
 42     public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
 43         if (holder instanceof CbHolder){
 44             CbHolder cbHolder= (CbHolder) holder;
 45             final Box box=list.get(position);
 46 
 47             cbHolder.tv_cb.setText( "id "+box.getId()+ "  "+box.getName());
 48 
 49             cbHolder.cb.setVisibility(CbActivity.isMulChoice?View.VISIBLE:View.INVISIBLE);
 50 
 51             if (position%2==0){
 52                 cbHolder.rl_cb.setBackgroundResource(R.color.gray);
 53             }else {
 54                 cbHolder.rl_cb.setBackgroundResource(R.color.white);
 55 
 56             }
 57 
 58             if (onClick!=null){
 59 
 60                 cbHolder.rl_cb.setOnLongClickListener(new View.OnLongClickListener() {
 61                     @Override
 62                     public boolean onLongClick(View view) {
 63                         onClick.OnItemLongClick(view,position);
 64                         return true;
 65                     }
 66                 });
 67             }
 68 
 69             cbHolder.cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
 70                 @Override
 71                 public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
 72                     if (isChecked){
 73                         if (!CbActivity.selectid.containsKey(box.getId())){
 74                             CbActivity.selectid.put(box.getId(),"true");
 75                             Logger.e("put   "+box.getId());
 76                         }
 77                     }else {
 78                         if (CbActivity.selectid.containsKey(box.getId())){
 79                             CbActivity.selectid.remove(box.getId());
 80                             Logger.e("remove   "+box.getId());
 81                         }
 82                     }
 83 
 84                 }
 85             });
 86 
 87             if (CbActivity.selectid!=null){
 88                 cbHolder.cb.setChecked(CbActivity.selectid.containsKey(box.getId())?true:false);
 89             }else {
 90                 cbHolder.cb.setChecked(false);
 91             }
 92         }
 93     }
 94 
 95     @Override
 96     public int getItemCount() {
 97         return list==null?0:list.size();
 98     }
 99 
100     class CbHolder extends RecyclerView.ViewHolder{
101 
102         @Bind(R.id.tv_cb)
103         TextView tv_cb;
104         @Bind(R.id.cb)
105         CheckBox cb;
106         @Bind(R.id.rl_cb)
107         RelativeLayout rl_cb;
108 
109         public CbHolder(View itemView) {
110             super(itemView);
111             ButterKnife.bind(this,itemView);
112         }
113     }
114 }

 

 

activity的布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.demon.testservice.ui.CbActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rcv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:id="@+id/ll_btn"
        android:visibility="gone"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:weightSum="4"
        android:layout_gravity="center_horizontal|bottom">

        <Button
            android:id="@+id/btn_cancle"
            android:text="撤销"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_xxx"
            android:visibility="invisible"
            android:layout_width="0dp"
            android:layout_weight="2"
            android:layout_height="wrap_content"/>

        <Button
            android:id="@+id/btn_del"
            android:text="删除"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>
    </LinearLayout>

</FrameLayout>
View Code

 

最后还有一个地方要注意一下

虽然我在RecyclerView尝试自定义了一下CheckBox的setOnCheckedChangeListener事件的接口,不过貌似没有用

另外 CheckBox 不要同时设置 setOnClickListener 和 setOnCheckedChangeListener,它只会响应前者

posted @ 2016-10-22 20:25  demon9  阅读(2057)  评论(0编辑  收藏  举报