Widget Switch UI定制

我们知道自定义控件是最直接的方式,但是我想要的其实就是原生的switch的功能,仅仅是样式不同,所以去造一个哪怕是简易的仿造都显得麻烦。

下面这个就是我们想要的样式,on的时候track是绿色,thumb是白色;off的时候track是白色,thumb是绿色。

image.png

常见的switch长成这个样子

image

简单地修改一下, 你会发现宽高的修改完全与switch无关,改的是整个控件的大小。


image

再修改一下,加上android:switchMinWidth, 把背景换一换,让白色的thumb明显一点

    
image.png

好,到这里你就开始发现所有的switch的attr中设置的可变的参数都影响不了thumb的宽度或者track的高度了,各种padding都是浮云, 内心撕裂[流泪]。
几乎就要放弃的时候去自己写控件的时候,突然想到这个图片本身带点空白不就好了吗?然而,我没有切图工具也不会切图。所以我自己画一个吧



    
    
    

顺便把字也加上


image.png
image.png

对于这个字怎么加也想了一会,要求textOn、textOff显示的内容是不一样的,原生的控件是有textOn和textOff属性,但是它们是在thumb上

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (mShowText) {
        if (mOnLayout == null) {
            mOnLayout = makeLayout(mTextOn);
        }

        if (mOffLayout == null) {
            mOffLayout = makeLayout(mTextOff);
        }
    }
...
private Layout makeLayout(CharSequence text) {
    final CharSequence transformed = (mSwitchTransformationMethod != null)
                ? mSwitchTransformationMethod.getTransformation(text, this)
                : text;

    int width = (int) Math.ceil(Layout.getDesiredWidth(transformed, 0,
            transformed.length(), mTextPaint, getTextDirectionHeuristic()));
    return new StaticLayout(transformed, mTextPaint, width,
            Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    ...
    if (thumbDrawable != null) {
        thumbDrawable.draw(canvas);
    }

    final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
    if (switchText != null) {
        final int drawableState[] = getDrawableState();
        if (mTextColors != null) {
            mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
        }
        mTextPaint.drawableState = drawableState;

        final int cX;
        if (thumbDrawable != null) {
            final Rect bounds = thumbDrawable.getBounds();
            cX = bounds.left + bounds.right;
        } else {
            cX = getWidth();
        }

        final int left = cX / 2 - switchText.getWidth() / 2;
        final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
        canvas.translate(left, top);
        switchText.draw(canvas);
    }

    canvas.restoreToCount(saveCount);
}

原生的switchText是在thumb上的呢,所以自食其力吧,写两textView。
最简单的实现

CompoundButton.OnCheckedChangeListener mSwitchTutorListener = new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
            mTvSwitchOff.setVisibility(View.GONE);
            mTvSwitchOn.setVisibility(View.VISIBLE);
        } else {
            mTvSwitchOff.setVisibility(View.VISIBLE);
            mTvSwitchOn.setVisibility(View.GONE);
        }
    }
};

这个是最简单的实现,然后你会发现,这个字唰一下出现唰一下没有真是一点也不美好,加点渐变动画吧。
你肯定会想到alpha动画的fadein和fadeout吧,要写个animation?不用不用,可以用view的crossfade animation:https://developer.android.com/training/animation/reveal-or-hide-view

使用起来非常简单:

CompoundButton.OnCheckedChangeListener mSwitchTutorListener = new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        mTvSwitchOff.setVisibility(View.VISIBLE);
        mTvSwitchOn.setVisibility(View.VISIBLE);
        if (isChecked) {
            mTvSwitchOff.animate().alpha(0f).setDuration(50).setListener(null);
            mTvSwitchOn.animate().alpha(1f).setDuration(250).setListener(null);
        } else {
            mTvSwitchOff.animate().alpha(1f).setDuration(250).setListener(null);
            mTvSwitchOn.animate().alpha(0f).setDuration(50).setListener(null);
        }
    }
};

这样我们就实现了渐变退出和进入啦,世界美好许多。
这个有个事情要注意的是,动画的终态如果是alpha等于0,下次你要再显示它记得把alpha值给设回来。我一开始就忘记了,Visibility半天没改回来一脸懵。

你可能感兴趣的:(Widget Switch UI定制)