热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

带checkbox的ListView实现

转载自:http:blog.csdn.netharvic880925articledetails41948211前言:看来总结的速度还是太慢了,要写博客的内容列表已经

转载自:http://blog.csdn.net/harvic880925/article/details/41948211


前言:看来总结的速度还是太慢了,要写博客的内容列表已经排到了六篇,但并不想为了写博客而写博客,还是想给大家推出高品质的博客,能尽量写的详细一点,工作上也是忙,只有每天晚上抽时间写出来。这篇文章是大家在实际开发中都会遇到的问题——如何实现checkableImageview,虽然大家用其它替代方法也能实现类似效果,但我觉得只有真正实现checkable接口的自定义控件才够正宗。下面在第二篇的基本上,改进工程;


相关文章:

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


本文效果:


本篇文章建立在第二篇《带checkbox的ListView实现(二)——自定义Checkable控件的实现方法》的基础之上,建议先把这第二篇先看一遍,因为里面涉及到整体架构和CheckableFrameLayout的实现,如果不看的话,估计这一篇是看不大懂的。


好啦,言规正转,当大家看完第二篇,应该会想,这一篇还不简单,直接仿照CheckableFrameLayout重新实现一个自定义控件呗。好,那我们就先仿照CheckableFrameLayout实现一个看看。

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

MainActivity布局依旧不变:

[html] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  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.checkableimageview.MainActivity" >  
  6.   
  7.     <ListView  
  8.         android:id="@+id/list"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:layout_marginBottom="100dp"  
  12.         android:choiceMode="multipleChoice"  
  13.         android:dividerHeight="1px"  
  14.         android:scrollbars="none" />  
  15.       
  16.     <Button android:id="@+id/all_sel"  
  17.         android:layout_width="fill_parent"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_marginBottom="50dip"  
  20.         android:layout_gravity="bottom"  
  21.         android:text="全选"  
  22.         />  
  23.     <Button android:id="@+id/all_unsel"  
  24.         android:layout_width="fill_parent"  
  25.         android:layout_height="wrap_content"  
  26.         android:layout_gravity="bottom"  
  27.         android:text="全部取消"/>  
  28. FrameLayout>  
 
 

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

先看看布局代码:

[html] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. xml version="1.0" encoding="utf-8"?>  
  2. <com.harvic.checkableimageview.CheckableFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="68dp" >  
  5.   
  6.     <com.harvic.checkableimageview.CheckableImageView  
  7.         android:layout_gravity="right|center_vertical"  
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content"  
  10.         android:layout_alignParentRight="true"  
  11.         android:layout_centerVertical="true"  
  12.         android:layout_marginRight="10dp"  
  13.         android:clickable="false"  
  14.         android:src="@drawable/toggle" />  
  15.   
  16.     <LinearLayout  
  17.         android:layout_width="match_parent"  
  18.         android:layout_height="match_parent"  
  19.         android:layout_marginBottom="17dp"  
  20.         android:layout_marginTop="17dp"  
  21.         android:orientation="vertical" >  
  22.   
  23.         <TextView  
  24.             android:id="@+id/title"  
  25.             android:layout_width="wrap_content"  
  26.             android:layout_height="wrap_content"  
  27.             android:textSize="16sp" />  
  28.   
  29.         <TextView  
  30.             android:id="@+id/subtitle"  
  31.             android:layout_width="wrap_content"  
  32.             android:layout_height="wrap_content"  
  33.             android:textSize="12sp" />  
  34.     LinearLayout>  
  35.   
  36. com.harvic.checkableimageview.CheckableFrameLayout>  



    

    

        

        
    

这里除了使用CheckableFrameLayout,另外把第二篇中的Checkbox换成了自定义的CheckableImageView, 其实整篇文章跟第二篇相比,什么都没有变,只是这里把checkbox换成了自定义的CheckableImageView。
我单独把CheckableImageView的代码拿出来:

[html] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. <com.harvic.checkableimageview.CheckableImageView  
  2.     android:layout_gravity="right|center_vertical"  
  3.     android:layout_width="wrap_content"  
  4.     android:layout_height="wrap_content"  
  5.     android:layout_alignParentRight="true"  
  6.     android:layout_centerVertical="true"  
  7.     android:layout_marginRight="10dp"  
  8.     android:clickable="false"  
  9.     android:src="@drawable/toggle" />  
    
因为我们要让它显示图片的不同状态,所以CheckableImageVIew应该派生于ImageVIew,也就是说它是一个ImageView的派生类,所以它具有src属性,它指向听toggle.xml是一个selector,在不同状态下选择不同的图片显示:

[html] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. <selector android:constantSize="true" android:variablePadding="false" xmlns:android="http://schemas.android.com/apk/res/android">  
  2.     <item android:drawable="@drawable/toggle_on"  android:state_checked="true"/>  
  3.     <item android:drawable="@drawable/toggle_off" android:state_checked="false"/>  
  4.     <item android:drawable="@drawable/toggle_off"/>  
  5. selector>  

    
    
    
好啦,下面就是CheckableImageView的实现了

我们仿照CheckableFrameLayout实现Checkable接口,又因为CheckableImageView要显示图片,所以又要派生自ImageView,所以代码如下:

[Javascript] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. public class CheckableImageView extends ImageView implements Checkable{  
  2.   
  3.     /** @param context 
  4.      * @param attrs */  
  5.     public CheckableImageView(Context context, AttributeSet attrs) {  
  6.         super(context, attrs);  
  7.         // TODO Auto-generated constructor stub  
  8.     }  
  9.       
  10.     private boolean mChecked = false;  
  11.     @Override  
  12.     public void setChecked(boolean checked) {  
  13.         // TODO Auto-generated method stub  
  14.         if (mChecked != checked) {  
  15.             mChecked = checked;  
  16.             refreshDrawableState();  
  17.         }  
  18.     }  
  19.   
  20.     @Override  
  21.     public boolean isChecked() {  
  22.         // TODO Auto-generated method stub  
  23.         return mChecked;  
  24.     }  
  25.   
  26.     @Override  
  27.     public void toggle() {  
  28.         // TODO Auto-generated method stub  
  29.         setChecked(!mChecked);  
  30.     }  
  31.   
  32. }  
public class CheckableImageView extends ImageView implements Checkable{

	/** @param context
	 * @param attrs */
	public CheckableImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	
	private boolean mChecked = false;
	@Override
	public void setChecked(boolean checked) {
		// TODO Auto-generated method stub
		if (mChecked != checked) {
			mChecked = checked;
			refreshDrawableState();
		}
	}

	@Override
	public boolean isChecked() {
		// TODO Auto-generated method stub
		return mChecked;
	}

	@Override
	public void toggle() {
		// TODO Auto-generated method stub
		setChecked(!mChecked);
	}

}
其它部分(MainActivity、ListItemAdapter)都不变,这里就不再列代码了,没什么意义,看看效果:


没效果!!!!!为什么会这样!!!!!!!!
放用户点击某个Item的时候,我们明明设置了SetChecked()了啊,在SetChecked()内部:

[java] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. public void setChecked(boolean checked) {  
  2.     // TODO Auto-generated method stub  
  3.     if (mChecked != checked) {  
  4.         mChecked = checked;  
  5.         refreshDrawableState();  
  6.     }  
  7. }  
public void setChecked(boolean checked) {
	// TODO Auto-generated method stub
	if (mChecked != checked) {
		mChecked = checked;
		refreshDrawableState();
	}
}
会将状态设为checked并且调用refreshDrawableState()来刷新Drawable状态的啊,在刷新状态时,会调用我们的Selector:

[html] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. <item android:drawable="@drawable/toggle_on"  android:state_checked="true"/>  
注意!!!!!这里有个问题!!!!!我们的ImageView控件并不像Checkbox一样有state_cheked(选中)状态,所以我们给他设置android:state_checked="true"标签让它自已匹配选中状态是没用的!!!!!因为它根本没有选中状态。那问题来了,我们怎么样能让ImageView具有选中状态呢。当他有了选中状态以后,那么state_checked标签就有用了。所以下面我们就想方设法让它具有选中状态。
首先,我们可以重写onCreateDrawableState函数,来指定控件所具有的状态。即当控件在获取自己所应具有的状态时,会调用onCreateDrawableState(int extraSpace)方法,其定义如下:

[java] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. public int[] onCreateDrawableState(int extraSpace){  
  2. }  
public int[] onCreateDrawableState(int extraSpace){
}
int extraSpace:代表额外的空间,即如果为0,即代表用户不再另外指定属性,直接返回本身所具有的控件状态集。如果不为0,多余的位置就可以用来放置自定义的状态,使该Drawable具有我们添加的属性。

返回值:如果extraSpace为0,直接返回控件本身所具有的状态集。如果extraSpace不为0,返回的值除了具有控件本身所具有的状态集,会额外分配指定的空间以便用户自主指定状态。

下面看看我们重写onCreateDrawableState()的完整代码:

[java] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. int[] CHECKED_STATE_SET = { android.R.attr.state_checked };  
int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
android.R.attr.state_checked:指示控件已经选中时的状态,如果给控件指定这个属性,就代表控件就已经选中,会调用selector里的android:state_checked="true"来加载它的显示图片。

[java] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public int[] onCreateDrawableState(int extraSpace) {  
  3.     final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);  
  4.     if (isChecked()) {  
  5.         mergeDrawableStates(drawableState, CHECKED_STATE_SET);  
  6.     }  
  7.     return drawableState;  
  8. }  
@Override
public int[] onCreateDrawableState(int extraSpace) {
	final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
	if (isChecked()) {
		mergeDrawableStates(drawableState, CHECKED_STATE_SET);
	}
	return drawableState;
}
首先:

[java] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);  
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
获取控件本身所具有的状态,并且我们要另开一个位置存放android.R.attr.state_checked状态,所以要加1;

然后,当控件被选中的时候,我们要给它添加上被选中的状态,让它调用selector里的Android:state_checked="true"来加载当前选中时的图片。

所以完整的代码应该是这样的:

[java] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. public class CheckableImageView extends ImageView implements Checkable{  
  2.   
  3.     /** @param context 
  4.      * @param attrs */  
  5.     public CheckableImageView(Context context, AttributeSet attrs) {  
  6.         super(context, attrs);  
  7.         // TODO Auto-generated constructor stub  
  8.     }  
  9.       
  10.     private boolean mChecked = false;  
  11.     private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };  
  12.   
  13.   
  14.     @Override  
  15.     public int[] onCreateDrawableState(int extraSpace) {  
  16.         final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);  
  17.         if (isChecked()) {  
  18.             mergeDrawableStates(drawableState, CHECKED_STATE_SET);  
  19.         }  
  20.         return drawableState;  
  21.     }  
  22.       
  23.     @Override  
  24.     public void setChecked(boolean checked) {  
  25.         // TODO Auto-generated method stub  
  26.         if (mChecked != checked) {  
  27.             mChecked = checked;  
  28.             refreshDrawableState();  
  29.         }  
  30.     }  
  31.   
  32.     @Override  
  33.     public boolean isChecked() {  
  34.         // TODO Auto-generated method stub  
  35.         return mChecked;  
  36.     }  
  37.   
  38.     @Override  
  39.     public void toggle() {  
  40.         // TODO Auto-generated method stub  
  41.         setChecked(!mChecked);  
  42.     }  
  43.   
  44. }  
public class CheckableImageView extends ImageView implements Checkable{

	/** @param context
	 * @param attrs */
	public CheckableImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	
	private boolean mChecked = false;
	private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };


	@Override
	public int[] onCreateDrawableState(int extraSpace) {
		final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
		if (isChecked()) {
			mergeDrawableStates(drawableState, CHECKED_STATE_SET);
		}
		return drawableState;
	}
	
	@Override
	public void setChecked(boolean checked) {
		// TODO Auto-generated method stub
		if (mChecked != checked) {
			mChecked = checked;
			refreshDrawableState();
		}
	}

	@Override
	public boolean isChecked() {
		// TODO Auto-generated method stub
		return mChecked;
	}

	@Override
	public void toggle() {
		// TODO Auto-generated method stub
		setChecked(!mChecked);
	}

}
附:

android.R.attr.state_checked 的官方说明是这样的:
State identifier indicating that the object is currently checked. See state_checkable for an additional identifier that can indicate if any object may ever display a check,regardless of whether state_checked is currently set. Must be a boolean value, either "true" or "false". This may also be a reference to a resource (in the form "@[package:]type:name") or  theme attribute (in the form "?[package:][type:]name") containing a value of this type. 

CheckableImageView总结:

(1)CheckableImageView执行流程:setChecked -> refreshDrawableState ->onCreateDrawableState ->调用selector设置状态

(2)CheckableImageView派生自Checkable接口,使CheckableImageView具有的可选中的状态,但当用户点击选中时,我们感觉会调用selector的state_checked="true"的状态,但state_checked属性对ImageView是无效的,因为ImageView并不具有可选中的属性,所以我们在调用selector前,应该为ImageView添加上state_checked属性这就是重写onCreateDrawableState()的原因,当用户选中时,给ImageView设置选中状态,强制使它处于选中状态中,这时,它就会调用我们的state_checked属性

OK啦,本文就到了,这里只列出来了改变的部分,大家参考源码看一下吧。


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

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

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


推荐阅读
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • IOS Run loop详解
    为什么80%的码农都做不了架构师?转自http:blog.csdn.netztp800201articledetails9240913感谢作者分享Objecti ... [详细]
  • 本文介绍如何在 Android 中自定义加载对话框 CustomProgressDialog,包括自定义 View 类和 XML 布局文件的详细步骤。 ... [详细]
  • Android开发技巧:使用IconFont减少应用体积
    本文介绍如何在Android应用中使用IconFont来显示图标,从而有效减少应用的体积。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文详细解析了 Yii2 框架中视图和布局的各种函数,并综述了它们在实际开发中的应用场景。通过深入探讨每个函数的功能和用法,为开发者提供了全面的参考,帮助他们在项目中更高效地利用这些工具。 ... [详细]
  • 【问题】在Android开发中,当为EditText添加TextWatcher并实现onTextChanged方法时,会遇到一个问题:即使只对EditText进行一次修改(例如使用删除键删除一个字符),该方法也会被频繁触发。这不仅影响性能,还可能导致逻辑错误。本文将探讨这一问题的原因,并提供有效的解决方案,包括使用Handler或计时器来限制方法的调用频率,以及通过自定义TextWatcher来优化事件处理,从而提高应用的稳定性和用户体验。 ... [详细]
  • 在Android开发中,当TextView的高度固定且内容超出时,可以通过设置其内置的滚动条属性来实现垂直滚动功能。具体来说,可以通过配置`android:scrollbars="vertical"`来启用垂直滚动,确保用户能够查看完整的内容。此外,为了优化用户体验,建议结合`setMovementMethod(ScrollerMovementMethod.getInstance())`方法,使滚动操作更加流畅和自然。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 在Android开发中,实现多点触控功能需要使用`OnTouchListener`监听器来捕获触摸事件,并在`onTouch`方法中进行详细的事件处理。为了优化多点触控的交互体验,开发者可以通过识别不同的触摸手势(如缩放、旋转等)并进行相应的逻辑处理。此外,还可以结合`MotionEvent`类提供的方法,如`getPointerCount()`和`getPointerId()`,来精确控制每个触点的行为,从而提升用户操作的流畅性和响应性。 ... [详细]
author-avatar
叮叮当叮叮当叮叮当_212
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有