`

自定义控件 — 创建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;
	}

}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics