Android 颜色渐变 属性动画

发布于 2019-04-02  146 次阅读


最近用到的一个效果,见下图文字颜色渐变
(周围的晃来晃去的框框是轨迹动画,下篇博客说)

在这里插入图片描述

1.原理

  • 计算机颜色由绿三色混合组成(值为0-255
  • 红、绿、蓝之间色值,按照不同大小比例 组成不同颜色 和深浅的视觉颜色
  • 这里的颜色渐变动画就是利用属性动画ValueAnimator平滑的改变色值的大小,达到颜色的渐变效果

2.上代码

TextView text = findViewById(233);
ValueAnimator animator = ObjectAnimator.ofInt(text,"textColor",
        0x88333833, 0x88ca0007, 0x880333dc, 0x88089905);
animator.setDuration(2000);
animator.setEvaluator(new ArgbEvaluator());
animator.setRepeatCount(-1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();

3.关于上面那个代码

3.1.textColor

即是文本颜色属性的java的反射名字,相当于text .setTextColor()
类似的(比如想修改背景色):
text.setBackgroundColor()反射写法为backgroundColor

3.2.0x88333833, 0x88ca0007, 0x880333dc, 0x88089905

即使颜色变化轨迹:黑色→红色→蓝色→绿色
注意:
这里的颜色必须是ARGB(带alpha通道的)。
0x88333833中的88即是通道值

3.3.ArgbEvaluator

颜色估计器
这个的作用是计算颜色平滑的改变数字(输出其实是一个数组)

3.4.其他的就是属性动画的一般属性了

4.颜色估计器

这里来倒腾一下估计器的源码

4.1.先来说说颜色的计算方法

就拿这个色号 #074bad来说事把
在这里插入图片描述

android的sdk里有不少拾取颜色的方法,比如Context.getColor(),Color.parseColor()
它们返回的是一个int的数字,如:#074bad转化为int是-425315
然后,把它转换成0-255rgb四四

int color=-16299091;
int red= ((color & 0xff0000) >> 16);//红色=7,范围[0,255]
int green = ((color & 0x00ff00) >> 8);//绿色=75,范围[0,255]
int blue = (color & 0x0000ff);//蓝色=173,范围[0,255]

在这里插入图片描述

现在我想让这个颜色变得浅一点
这里,数值越高,颜色月亮

//先增40玩玩
red+=40;//红色:47
green +=40;//绿色:115
blue +=40;//蓝色:213
//注意不能超过255

在这里插入图片描述

这个时候就得到了一个更浅的颜色
但grb的表达方式,再android里面几乎都不能直接使用,现在把它再转换为int

int colorLighter = 0xff000000 | (red << 16) | (green << 8) | blue

现在就可以直接设置到控件的属性上了

4.2.ArgbEvaluator

evaluate方法的3个参数
float fraction:动画过渡时间因子,决定动画变化的速率[0,1]
Object startValue:动画起始颜色
Object endValue:动画结束颜色
下面,具体的计算过程就在注释里解释了,上代码了

public class ArgbEvaluator implements TypeEvaluator {
...................................
 @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;

        //起始颜色ARGB颜色通道拆分
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >> 8) & 0xff) / 255.0f;
        float startB = (startInt & 0xff) / 255.0f;//透明度
        /*
         * 结束颜色ARGB颜色通道拆分
         */
        int endInt = (Integer) endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >> 8) & 0xff) / 255.0f;
        float endB = (endInt & 0xff) / 255.0f;//透明度

        // 颜色数值线性增加
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);
        /*
         *
         */
        // 根据时间因子,计算出过渡的颜色插值
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // 再将颜色转换回ARGB[0,255]
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        //将分离ARGB颜色通道打包装车
        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }
...................................
}

职业移动开发,业余整点音乐