【转】带checkbox的ListView实现(二)——自定义Checkable控件的实现方法

原文网址:http://blog.csdn.net/harvic880925/article/details/40475367

前言:前一篇文章给大家展示了传统的Listview的写法,但有的时候我们并不想在DataHolder类中加一个标识是否选中的checked的成员变量,因为在项目开发中,大部分的ListItemLayout布局都是大家共用的,有些人根本不需要checkbox控件,所以会在初始化的时候把这个控件给隐藏掉,但我们的DataHolder在构造的时候以及ListItemAdapter在渲染的时候都需要checked变量,这就有点坑了,所以要想办法能让checkbox不与数据相关联,可能我说到这大家都不大明白我在说什么,其实我也感觉我没讲明白,没关系,往下看,等这篇文章看完之后,如果还没明白,那就给我留言吧。

相关文章:

1、《带checkbox的ListView实现(一)——数据与渲染完全分离的传统实现方式》
2、《带checkbox的ListView实现(二)——自定义Checkable控件的实现方法》
3、《带checkbox的ListView实现(三)——CheckableImageView的实现方法》

同样,还是先给大家看看效果图:(与上篇的效果一样,其实我就是用的上一篇的效果图

同样,我们还是从布局开始讲。

一、activity_main.xml ——MainActivity布局文件

[html] view plaincopy

  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context="com.harvic.trylistviewcheckbox.MainActivity" >
  6. <ListView
  7. android:id="@+id/list"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:layout_marginBottom="100dp"
  11. android:choiceMode="multipleChoice"
  12. android:dividerHeight="1px"
  13. android:scrollbars="none" />
  14. <Button android:id="@+id/all_sel"
  15. android:layout_width="fill_parent"
  16. android:layout_height="wrap_content"
  17. android:layout_marginBottom="50dip"
  18. android:layout_gravity="bottom"
  19. android:text="全选"
  20. />
  21. <Button android:id="@+id/all_unsel"
  22. android:layout_width="fill_parent"
  23. android:layout_height="wrap_content"
  24. android:layout_gravity="bottom"
  25. android:text="全部取消"/>
  26. </FrameLayout>

注意啦:

这里的布局是与上一篇一样一样的,一个ListView两个按钮。但这里有个参数必须要添加:

在ListView中:

[html] view plaincopy

  1. android:choiceMode="multipleChoice"

这个很重要,android:choiceMode中有三个取值:none、singleChoice、multipleChoice;分别代表:不可选择,单选和多选。在这里,不同的取值对ListView的影响是不一样的,但这个影响仅对ListView的Item自己带有checkable属性时才起作用,对于没有checkable属性的ListView是没有任何效果的,比如,你把android:choiceMode这个参数放在上篇的代码中,无论你取什么值都没有任何作用,具体为什么,下面再讲。

二、check_list_item.xml —— 单个Item布局

[html] view plaincopy

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.harvic.trylistviewcheckbox.CheckableFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="68dp">
  5. <CheckBox
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"
  8. android:layout_gravity="right|center_vertical"
  9. android:button="@drawable/checkbox_selector"
  10. android:clickable="false"
  11. android:focusable="false" />
  12. <LinearLayout
  13. android:layout_width="match_parent"
  14. android:layout_height="match_parent"
  15. android:layout_marginBottom="17dp"
  16. android:layout_marginTop="17dp"
  17. android:orientation="vertical">
  18. <TextView
  19. android:id="@+id/title"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"
  22. android:textSize="16sp" />
  23. <TextView
  24. android:id="@+id/subtitle"
  25. android:textSize="12sp"
  26. android:layout_width="wrap_content"
  27. android:layout_height="wrap_content" />
  28. </LinearLayout>
  29. </com.harvic.trylistviewcheckbox.CheckableFrameLayout>

这里与上一篇有两个地方不同:

1、很明显,使用的自定义控件CheckableFrameLayout;

2、CheckBox控件没有定义ID值,如果根据上一篇的方式,大家可能会打个问号,没有ID怎么获取这个控件,又怎么让它显示选中与不选中呢。
下面看看自定义的控件类CheckableFrameLayout的实现:

[java] view plaincopy

  1. package com.harvic.trylistviewcheckbox;
  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.view.View;
  5. import android.widget.Checkable;
  6. import android.widget.FrameLayout;
  7. public class CheckableFrameLayout extends FrameLayout implements Checkable {
  8. public CheckableFrameLayout(Context context, AttributeSet attrs) {
  9. super(context, attrs);
  10. }
  11. private boolean mChecked = false;
  12. @Override
  13. public void toggle() {
  14. setChecked(!mChecked);
  15. }
  16. @Override
  17. public boolean isChecked() {
  18. return mChecked;
  19. }
  20. @Override
  21. public void setChecked(boolean checked) {
  22. if (mChecked != checked) {
  23. mChecked = checked;
  24. refreshDrawableState();
  25. for (int i = 0, len = getChildCount(); i < len; i++) {
  26. View child = getChildAt(i);
  27. if(child instanceof Checkable){
  28. ((Checkable) child).setChecked(checked);
  29. }
  30. }
  31. }
  32. }
  33. }

因为我们用到的是FrameLayout控件,所以这里派生自FrameLayout,如果用到诸如LinearLayout,RelativeLayout控件等,就要改成对应的类。最后还继承了Checkable接口;

FrameLayout没什么好讲的,就是帧布局。关键问题在于Checkable接口,凡实现这个接口的控件都将具有可选中状态的属性;在普通控件中,具有这个状态的有:CheckBox, CheckedTextView, CompoundButton, RadioButton, ToggleButton等。(《Android 中文API (33) —— Checkable》)对于如何展示它的选中状态需要用户自主实现三个函数:isChecked(),toggle(),setChecked();也就是说,当用户使用ListView.setItemChecked(int position,bool checked)函数来将指定的Item设为Checked标识时,就会自动调用这里的SetChecked()函数。在代码中,我们如何设计,用户界面就会显示怎样的选中状态;

把SetChecked()函数单独拿出来看看:

[java] view plaincopy

  1. public void setChecked(boolean checked) {
  2. if (mChecked != checked) {
  3. mChecked = checked;
  4. refreshDrawableState();
  5. for (int i = 0, len = getChildCount(); i < len; i++) {
  6. View child = getChildAt(i);
  7. if(child instanceof Checkable){
  8. ((Checkable) child).setChecked(checked);
  9. }
  10. }
  11. }
  12. }

由于CheckableFrameLayout在ListItem的布局中有三个控件,两个TextView和一个checkbox;所以当用户设置点击属性时,我们要将CheckableFrameLayout的子控件checkbox根据传进来的checked参数更改当前的状态,所以对它下面的所有子控件进行轮循,因为checkbox是具有checkable属性的,所以如果此控件具有checkable属性说明肯定会checkbox,就将它设置为用户指定的checked状态;

三、ViewHolder——ListItem对应的视图类

[java] view plaincopy

  1. public class ViewHolder{
  2. public TextView mTitle;
  3. public TextView mSubTitile;
  4. };

注意,这里没有了checkbox控件所对应的mCheckBox对象;

四、DataHolder——ListItem对应的数据类

[java] view plaincopy

  1. package com.harvic.trylistviewcheckboxdata;
  2. public class DataHolder{
  3. public String titleStr;
  4. public String subTitleStr;
  5. public DataHolder(String title,String subTitle){
  6. titleStr = title;
  7. subTitleStr = subTitle;
  8. }
  9. }

同样,这里有标识主标题文字的titleStr和标识副标题的subTitleStr;但没有了标识选中状态的checked变量,因为我们的控件选中的处理是listviewItem自己完成的。

五、ListItemAdapter

同样,先列出全部代码,然后再看看有什么不同。

[java] view plaincopy

  1. package com.harvic.trylistviewcheckbox;
  2. import java.util.List;
  3. import com.example.trylistviewcheckbox.R;
  4. import android.content.Context;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.BaseAdapter;
  9. import android.widget.TextView;
  10. public class ListitemAdapter extends BaseAdapter {
  11. private List<DataHolder> mList;
  12. private Context mContext;
  13. private LayoutInflater mInflater;
  14. public ListitemAdapter(Context context,List<DataHolder> list){
  15. mList = list;
  16. mContext = context;
  17. mInflater = LayoutInflater.from(context);
  18. }
  19. @Override
  20. public int getCount() {
  21. // TODO Auto-generated method stub
  22. return mList.size();
  23. }
  24. @Override
  25. public Object getItem(int position) {
  26. // TODO Auto-generated method stub
  27. return mList.get(position);
  28. }
  29. @Override
  30. public long getItemId(int position) {
  31. // TODO Auto-generated method stub
  32. return position;
  33. }
  34. @Override
  35. public View getView(int position, View convertView, ViewGroup parent) {
  36. // TODO Auto-generated method stub
  37. ViewHolder holder = null;
  38. if (convertView == null) {
  39. holder=new ViewHolder();
  40. convertView = mInflater.inflate(R.layout.check_list_item, null);
  41. holder.mTitle = (TextView)convertView.findViewById(R.id.title);
  42. holder.mSubTitile = (TextView)convertView.findViewById(R.id.subtitle);
  43. convertView.setTag(holder);
  44. }else {
  45. holder = (ViewHolder)convertView.getTag();
  46. }
  47. holder.mTitle.setText((String)mList.get(position).titleStr);
  48. holder.mSubTitile.setText((String)mList.get(position).subTitleStr);
  49. return convertView;
  50. }
  51. }

在渲染等等上基本一样,唯一不同之处在于没有了对checkbox控件的处理。

六、 MainActivity

先看看MainActivity的全部代码,然后慢慢讲。

[java] view plaincopy

  1. package com.harvic.trylistviewcheckbox;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import com.example.trylistviewcheckbox.R;
  5. import android.app.Activity;
  6. import android.os.Bundle;
  7. import android.view.Menu;
  8. import android.view.MenuItem;
  9. import android.view.View;
  10. import android.widget.Button;
  11. import android.widget.ListView;
  12. public class MainActivity extends Activity {
  13. @Override
  14. protected void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.activity_main);
  17. //构造数据
  18. final List<DataHolder> dataList = new ArrayList<DataHolder>();
  19. for(int i=0;i<10;i++){
  20. dataList.add(new DataHolder("harvic的blog------"+i,"harvic"));
  21. }
  22. //构造Adapter
  23. ListitemAdapter adapter = new ListitemAdapter(MainActivity.this, dataList);
  24. final ListView listView = (ListView)findViewById(R.id.list);
  25. listView.setAdapter(adapter);
  26. //全部选中按钮的处理
  27. Button all_sel = (Button)findViewById(R.id.all_sel);
  28. Button all_unsel = (Button)findViewById(R.id.all_unsel);
  29. all_sel.setOnClickListener(new View.OnClickListener() {
  30. @Override
  31. public void onClick(View v) {
  32. // TODO Auto-generated method stub
  33. for(int i=0;i<dataList.size();i++){
  34. listView.setItemChecked(i, true);
  35. }
  36. }
  37. });
  38. //全部取消按钮处理
  39. all_unsel.setOnClickListener(new View.OnClickListener() {
  40. @Override
  41. public void onClick(View v) {
  42. // TODO Auto-generated method stub
  43. for(int i=0;i<dataList.size();i++){
  44. listView.setItemChecked(i, false);
  45. }
  46. }
  47. });
  48. }
  49. }

先看一下处理步骤:构造数据-》构造Adapter并设置

但!但!但!没有listView.setOnItemClickListener()的设置!!!!!!!!!!!

到这里大家可能要疑问了,为什么没有设计ItemClick的设置,它依然能处理checkbox的事件响应呢?当然是因为我们前面让自定义的CheckableFrameLayout具有了标识可以选中状态的Checkable接口,所以ListView的每一个Item现在都具有Checkbox的点击属性,换句话说,我们的CheckableFrameLayout其实就是扩展的Checkbox控件!当然也可以对ListView设置OnItemClick事件监听,用以处理Item项点击事件;

再看看全选按钮的实现:

[java] view plaincopy

  1. all_sel.setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. // TODO Auto-generated method stub
  5. for(int i=0;i<dataList.size();i++){
  6. listView.setItemChecked(i, true);
  7. }
  8. }
  9. });

因为我们的每个ListViewItem都具有Checkable属性,所以调用ListView的setItemChecked()函数是有作用的,如果我们的ListviewItem不具有Checkable属性,那么无论你怎么调用SetItemChecked函数都不会起什么效果!

全部取消也很简单了,同样是轮循所有的Item,然后把利用SetItemChecked(i,false)即可。

七、附:获取所有选中行的行号

上面,我们基本实现了自定义控件实现自动选中checkbox的功能,但有时,我们在选中后,更需要知道,我们都选中了哪些,下面的代码就实现了这个功能:其中position就是获取到了当前选中行的position

[java] view plaincopy

  1. SparseBooleanArray checkedArray = mListView.getCheckedItemPositions();
  2. for (int i = 0; i < checkedArray.size(); i++) {
  3. if (checkedArray.valueAt(i)){
  4. ……//i就是选中的行号
  5. }
  6. }

OK啦 ,到这就全部讲完了,对于自定义控件的这部分涉及的到东东比较多,不知道大家理解的怎么样,如果有哪部分没理解的话,在评论中回复下,我再修改内容。或许能直接给出应该怎么组织本文的建议就更好不过了,谢谢。

如果本文有帮到你,记得加关注哦!

源码下载地址:http://download.csdn.net/detail/harvic880925/8083133

请大家尊重原创者版权,转载请标明出处哦:http://blog.csdn.net/harvic880925/article/details/40475367  谢谢!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-02 01:25:21

【转】带checkbox的ListView实现(二)——自定义Checkable控件的实现方法的相关文章

arcgis api for js共享干货系列之二自定义Navigation控件样式风格

arcgis api for js默认的Navigation控件样式风格如下图: 这样的风格不能说不好,各有各的爱好,审美观,这里也不是重点,这里的重点是如何自定义一套自己喜欢的样式风格呢:自己自定义一个NavigationControl控件类,最终实现的效果如下图: 思路如下:其实就是在网上参照天地图或者谷歌地图的Navigation风格样式,下载它们的图片模版,然后自己创建div来实现图片的缩放平移.全图.左右上下平移等等地图导航功能: Navigation图片目录如下: 调用函数: //显

自定义View控件(手写,xib)须知

 1. 目的 :提高代码的复用性,屏蔽内部的实现细节 2. 步骤 :    * 1> 自定义一个类继承于UIView   * 2> 在initWithFrame方法中添加子控件   * 3> 在layoutSubviews中设置子控件的位置   * 4> 提供一个属性保存外界传入的数据(模型对象), 重写setter方法设置子控件的数据 3. 类工厂方法(便利构造器):   * 按照苹果的风格和规范, 一般情况一个用于创建对象的对象方法会对应一个类方法   * 可以通过类工厂方法,

自定义ComboBox控件,完美解决C#自带的ComboBox效率慢的问题

自定义ComboBox控件,完美解决C#自带的ComboBox效率慢的问题 欢迎关注http://blog.csdn.net/aaa123524457 转载请注明出处:http://blog.csdn.net/aaa123524457/article/details/47058675 在做项目的时候,用到了ComboBox来做下拉列表的功能:但是在用的时候发现C#自带的ComboBox效率非常的慢! 当然我添加的是股票.期货的合约数据,大概有几千条信息,算是比较大的.如果用到的数据很少,就可以直

Android自定义用户控件简单范例(二)

对于完全由后台定制的控件,并不是很方便其他人的使用,因为我们常常需要看到控件放到xml界面上的效果,并根据效果进行布局的调整,这就需要一个更加标准的控件制作流程: 我们的自定义控件和其他的控件一样,应该写成一个类,而这个类的属性是是有自己来决定的. 我们要在res/values目录下建立一个attrs.xml的文件,并在此文件中增加对控件的属性的定义. 使用AttributeSet来完成控件类的构造函数,并在构造函数中将自定义控件类中变量与attrs.xml中的属性连接起来. 在自定义控件类中使

自定义组合控件,适配器原理-Day31

自定义组合控件,适配器原理-Day31 mobile2.1 主页定义 手机上锁功能 1.弹出设置密码框. 手机下载进度 自定定义控件 控件的属性其实就是控件类一个属性设置属性调用类的set方法方法, 自定义组合控件的思路 生命一个View对象继承自相对布局,线性布局或者其他的ViewGroup 在View对象重写构造方法,然后初始化布局,通过View.inflate()方法把我们自己定义的布局挂到界面当中. 自定义属性在res/values目录下创建attrs.xml里面定义一些属性, <res

Android自定义组合控件的实现

需求:在黑马做安全卫士的时候,功能9设置中心界面如下: 在点击item的时候,复选框会反转状态,同时"自动更新已经关闭"会变换内容和颜色. 可以发现这个界面类似ListView,但又不是ListView,因为它的item数量是固定的,且最后一 item和之前的都不一样.虽然这个看着像是标准的List结构,实则每个item不是完全一样,因为 每个item的提示文本(如"自动更新已经关闭")的内容并不完全一样. 假如用一般方式来布局的话,4个item就会有3*4 = 1

Android实例-手机安全卫士(七)-自定义组合控件

一.目标. 将多个系统控件(TextView.Button.CheckBox等)组合成一个自定义的控件,并像系统控件一样使用.如图所示第1个自动更新控件是根据相对布局放置而成的,第2个自动更新控件即为自定义组合控件,它可以想一般的TextView等系统控件一样重复使用. 自定义控件如图: 二.代码实现. 1.在layout文件夹下新建一个xml文件(取名model_setting_item.xml),用于保存自定义控件的布局. 2.在新建的xml文件(model_setting_item.xml

android 自定义组合控件

自定义控件是一些android程序员感觉很难攻破的难点,起码对我来说是这样的,但是我们可以在网上找一些好的博客关于自定义控件好好拿过来学习研究下,多练,多写点也能找到感觉,把一些原理弄懂,今天就讲下自定义组合控件,这个特别适合在标题栏或者设置界面,看下面图: 就非常适合使用组合控件了,现在写一个玩玩: activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

iOS开发UI篇—Quartz2D(自定义UIImageView控件)

一.实现思路 Quartz2D最大的用途在于自定义View(自定义UI控件),当系统的View不能满足我们使用需求的时候,自定义View. 使用Quartz2D自定义View,可以从模仿系统的ImageView的使用开始. 需求驱动开发:模仿系统的imageview的使用过程 1.创建 2.设置图片 3.设置frame 4.把创建的自定义的view添加到界面上(在自定义的View中,需要一个image属性接收image图片参数->5). 5.添加一个image属性(接下来,拿到image之后,应