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

一、動(dòng)畫效果
? 1.動(dòng)效描述
? 2.關(guān)鍵點(diǎn)
? 3.實(shí)現(xiàn)方式 ?
二觉壶、LinearGradient簡(jiǎn)介
三、代碼功能實(shí)現(xiàn)
?1.繪制閃光
? 2.兩道閃光順序出現(xiàn)


一、動(dòng)畫效果

1.動(dòng)效描述

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

2.關(guān)鍵點(diǎn)

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

3.實(shí)現(xiàn)方式

可以用FrameLayout序苏,在背景圖或文字上兩個(gè)View,然后對(duì)這兩個(gè)view做動(dòng)畫捷凄,控制時(shí)間忱详、旋轉(zhuǎn)角度等。這里主要講怎么用LinearGradient來(lái)實(shí)現(xiàn)兩道光閃過(guò)的動(dòng)畫效果跺涤。

二匈睁、LinearGradient簡(jiǎn)介

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

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

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

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

代碼功能實(shí)現(xiàn)

1.繪制閃光

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

(1)閃光傾斜-330°

調(diào)節(jié)漸變閃光的傾斜角度米碰,需用LinearGradient構(gòu)造函數(shù)中的x0窝革,y0,x1吕座,y1參數(shù)虐译,即調(diào)節(jié)漸變的起始點(diǎn),更多用法可參考Android中的LinearGradient吴趴。所以我們將這個(gè)4個(gè)參數(shù)設(shè)置成如下:

(2)兩道閃光

這里主要用到LinearGradient構(gòu)造函數(shù)中的colors漆诽,positions參數(shù)。colors參數(shù)很好理解锣枝,就是一組顏色值厢拭;positions的釋義是“相對(duì)位置、權(quán)重”撇叁,看完釋義是不是還是沒(méi)有太明白(/□\*)供鸠,來(lái)直接上代碼和效果圖。

 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ù)值分別在相對(duì)應(yīng)的0.2f, 0.35f, 0.45f, 0.5f, 0.8f中顯示:

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

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

現(xiàn)在兩道光用LinearGradient一起繪制出來(lái)了帖蔓,要怎樣實(shí)現(xiàn)順序出現(xiàn)呢?這里配合Matrix瞳脓、屬性動(dòng)畫ValueAnimator來(lái)控制塑娇,先看核心代碼:

 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();
                //? 改變每次動(dòng)畫的平移x、y值
                mTranslateX = 4 * mViewWidth * v - mViewWidth * 2;
                mTranslateY = mViewHeight * v;
                //? mGradientMatrix為變換矩陣劫侧,設(shè)置矩陣x埋酬、y平移量
                if (mGradientMatrix != null) {
                    mGradientMatrix.setTranslate(mTranslateX, mTranslateY);
                }
                //? 為線性漸變mGradient設(shè)置matrix
                if (mGradient != null) {
                    mGradient.setLocalMatrix(mGradientMatrix);
                }
                //? 重繪
                invalidate();
            }
        });  
 }

重點(diǎn)看下第?步怎么移動(dòng)的,每次根據(jù)當(dāng)前的動(dòng)畫屬性值設(shè)置x烧栋、y平移量写妥,x的范圍是[-2mViewWidth, 2mViewWidth],y的范圍是范圍是[0, mViewHeight]审姓,如下圖所示(x軸)珍特。也就是兩道閃光從不可見(jiàn)到可見(jiàn),調(diào)節(jié)valueAnimator的duration魔吐,或者更改x扎筒、y變化方式就能控制兩道閃光的出場(chǎng)順序了莱找。


注:上面方式實(shí)現(xiàn)的閃光動(dòng)效和文章開頭列的條件并不是百分百一樣,大致效果相同嗜桌。
最后奥溺,自定義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; //是否自動(dòng)運(yùn)行動(dòng)畫

    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) {
                //亮光閃過(guò)
                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();
                //? 改變每次動(dòng)畫的平移x、y值骨宠,范圍是[-2mViewWidth, 2mViewWidth]
                mTranslateX = 4 * mViewWidth * v - mViewWidth * 2;
                mTranslateY = mViewHeight * v;
                //? 平移matrix, 設(shè)置平移量
                if (mGradientMatrix != null) {
                    mGradientMatrix.setTranslate(mTranslateX, mTranslateY);
                }
                //? 設(shè)置線性變化的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();
                    }
                }
            });
        }
    }

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浮定,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子层亿,更是在濱河造成了極大的恐慌桦卒,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棕所,死亡現(xiàn)場(chǎng)離奇詭異闸盔,居然都是意外死亡悯辙,警方通過(guò)查閱死者的電腦和手機(jī)琳省,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)躲撰,“玉大人针贬,你說(shuō)我怎么就攤上這事÷5埃” “怎么了桦他?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)谆棱。 經(jīng)常有香客問(wèn)我快压,道長(zhǎng),這世上最難降的妖魔是什么垃瞧? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任蔫劣,我火速辦了婚禮,結(jié)果婚禮上个从,老公的妹妹穿的比我還像新娘脉幢。我一直安慰自己,他們只是感情好嗦锐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布嫌松。 她就那樣靜靜地躺著,像睡著了一般奕污。 火紅的嫁衣襯著肌膚如雪萎羔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天碳默,我揣著相機(jī)與錄音外驱,去河邊找鬼育灸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昵宇,可吹牛的內(nèi)容都是我干的磅崭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瓦哎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼砸喻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蒋譬,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤割岛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后犯助,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體癣漆,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年剂买,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惠爽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瞬哼,死狀恐怖婚肆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坐慰,我是刑警寧澤较性,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站结胀,受9級(jí)特大地震影響赞咙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜糟港,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一攀操、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧着逐,春花似錦崔赌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至秀姐,卻和暖如春慈迈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工痒留, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谴麦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓伸头,卻偏偏與公主長(zhǎng)得像匾效,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子恤磷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • Android繪圖之Shader Shader是繪圖過(guò)程中的著色器面哼,它有五個(gè)子類: BitmapShader Co...
    lavor閱讀 15,239評(píng)論 3 62
  • Paint 類持有繪制圖形、文本扫步、圖像的樣式和色彩信息魔策,并且對(duì)外提供了一系列方法來(lái)設(shè)置這些信息。 一河胎、畫筆基本操作...
    秀花123閱讀 4,301評(píng)論 1 7
  • 在上篇說(shuō)道BitmapShader的使用關(guān)于Shader.TileMode這個(gè)參數(shù)在說(shuō)明一下Shader.Tile...
    大大大寒閱讀 1,530評(píng)論 3 1
  • 用來(lái)實(shí)現(xiàn)線性漸變效果 此類是Shader的子類通過(guò)paint.setShader來(lái)設(shè)置漸變闯袒。 有兩個(gè)構(gòu)造方法分別如...
    gaaaaaaaaaao閱讀 38,286評(píng)論 0 29
  • 所謂在夾縫中生存,很多在大城市里生活的上班族應(yīng)該和我有一樣的想法吧…擁擠的交通游岳,繁忙的街道政敢,信號(hào)燈似乎都沒(méi)有時(shí)間理...
    jojo閱讀 344評(píng)論 0 1