自定义控件 — 创建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>
<?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>
<?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>
/** * 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();}@Overridepublic boolean performClick() {// 拦截点击事件处理checkif (personality == PERSONALITY_CHECK_BUTTON) {toggle();} else if (personality == PERSONALITY_RADIO_BUTTON) {setChecked(true);}return super.performClick();}@Overridepublic 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;}@Overridepublic boolean isChecked() {return mChecked;}@Overridepublic void toggle() {setChecked(!mChecked);}@Overridepublic int[] onCreateDrawableState(int extraSpace) {int[] states = super.onCreateDrawableState(extraSpace + 1);if (isChecked()) {mergeDrawableStates(states, CHECKED_STATE_SET);}return states;}@Overrideprotected 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);}@Overridepublic void writeToParcel(Parcel dest, int flags) {super.writeToParcel(dest, flags);dest.writeValue(checked);}public static final Parcelable.Creator<SaveState> CREATOR = new Creator<CheckableImageButton.SaveState>() {@Overridepublic SaveState[] newArray(int size) {return new SaveState[size];}@Overridepublic SaveState createFromParcel(Parcel source) {return createFromParcel(source);}};}@Overrideprotected Parcelable onSaveInstanceState() {Parcelable superParcelable = super.onSaveInstanceState();SaveState ss = new SaveState(superParcelable);ss.checked = isChecked();return ss;}@Overrideprotected 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;}}