美文网首页高级UI我收藏的Android开发文章
Android实现ListView嵌套Checkbox真正的多选

Android实现ListView嵌套Checkbox真正的多选

作者: Android高级工程师 | 来源:发表于2019-05-06 17:01 被阅读42次

    我们在开发APP的时候,很多情况下会使用到ListView嵌套CheckBox的情况,其实很多人要说这个其实很简单了,并没有那么复杂,为什么还要单独用一篇博客来写呢?事实上并非如此,我们在使用ListView嵌套CheckBox复选框的时候会出现很多问题,

    废话不多说,直接进入主题,首先我们来看ListView的item的布局文件:

    listview_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:gravity="center">
    
        <CheckBox
            android:id="@+id/cb_button"
            android:checked="false"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@drawable/checkbox_selector"
            android:clickable="true"
            android:focusable="true"
            android:marginLeft="30dp" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15sp"
            android:layout_marginLeft="200dp"
            android:text="你好"
            android:id="@+id/tv_name"/>
    
    </LinearLayout>
    

    布局文件中使用了一个checkbox复选框和一个textview,这样做是为了解决初学者的疑惑,这里要贴别注意checkbox的xml代码,如果不把android:focusable设置为false的话,会在后面让listview的item无法获得焦点

    上面是listview的每个item的布局文件,没什么难度,接下来看看主布局文件:

    activity_main.xml

    <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_marginTop="100dp"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
            <CheckBox
                android:id="@+id/cb_all_button"
                android:checked="false"
                android:button="@drawable/checkbox_selector"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="20dp"
                android:text="全选"
                android:textSize="15sp"
                android:gravity="center_vertical"
                android:paddingLeft="10dp"
                android:focusable="false"
                android:onClick="allSelect" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="20dp"
                android:orientation="horizontal" >
    
                <Button
                    android:id="@+id/btn_fanxuan"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="5dp"
                    android:layout_weight="1"
                    android:gravity="center"
                    android:background="@drawable/button_selector"
                    android:textSize="15sp"
                    android:text="反选" />
    
                <Button
                    android:id="@+id/btn_cancel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="5dp"
                    android:layout_weight="1"
                    android:gravity="center"
                    android:textSize="15sp"
                    android:background="@drawable/button_selector"
                    android:text="取消" />
    
            </LinearLayout>
        </LinearLayout>
        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
        </ListView>
        </LinearLayout>
    

    上面的是主界面的布局文件,主文件中放了一个全选的checkbox复选框,和两个按钮用来实现反选取消,也挺简单的,这里就不多说了,其中的background引用的是资源文件,也就是点击的按钮的效果文件,接下来我们看看主要的代码文件:
    Adapter适配器

    public class MyListAdapter extends BaseAdapter{
    
        List<Test> list = new ArrayList<Test>();
        private static SparseBooleanArray isSelected;/**用SparseBooleanArray来代替map**/
        Context context;
        HolderView holderView = null;
        /**
         * 全选回调接口
         */
        CheckedAllListener mListener;
    
        public void setCheckedAllListener(CheckedAllListener listener) {  
            mListener = listener;  
        }
    
    
        public MyListAdapter(List<Test> list, Context context) {
            // TODO Auto-generated constructor stub
            this.context = context;
            this.list = list;
            isSelected = new SparseBooleanArray();
            initData();
        }
    
        /**
         * 初始化数据
         */
        private void initData()
        {
            for (int i = 0; i < list.size(); i++) {
    
                getIsSelected().put(i, false);
    
            }
        }
    
    
        public static SparseBooleanArray getIsSelected()
        {
            return isSelected;
        }
    
        public static void setIsSelected(SparseBooleanArray isSelected) {  
            MyListAdapter.isSelected = isSelected;
        } 
    
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return list.size();
        }
    
        @Override
        public Test getItem(int position) {
            // TODO Auto-generated method stub
            return list.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }
    
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            View view = convertView;
            if (view == null) {
                holderView = new HolderView();
                //得到资源文件
                LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.listview_item, parent, false);
                holderView.cb_button = (CheckBox)view.findViewById(R.id.cb_all_button);
                holderView.tv_name = (TextView)view.findViewById(R.id.tv_name);
                view.setTag(holderView);
    
            }
            else {
                holderView = (HolderView)view.getTag();
            }
    
            final Test item = getItem(position);
            if (item != null) {
                holderView.tv_name.setText(item.getName());
                holderView.cb_button.setChecked(isSelected.get(position));
    
            }
            /**
             * 增加checkbox的改变事件,每个item的点击事件
             */
            holderView.cb_button.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    // TODO Auto-generated method stub
                    //                      holderView.cb_button.toggle();
                    if (buttonView.isPressed()) {
    
                        isSelected.put(position,isChecked);
                        //监听回调,是否改变全选按钮的状态
                        mListener.CheckAll(isSelected);
    
                    }
                    item.setCheck(isChecked);
                }
            });
            return view;
        }
    
    
        class HolderView
        {
            private CheckBox cb_button;
            private TextView tv_name;
        }
    
        /**
         * 当所有CheckBox全选时回调
         * @author Administrator
         *
         */
        public interface CheckedAllListener
        {
    
            void CheckAll(SparseBooleanArray checkall);
    
        }
    
    }
    

    适配器的内容也比较简单,这里我在适配器中解决了滑动listview出现的checkbox状态错乱的问题,然后增加了一个checkbox的全选回调,就是说每次点击item的复选框都会去调用一下这个借口,来判断对否需要对全选按钮做处理,如果有不懂接口的回调方法,我会在以后的文章中进行讲解,有些不懂的我也用注释标了一下,其中的Test.java比较简单,说白了,就是纯粹的为了好看,帮助大家理解,大家也可以看下:
    Test.java

    public class Test {
        private String name;
        private boolean isCheck;
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
        public boolean isCheck() {
            return isCheck;
        }
        public void setCheck(boolean isCheck) {
            this.isCheck = isCheck;
        }
    }
    

    这个也没有啥好介绍的,然后我们再来看看mainActivity.java文件,
    mainActivity.java

    public class MainActivity extends AppCompatActivity implements MyListAdapter.CheckedAllListener {
    
        MyListAdapter adapter;
        ListView listView;
        List<Test> list;
        CheckBox cb_button_all;
    
        Button btn_select;
        Button btn_select_cancel;
    
        SparseBooleanArray isCheckeds;
        //判断是否全选按钮按下
        boolean flag = false;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            listView = (ListView)findViewById(R.id.list_view);
            cb_button_all = (CheckBox)findViewById(R.id.cb_all_button);
            btn_select = (Button)findViewById(R.id.btn_fanxuan);
            btn_select_cancel = (Button)findViewById(R.id.btn_cancel);
            setSupportActionBar(toolbar);
    
            isCheckeds = new SparseBooleanArray();
            list = new ArrayList<>();
            for (int i = 0; i <= 20; i++)
            {
                Test test = new Test();
                test.setName("sister" + i);
                list.add(test);
            }
            adapter = new MyListAdapter(list,this);
            adapter.setCheckedAllListener(this);
            listView.setAdapter(adapter);
    
            btn_select.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 遍历list的长度,将已选的设为未选,未选的设为已选
                    for (int i = 0; i < list.size(); i++) {
                        if (MyListAdapter.getIsSelected().get(i)) {
                            MyListAdapter.getIsSelected().put(i, false);
                        } else {
                            MyListAdapter.getIsSelected().put(i, true);
                        }
                    }
                    // 刷新listview和TextView的显示
                    adapter.notifyDataSetChanged();
                }
            });
    
            btn_select_cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    // 遍历list的长度,将已选的按钮设为未选
                    for (int i = 0; i < list.size(); i++) {
                        if (MyListAdapter.getIsSelected().get(i)) {
                            MyListAdapter.getIsSelected().put(i, false);
                        }
                    }
                    // 刷新listview和TextView的显示
                    adapter.notifyDataSetChanged();
                }
            });
        }
    
        /**
         * 该点击事件放在了xml文件的android:onclick中
         * @param v
         */
        public void allSelect(View v)
        {
            System.out.println("========>>>>>>" + cb_button_all.isChecked());
            if (cb_button_all.isChecked()) {
                flag = true;
            }
            else {
                flag = false;
            }
            if (flag) {
                for (int i = 0; i < list.size(); i++) {
    
                    isCheckeds.put(i, true);
                    MyListAdapter.setIsSelected(isCheckeds);
                }
            }else {
                for (int i = 0; i < list.size(); i++) {
    
                    isCheckeds.put(i, false);
                    MyListAdapter.setIsSelected(isCheckeds);
                }
            }
            //更新适配器
            adapter.notifyDataSetChanged();
        }
    
        /**
         * 全选按钮的回调事件,手否进行全选
         * @param checkall
         */
        @Override
        public void CheckAll(SparseBooleanArray checkall) {
            int a = checkall.indexOfValue(false);
            int b = checkall.indexOfValue(true);
            System.out.println(a + "----" + b);
            //判断SparseBooleanArray是否含有true
            if (checkall.indexOfValue(true) < 0) {
    
                if (cb_button_all.isChecked()) {
                    this.flag = false;
                    cb_button_all.setChecked(false);
                }
    
            }else if(checkall.indexOfValue(false) < 0){
                if (!cb_button_all.isChecked()) {
                    this.flag = false;
                    cb_button_all.setChecked(true);
                }
    
            }
            else if(checkall.indexOfValue(false) >= 0 && checkall.indexOfValue(true) >= 0){
                if (cb_button_all.isChecked()) {
                    this.flag = true;
                    cb_button_all.setChecked(false);
                }
            }
        }
    }
    

    在mainActivity.java中我实现了checkbox全选的回调,然后设置了一个flag来做一个标识,初始化的时候将所有的checkbox设置为false
    效果图

    image.png

    喜欢请点击+关注哦

    相关文章

      网友评论

        本文标题:Android实现ListView嵌套Checkbox真正的多选

        本文链接:https://www.haomeiwen.com/subject/bnsdoqtx.html