Android 自定义按钮状态

需求描述:

最近做个项目,有一个按钮,有下载,安装,点击,安装中,下载中和使用这六个不同的状态,每个状态对应的按钮颜色也是不一样的,加上按下去的变色,大概有12种状态。

解决方案:

  • 6种状态对应不一样的background,设置为不同的状态的时候,换上对应的背景。
  • 自定义按钮状态

选择方案:

其实第二种和第一种的本质区别就是把所有的状态的文件写到一个xml里,但是更优雅,果断使用第二种

方案实现:

  • 定义自己的状态
  • 重写控件的onCreateDrawableState(int extraSpace) 告诉系统你有多少种状态

就这两个步骤,非常简单

定义自己的状态
   <declare-styleable name="ColorStateButton">
        <attr name="state_download" format="boolean"/>
        <attr name="state_downloading" format="boolean"/>
        <attr name="state_install" format="boolean"/>
        <attr name="state_installing" format="boolean"/>
        <attr name="state_open" format="boolean"/>
    </declare-styleable>

其实我想试试可不可以直接用数字类型的,当时时间比较紧急,就没试了,有兴趣的可以试试

重写onCreateDrawableState
 @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mColorStatus != null && mColorStatus.getMergeState() != null && isEnabled()) {
            final int[] drawableStatus = super.onCreateDrawableState(extraSpace + mColorStatus.getMergeState().length);//告诉系统你要添加拓展的状态数量
            //告诉系统你要合并的状态
            mergeDrawableStates(drawableStatus, mColorStatus.getMergeState());
//            printList(drawableStatus);
            return drawableStatus;
        }¡
        return super.onCreateDrawableState(extraSpace);
    }

详细代码:

按钮的background
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
    <!-- 需要下载状态-->
    <item
        android:drawable="@drawable/ic_color_button_download_normal"
        android:state_pressed="false"
        app:state_download="true"/>
    <item
        android:drawable="@drawable/ic_color_button_download_pressed"
        android:state_pressed="true"
        app:state_download="true"/>

    <!--需要安装状态-->
    <item
        android:drawable="@drawable/ic_color_button_install"
        android:state_pressed="false"
        app:state_install="true"/>
    <item
        android:drawable="@drawable/ic_color_button_install_pressed"
        android:state_pressed="true"
        app:state_install="true"/>
    <!--按钮不可用-->
    <item
        android:drawable="@drawable/ic_color_button_disable"
        android:state_enabled="false"/>

    <item
        android:drawable="@drawable/ic_color_button_normal_pressed"
        android:state_pressed="true"/>
    <!--正常状态-->
    <item
        android:drawable="@drawable/ic_color_button_normal"/>
</selector>
按钮的源码
package com.bingwish.bibao.ui.fragment;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.annotation.StringRes;
import android.util.AttributeSet;
import android.widget.Button;

import com.bingwish.bibao.R;
import com.hangox.xlog.XLog;

/**
 * Created With Android Studio
 * User hangox
 * Date 16/1/11
 * Time 下午8:58
 * 下载显示按钮
 */
public class ColorStateButton extends Button {
    public static final int[] STATUS_DOWNLOAD = {R.attr.state_download};
    public static final int[] STATUS_INSTALL = {R.attr.state_install};
    private ColorStatus mColorStatus = ColorStatus.DOWNLOAD;

    public ColorStateButton(Context context) {
        super(context);
        init(context);
    }

    public ColorStateButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ColorStateButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ColorStateButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    private void init(Context context) {
        setColorState(ColorStatus.DOWNLOAD);
    }

    /***
     * 设置颜色类型
     *
     * @param colorState
     */
    public void setColorState(ColorStatus colorState) {
        setText(colorState.getButtonTextRes());
        switch (colorState) {
            case DOWNLOADING:
            case INSTALLING:
                setEnabled(false);
                return;
        }
        setEnabled(true);
        mColorStatus = colorState;
        refreshDrawableState();
        invalidate();
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mColorStatus != null && mColorStatus.getMergeState() != null && isEnabled()) {
            final int[] drawableStatus = super.onCreateDrawableState(extraSpace + mColorStatus.getMergeState().length);
            mergeDrawableStates(drawableStatus, mColorStatus.getMergeState());
//            printList(drawableStatus);
            return drawableStatus;
        }
        return super.onCreateDrawableState(extraSpace);
    }

    private void printList(int[] ints) {
        StringBuilder builder = new StringBuilder();
        for (int state : ints) {
            builder.append(state).append("#");
        }

        XLog.i(builder.toString());
    }

    public enum ColorStatus {
        DOWNLOAD(STATUS_DOWNLOAD, R.string.state_download),
        CLICK(STATUS_INSTALL, R.string.state_click),
        OPEN(null, R.string.state_open),
        DOWNLOADING(null, R.string.state_downloading),
        INSTALL(STATUS_INSTALL, R.string.state_install),
        INSTALLING(null, R.string.state_installing);
        int[] mergeState;
        @StringRes
        int mButtonTextRes;

        ColorStatus(int[] statusDownload, @StringRes int buttonTextRes) {
            mergeState = statusDownload;
            mButtonTextRes = buttonTextRes;
        }

        public int getButtonTextRes() {
            return mButtonTextRes;
        }

        public int[] getMergeState() {
            return mergeState;
        }
    }

}