• andoid-解决RecyclerView+CheckBox选中混乱的问题


    引子

    今天,使用RecyclerView + Checkbox的时候,发生了checkbox状态错乱的问题。

    RecyclerView 为了提高效率,使用了Recycler回收机制,它的作用就是,不会产生多余的itemView,如果产生了向上滑动,就将最上方的itemView保存起来,然后接到最下面,然后重新加载数据(onBindViewHolder会被调用)。

    但是这种方式,如果itemView中有checkbox,要继承之前的勾选状态,那就坑了爹了。因为重用的itemView会保留之前的check状态。

    必须要想办法,标记它的勾选状态,才能正常显示勾选。

    代码

    解决此问题,最重要的代码在adapter里面。红色的,是关键代码.

    主要思路: 利用一组map来记录每一个checkbox的选中状态,然后在checkbox的选中事件中,对这个map进行维护。具体的,请看下面代码。

     1 import android.content.Context;
     2 import android.support.annotation.NonNull;
     3 import android.support.v7.widget.RecyclerView;
     4 import android.view.LayoutInflater;
     5 import android.view.View;
     6 import android.view.ViewGroup;
     7 import android.widget.CheckBox;
     8 import android.widget.CompoundButton;
     9 import android.widget.TextView;
    10 
    11 import java.util.ArrayList;
    12 import java.util.HashMap;
    13 import java.util.List;
    14 import java.util.Map;
    15 
    16 public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    17 
    18     private Context context;
    19 
    20     //先造一组模拟数据
    21     private List<String> listData;
    22 
    23     private Map<Integer, Boolean> checkStatus;//用来记录所有checkbox的状态
    24 
    25     public MyAdapter(Context context) {
    26         this.context = context;
    27         initData();
    28     }
    29 
    30     private void initData() {
    31         listData = new ArrayList<>();
    32         for (int i = 0; i < 100; i++) {
    33             listData.add("testData" + i);
    34         }
    35 
    36         checkStatus = new HashMap<>();
    37         for (int i = 0; i < listData.size(); i++) {
    38             checkStatus.put(i, false);// 默认所有的checkbox都是没选中
    39         }
    40 
    41     }
    42 
    43     public class MyViewHolder extends RecyclerView.ViewHolder {
    44         CheckBox checkbox;
    45         TextView textView;
    46 
    47         public MyViewHolder(View itemView) {
    48             super(itemView);
    49             checkbox = itemView.findViewById(R.id.checkbox);
    50             textView = itemView.findViewById(R.id.textView);
    51         }
    52     }
    53 
    54     @NonNull
    55     @Override
    56     public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    57         View v = LayoutInflater.from(context).inflate(R.layout.layout, parent, false);
    58         MyViewHolder holder = new MyViewHolder(v);
    59         return holder;
    60     }
    61 
    62     @Override
    63     public void onBindViewHolder(@NonNull MyAdapter.MyViewHolder holder, final int position) {
    64         holder.textView.setText(listData.get(position));
    65         holder.checkbox.setOnCheckedChangeListener(null);//清掉监听器
    66         holder.checkbox.setChecked(checkStatus.get(position));//设置选中状态
    67         holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {//再设置监听器
    68             @Override
    69             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    70                 checkStatus.put(position, isChecked);//check状态一旦改变,保存的check值也要发生相应的变化
    71             }
    72         });
    73     }
    74 
    75     @Override
    76     public int getItemCount() {
    77         if (listData == null) return 0;
    78         return listData.size();
    79     }
    80 }

    下面给出其他代码:

    MainActivity.java

     1 package com.example.recyclerview2;
     2 
     3 import android.support.v7.app.AppCompatActivity;
     4 import android.os.Bundle;
     5 import android.support.v7.widget.LinearLayoutManager;
     6 import android.support.v7.widget.RecyclerView;
     7 
     8 public class MainActivity extends AppCompatActivity {
     9 
    10     private RecyclerView rv_1;
    11 
    12     @Override
    13     protected void onCreate(Bundle savedInstanceState) {
    14         super.onCreate(savedInstanceState);
    15         setContentView(R.layout.activity_main);
    16 
    17         rv_1 = findViewById(R.id.rv_1);
    18         RecyclerView.LayoutManager manager = new LinearLayoutManager(this);
    19         rv_1.setLayoutManager(manager);
    20         MyAdapter adapter = new MyAdapter(this);
    21         rv_1.setAdapter(adapter);
    22     }
    23 
    24 
    25 }

    activity_main.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     xmlns:tools="http://schemas.android.com/tools"
     4     android:layout_width="match_parent"
     5     android:layout_height="match_parent"
     6     tools:context=".MainActivity">
     7 
     8     <android.support.v7.widget.RecyclerView
     9         android:id="@+id/rv_1"
    10         android:layout_width="match_parent"
    11         android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
    12 
    13 </android.support.constraint.ConstraintLayout>

    layout.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="wrap_content"
     5     android:gravity="center"
     6     android:orientation="horizontal">
     7 
     8     <TextView
     9         android:id="@+id/textView"
    10         android:layout_width="wrap_content"
    11         android:layout_height="wrap_content"
    12         android:layout_margin="10dp"
    13         android:text="111" />
    14 
    15     <CheckBox
    16         android:id="@+id/checkbox"
    17         android:layout_width="wrap_content"
    18         android:layout_height="wrap_content"
    19         android:layout_margin="10dp" />
    20 
    21 </LinearLayout>

    结语:

     这里有一句代码很精髓,那就是

    holder.checkbox.setOnCheckedChangeListener(null);//清掉监听器

    Checkbox的监听器有一个特性,无论你是认为操作,还是用api来setChecked,都会触发监听器。所以,在itemView重新加载好之前,不要设置checkbox的check事件监听,否则会出现另外的混乱情况,有兴趣的可以试试看。

    问题已解决,OK,就酱紫。
  • 相关阅读:
    Web安全测试之XSS(转)
    轻松学习RSA加密算法原理 (转)
    firewall 允许app访问网络
    点击了一个link button,查看后台调用
    kentico中提示Message: An invalid SQL query was used.
    iis browse的时候,直接通过本地的局域网ip打开页面
    asp.net web site中reference的version的autoupdate
    Adding Kentico controls to the Visual Studio toolbox
    sql server 数据库展开变慢
    kentico中的page template的使用
  • 原文地址:https://www.cnblogs.com/hankzhouAndroid/p/9139757.html
Copyright © 2020-2023  润新知