Android中如何为自定义控件增加状态?

  

在android开发中我们常常需要对控件进行相关操作,虽然网上已有很多对控件酷炫的操作,但小编今天给大家分享的纯属实用出发。在查看了一些列安卓教程和文档后,发现了一位大牛分享的非常不错的有关android自定义控件增加状态的文章,分享给大家,学习、参考。

 

 

场景

 

View类是Android UI组件的基础构建模块,主要负责组件的绘制及事件的处理。我们在一些自定义控件的场合,可能需要在一个组件上画些东西,也是通过重写View的onDraw方法,通过其参数的Canvas对象进行绘制。

 

我们学习<selector/>的时候,就知道了关于一个视图组件会有许多种状态,比如按下(pressed),选择(selected),可用(enabled),正常状态,其他状态等等。View也处理了关于一个组件在不同状态下的显示的绘制逻辑,通常继承自View的组件都有着以上所说的这些状态。但是也有一些状态是View没有提供的,而我们可能正需要它们,所以就需要对状态进行扩展,增加我们的状态,比如增加checked。

 

这里有一个具体的场景:

 

这是一个开关按钮,开关状态下背景不同,文字不同,文字旁边的图片也不同。状态我用checked,文字我定义了两个属性:onText以及offText,文字旁边的图片我打算只用一个foreground属性,但需要写一个selector来定义正常状态(未锁)和checked状态(锁定)下的图片。

 

 

实现

 

首先写一个类继承自TextView,因为我打算用TextView的setCompoundDrawables来设定文字旁边的图片。

 

然后定义属性:

 

    <declare-styleable name="ToggleView">

        <attr name="android:foreground"/>

        <attr name="pwOnText"/>

        <attr name="pwOffText"/>

        <attr name="pwColor"/>

        <attr name="pwDrawableHeight"/>

    </declare-styleable>

 

读取属性:

 

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ToggleView);

        stateListDrawable = (StateListDrawable) a.getDrawable(R.styleable.ToggleView_android_foreground);

        colorStateList = a.getColorStateList(R.styleable.ToggleView_pwColor);

        offText = a.getString(R.styleable.ToggleView_pwOffText);

        onText = a.getString(R.styleable.ToggleView_pwOnText);

        drawableHeight = a.getDimensionPixelSize(R.styleable.ToggleView_pwDrawableHeight, 0);

        a.recycle();

 

 

通过在类中实现Checkable接口,可以完成选中的逻辑,但是画出来的状态却没有更新,所以接下来的实现过程就是本篇的主要内容:

 

首先定义状态集:

 

    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};

 

然后我们要把状态给加进去。我们需要重写protected int[] onCreateDrawableState(int extraSpace)方法,如下:

 

    @Override

    protected int[] onCreateDrawableState(int extraSpace) {

        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);

        if (isChecked) {

            mergeDrawableStates(drawableState, CHECKED_STATE_SET);

        }

        return drawableState;

    }

 

先调用父类的onCreateDrawableState方法得到状态数组对象drawableState,但是参数extraSpace要加上1,因为我们要往里面增加一个状态。然后判断在代码逻辑中,是否为选中状态,如果是的话,调用mergeDrawableStates(drawableState, CHECKED_STATE_SET)方法把我们的状态值给加进去,最终返回drawableState。

 

但是我们虽然实现了Checkable接口,在设置状态时却没有触发到这个状态。所以我们需要自己去触发这个状态。

 

    @Override

    public void setChecked(boolean checked) {

        if (isChecked != checked) {

            isChecked = checked;

            refreshDrawableState();

        }

    }

 

在状态改变时,调用refreshDrawableState()刷新状态。

 

最后,我们要重写drawableStateChanged()方法,获取到当前状态的drawable,然后绘制出来。

 

    @Override

    protected void drawableStateChanged() {

        super.drawableStateChanged();

        if (stateListDrawable != null) {

            int[] myDrawableState = getDrawableState();

            stateListDrawable.setState(myDrawableState);

            Drawable drawable = stateListDrawable.getCurrent();

            if(drawableHeight != 0) {

                drawable.setBounds(0, 0, drawable.getIntrinsicWidth() * drawableHeight / drawable.getIntrinsicHeight(), drawableHeight);

            } else {

                drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());

            }

            if (isChecked) {

                setCompoundDrawables(drawable, null, null, null);

            } else {

                setCompoundDrawables(null, null, drawable, null);

            }

        }

        setText(isChecked ? onText : offText);

    }

 

这部分代码中我需要设定drawable的大小,以及在不同的状态下设置drawable的位置,因此稍微比较复杂一点点,实际上逻辑只需要如下:

 

获取当前的drawableState状态

对stateListDrawable(带状态的drawable集)设置状态。

获取stateListDrawable的当前状态的drawable

进行你所想要的绘制。

这样就完成了。

 

总结

 

从上面可知,增加状态的过程如下:

 

定义状态数组

重写protected int[] onCreateDrawableState(int extraSpace)

调用refreshDrawableState()

重写protected void drawableStateChanged()

 

以上就是android自定义控件增加状态的方法,如果你还有更好的实现方法,欢迎补充分享。

相关文章:《如何实现自己的Android MVP框架?

原文地址:https://www.cnblogs.com/gaobig/p/5013174.html