Android 顏色漸變 屬性動畫

KosmoSakura發表於2019-04-02

最近用到的一個效果,見下圖文字顏色漸變
(周圍的晃來晃去的框框是軌跡動畫,下篇部落格說)

在這裡插入圖片描述

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);
    }
...................................
}

相關文章