http://blog.csdn.net/simtice/article/details/7068774
在Android某些开发需求当中,有时候需要在listveiw中加入checkbox实现单选,多选操作。表面上看上去只是改变checkbox那么简单,然而实际开发中,实现起来并不是那么得心应手。尤其当listview比较多(比如屏幕最多只能显示10个item,但总共有12个item,也就是说listview的item数大于屏幕能够显示的item数)滑动屏幕的时候,由于适配器中getview()会重复使用被移除屏幕的item,所以会造成checkbox选择状态不正常的现象。自己在开发中碰到这样的问题很是苦恼,查了下资料,发现网上很少没有针对这类批量操作并没有一个完整的例子。搜了很多篇帖子才完美的实现这一常用的操作。所以在这里把这个Demo贴出来,供大家参考,希望能对大家有所帮助。
主界面的布局main.xml 这个就不多说什么
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- >
- <TextView
- android:id="@+id/tv"
- android:layout_width="fill_parent"
- android:layout_height="50dip"
- android:textColor="#FCFCFC"
- android:textSize="11pt"
- android:gravity="center_vertical"
- android:layout_marginLeft="10dip"
- />
- <ListView
- android:id="@+id/lv"
- android:layout_width="fill_parent"
- android:layout_height="381dip"
- android:cacheColorHint="#00000000"
- ></ListView>
- </LinearLayout>
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="53dip"
- android:orientation="horizontal"
- >
- <Button
- android:id="@+id/selectall"
- android:layout_width="80dip"
- android:layout_height="50dip"
- android:layout_marginLeft="20dip"
- android:text="全选"
- android:gravity="center"
- />
- <Button
- android:id="@+id/inverseselect"
- android:layout_width="80dip"
- android:layout_height="50dip"
- android:layout_marginLeft="118dip"
- android:text="反选"
- android:gravity="center"
- />
- <Button
- android:id="@+id/cancel"
- android:layout_width="80dip"
- android:layout_height="50dip"
- android:layout_marginLeft="213dip"
- android:text="取消已选"
- android:gravity="center"
- />
- </RelativeLayout>
- </LinearLayout>
ListView每个item的布局,listviewitem.xml:
这里需要注意的是,由于checkbox的点击事件优先级比listview的高,所以要添加android:focusable="false"属性,使得checkbox初始的时候没有获取焦点。
另外这里是点击ListView的item控制checkbox的状态改变,也就是让item接收clik事件,所以需要加上android:focusableInTouchMode="false"这一属性。
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="55dip"
- android:orientation="horizontal"
- android:layout_marginTop="20dip"
- >
- <TextView
- android:id="@+id/item_tv"
- android:layout_width="267dip"
- android:layout_height="40dip"
- android:textSize="10pt"
- android:gravity="center_vertical"
- android:layout_marginLeft="10dip"
- />
- <CheckBox
- android:id="@+id/item_cb"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="false"
- android:focusableInTouchMode="false"
- android:clickable="false"
- android:layout_toRightOf="@id/item_tv"
- android:layout_alignParentTop="true"
- android:layout_marginRight="5dip"
- />
- </RelativeLayout>
ViewHolder类
- packagesimtice.test.listview.viewholder;
- importandroid.widget.CheckBox;
- importandroid.widget.TextView;
- publicclassViewHolder{
- publicTextViewtv=null;
- publicCheckBoxcb=null;
- }
为listview自定义适配器,该类为主Activity类MainActivity.java的内部类
- publicstaticclassMyAdapterextendsBaseAdapter{
- publicstaticHashMap<Integer,Boolean>isSelected;
- privateContextcontext=null;
- privateLayoutInflaterinflater=null;
- privateList<HashMap<String,Object>>list=null;
- privateStringkeyString[]=null;
- privateStringitemString=null;//记录每个item中textview的值
- privateintidValue[]=null;//id值
- publicMyAdapter(Contextcontext,List<HashMap<String,Object>>list,
- intresource,String[]from,int[]to){
- this.context=context;
- this.list=list;
- keyString=newString[from.length];
- idValue=newint[to.length];
- System.arraycopy(from,0,keyString,0,from.length);
- System.arraycopy(to,0,idValue,0,to.length);
- inflater=LayoutInflater.from(context);
- init();
- }
- //初始化设置所有checkbox都为未选择
- publicvoidinit(){
- isSelected=newHashMap<Integer,Boolean>();
- for(inti=0;i<list.size();i++){
- isSelected.put(i,false);
- }
- }
- @Override
- publicintgetCount(){
- returnlist.size();
- }
- @Override
- publicObjectgetItem(intarg0){
- returnlist.get(arg0);
- }
- @Override
- publiclonggetItemId(intarg0){
- return0;
- }
- @Override
- publicViewgetView(intposition,Viewview,ViewGrouparg2){
- ViewHolderholder=null;
- if(holder==null){
- holder=newViewHolder();
- if(view==null){
- view=inflater.inflate(R.layout.listviewitem,null);
- }
- holder.tv=(TextView)view.findViewById(R.id.item_tv);
- holder.cb=(CheckBox)view.findViewById(R.id.item_cb);
- view.setTag(holder);
- }else{
- holder=(ViewHolder)view.getTag();
- }
- HashMap<String,Object>map=list.get(position);
- if(map!=null){
- itemString=(String)map.get(keyString[0]);
- holder.tv.setText(itemString);
- }
- holder.cb.setChecked(isSelected.get(position));
- returnview;
- }
- }
最后,最重要的就是MainActivity.java中一些事件响应的处理
- publicclassMainActivityextendsActivity{
- TextViewtv=null;
- ListViewlv=null;
- Buttonbtn_selectAll=null;
- Buttonbtn_inverseSelect=null;
- Buttonbtn_calcel=null;
- Stringname[]={"G1","G2","G3","G4","G5","G6","G7","G8","G9",
- "G10","G11","G12","G13","G14"};
- ArrayList<String>listStr=null;
- privateList<HashMap<String,Object>>list=null;
- privateMyAdapteradapter;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tv=(TextView)this.findViewById(R.id.tv);
- lv=(ListView)this.findViewById(R.id.lv);
- btn_selectAll=(Button)this.findViewById(R.id.selectall);
- btn_inverseSelect=(Button)this.findViewById(R.id.inverseselect);
- btn_calcel=(Button)this.findViewById(R.id.cancel);
- showCheckBoxListView();
- //全选
- btn_selectAll.setOnClickListener(newOnClickListener(){
- @Override
- publicvoidonClick(Viewarg0){
- listStr=newArrayList<String>();
- for(inti=0;i<list.size();i++){
- MyAdapter.isSelected.put(i,true);
- listStr.add(name[i]);
- }
- adapter.notifyDataSetChanged();//注意这一句必须加上,否则checkbox无法正常更新状态
- tv.setText("已选中"+listStr.size()+"项");
- }
- });
- //反选
- btn_inverseSelect.setOnClickListener(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- for(inti=0;i<list.size();i++){
- if(MyAdapter.isSelected.get(i)==false){
- MyAdapter.isSelected.put(i,true);
- listStr.add(name[i]);
- }
- else{
- MyAdapter.isSelected.put(i,false);
- listStr.remove(name[i]);
- }
- }
- adapter.notifyDataSetChanged();
- tv.setText("已选中"+listStr.size()+"项");
- }
- });
- //取消已选
- btn_calcel.setOnClickListener(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- for(inti=0;i<list.size();i++){
- if(MyAdapter.isSelected.get(i)==true){
- MyAdapter.isSelected.put(i,false);
- listStr.remove(name[i]);
- }
- }
- adapter.notifyDataSetChanged();
- tv.setText("已选中"+listStr.size()+"项");
- }
- });
- }
- //显示带有checkbox的listview
- publicvoidshowCheckBoxListView(){
- list=newArrayList<HashMap<String,Object>>();
- for(inti=0;i<name.length;i++){
- HashMap<String,Object>map=newHashMap<String,Object>();
- map.put("item_tv",name[i]);
- map.put("item_cb",false);
- list.add(map);
- adapter=newMyAdapter(this,list,R.layout.listviewitem,
- newString[]{"item_tv","item_cb"},newint[]{
- R.id.item_tv,R.id.item_cb});
- lv.setAdapter(adapter);
- listStr=newArrayList<String>();
- lv.setOnItemClickListener(newOnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>arg0,Viewview,
- intposition,longarg3){
- ViewHolderholder=(ViewHolder)view.getTag();
- holder.cb.toggle();//在每次获取点击的item时改变checkbox的状态
- MyAdapter.isSelected.put(position,holder.cb.isChecked());//同时修改map的值保存状态
- if(holder.cb.isChecked()==true){
- listStr.add(name[position]);
- }else{
- listStr.remove(name[position]);
- }
- tv.setText("已选中"+listStr.size()+"项");
- }
- });
- }
- }
- //为listview自定义适配器内部类
- publicstaticclassMyAdapterextendsBaseAdapter{
- ...
- }
- }
好了,来看运行结果
我选择了G2、G3、G11三项,现在屏幕滑动到底部,看以看到状态保存的很好,TextView显示已选中3项。全选、反选、取消已选功能正常,多选操作完美解决!