本文主要给大家介绍ListView 的多选操作模式,文章内容都是笔者用心摘选和编辑的,具有一定的针对性,对大家的参考意义还是比较大的,下面跟笔者一起了解下ListView 的多选操作模式吧。

<LinearLayoutxmlns: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:orientation="vertical"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:onClick="showSelectAuthors"android:text="@string/select_authors"android:textSize="25sp"/><ListViewandroid:id="@+id/list"android:layout_width="match_parent"android:layout_height="match_parent"android:choiceMode="multipleChoice"/></LinearLayout>

Activity的代码如下,没有用适配器来处理数据,简单使用了ArrayAdapter:

packagecom.example.choicelistviewtest2;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.ArrayAdapter;importandroid.widget.ListView;importandroid.widget.Toast;publicclassRadioButtonListActivityextendsActivity{privateListViewradioButtonList;privateString[]names=newString[]{"芥川龙之介","三岛由纪夫","川端康成","村上春树","东野圭吾","张爱玲","金庸","钱钟书","老舍","梁实秋","亨利米勒","海明威","菲兹杰拉德","凯鲁亚克","杰克伦敦","小仲马","杜拉斯","福楼拜","雨果","巴尔扎克","莎士比亚","劳伦斯","毛姆","柯南道尔","笛福"};@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);radioButtonList=(ListView)findViewById(R.id.list);ArrayAdapter<String>adapter=newArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice,names);radioButtonList.setAdapter(adapter);}publicvoidshowSelectAuthors(Viewv){long[]authorsId=radioButtonList.getCheckItemIds();Stringname="";Stringmessage;if(authorsId.length>0){//用户至少选择了一位作家for(inti=0;i<authorsId.length;i++){name+=","+names[(int)authorsId[i]];}//将第一个作家前面的“,”去掉message=name.substring(1);}else{message="请至少选择一位作家!";}Toast.makeText(RadioButtonListActivity.this,message,Toast.LENGTH_LONG).show();}}

上面的代码是成功的,程序运行也OK,本以为可以这样结束了,却发现一个问题:

从图上可以看出“getCheckItemIds()”这个方法是弃用的。事实上ListView的getCheckItemIds()方法所得到数据并不精确,据说在某些Android版本上测试发现,当我们选中ListView的一条Item,然后再次取消,getCheckItemIds()方法还是可以拿到取消的Item的id,即返回的数组中还保留该id。这是源码自己的Bug。

虽然经过测试,我的手机上没发现这个问题(我的手机Android版本是4.3),但是我想这个方法还是避免使用吧。版本更新后Android推荐使用的是“getCheckedItemIds()”这个方法(注意方法名多加了“ed”),不过这个方法也不是那么好用——“Returns the set of checked items ids. The result is only valid if the choice mode has not been set to CHOICE_MODE_NONE and the adapter has stable IDs. (hasStableIds() == true)。”这个方法返回ListView中被选中Item的id集合。该方法使用有两个条件,第一是ListView的选择模式没有被设置为CHOICE_MODE_NONE(这一点我们满足,我们设置ListView的选择模式为CHOICE_MODE_MULTIPLE),第二是适配器有稳定的 ID(hasStableIds()==true)。这一点是不满足的,诸如ArrayAdapter、SimpleAdapter,不支持稳定的ID(可以通过adapter.hasStableIds()方法查看,返回值为false)。这就要求我们自己创建Adapter,从hasStableIds()方法中返回true。

我只好又自定义适配器试了一下这个方法,是成功的,布局文件没有改变,就不再贴了,主要是适配器,代码如下:

packagecom.example.choicelistviewtest3;importandroid.content.Context;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.BaseAdapter;publicclassRadioAdapterextendsBaseAdapter{privateString[]authors;privateContextc;publicRadioAdapter(Contextc,String[]authors){super();this.c=c;this.authors=authors;}@OverridepublicintgetCount(){returnauthors.length;}@OverridepublicObjectgetItem(intarg0){returnnull;}@OverridepubliclonggetItemId(intarg0){//返回每一条Item的Idreturnarg0;}@OverridepublicbooleanhasStableIds(){//getCheckedItemIds()方法要求此处返回为真returntrue;}@OverridepublicViewgetView(intarg0,Viewarg1,ViewGrouparg2){ChoiceListItemViewchoiceListItemView=newChoiceListItemView(c,null);choiceListItemView.setName(authors[arg0]);returnchoiceListItemView;}}

ChoiceListItemView类与《ListView的单选模式》中的大同小异,只是去掉了Button背景的设置,还原CheckBox原有的样子,因为现在ListView是多选模式。ChoiceListItemView代码与它的XML文件(Item的布局文件)如下:

packagecom.example.choicelistviewtest3;importandroid.content.Context;importandroid.util.AttributeSet;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.widget.CheckBox;importandroid.widget.Checkable;importandroid.widget.LinearLayout;importandroid.widget.TextView;publicclassChoiceListItemViewextendsLinearLayoutimplementsCheckable{privateTextViewnameTxt;privateCheckBoxselectBtn;publicChoiceListItemView(Contextcontext,AttributeSetattrs){super(context,attrs);LayoutInflaterinflater=LayoutInflater.from(context);Viewv=inflater.inflate(R.layout.item_list,this,true);nameTxt=(TextView)v.findViewById(R.id.author);selectBtn=(CheckBox)v.findViewById(R.id.radio);}publicvoidsetName(Stringtext){nameTxt.setText(text);}@OverridepublicbooleanisChecked(){returnselectBtn.isChecked();}@OverridepublicvoidsetChecked(booleanchecked){selectBtn.setChecked(checked);}@Overridepublicvoidtoggle(){selectBtn.toggle();}}

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#fff"android:orientation="horizontal"><TextViewandroid:id="@+id/author"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:padding="10dp"android:textSize="20sp"/><CheckBoxandroid:id="@+id/radio"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_gravity="center_vertical"android:clickable="false"android:focusable="false"android:focusableInTouchMode="false"android:padding="10dp"/></RelativeLayout>

这样,在主类中就可以使用“getCheckedItemIds()”这个方法了,代码如下:

packagecom.example.choicelistviewtest3;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.ListView;importandroid.widget.Toast;publicclassRadioButtonListActivityextendsActivity{privateListViewradioButtonList;privateRadioAdapteradapter;privateString[]authors=newString[]{"芥川龙之介","三岛由纪夫","川端康成","村上春树","东野圭吾","张爱玲","金庸","钱钟书","老舍","梁实秋","亨利米勒","海明威","菲兹杰拉德","凯鲁亚克","杰克伦敦","小仲马","杜拉斯","福楼拜","雨果","巴尔扎克","莎士比亚","劳伦斯","毛姆","柯南道尔","笛福"};@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_radio_button_list);radioButtonList=(ListView)findViewById(R.id.list);adapter=newRadioAdapter(this,authors);radioButtonList.setAdapter(adapter);}publicvoidshowSelectAuthors(Viewv){long[]authorsId=radioButtonList.getCheckedItemIds();Stringname="";Stringmessage;if(authorsId.length>0){//用户至少选择了一位作家for(inti=0;i<authorsId.length;i++){name+=","+authors[(int)authorsId[i]];}//将第一个作家前面的“,”去掉message=name.substring(1);}else{message="请至少选择一位作家!";}Toast.makeText(RadioButtonListActivity.this,message,Toast.LENGTH_LONG).show();}}

它与choicelistviewtest2包中的RadioButtonListActivity 相比(也就是刚开始的那个RadioButtonListActivity 类),变化很小。显然,如果只是简单地显示一下作家的名字和复选框,而并不需要太多的要求,自定义Adapter实现拥有稳定的ID,这样做事实上是比较麻烦的。下面换一种简单的方法,还是使用ArrayAdapter,只是需要自己来写获取选中Item的ID的方法了,将choicelistviewtest2包中的RadioButtonListActivity增加一个方法:

packagecom.example.choicelistviewtest2;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.ArrayAdapter;importandroid.widget.ListView;importandroid.widget.Toast;publicclassRadioButtonListActivityextendsActivity{privateListViewradioButtonList;privateString[]names=newString[]{"芥川龙之介","三岛由纪夫","川端康成","村上春树","东野圭吾","张爱玲","金庸","钱钟书","老舍","梁实秋","亨利米勒","海明威","菲兹杰拉德","凯鲁亚克","杰克伦敦","小仲马","杜拉斯","福楼拜","雨果","巴尔扎克","莎士比亚","劳伦斯","毛姆","柯南道尔","笛福"};@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);radioButtonList=(ListView)findViewById(R.id.list);ArrayAdapter<String>adapter=newArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice,names);radioButtonList.setAdapter(adapter);}publicvoidshowSelectAuthors(Viewv){//long[]authorsId=radioButtonList.getCheckItemIds();long[]authorsId=getListSelectededItemIds(radioButtonList);Stringname="";Stringmessage;if(authorsId.length>0){//用户至少选择了一位作家for(inti=0;i<authorsId.length;i++){name+=","+names[(int)authorsId[i]];}//将第一个作家前面的“,”去掉message=name.substring(1);}else{message="请至少选择一位作家!";}Toast.makeText(RadioButtonListActivity.this,message,Toast.LENGTH_LONG).show();}//避免使用getCheckItemIds()方法publiclong[]getListSelectededItemIds(ListViewlistView){long[]ids=newlong[listView.getCount()];//getCount()即获取到ListView所包含的item总个数//定义用户选中Item的总个数intcheckedTotal=0;for(inti=0;i<listView.getCount();i++){//如果这个Item是被选中的if(listView.isItemChecked(i)){ids[checkedTotal++]=i;}}if(checkedTotal<listView.getCount()){//定义选中的Item的ID数组finallong[]selectedIds=newlong[checkedTotal];//数组复制idsSystem.arraycopy(ids,0,selectedIds,0,checkedTotal);returnselectedIds;}else{//用户将所有的Item都选了returnids;}}}

其中用到了System.arraycopy()这个方法,解释如下:

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。

这就真正OK了,效果图:

看完以上关于ListView 的多选操作模式,很多读者朋友肯定多少有一定的了解,如需获取更多的行业知识信息 ,可以持续关注我们的行业资讯栏目的。