最近用到的一个效果,见下图文字颜色渐变
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-255
的rgb
四四
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);
}
...................................
}