自定義View 實現一道亮光閃過

package com.example.lightline;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;

import androidx.annotation.Nullable;

public class LightingView 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 RectF rect;
    private ValueAnimator valueAnimator;
    private boolean autoRun = true; //是否自動運行動畫
    public String TAG = "LightingView ";
    private long timeMillis;

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

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

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

    private void init() {
        timeMillis = System.currentTimeMillis();
        rect = new RectF();
        mPaint = new Paint();
        initGradientAnimator();
    }

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

    //  onSizeChanged 這個方法肯定在onMeasure 之後,因爲這個方法可以獲取到真正的寬高,
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
//        onMeasure 方法之後寬高就會測量完畢
        Log.i(TAG, "onSizeChanged ------------  ==" + mViewWidth);
        if (mViewWidth == 0) {
            mViewWidth = getWidth();
            mViewHeight = getHeight();
            if (mViewWidth > 0) {
                //亮光閃過
//                Shader 著色器的意思
//                Shader.TileMode.CLAMP  表示繪製邊緣
//                Shader.TileMode.MIRROR  表示鏡像繪製
//                Shader.TileMode.REPEAT  表示重複繪製

//             繪製寬度爲 控件寬度一般,高度爲控件高度的過渡view
                mGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2, getMeasuredHeight(),
                        new int[]{0x007965FF, 0xff7965FF, 0xffD6D8FF},
                        new float[]{0.0f, 0.4f, 1f},
                        Shader.TileMode.REPEAT);// 以邊緣色調繪製剩餘的部分
//                給paint 添加着色器
                mPaint.setShader(mGradient);
//                setLayerType(View.LAYER_TYPE_SOFTWARE, null);//關掉硬件加速
//
//                PorterDuff.Mode.DST  丟棄原像素,使目標保持不變,這裏的目標指的是,LightView 的背景圖片
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
                mGradientMatrix = new Matrix();
//                這個是控制繪製時最開始的 偏移量,
//                mGradientMatrix.setTranslate(-1 *mViewWidth , mViewHeight);
                mGradient.setLocalMatrix(mGradientMatrix);
                rect.set(0, 0, w, h);
            }
        }
    }
//
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.i(TAG, "onDraw ------------");
        if (mAnimating && mGradientMatrix != null) {
//            表示繪製,一個矩形,
            canvas.drawRoundRect(rect, 15, 15, mPaint);
        }
    }

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

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float v = (Float) animation.getAnimatedValue();
//                Log.i(TAG,System.currentTimeMillis()- timeMillis +" timeMi");
                //❶ 改變每次動畫的平移x、y值,範圍是[-mViewWidth, mViewWidth]
                mTranslateX = 2 * mViewWidth * v - mViewWidth * 1;
                mTranslateY = mViewHeight * v;
                //❷ 平移matrix, 設置平移量
                if (mGradientMatrix != null) {
                    mGradientMatrix.setTranslate(mTranslateX, mTranslateY);
                }
                //❸ 設置線性變化的matrix
                if (mGradient != null) {
                    mGradient.setLocalMatrix(mGradientMatrix);
                }
                //❹ 重繪
                invalidate();
//                if (v >= 1) {
//                    System.out.println("stop ----------------------");
//                    stopAnimation();
//                }
            }
        });
        if (autoRun) {
            getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

                @Override
                public void onGlobalLayout() {
                    getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    mAnimating = true;
                    if (valueAnimator != null) {
                        Log.i(TAG, System.currentTimeMillis() - timeMillis + " timeMi");
//                        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();
        }
    }
}

發佈了55 篇原創文章 · 獲贊 7 · 訪問量 4257
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章