当前位置: 代码迷 >> Android >> android UI进阶之兑现listview中checkbox的多选与记录
  详细解决方案

android UI进阶之兑现listview中checkbox的多选与记录

热度:74   发布时间:2016-05-01 20:21:28.0
android UI进阶之实现listview中checkbox的多选与记录

今天继续和大家分享涉及到listview的内容。在很多时候,我们会用到listview和checkbox配合来提供给用户一些选择操作。比如在一个清单页面,我们需要记录用户勾选了哪些条目。这个的实现并不太难,但是有很多朋友来问我如何实现,他们有遇到各种各样的问题,这里就一并写出来和大家一起分享。

?

ListView的操作就一定会涉及到item和Adapter,我们还是先来实现这部分内容。

首先,写个item的xml布局,里面放置一个TextView和一个CheckBox。要注意的时候,这里我设置了CheckBox没有焦点,这样的话,无法单独点击checkbox,而是在点击listview的条目后,Checkbox会响应操作。

?

[html]?view plaincopy
  1. <?xml?version="1.0"?encoding="utf-8"?>??
  2. <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  3. ????android:layout_width="fill_parent"??
  4. ????android:layout_height="fill_parent"??
  5. ????android:orientation="horizontal"?>??
  6. ??
  7. ????<TextView??
  8. ????????android:id="@+id/item_tv"??
  9. ????????android:layout_width="0dp"??
  10. ????????android:layout_height="wrap_content"??
  11. ????????android:layout_weight="1"??
  12. ????????android:gravity="center_vertical"??
  13. ?????????/>??
  14. ??
  15. ????<CheckBox??
  16. ????????android:id="@+id/item_cb"??
  17. ????????android:layout_width="wrap_content"??
  18. ????????android:layout_height="wrap_content"??
  19. ????????android:clickable="false"??
  20. ????????android:focusable="false"??
  21. ????????android:focusableInTouchMode="false"???
  22. ????????android:gravity="center_vertical"??
  23. ????????/>??
  24. ??
  25. </LinearLayout>??

?

下面就写一个Adapter类,我们依然继承BaseAdapter类。这里我们使用一个HashMap<Integer,boolean>的键值来记录checkbox在对应位置的选中状况,这是本例的实现的基础。

[java]?view plaincopy
  1. package?com.notice.listcheck;??
  2. ??
  3. import?java.util.ArrayList;??
  4. import?java.util.HashMap;??
  5. ??
  6. import?android.content.Context;??
  7. import?android.view.LayoutInflater;??
  8. import?android.view.View;??
  9. import?android.view.ViewGroup;??
  10. import?android.widget.BaseAdapter;??
  11. import?android.widget.CheckBox;??
  12. import?android.widget.TextView;??
  13. ??
  14. public?class?MyAdapter?extends?BaseAdapter{??
  15. ????//?填充数据的list??
  16. ????private?ArrayList<String>?list;??
  17. ????//?用来控制CheckBox的选中状况??
  18. ????private?static?HashMap<Integer,Boolean>?isSelected;??
  19. ????//?上下文??
  20. ????private?Context?context;??
  21. ????//?用来导入布局??
  22. ????private?LayoutInflater?inflater?=?null;??
  23. ??????
  24. ????//?构造器??
  25. ????public?MyAdapter(ArrayList<String>?list,?Context?context)?{??
  26. ????????this.context?=?context;??
  27. ????????this.list?=?list;??
  28. ????????inflater?=?LayoutInflater.from(context);??
  29. ????????isSelected?=?new?HashMap<Integer,?Boolean>();??
  30. ????????//?初始化数据??
  31. ????????initDate();??
  32. ????}??
  33. ??
  34. ????//?初始化isSelected的数据??
  35. ????private?void?initDate(){??
  36. ????????for(int?i=0;?i<list.size();i++)?{??
  37. ????????????getIsSelected().put(i,false);??
  38. ????????}??
  39. ????}??
  40. ??
  41. ????@Override??
  42. ????public?int?getCount()?{??
  43. ????????return?list.size();??
  44. ????}??
  45. ??
  46. ????@Override??
  47. ????public?Object?getItem(int?position)?{??
  48. ????????return?list.get(position);??
  49. ????}??
  50. ??
  51. ????@Override??
  52. ????public?long?getItemId(int?position)?{??
  53. ????????return?position;??
  54. ????}??
  55. ??
  56. ????@Override??
  57. ????public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{??
  58. ????????ViewHolder?holder?=?null;??
  59. ????????????if?(convertView?==?null)?{??
  60. ????????????//?获得ViewHolder对象??
  61. ????????????holder?=?new?ViewHolder();??
  62. ????????????????//?导入布局并赋值给convertview??
  63. ????????????????convertView?=?inflater.inflate(R.layout.listviewitem,?null);??
  64. ????????????holder.tv?=?(TextView)?convertView.findViewById(R.id.item_tv);??
  65. ????????????holder.cb?=?(CheckBox)?convertView.findViewById(R.id.item_cb);??
  66. ????????????//?为view设置标签??
  67. ????????????convertView.setTag(holder);??
  68. ????????}?else?{??
  69. ????????????//?取出holder??
  70. ????????????holder?=?(ViewHolder)?convertView.getTag();??
  71. ????????????}??
  72. ??
  73. ??
  74. ????????//?设置list中TextView的显示??
  75. ????????holder.tv.setText(list.get(position));??
  76. ????????//?根据isSelected来设置checkbox的选中状况??
  77. ????????holder.cb.setChecked(getIsSelected().get(position));??
  78. ????????return?convertView;??
  79. ????}??
  80. ??
  81. ????public?static?HashMap<Integer,Boolean>?getIsSelected()?{??
  82. ????????return?isSelected;??
  83. ????}??
  84. ??
  85. ????public?static?void?setIsSelected(HashMap<Integer,Boolean>?isSelected)?{??
  86. ????????MyAdapter.isSelected?=?isSelected;??
  87. ????}??
  88. ??
  89. }??


?

注释已经写的非常详尽了,通过

holder.cb.setChecked(getIsSelected().get(position));

这行代码我们实现了设置CheckBox的选中状况。

那么我们只需要在点击事件中,控制isSelected的键值即可控制对应位置checkbox的选中了。

在Activity中我们除了放置一个ListView外,还放置了三个按钮,分别实现全选,取消和反选。

看下Activity类的代码:

?

[java]?view plaincopy
  1. package?com.notice.listcheck;??
  2. ??
  3. import?java.util.ArrayList;??
  4. ??
  5. import?android.app.Activity;??
  6. import?android.os.Bundle;??
  7. import?android.view.View;??
  8. import?android.view.View.OnClickListener;??
  9. import?android.widget.AdapterView;??
  10. import?android.widget.AdapterView.OnItemClickListener;??
  11. import?android.widget.Button;??
  12. import?android.widget.ListView;??
  13. import?android.widget.TextView;??
  14. ??
  15. public?class?Ex_checkboxActivity?extends?Activity?{??
  16. ??????
  17. ????private?ListView?lv;??
  18. ????private?MyAdapter?mAdapter;??
  19. ????private?ArrayList<String>?list;??
  20. ????private?Button?bt_selectall;??
  21. ????private?Button?bt_cancel;??
  22. ????private?Button?bt_deselectall;??
  23. ????private?int?checkNum;?//?记录选中的条目数量??
  24. ????private?TextView?tv_show;//?用于显示选中的条目数量??
  25. ??????
  26. ????/**?Called?when?the?activity?is?first?created.?*/??
  27. ????@Override??
  28. ????public?void?onCreate(Bundle?savedInstanceState)?{??
  29. ????????super.onCreate(savedInstanceState);??
  30. ????????setContentView(R.layout.main);??
  31. ????????/*?实例化各个控件?*/??
  32. ????????lv?=?(ListView)?findViewById(R.id.lv);??
  33. ????????bt_selectall?=?(Button)?findViewById(R.id.bt_selectall);??
  34. ????????bt_cancel?=?(Button)?findViewById(R.id.bt_cancelselectall);??
  35. ????????bt_deselectall?=?(Button)?findViewById(R.id.bt_deselectall);??
  36. ????????tv_show?=?(TextView)?findViewById(R.id.tv);??
  37. ????????list?=?new?ArrayList<String>();??
  38. ????????//?为Adapter准备数据??
  39. ????????initDate();??
  40. ????????//?实例化自定义的MyAdapter??
  41. ????????mAdapter?=?new?MyAdapter(list,?this);??
  42. ????????//?绑定Adapter??
  43. ????????lv.setAdapter(mAdapter);??
  44. ??
  45. ????????//?全选按钮的回调接口??
  46. ????????bt_selectall.setOnClickListener(new?OnClickListener()?{??
  47. ??
  48. ????????????@Override??
  49. ????????????public?void?onClick(View?v)?{??
  50. ????????????????//?遍历list的长度,将MyAdapter中的map值全部设为true??
  51. ????????????????for?(int?i?=?0;?i?<?list.size();?i++)?{??
  52. ????????????????????MyAdapter.getIsSelected().put(i,?true);??
  53. ????????????????}??
  54. ????????????????//?数量设为list的长度??
  55. ????????????????checkNum?=?list.size();??
  56. ????????????????//?刷新listview和TextView的显示??
  57. ????????????????dataChanged();??
  58. ??
  59. ????????????}??
  60. ????????});??
  61. ????????//?取消按钮的回调接口??
  62. ????????bt_cancel.setOnClickListener(new?OnClickListener()?{??
  63. ??
  64. ????????????@Override??
  65. ????????????public?void?onClick(View?v)?{??
  66. ????????????????//?遍历list的长度,将已选的按钮设为未选??
  67. ????????????????for?(int?i?=?0;?i?<?list.size();?i++)?{??
  68. ????????????????????if?(MyAdapter.getIsSelected().get(i))?{??
  69. ????????????????????????MyAdapter.getIsSelected().put(i,?false);??
  70. ????????????????????????checkNum--;//?数量减1??
  71. ????????????????????}??
  72. ????????????????}??
  73. ????????????????//?刷新listview和TextView的显示??
  74. ????????????????dataChanged();??
  75. ??
  76. ????????????}??
  77. ????????});??
  78. ??
  79. ????????//?反选按钮的回调接口??
  80. ????????bt_deselectall.setOnClickListener(new?OnClickListener()?{??
  81. ??
  82. ????????????@Override??
  83. ????????????public?void?onClick(View?v)?{??
  84. ????????????????//?遍历list的长度,将已选的设为未选,未选的设为已选??
  85. ????????????????for?(int?i?=?0;?i?<?list.size();?i++)?{??
  86. ????????????????????if?(MyAdapter.getIsSelected().get(i))?{??
  87. ????????????????????????MyAdapter.getIsSelected().put(i,?false);??
  88. ????????????????????????checkNum--;??
  89. ????????????????????}?else?{??
  90. ????????????????????????MyAdapter.getIsSelected().put(i,?true);??
  91. ????????????????????????checkNum++;??
  92. ????????????????????}??
  93. ??
  94. ????????????????}??
  95. ????????????????//?刷新listview和TextView的显示??
  96. ????????????????dataChanged();??
  97. ????????????}??
  98. ????????});??
  99. ??????????
  100. ????????//?绑定listView的监听器??
  101. ????????lv.setOnItemClickListener(new?OnItemClickListener()?{??
  102. ??
  103. ????????????@Override??
  104. ????????????public?void?onItemClick(AdapterView<?>?arg0,?View?arg1,?int?arg2,??
  105. ????????????????????long?arg3)?{??
  106. ????????????????//?取得ViewHolder对象,这样就省去了通过层层的findViewById去实例化我们需要的cb实例的步骤??
  107.           ViewHolder?holder?=?(ViewHolder)?arg1.getTag();??
  108. ????????????????//?改变CheckBox的状态??
  109. ????????????????holder.cb.toggle();??
  110. ????????????????//?将CheckBox的选中状况记录下来??
  111. ????????????????MyAdapter.getIsSelected().put(arg2,?holder.cb.isChecked());???
  112. ????????????????//?调整选定条目??
  113. ????????????????if?(holder.cb.isChecked()?==?true)?{??
  114. ????????????????????checkNum++;??
  115. ????????????????}?else?{??
  116. ????????????????????checkNum--;??
  117. ????????????????}??
  118. ????????????????//?用TextView显示??
  119. ????????????????tv_show.setText("已选中"+checkNum+"项");??
  120. ??????????????????
  121. ????????????}??
  122. ????????});??
  123. ????}??
  124. ??
  125. ????//?初始化数据??
  126. ????private?void?initDate()?{??
  127. ????????for?(int?i?=?0;?i?<?15;?i++)?{??
  128. ????????????list.add("data"?+?"???"?+?i);??
  129. ????????}??
  130. ????}??
  131. ??
  132. ????//?刷新listview和TextView的显示??
  133. ????private?void?dataChanged()?{??
  134. ????????//?通知listView刷新??
  135. ????????mAdapter.notifyDataSetChanged();??
  136. ????????//?TextView显示最新的选中数目??
  137. ????????tv_show.setText("已选中"?+?checkNum?+?"项");??
  138. ????}??
  139. ??
  140. ??????
  141. }??


?


代码中在item的点击事件中,直接调用

 holder.cb.toggle();

先改变CheckBox的状态,然后将值存进map记录下来

 MyAdapter.getIsSelected().put(arg2, holder.cb.isChecked());

而其他几个Button的点击事件,都是通过遍历list的长度来设置isSelected的值,进而通知listview根据已经变化的adapter刷新,来实现Checkbox的对应选中状态。因为对listview的处理中我们仍然使用了ViewHolder来优化ListView的效率(通过findViewById层层查找是比较耗时的,这里不了解的朋友可以看我另一篇博客android应用开发全程实录-你有多熟悉listview?,全面解析listview的)。

最后,来看下运行效果:

?

? ??

好了,就写到这里。相信大家都能明白了。这里要说下一个问题,有很多朋友留言或者发邮件要博客中的一些源码。我在这里声明下,我不会去发任何我觉得已经在博客里介绍的非常清楚的实例的源码,有些实例我已经把所有代码都贴出来了,还是有人要源码。。。我希望看我博客的朋友都能真正理解这个实例,能学到更多的知识,最好能有自己的改进然后再和大家一起分享。很多朋友现在已经习惯了拿别人的源码,功能类似的就直接搬到自己项目里,这是非常不好的习惯。动动手,多写写,你会学到更多。