妖艳的SwitchButton控件-隔壁产品都馋哭了

473 阅读4分钟

废话不多说,来人,上图

这Q弹的动画,妖艳的色彩转换,着实和市面上的普通Switch控件不太一样。下面对它逐一拆解,从0到1实现它。

一、设计思路

Android系统提供的SwitchButon很好地体现了metiarial design设计风格,但不够妖艳。我希望用两个比较冲突的对比色进行控件的颜色设计,这样摆在浅色背景页面的时,控件可以达到一种直刺眼睛的效果。抓人、妖艳、骚气外放。只要整体页面搭配得当,该控件必定可以“外骚内纯”。微微模糊的光晕可以使得本就亮丽的颜色变得更加妖艳。为增加设计的可扩展性,可以改变颜色从而体现不同的风格。

二、实现方式

总体而言,虽然控件的外表非常妖艳,但交互逻辑是比较简单的。不考虑继承自系统Switch,因为并不需要再去了解如何扩展Switch。因此直接继承自View即可。整个逻辑控制在onTouchEvent中实现,声明好各个可配置的属性,如颜色、大小等等。

  • UI绘制

可以看到,图形由两大部分构成,一个是前面蓝色的圆角矩形(指示器),一个是后面红色的长条矩形(背景条),分别对这两个图形进行绘制即可。onDraw部分的代码如下:

画背景条:

其中bkgRect代表待绘制矩形区域范围,height、width为控件长宽,bkgBarW、bkgBarH为背景条长宽,由于是圆角矩形,调用canvas的drawRoundRect方法进行绘制,bkgBarPaint控制背景条颜色

//画背景条
RectF bkgRect = new RectF((width - bkgBarW) / 2f, height / 2 - (bkgBarH / 2), (width - bkgBarW) / 2f + bkgBarW, height / 2 + (bkgBarH / 2));
canvas.drawRoundRect(bkgRect, bkgBarH / 4, bkgBarH / 4, bkgBarPaint);

画前景圆角矩形:

同样的,indicatorRect为待绘制圆角矩形的区域范围,indicatorW、indicatorH为指示器宽高,indicatorX、indicatorY为指示器的中心坐标点,该坐标之后会结合animator进行动态计算,最后调用canvas的drawRoundRect进行绘制

//画指示器
RectF indicatorRect = new RectF(
        indicatorX,
        indicatorY,
        indicatorW + indicatorX,
        (height - indicatorH) / 2 + indicatorH
);
canvas.drawRoundRect(indicatorRect, indicatorH / 6, indicatorH / 6, indicatorPaint);

画图标或文字:

这部分计算好文字或图标的坐标进行绘制即可,需要注意的是,如果要绘制文字,需要计算出文字的基线位置,方便与指示器在视觉上居中

//画图标
int baseLineY = (int) (indicatorRect.centerY() - textTop / 2 - textBottom / 2);//基线中间点的y轴计算公式
if (status == false) {
    canvas.drawText("♂", indicatorRect.centerX(), baseLineY, textPaint);
} else {
    canvas.drawText("♀", indicatorRect.centerX(), baseLineY, textPaint);
}
  • 动画实现

为方便控制,定义两个AnimatorSet,分别为animOnSet、animOffSet,animOnSet代表开关选择器打开时的动画合集,animOffSet代表开关选择器关闭时的动画合集。设置为BounceInterpolator即可配置弹性效果。

animatorOn = ValueAnimator.ofFloat(indicatorStartX, indicatorEndX);
animatorOn.setDuration(500);
animatorOn.setInterpolator(new BounceInterpolator());
animatorOn.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        indicatorX = (float) animation.getAnimatedValue();
        postInvalidate();
    }
});
animOnSet = new AnimatorSet();
animOnSet.playTogether(animatorOn, animatorColorOn);


animatorOff = ValueAnimator.ofFloat(indicatorEndX, indicatorStartX);
animatorOff.setDuration(500);
animatorOff.setInterpolator(new BounceInterpolator());
animatorOff.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        indicatorX = (float) animation.getAnimatedValue();
        postInvalidate();
    }
});
animOffSet = new AnimatorSet();
animOffSet.playTogether(animatorColorOff, animatorOff);
  • 加亿点细节

仔细观察可以注意到,指示器是带有同颜色的阴影的,淡淡的阴影向四周晕开,如同光雾一般。这里使用设计好的阴影背景图切图即可,但为了增加控件通用性,采取了讨巧的办法。通过对Bitmap的处理从而在指示器颜色变化时,绘制的阴影颜色也随之变化。代码如下,bmShdow为待绘制的阴影图片

bmShadow = BitmapFactory.decodeResource(getResources(), R.drawable.img_shadow_rect_blue);
//sex_blue为配置的指示器为“开”状态时的颜色,int值
bmShadow = BitmapUtils.replacePixelColor(bmShadow, sex_blue);

再仔细以观察,会发现在指示器动画执行的过程中,指示器颜色也完成了一个渐变过渡。这里有个变换颜色动态计算的操作,依然采用animator进行计算,其中indicatorPaint控制指示器颜色

animatorColorOn = new ValueAnimator();
animatorColorOn.setIntValues(sex_blue, sex_red);
animatorColorOn.setEvaluator(new ArgbEvaluator());
animatorColorOn.setDuration(500);
animatorColorOn.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int color = (int) animation.getAnimatedValue();
        indicatorPaint.setColor(color);
    }
});

animatorColorOff = new ValueAnimator();
animatorColorOff.setIntValues(sex_red, sex_blue);
animatorColorOff.setEvaluator(new ArgbEvaluator());
animatorColorOff.setDuration(500);
animatorColorOff.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int color = (int) animation.getAnimatedValue();
        indicatorPaint.setColor(color);
    }
});

三、后记

鲁迅曾说过,“ 猛兽总是独行,牛羊才成群结队。”因为该控件的妖艳,而显得它特立独行;又因它的特立独行,才会和其它市面上的妖艳贱货不一样。

控件设计或开发,无处不体现着“自顶向下”的思想。弄清需求,理清逻辑,看清细节,做到这三点,绝大部分控件设计或开发的难题一定可以迎刃而解。

既然看到这里了,是时候亮出我的公众号了,啊,我还没有公众号。需要此控件的扫一扫加我vx