Android使用LinearGradient實現(xiàn)兩道閃光效果

一、動畫效果
? 1.動效描述
? 2.關鍵點
? 3.實現(xiàn)方式 ?
二、LinearGradient簡介
三、代碼功能實現(xiàn)
?1.繪制閃光
? 2.兩道閃光順序出現(xiàn)


一、動畫效果

1.動效描述

實現(xiàn)的動畫效果主要就是,一束白光從圖片或者文字上閃過,這束光由兩道光組成,具體細節(jié)描述如下:

2.關鍵點

  • 兩道閃光,傾斜-330°,透明度、寬度不一樣
  • 兩道閃光按順序先后出現(xiàn)

3.實現(xiàn)方式

可以用FrameLayout,在背景圖或文字上兩個View,然后對這兩個view做動畫,控制時間、旋轉(zhuǎn)角度等。這里主要講怎么用LinearGradient來實現(xiàn)兩道光閃過的動畫效果。

二、LinearGradient簡介

講實現(xiàn)之前先認識下主角LinearGradient。LinearGradient作用是實現(xiàn)某一區(qū)域內(nèi)顏色的線性漸變效果,網(wǎng)上相關資料也很多,這里就簡單介紹下常用的構造函數(shù):
public LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions,Shader.TileMode tile)
注:Android中計算x,y坐標都是以屏幕左上角為原點,向右為x+,向下為y+

  • float x0:漸變起始點x坐標
  • float y0:漸變起始點y坐標
  • float x1:漸變結束點x坐標
  • float y1:漸變結束點y坐標
  • int[] colors:顏色 的int 數(shù)組
  • float[] positions: 相對位置的顏色數(shù)組,可為null,若為null,顏色沿漸變線均勻分布
  • Shader.TileMode tile: 渲染器平鋪模式

Shader.TileMode有3種參數(shù)可供選擇,分別為CLAMP、REPEAT和MIRROR:

  • CLAMP的作用是如果渲染器超出原始邊界范圍,則會復制邊緣顏色對超出范圍的區(qū)域進行著色
  • REPEAT的作用是在橫向和縱向上以平鋪的形式重復渲染位圖
  • MIRROR的作用是在橫向和縱向上以鏡像的方式重復渲染位圖

代碼功能實現(xiàn)

1.繪制閃光

閃光的繪制由LinearGradient完成,通過改變其構造函數(shù)各個參數(shù)值,就能繪制出不同的光效果

(1)閃光傾斜-330°

調(diào)節(jié)漸變閃光的傾斜角度,需用LinearGradient構造函數(shù)中的x0,y0,x1,y1參數(shù),即調(diào)節(jié)漸變的起始點,更多用法可參考Android中的LinearGradient。所以我們將這個4個參數(shù)設置成如下:

(2)兩道閃光

這里主要用到LinearGradient構造函數(shù)中的colors,positions參數(shù)。colors參數(shù)很好理解,就是一組顏色值;positions的釋義是“相對位置、權重”,看完釋義是不是還是沒有太明白(/□\*),來直接上代碼和效果圖。

 LinearGradient mGradient = new LinearGradient(0, 0, mViewWidth / 2, mViewHeight,
                        new int[]{0x00ffffff, 0x73ffffff, 0x00ffffff,  0x99ffffff, 0x00ffffff},
                        new float[]{0.2f,       0.35f,      0.45f,        0.5f,      0.8f},
                        Shader.TileMode.CLAMP);

上面代碼可以這么理解,它定義了一組漸變的數(shù)值是{ 0x00ffffff, 0x73ffffff, 0x00ffffff, 0x99ffffff, 0x00ffffff},這組數(shù)值分別在相對應的0.2f, 0.35f, 0.45f, 0.5f, 0.8f中顯示:

  • 第一道閃光顏色有效值是0.35f位置的35%白色,0.35f前后位置的顏色值都為透明,調(diào)節(jié)這兩個透明顏色的position值就可以調(diào)節(jié)第一道閃光的寬度;
  • 第二道閃光顏色有效值是0.5f位置的50%白色,同理0.5f前后位置顏色為透明,調(diào)節(jié)第二道閃光寬度就可以調(diào)節(jié)這兩個position值;
  • 中間0.45f位置設為透明,也就把第一道光和第二道光隔開了。

2.兩道閃光順序出現(xiàn)

現(xiàn)在兩道光用LinearGradient一起繪制出來了,要怎樣實現(xiàn)順序出現(xiàn)呢?這里配合Matrix、屬性動畫ValueAnimator來控制,先看核心代碼:

 private void initGradientAnimator() {
        valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(5000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float v = (Float) animation.getAnimatedValue();
                //? 改變每次動畫的平移x、y值
                mTranslateX = 4 * mViewWidth * v - mViewWidth * 2;
                mTranslateY = mViewHeight * v;
                //? mGradientMatrix為變換矩陣,設置矩陣x、y平移量
                if (mGradientMatrix != null) {
                    mGradientMatrix.setTranslate(mTranslateX, mTranslateY);
                }
                //? 為線性漸變mGradient設置matrix
                if (mGradient != null) {
                    mGradient.setLocalMatrix(mGradientMatrix);
                }
                //? 重繪
                invalidate();
            }
        });  
 }

重點看下第?步怎么移動的,每次根據(jù)當前的動畫屬性值設置x、y平移量,x的范圍是[-2mViewWidth, 2mViewWidth],y的范圍是范圍是[0, mViewHeight],如下圖所示(x軸)。也就是兩道閃光從不可見到可見,調(diào)節(jié)valueAnimator的duration,或者更改x、y變化方式就能控制兩道閃光的出場順序了


注:上面方式實現(xiàn)的閃光動效和文章開頭列的條件并不是百分百一樣,大致效果相同。
最后,自定義LightningView的的所有代碼:

public class LightningView extends View {
    private Shader mGradient;
    private Matrix mGradientMatrix;
    private Paint mPaint;
    private int mViewWidth = 0, mViewHeight = 0;
    private float mTranslateX = 0, mTranslateY = 0;
    private boolean mAnimating = false;
    private Rect rect;
    private ValueAnimator valueAnimator;
    private boolean autoRun = true; //是否自動運行動畫

    public LightningView(Context context) {
        super(context);
        init();
    }

    public LightningView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public LightningView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        rect = new Rect();
        mPaint = new Paint();
        initGradientAnimator();
    }

    public void setAutoRun(boolean autoRun) {
        this.autoRun = autoRun;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        rect.set(0, 0, getWidth(), getHeight());
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mViewWidth == 0) {
            mViewWidth = getWidth();
            mViewHeight = getHeight();
            if (mViewWidth > 0) {
                //亮光閃過
                mGradient = new LinearGradient(0, 0, mViewWidth / 2, mViewHeight,
                        new int[]{0x00ffffff, 0x73ffffff, 0x00ffffff,  0x99ffffff, 0x00ffffff},
                        new float[]{0.2f,       0.35f,      0.5f,        0.7f,      1},
                        Shader.TileMode.CLAMP);
                mPaint.setShader(mGradient);
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
                mGradientMatrix = new Matrix();
                mGradientMatrix.setTranslate(-2 * mViewWidth, mViewHeight);
                mGradient.setLocalMatrix(mGradientMatrix);
                rect.set(0, 0, w, h);
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mAnimating && mGradientMatrix != null) {
            canvas.drawRect(rect, mPaint);
        }
    }

    private void initGradientAnimator() {
        valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(5000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float v = (Float) animation.getAnimatedValue();
                //? 改變每次動畫的平移x、y值,范圍是[-2mViewWidth, 2mViewWidth]
                mTranslateX = 4 * mViewWidth * v - mViewWidth * 2;
                mTranslateY = mViewHeight * v;
                //? 平移matrix, 設置平移量
                if (mGradientMatrix != null) {
                    mGradientMatrix.setTranslate(mTranslateX, mTranslateY);
                }
                //? 設置線性變化的matrix
                if (mGradient != null) {
                    mGradient.setLocalMatrix(mGradientMatrix);
                }
                //? 重繪
                invalidate();
            }
        });
        if (autoRun) {
            valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
            getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

                @Override
                public void onGlobalLayout() {
                    getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    mAnimating = true;
                    if (valueAnimator != null) {
                        valueAnimator.start();
                    }
                }
            });
        }
    }

    //停止動畫
    public void stopAnimation() {
        if (mAnimating && valueAnimator != null) {
            mAnimating = false;
            valueAnimator.cancel();
            invalidate();
        }
    }

    //開始動畫
    public void startAnimation() {
        if (!mAnimating && valueAnimator != null) {
            mAnimating = true;
            valueAnimator.start();
        }
    }
}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容

  • Android繪圖之Shader Shader是繪圖過程中的著色器,它有五個子類: BitmapShader Co...
    lavor閱讀 15,333評論 3 62
  • Paint 類持有繪制圖形、文本、圖像的樣式和色彩信息,并且對外提供了一系列方法來設置這些信息。 一、畫筆基本操作...
    秀花123閱讀 4,388評論 1 7
  • 在上篇說道BitmapShader的使用關于Shader.TileMode這個參數(shù)在說明一下Shader.Tile...
    大大大寒閱讀 1,568評論 3 1
  • 用來實現(xiàn)線性漸變效果 此類是Shader的子類通過paint.setShader來設置漸變。 有兩個構造方法分別如...
    gaaaaaaaaaao閱讀 38,349評論 0 29
  • 所謂在夾縫中生存,很多在大城市里生活的上班族應該和我有一樣的想法吧…擁擠的交通,繁忙的街道,信號燈似乎都沒有時間理...
    jojo閱讀 351評論 0 1