`

自定义控件 — 创建Checkable ImageButton

阅读更多
创建自定义控件根据控件的需求主要有一下几种方案:

1、如果现有的控件已经具备了你想要的功能,那么修改或者扩展它们的外观或行为。通过override事件处理函数和onDraw,仍然调用父类的方法,在你定制控件时就不需要重新实现它的功能。
2、组合控件来创建原子的、可重用的widgets,它会引发一些相互关联的控件的功能性发生变化。例如,你可以创建一个下拉的combobox,通过组合一个TextView和一个Button,当点击Button时,显示一个浮动的ListView。

3、当你需要一个完全不同的界面,而不能通过改变和组合现有的控件来达到的时候,选择创建一个全新的控件。

CheckableImageButton

Android自带的ImageButton是不支持像CheckBox, RadioButton拥有的check(选中)状态的,Android提供的组件还算丰富,我们能用这些组件快速开发一个简单的应用程序,但在比较复杂项目中就会感觉捉襟见肘了,但幸好在Android系统上开发者能自由定制自己的UI组件,来弥补现有组件的不足。

创建一个CheckableImageButton需要做的工作:

1. 添加资源文件 res/values/attrs.xml,添加自定义组件CheckableImageButton,声明is_checked和personality属性,以后就能通过这两个属性在XML文件中指定相关属性的值。

<?xml version="1.0" encoding="utf-8"?>
<resources>    
	<!-- custom checkable imageButton -->    
	<declare-styleable name="CheckableImageButton">        
		<attr name="is_checked" format="boolean"/>        
		<attr name="personality">            
			<enum name="radio" value="0"/>            
			<enum name="check" value="1"/>        
		</attr>    
	</declare-styleable>
</resources> 

2. 创建ImageButton的背景,使用Selector Drawable。

<?xml version="1.0" encoding="UTF-8"?>
<selector  xmlns:android="http://schemas.android.com/apk/res/android"  
	xmlns:jimi="http://schemas.android.com/apk/res/com.seclock.jimi">  
	<item android:state_pressed="true" android:drawable="@drawable/transparent"  />  
	<item jimi:is_checked="true" android:drawable="@drawable/checkable_image_btn_state_checked"  />  
	<item android:drawable="@drawable/transparent"  />
</selector> 

jimi:is_checked="true"是(1)中自定义的属性

3. 创建布局文件,可以指定自定义属性的值。
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:jimi="http://schemas.android.com/apk/res/com.seclock.jimi"    
	android:layout_width="fill_parent"    
	android:layout_height="fill_parent">    
	<you.package.name.CheckableImageButton        
	android:layout_width="fill_parent"        
	android:layout_height="fill_parent"        
	jimi:is_check="true"        
	jimi:personality="radio"    
	/>
</LinearLayout> 


4. 创建自定义类,继承至ImageButton。让自定义类有ImageButton的所有功能。在构造方法中通过TypedArray读取自定义属性的值。

5. 实现Checkable接口。

接口如下:

/**     
* Change the checked state of the view     
*      
* @param checked The new checked state     
*/    
void setChecked(boolean checked);            
/**     
* @return The current checked state of the view     
*/    
boolean isChecked();        
/**     
* Change the checked state of the view to the inverse of its current state     
*     
*/    
void toggle(); 

自定义类全部代码:

public class CheckableImageButton extends ImageButton implements Checkable {
	private static final String DEBUG_TAG = CheckableImageButton.class
			.getSimpleName();

	private static final int PERSONALITY_RADIO_BUTTON = 0;
	private static final int PERSONALITY_CHECK_BUTTON = 1;
	private static final int[] CHECKED_STATE_SET = { R.attr.checked };

	private boolean mChecked;
	private int personality;
	private boolean mBroadcasting;
	private OnCheckedChangeListener mOnCheckedChangeListener;

	public CheckableImageButton(Context context) {
		super(context);
	}

	public CheckableImageButton(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);
	}

	public CheckableImageButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 获取自定义属性的值
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.checkedImageButton);
		mChecked = a.getBoolean(R.styleable.checkedImageButton_checked, false);
		personality = a.getInt(R.styleable.checkedImageButton_personality,
				PERSONALITY_RADIO_BUTTON);
		setChecked(mChecked);
		// Give back a previously retrieved StyledAttributes, for later re-use.
		a.recycle();
	}

	@Override
	public boolean performClick() {
		// 拦截点击事件处理check
		if (personality == PERSONALITY_CHECK_BUTTON) {
			toggle();
		} else if (personality == PERSONALITY_RADIO_BUTTON) {
			setChecked(true);
		}
		return super.performClick();
	}

	@Override
	public void setChecked(boolean checked) {
		Log.d(DEBUG_TAG, "setChecked:" + checked);
		if (mChecked != checked) {
			mChecked = checked;
			// 状态改变刷新视图
			refreshDrawableState();
		}
		if (mBroadcasting) {
			return;
		}
		mBroadcasting = true;
		if (null != mOnCheckedChangeListener) {
			mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
		}
		mBroadcasting = false;
	}

	@Override
	public boolean isChecked() {
		return mChecked;
	}

	@Override
	public void toggle() {
		setChecked(!mChecked);
	}

	@Override
	public int[] onCreateDrawableState(int extraSpace) {
		int[] states = super.onCreateDrawableState(extraSpace + 1);
		if (isChecked()) {
			mergeDrawableStates(states, CHECKED_STATE_SET);
		}
		return states;
	}

	@Override
	protected void drawableStateChanged() {
		super.drawableStateChanged();
		// invalidate();
	}

	public static interface OnCheckedChangeListener {
		/**
		 * interface definition for a callback to be invoked when the checked
		 * image button changed
		 * 
		 * @param button
		 * @param isChecked
		 * */
		public void onCheckedChanged(CheckableImageButton button,
				boolean isChecked);
	}

	/**
	 * @Title: 保存状态.
	 * @author Anders
	 */
	static class SaveState extends BaseSavedState {
		boolean checked;

		public SaveState(Parcel in) {
			super(in);
			checked = (Boolean) in.readValue(null);
		}

		public SaveState(Parcelable superState) {
			super(superState);
		}

		@Override
		public void writeToParcel(Parcel dest, int flags) {
			super.writeToParcel(dest, flags);
			dest.writeValue(checked);
		}

		public static final Parcelable.Creator<SaveState> CREATOR = new Creator<CheckableImageButton.SaveState>() {

			@Override
			public SaveState[] newArray(int size) {
				return new SaveState[size];
			}

			@Override
			public SaveState createFromParcel(Parcel source) {
				return createFromParcel(source);
			}
		};
	}

	@Override
	protected Parcelable onSaveInstanceState() {
		Parcelable superParcelable = super.onSaveInstanceState();
		SaveState ss = new SaveState(superParcelable);
		ss.checked = isChecked();
		return ss;
	}

	@Override
	protected void onRestoreInstanceState(Parcelable state) {
		SaveState ss = (SaveState) state;
		super.onRestoreInstanceState(ss.getSuperState());
		setChecked(ss.checked);
	}

	public OnCheckedChangeListener getmOnCheckedChangeListener() {
		return mOnCheckedChangeListener;
	}

	public void setmOnCheckedChangeListener(
			OnCheckedChangeListener mOnCheckedChangeListener) {
		this.mOnCheckedChangeListener = mOnCheckedChangeListener;
	}

}
分享到:
评论

相关推荐

    自定义Checkable控件实现点击ListViewItem选中checkbox

    为了解决这个问题,我们可以自定义一个Checkable控件,使得点击ListView的任何一项即可选中或取消选中对应的checkbox。下面将详细介绍如何实现这一功能。 首先,我们需要创建一个新的View类,继承自Checkable接口。...

    android自定义控件 带有check状态的ImageView

    在Android开发中,自定义控件是提升应用用户体验和界面个性化的重要手段。本教程将深入讲解如何创建一个具有检查状态的自定义ImageView,允许显示"checked"和"unchecked"两种不同的图片状态。虽然当前实现中,这两种...

    《 带checkbox的ListView实现(二)——自定义Checkable控件的实现方法》对应源码

    博客《 带checkbox的ListView实现(二)——自定义Checkable控件的实现方法》对应源码,博客地址:http://blog.csdn.net/harvic880925/article/details/40475367

    自定义控件样

    - `android:state_checkable`: 如果为`true`,表示控件可被选中或取消选中,如CheckBox。 - `android:state_checked`: 如果为`true`,表示控件当前处于选中状态,如RadioButton或CheckBox。 - `android:state_...

    Android自定义控件样式实例详解

    本文将深入探讨如何在Android中创建自定义控件样式,以及如何通过XML文件来实现这些样式。 首先,自定义控件样式通常在项目的`res/drawable`目录下定义,通过XML文件来描述。这些XML文件可以定义多种状态,并为不同...

    checkable-chip-view.zip

    自定义控件的创建通常涉及到重写onDraw()方法来绘制自定义的UI,或者使用LayoutInflater和XML布局文件来定义控件的外观。 在Android的UI开发中,使用自定义View可以提供更大的灵活性,允许开发者创造出与应用品牌...

    Android自定义ImageView实现点击两张图片切换效果

    通过自定义ImageView,实现了Checkable接口,使用了attrs.xml文件添加自定义属性,实现了图片的切换效果。 知识点1:Android ImageView的基本知识 ImageView是Android中一个基本的控件,用于显示图片。它有多种展示...

    Qt 自定义 Button 之美

    了解其属性(如 text、icon、checkable 等)和信号(如 clicked())对于自定义 Button 是必要的起点。 3. **QGraphicsView 和 QGraphicsScene**:为了实现更复杂的自定义效果,可以使用 QGraphicsView 和 ...

    android自定义可选择ListView

    如果系统提供的CheckedTextView不能满足需求,可以创建自定义的Checkable布局。实现Checkable接口,覆写其`setChecked()`、`isChecked()`和`toggle()`方法,以实现自定义的选中效果。 8. **优化性能**: 考虑使用...

    Android开发之自定义CheckBox

    在Android开发中,自定义控件是一个常见的需求,特别是对于UI元素如CheckBox,有时需要根据设计需求进行定制化。本文将详细介绍如何自定义一个CheckBox,包括处理`wrap_content`问题和实现动画效果。 首先,从描述...

    Android-CheckableChipView一个AndroidChipview控件

    在Android应用开发中,`Chip`控件是一个非常实用的组件,它通常用于展示可选的、标签式的信息。...同时,通过学习这个项目的源码,你还可以学习到如何在Android中创建自定义视图组件,提升你的开发技能。

    iphone checkable uipickerview

    在本项目中,开发者创建了一个自定义的 `UIPickerView`,名为 "ALPickerView",它增加了选择功能,使得用户界面更加友好且实用。下面我们将详细探讨 `UIPickerView` 的基本概念,以及如何通过自定义来增强其功能。 ...

    安卓listview相关相关-androidlistview长按子项动态添加自定义viewTestView.rar

    另外,如果自定义View需要根据用户的选择状态改变显示,可以使用`CheckedTextView`或自定义的Checkable接口。 总的来说,这个示例提供了如何在Android的ListView中实现长按子项添加自定义View的参考。通过学习和...

    Android-一个简单灵活的CheckedTextView或CheckableTextView

    1. **自定义类**:首先,我们需要创建一个新的Java类,继承自TextView,然后实现Checkable接口。Checkable接口包含三个方法:`isChecked()`, `setChecked(boolean checked)`, 和 `toggle()`。我们需要在这些方法中...

    自定义Layout选中边框变红.zip

    1. **自定义View/布局类**:创建一个继承自Android原生布局(如LinearLayout或RelativeLayout)的自定义布局类。在这个类中,我们可以添加额外的属性和行为,例如选中状态。 2. **选中状态管理**:利用Android的`...

    Android高级应用源码-UITableView ios风格控件.rar

    这个"Android高级应用源码-UITableView ios风格控件.rar"压缩包提供了一个专为Android设计的仿iOS UITableView风格的控件,它可以帮助开发者创建具有滚动列表功能的界面,这些界面在视觉和交互上接近于iOS的应用。...

    DTree(最好用的JS写成的树形菜单控件.内含API)

    通过以上介绍,我们可以看出DTree作为一款JavaScript树形菜单控件,不仅提供了丰富的功能,还具备良好的扩展性和自定义性。无论是小型项目还是大型应用,DTree都能提供优秀的用户体验。在实际开发中,结合压缩包中的...

    Android ListView 选中效果 自定义

    在Android开发中,ListView是常用的一种控件,用于展示大量数据列表。自定义ListView的选中效果是一项常见的需求,这可以提升用户体验并增加应用的视觉吸引力。本篇将深入探讨如何实现Android ListView的自定义选中...

Global site tag (gtag.js) - Google Analytics