[Android]自定义CheckableImageButton

本文介绍如何作为Android开发者,通过自定义CheckableImageButton实现使用图片按钮的单选功能,代替不美观的RadioButton。步骤包括在attrs.xml定义style,创建Selector文件指定选中和未选中状态的图片,编写自定义CheckableImageView类,并在布局及MainActivity中应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现如今大多数app的UI都越做越精细,身为一名Android开发者,我经常遇到这种情况——实现采用自定义图片的按钮(如ImageButton)而非RadioButton来实现单选功能,虽然RadioButton本身就是Android提供的单选按钮,但因为其自带的button并不美观,往往会被要求直接采用图片来充当Button。今天就为大家带来一篇自定义CheckableImageButton的文章。
首先,和大部分自定义控件一样,我们需要先在attrs.xml文件中定义相应的style。

attrs.xml

<declare-styleable name="CheckableImageButton">
        <attr name="isChecked" format="boolean"/>
</declare-styleable>
接着,我们可以为我们的可选中ImageButton创建Selector文件,指定其在选中和未被选中时呈现的图片
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:myApp="http://schemas.android.com/apk/res/com.yourPackage.xxx">
    <item dxx:isChecked="true" android:drawable="@mipmap/users"></item>
    <item dxx:isChecked="false" android:drawable="@mipmap/users_g"></item>
</selector>
注意:上面selector里的xmlns:myApp=”http://schemas.android.com/apk/res/com.yourPackage.xxx”路径改为自己的工程路径
现在我们可以开始写自定义CheckableImageView了

代码如下
CheckableImageView.java

public class CheckableImageButton extends ImageButton implements Checkable{
    //判断是否被点击
    private boolean isChecked;
    private OnCheckedChangeListener mOnCheckedChangeListener;
    private static final int[] CHECKED_STATE_SET = { R.attr.isChecked };
    public CheckableImageButton(Context context) {
        super(context);
    }

    public CheckableImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取自定义属性
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckableImageButton);
        isChecked = a.getBoolean(R.styleable.CheckableImageButton_isChecked, false);
        setChecked(isChecked);
        a.recycle();
    }

    public CheckableImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取自定义属性
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckableImageButton);
        isChecked = a.getBoolean(R.styleable.CheckableImageButton_isChecked, false);
        setChecked(isChecked);
        a.recycle();
    }

    @Override
    public boolean performClick() {
        //拦截点击事件
        setChecked(true);
        return super.performClick();
    }

    @Override
    public void setChecked(boolean checked) {
        if (isChecked != checked) {
            isChecked = checked;
            refreshDrawableState();
            if (null != mOnCheckedChangeListener) {
                mOnCheckedChangeListener.onCheckedChanged(this, isChecked);
                refreshDrawableState();
            }
        }
    }

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

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

    @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();
    }

    @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;
    }

    //自定义接口,用来监听check的改变
    public static interface OnCheckedChangeListener {
        public void onCheckedChanged(CheckableImageButton button, boolean isChecked);
    }
    //用于恢复Check状态信息
    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);
            }
        };
    }
}
下面就可以在layout文件中调用了
<LinearLayout
            xmlns:dxx="http://schemas.android.com/apk/res/philips.com.myapplication"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true">
            <philips.com.myapplication.customview.CheckableImageButton
                android:id="@+id/firstIb"
                android:layout_width="0dp"
                android:layout_height="20dp"
                android:layout_weight="1"
                android:background="@null"
                android:src="@drawable/image_button_first"
                android:scaleType="fitCenter"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                dxx:isChecked="true"
                />
            <philips.com.myapplication.customview.CheckableImageButton
                android:id="@+id/secondIb"
                android:layout_width="0dp"
                android:layout_height="20dp"
                android:layout_weight="1"
                android:background="@null"
                android:src="@drawable/image_button_second"
                android:scaleType="fitCenter"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                />
            <philips.com.myapplication.customview.CheckableImageButton
                android:id="@+id/thirdIb"
                android:layout_width="0dp"
                android:layout_height="20dp"
                android:layout_weight="1"
                android:background="@null"
                android:src="@drawable/image_button_third"
                android:scaleType="fitCenter"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                />

        </LinearLayout>
在MainActivity里的调用代码
    @Override
    public void onCheckedChanged(CheckableImageButton button, boolean isChecked) {
        if (isChecked) {
            switch (button.getId()) {
                case R.id.firstIb:
                    checkableImageButton2.setChecked(false);
                    checkableImageButton3.setChecked(false);
                    break;
                case R.id.secondIb:
                    checkableImageButton1.setChecked(false);
                    checkableImageButton3.setChecked(false);
                    break;
                case R.id.thirdIb:
                    checkableImageButton1.setChecked(false);
                    checkableImageButton2.setChecked(false);
            }
        }
   }
现在就可以实现RadioButton的效果了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值