创建自定义控件根据控件的需求主要有一下几种方案:
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文件中指定相关属性的值。
2. 创建ImageButton的背景,使用Selector Drawable。
jimi:is_checked="true"是(1)中自定义的属性
3. 创建布局文件,可以指定自定义属性的值。
4. 创建自定义类,继承至ImageButton。让自定义类有ImageButton的所有功能。在构造方法中通过TypedArray读取自定义属性的值。
5. 实现Checkable接口。
接口如下:
自定义类全部代码:
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;
- }
- }