最简洁代码实现Listview多选

来源:互联网 发布:51排课软件 编辑:程序博客网 时间:2024/05/21 17:44

记得刚开始学android开发时要实现Listview多选然后批量操作的时候,用Checkbox+Textview,因为adapter复用后上下翻页的时候Checkbox状态无法保存,然后用一个全局变量记住该状态,翻页的时候再恢复状态。现在想想这么搞不仅low爆了,而且效率低。由于最近项目又需要实现类似的功能,想想不能重蹈覆辙,于是谷歌了一把,看到CheckedTextView,原来谷歌工程师已经帮我们实现了类似的功能。本来以为很简单,随便两下就搞定,等到自己动手,才发现不是那么回事,于是写下此文记录下来。

先来看完整的过程:
1.添加控件

<ListView    android:id="@+id/lvMain"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:choiceMode="multipleChoice" />

2.设置数据

for (int i=0;i<100;i++)        {     mDataList.add("item--"+i);     }
MyBaseAdapterListview<String>adapter=new MyBaseAdapterListview<String>(this,mDataList,android.R.layout.simple_list_item_multiple_choice,true) {    @Override    public void convert(MyViewHolderExpandbleListView holder, String s, int position) {         CheckedTextView  checkedTextView = holder.getView(android.R.id.text1);        checkedTextView.setText(s);    }};

上面MyBaseAdapterListview是我自己封装的一个Adapter类,用来填充Listview数据,是不是简单易用?工具包含三个类,Demo里面有,可以直接拿来用。也可以从github引用,地址为https://github.com/crook3/ExpandableListviewAdapter
3.监听点击事件

lvMain.setOnItemClickListener(new AdapterView.OnItemClickListener() {    @Override    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {        sparseBooleanArray=lvMain.getCheckedItemPositions();        int size=sparseBooleanArray.size();        String result = "";        for (int i=0;i<size;i++)        {            if (sparseBooleanArray.valueAt(i))result+=sparseBooleanArray.keyAt(i)+"*";        }        Toast.makeText(MainActivity.this,result,Toast.LENGTH_LONG).show();    }});

运行结果:
image

OK,完美!
使用系统提供的布局方便简单,不用自己管理Checkbox的状态了,多么美好啊。但是有时候并不能满足我们的需求,比如说需要添加一张图片。这个时候就需要自定义了Listview的item的布局了,好,那直接来一个LinearLayout,里面包Imageview和 CheckedTextView,不就可以了吗。恩,你还是太年轻了,如果这么搞你会发现chechbox的状态无法像之前进行自我管理了,这应该是因为CheckedTextView
不再是根布局导致系统无法管理。所以最后,为了保证CheckedTextView就是根布局,我们只能如下布局activity_main_item:

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/tv1"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:gravity="center_vertical"    android:checkMark="?android:attr/listChoiceIndicatorMultiple"    android:drawableLeft="@mipmap/ic_launcher"    />

然后添加数据源的时候采用在一个Textview里面进行换行的思想来实现多行的效果,这样以最少的代码基本满足我们的需求了。

mDataList.add("item--"+i+" \n test1 \n test2");
MyBaseAdapterListview<String>adapter=new MyBaseAdapterListview<String>(this,mDataList,R.layout.activity_main_item,true) {            @Override            public void convert(MyViewHolderExpandbleListView holder, String s, int position) {                 CheckedTextView  checkedTextView = holder.getView(R.id.tv1);                checkedTextView.setText(s);           }       };

自定义布局运行界面
image

自定义复选框颜色及左右,

android:checkMarkTint="@android:color/holo_green_dark"    android:checkMark="?android:attr/listChoiceIndicatorMultiple"    android:drawableTint="@android:color/holo_blue_bright"    android:drawableLeft="?android:attr/listChoiceIndicatorMultiple"

运行结果

image

如果想子item文本之间间隔更大,使用android:lineSpacingExtra="10dp"

image

至此,整个过程结束,相信大家使用起来没什么问题了。

有两点需要说明
1、从 class CheckedTextView extends TextView implements Checkable看出CheckedTextView 兼具Textview和CheckBox特性。
2、lvMain.getCheckedItemPositions()的返回值用SparseBooleanArray数组接收,要知道通过键值对的方式去取值sparseBooleanArray.valueAt(i)和sparseBooleanArray.keyAt(i)。

源码下载地址