• 超简单的单选和多选ListView

在开发过程中,我们经常会使用ListView去呈现列表数据,比如商品列表,通话记录,联系人列表等等,在一些情况下,我们还需要去选择其中的一些列表数据进行编辑。以前,我在项目开发中,都是在自定义的Adapter中去维护一个SparseBooleanArray变量来保存当前ListView中已经被选中的项,然后在自定义Adapter的getView()和ListView的setOnItemClickListener()方法中去实时更新SparseBooleanArray变量,从而当用户选择提交数据的时候,直接遍历SparseBooleanArray中的值就可以了,这种做法,虽然也能实现功能,但是无疑增加了代码开销。

今天,在看文档的时候,发现了一个更好的解决方案(很多人已经用过了吧):使用ListView的choiceMode,官方文档见如下:

根据上面的文档说明,可以知道,android:choiceMode有以下几个值:默认(不设置android:choiceMode属性,即不支持单选或多选),singleChoice(单选),multipleChoice(多选),mutipleChoiceModal(特殊多选模式,可以通过设置MultiChoiceModeListener进行监听选择模式,类似ActionBar的ActionMode)。在XML中给ListView设置了android:choiceMode属性一个值后,我们还需要给ListView一个适配器,这里我们使用默认的ArrayAdapter:

  1. //如果是单选模式,则可以使用 android.R.layout.simple_list_item_single_choice
  2. ArrayAdapter<String> myAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice, mDatas);
  3. mListView.setAdapter(myAdapter);

这样我们就已经完成了ListView的多选或单选实现。

另外一个问题是:我们怎样才能获取当前ListView中被选中的那些项呢?

我们其实可以通过ListView的isItemChecked(int position)方法判断一项是否被选中,或直接使用ListView.getCheckedItemPositions()来获取所有选中的项,这个方法返回一个SparseBooleanArray对象,遍历它就可以获取所有选中的项。

  • 自定义ListView的多选和单选项布局

  对于一些简单的列表,上面的方法可能已经能够满足需求。其实,上面的列表项只显示了一个标题和一个复选框,但在实际开发中,UE或产品经理可能要求我们去实现的列表远比上面的列表复杂得多,所以往往就需要使用自定义的Adapter来填充ListView。

但是,如果我们使用自定义的Adapter来填充ListView,那怎么让我们自定义的Checkbox能够无缝衔接ListView的选择状态呢?

一种普遍的做法是在重写自定义Adapter的getView()时,先通过convertView.findViewById()获取到Checkbox后,通过mList.isItemChecked(int position)判断当前position的状态后,再去更新Checkbox的选择状态。

这里,我介绍的是另外一种方法。
     首先,我们先来看下为什么我们使用android.R.layout.simple_list_item_multiple_choice布局来填充ArrayAdapter时,不需要我们自己去维护CheckBox的选择状态?
     查看ListView的源码,在ListView的setupChild方法中,有下面的一段代码:

  1. if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
  2. if (child instanceof Checkable) {
  3. ((Checkable) child).setChecked(mCheckStates.get(position));
  4. } else if (getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)
  5. {
  6. child.setActivated(mCheckStates.get(position));
  7. }
  8. }

即如果ListView的child(从自定义的Adapter的getView()方法中返回的View)实现了Checkable接口,那么当listView的项选择状态改变时,listView也会去同步更新这个child的状态(android 3.1或3.1以上平台,会触发setActivated方法),其实simple_list_item_multiple_choice.xml中只有一个CheckedTextView
  

  1. <CheckedTextView
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@android:id/text1"
  4. android:layout_width="match_parent"
  5. android:layout_height="?android:attr/listPreferredItemHeightSmall"
  6. android:textAppearance="?android:attr/textAppearanceListItemSmall"
  7. android:gravity="center_vertical"
  8. android:checkMark="?android:attr/listChoiceIndicatorMultiple"
  9. android:paddingStart="?android:attr/listPreferredItemPaddingStart"
  10. android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />

而CheckedTextView 是实现了Checkable接口的,所以当我们使用simple_list_item_multiple_choic.xml布局作为Adapter的getView()的返回值时,是不需要我们额外去关心Checkbox的状态问题。
    通过上面的分析,我们自定义一个View时,只需要实现了Checkable接口,那么就不用我们在getView中去额外维护选中状态了。如果android3.1或android3.1以上的平台,我们还可以重写setActivated方法来更新我们的选中状态。相关示例代码如下:

  1. package com.shaoxiong.li.marvel.myapplication;
  2.  
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.widget.CheckBox;
  8. import android.widget.Checkable;
  9. import android.widget.LinearLayout;
  10. import android.widget.TextView;
  11.  
  12. /**
  13. * Created by lishaoxiong on 16-2-22.
  14. */
  15. public class CustomCheckTextView extends LinearLayout implements Checkable {
  16.  
  17. private TextView titleView;
  18. private CheckBox mCheckBox;
  19.  
  20. public CustomCheckTextView(Context context) {
  21. this(context, null);
  22. }
  23.  
  24. public CustomCheckTextView(Context context, AttributeSet attrs) {
  25. this(context, attrs, 0);
  26. }
  27.  
  28. public CustomCheckTextView(Context context, AttributeSet attrs, int defStyleAttr) {
  29. super(context, attrs, defStyleAttr);
  30.  
  31. LayoutInflater mLayoutInflater = LayoutInflater.from(context);
  32. //将加载出来的View添加到当前View层级中去。
  33. //有两种方案,一种是加载布局时将rootView传进去,或直接使用addView添加进去
  34. //View v = mLayoutInflater.inflate(R.layout.layout_custom_ctv, null);
  35. View v = mLayoutInflater.inflate(R.layout.layout_custom_ctv, this, true);
  36. titleView = (TextView)v.findViewById(R.id.headListView_item_text);
  37. mCheckBox = (CheckBox)v.findViewById(R.id.headListView_item_cb);
  38. //this.addView(v);
  39. }
  40.  
  41. @Override
  42. public void setChecked(boolean checked) {
  43. mCheckBox.setChecked(checked);
  44. }
  45.  
  46. @Override
  47. public boolean isChecked() {
  48. return mCheckBox.isChecked();
  49. }
  50.  
  51. @Override
  52. public void toggle() {
  53. mCheckBox.toggle();
  54. }
  55.  
  56. public void setTitle(String title) {
  57. titleView.setText(title);
  58. }
  59.  
  60. @Override
  61. public void setActivated(boolean activated) {
  62. super.setActivated(activated);
  63. }
  64. }
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="horizontal"
  6. android:padding="20dp">
  7. <CheckBox
  8. android:id="@+id/headListView_item_cb"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:focusable="false"
  12. android:clickable="false"
  13. android:focusableInTouchMode="false"/>
  14.  
  15. <TextView
  16. android:id="@+id/headListView_item_text"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:layout_marginRight="10dp"/>
  20.  
  21. </LinearLayout>
  1. public class MyAdapter extends BaseAdapter {
  2.  
  3. private Context mContext;
  4. private ArrayList<String> dataList;
  5.  
  6. public MyAdapter(Context context, ArrayList<String> dataList) {
  7. this.mContext = context;
  8. this.dataList= dataList;
  9. }
  10.  
  11. @Override
  12. public int getCount() {
  13. return dataList.size();
  14. }
  15.  
  16. @Override
  17. public Object getItem(int position) {
  18. return dataList.get(position);
  19. }
  20.  
  21. @Override
  22. public long getItemId(int position) {
  23. return position;
  24. }
  25.  
  26. @Override
  27. public View getView(int position, View convertView, ViewGroup parent) {
  28. ViewHolder viewHolder = null;
  29. if(convertView == null) {
  30. convertView = LayoutInflater.from(mContext).inflate(R.layout.item_headlistview, null);
  31. viewHolder = new ViewHolder();
  32. //viewHolder.mTextView = (TextView)convertView.findViewById(R.id.headListView_item_text);
  33. // viewHolder.checkedTv = (CheckedTextView)convertView.findViewById(R.id.item_checked_tv);
  34. viewHolder.customCheckTextView = (CustomCheckTextView)convertView;
  35. convertView.setTag(viewHolder);
  36. }else {
  37. viewHolder = (ViewHolder)convertView.getTag();
  38. }
  39. // viewHolder.checkedTv.setText(dataList.get(position));
  40. // viewHolder.mTextView.setText(dataList.get(position));
  41. viewHolder.customCheckTextView.setTitle(dataList.get(position));
  42. return convertView;
  43. }
  44. }
  45.  
  46. static class ViewHolder {
  47. // TextView mTextView;
  48. // CheckedTextView checkedTv;
  49. CustomCheckTextView customCheckTextView;
  50. }

这样,通过上面的方法,你就可以去实现各种自己自定义好布局的多选或单选列表了。

ListView多选和单选模式重新整理的更多相关文章

  1. ListView多选操作模式详解CHOICE_MODE_MULTIPLE与CHOICE_MODE_MULTIPLE_MODAL

    这篇文章我们将详细的介绍如何实现ListView的多选操作,文中将会纠正在使用ListViewCHOICE_MODE_MULTIPLE或者CHOICE_MODE_MULTIPLE_MODAL时容易犯的 ...

  2. ListView多选操作模式——上下文操作模式

    1.什么叫上下文操作模式 2.如何进入上下文操作模式 1.ListView自身带了单选.多选模式,可通过listview.setChoiceMode来设置: listview.setChoiceMod ...

  3. easyui-datagrid单选模式下隐藏表头的全选框

    easyui-datagrid可以不使用复选框来进行单选,直接使用onSelect和 singleSelect:true就可以实现单选,但是有一些用户会比较习惯使用勾选框,这时会加一列checkbox ...

  4. Android实战之ListView复选框

    项目中有用到复选框的例子,啊啊......在网上查找有关资料,大多都是过于繁琐,所以自己决定写个这个方面的demo... 先给个效果图: 在ListView中添加复选框主要注意以下几个问题: 1.Li ...

  5. listview改变选中行字体颜色

    [android]listview改变选中行字体颜色 目标:选中item,其字体设置为#3197FF,未选中的,其字体为#FFFFFF 与listvew设置选中行item背景图片一样,使用select ...

  6. 【android】listview改变选中行背景图片

    [android]listview改变选中行背景图片 目标:当item选中时,改变其背景图片.效果图如下: 直接在listview的xml文件中使用listselector: 1 2 3 4 5 6 ...

  7. jq pagination分页 全选、单选的思考

    $().pagination(总条数,配置项); 后端分页的跨页选择: 思路:把浏览过的页整体保存为,整体拥有 curPage(当前页码).allChoice(当前页是否全选).selected当前页 ...

  8. [CSS]复选框单选框与文字对齐问题的研究与解决.

    前言:今天碰到的这个问题, 恰好找到一个很好的博文, 在这里转载过来 学习下. 原文地址:复选框单选框与文字对齐问题的研究与解决. 目前中文网站上面的文字,就我的个人感觉而言,绝大多数网站的主流文字大 ...

  9. ylbtech-数据库设计与优化-对作为复选框/单选列表的集合表的设计

    ylbtech-DatabaseDesgin:ylbtech-数据库设计与优化-对作为复选框/单选列表的集合表的设计 -- DatabaseName:通用表结构-- -- 主要是针对将要设计的表对象, ...

随机推荐

  1. 算法之美--1.蒙特卡洛方法计算pi

    基本思想: 利用圆与其外接正方形面积之比为pi/4的关系,通过产生大量均匀分布的二维点,计算落在单位圆和单位正方形的数量之比再乘以4便得到pi的近似值.样本点越多,计算出的数据将会越接近真识的pi(前 ...

  2. 【京东账户】——Mysql/PHP/Ajax爬坑之购物车列表分页

    一.引言 做京东账户项目中的购物车模块,功能之四就是购物车列表的分页显示.要用到的是Apach环境,Mysql.PHP以及Ajax. 二.查询数据 mysql: SELECT * FROM jd_pr ...

  3. T4模板编辑器

    一 二.工具  (T4模板编辑器) 使用效果 1.tangibleT4EditorPlusModellingToolsVS2013.msi 2.devart T4 Editor for Visual ...

  4. API接口管理工具postman等

    国外 postman Swagger:国外比较流行的一款管理工具,英文配置,需要一定的英文基础和服务器搭建基础,学习成本较高. 国内 Apizza: 风格类似postman,熟悉postman的会比较 ...

  5. Redis 在 Java 中的使用

    转:http://blog.csdn.net/jiangtao_st/article/details/8256610 一.下载jar包 https://github.com/xetorthio/jed ...

  6. wordpress账户防暴力破解攻击

    一.修改数据库表前缀 默认的表前缀是wp_,如果你安装博客的时候没有修改,可以参考这篇文章修改下表前缀. 修改完登录测试下,如果登录成功后提示“您没有足够的权限访问该页面”,说明前缀没有修改完整,参照 ...

  7. ext tree展开时的一些技巧

    加入子节点的时候.我们须要展开父节点.并选中刚加入好的节点. 这时候会有一个问题. 我用的ext-js-4.2起码有一种问题. 节点内部会混乱.要么多加一个. 要么层级会发生故障. 随后我发现一个窍门 ...

  8. Linux下MySQL定时按日期备份数据

    一.使用mysql内置命令 mysqldump Usage: mysqldump [OPTIONS] database [tables] mysqldump [OPTIONS] --databases ...

  9. Nginx绑定多个域名的方法

        nginx绑定多个域名可又把多个域名规则写一个配置文件里,也可又分别建立多个域名配置文件,我一般为了管理方便,每个域名建一个文件,有些同类域名也可又写在一个总的配置文件里.  一.每个域名一个 ...

  10. linux安装svn客户端subversion及使用方法

    1.下载 [maintain@HM16-213 software]$ wget http://subversion.tigris.org/downloads/subversion-deps-1.6.1 ...