Android ListView加入CheckBox/RadioButton选择状态保持、全选、反选

最近在一个项目中,需要在ListView的item中加入CheckBox,但是遇到的一个问题是上下滑动的时候如果有选择了的CheckBox,就会出现选择项错误的问题,下面将个人的解决方法总结如下;

先说思路:在ListView的Adapter中,用一个Map保存每一项item的选择状态,在getView方法中,设置Map中保存的某一项的选择状态就实现了状态的保存;

每一项的视图child.xml

  1. android:id="@+id/item_cb"
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content" />
  4. android:id="@+id/item_tv"
  5. android:layout_width="wrap_content"
  6. android:layout_height="wrap_content"
  7. android:text="hello" />
复制代码

Adapter.java

  1. public class CAdapter extends BaseAdapter {
  2. private List list;
  3. private LayoutInflater inflater;
  4. Map map;
  5. private OnSelectedItemChanged listener;
  6. private Holder holder = null;

  7. public CAdapter(Context context, List list,
  8. OnSelectedItemChanged listener) {
  9. super();
  10. inflater = LayoutInflater.from(context);
  11. this.list = list;
  12. map = new HashMap();
  13. for (int i = 0; i < list.size(); i++) {
  14. map.put(i, false);
  15. }
  16. this.listener = listener;
  17. }

  18. @Override
  19. public int getCount() {
  20. return list.size();
  21. }

  22. @Override
  23. public Object getItem(int position) {
  24. return list.get(position);
  25. }

  26. @Override
  27. public long getItemId(int position) {
  28. return position;
  29. }

  30. @Override
  31. public View getView(final int position, View convertView, ViewGroup parent) {
  32. View view = convertView;
  33. String item = list.get(position);
  34. if (view == null) {
  35. holder = new Holder();
  36. view = inflater.inflate(R.layout.child, null);
  37. TextView tv = (TextView) view.findViewById(R.id.item_tv);
  38. CheckBox cb = (CheckBox) view.findViewById(R.id.item_cb);
  39. holder.tv = tv;
  40. holder.cb = cb;
  41. view.setTag(holder);
  42. } else {
  43. holder = (Holder) view.getTag();
  44. holder.tv.setText(item);
  45. holder.cb.setChecked(map.get(position));
  46. }
  47. holder.tv.setText(list.get(position));
  48. final CheckBox cb = holder.cb;
  49. cb.setChecked(map.get(position));// 设置选择状态
  50. cb.setOnClickListener(new OnClickListener() {
  51. @Override
  52. public void onClick(View v) {
  53. map.put(position, cb.isChecked());
  54. listener.selectedItemChange(getSelectedCount(map));
  55. }
  56. });
  57. return view;
  58. }

  59. /**
  60. * 获取选择的项的数目

  61. * @param map
  62. * @return
  63. */
  64. public int getSelectedCount(Map map) {
  65. int i = 0;
  66. for (Entry entry : map.entrySet()) {
  67. if (entry.getValue()) {
  68. i++;
  69. }
  70. }
  71. return i;
  72. }

  73. class Holder {
  74. TextView tv;
  75. CheckBox cb;
  76. }

  77. /**
  78. * 向Activity暴露选择了多少项

  79. * @author cj

  80. */
  81. public interface OnSelectedItemChanged {
  82. public void selectedItemChange(int count);
  83. }

  84. public void selectAll() { // 全选
  85. for (int i = 0; i < list.size(); i++) {
  86. map.put(i, true);
  87. }
  88. notifyDataSetChanged();
  89. }

  90. public void disSelectAll() { // 全不选
  91. for (int i = 0; i < list.size(); i++) {
  92. map.put(i, false);
  93. }
  94. notifyDataSetChanged();
  95. }

  96. public void switchSelect() { // 反选
  97. for (int i = 0; i < list.size(); i++) {
  98. boolean select = map.get(i);
  99. map.put(i, !select);
  100. }
  101. notifyDataSetChanged();
  102. }
  103. }
复制代码

MainActivity.java

  1. public class MainActivity extends Activity {
  2. private ListView lv;
  3. private CAdapter adapter;

  4. @Override
  5. public void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. lv = (ListView) findViewById(R.id.lv);
  9. setAdapter();

  10. }

  11. private void setAdapter() {
  12. List list = new ArrayList();
  13. for (int i = 0; i < 50; i++) {
  14. list.add("item - " + i);
  15. }
  16. adapter = new CAdapter(getApplicationContext(), list,
  17. new OnSelectedItemChanged() {// Adapter接口暴露出来的选择项状态改变时选择的项的数目
  18. @Override
  19. public void selectedItemChange(int count) {
  20. Log.e("SelectedCount - ", count + "");
  21. }
  22. });
  23. lv.setAdapter(adapter);
  24. }

  25. // 全选
  26. public void selectAll(View v) {
  27. adapter.selectAll();
  28. }

  29. // 全不选
  30. public void disSelectAll(View v) {
  31. adapter.disSelectAll();
  32. }

  33. // 反选
  34. public void switchSelect(View v) {
  35. adapter.switchSelect();
  36. }
  37. }
复制代码

选择之后反选的效果(右边是点击反选之后的效果):

 

在上面用到一个比较好的思想就是用类的内部接口向外部调用类暴露本类的一些状态改变时,外部类可能想要获取的数据信息;
延伸思考:上面保存的状态是CheckBox,当需要使用RadioButton的时候,使用方法也是类似的;


但是RadioButton可能会有另一种需求{选择某一项的时候其它项就不选择,也即只选择一项},此种情况其实参考上面全选,反选的实现,实现起来也是比较简单,暂时没时间去写出来测试;

你可能感兴趣的:(Android ListView加入CheckBox/RadioButton选择状态保持、全选、反选)