Android自定義控件(六)——文字波浪加載效果

前面介紹了貝濟埃曲線,實現了波浪動畫,也介紹了顏色疊加相關模式,比如其中的SRC_OUT模式實現了刮刮樂,今天將反過來以目標圖像模式來是實現文字波浪加載動畫效果。

1.目標圖像模式DST_IN

在前面的刮刮樂中,SRC爲前綴的所有模式都是以源圖像顯示爲主;今天介紹的模式DST_IN在DST(目標相關模式)中,優先以目標圖像爲主,也就是說,SRC_IN與DST_IN,只要交換源圖像與目標圖像,其實實現的效果是相同的。

public PorterDuffXfermode(PorterDuff.Mode mode)

那麼什麼是DST_IN模式?

Mode.DST_IN是在相交時利用源圖像的透明度來改變目標圖像的透明度和飽和度的,也就是當源圖像透明度爲0時,目標圖像完全不顯示,同理SRC_IN就是把源圖像與目標圖像反過來。

那麼具體可以實現什麼效果呢?

比如今天小編要講解的文字波浪加載效果,假設文字圖像爲源圖像,藍色波浪爲目標圖像,那麼除文字圖像中文字不透明外,其他地方都是透明度爲0,也就是波浪目標圖像相交的透明區域不會顯示,那麼波浪就會附着在文字上面顯示,形成波浪文字加載效果。

2.實現文字播放加載效果

原理我們已經分析清楚了,接着按照自定義控件步驟,先自定義一個View,然後初始化成員變量,方便後面使用,代碼如下:

public class TextWaveView extends View {
    private Paint paint;//畫筆工具
    private Path path;//路徑
    private int waveLength=200;//波長
    private int dx,dy;//記錄動畫位置
    private Bitmap srcBitmap,dstBitmap;//源圖像,目標圖像
    public TextWaveView(Context context) {
        super(context);
    }

    public TextWaveView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.paint=new Paint();
        this.path=new Path();
        this.paint.setColor(Color.GREEN);
        this.paint.setStyle(Paint.Style.FILL_AND_STROKE);
        this.srcBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.text_name);//獲取源圖像
        this.dstBitmap=Bitmap.createBitmap(this.srcBitmap.getWidth(),this.srcBitmap.getHeight(),Bitmap.Config.ARGB_8888);/以源圖像大小創建目標圖像位圖
        this.startAnim();//這裏動畫實現
    }
}

上面都是一些自定義View後,所需要做的成員變量初始化,以防止空指針異常。細心的夥伴應該已經看到了,這裏有個動畫實現,那我們先來實現動畫。

這裏我們來分析一下,需要實現那些動畫?肯定有波浪移動動畫,也肯定有波浪慢慢覆蓋文字動畫,所以我們需要實現兩個動畫效果,這裏爲了代碼的可讀性,小編寫成了兩個動畫,後面會講解組合動畫,代碼如下:

/***
     * 動畫初始化
     */
private void startAnim(){
    ValueAnimator waveAnim=ValueAnimator.ofInt(0,this.waveLength);//波浪動畫,一個波長
    waveAnim.setDuration(2000);//動畫事件2秒
    waveAnim.setRepeatCount(ValueAnimator.INFINITE);//無限循環
    waveAnim.setInterpolator(new LinearInterpolator());//勻速變化,插值器,可以加速,減速以及自定義
    waveAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            dx=(Integer)animation.getAnimatedValue();//獲取動畫進度
            postInvalidate();//重繪
        }
    });
    //覆蓋文字動畫
    ValueAnimator CoverAnim=ValueAnimator.ofInt(0,this.waveLength/4,this.waveLength/4,this.waveLength/3,this.waveLength/3,this.waveLength/2,this.waveLength/2,this.waveLength);
    CoverAnim.setDuration(5000);//動畫事件爲5秒
    CoverAnim.setRepeatCount(ValueAnimator.INFINITE);//無線循環
    CoverAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            dy=(Integer)animation.getAnimatedValue();//獲取動畫進度
            postInvalidate();//重繪
       }
    });
    //開始動畫
    waveAnim.start();
    CoverAnim.start();
}

備註應該非常詳細了,這裏就不做過多的贅述,接着,我們需要繪製波浪,對於波浪效果的實現,在前面第三節貝濟埃曲線中已經詳細講解過了,這裏的代碼幾乎跟那裏的代碼一模一樣,也要用到貝濟埃曲線rQuadTo()函數,代碼如下:

***
 * 繪製波浪
 */
private void drawWavePath(){
    this.path.reset();//清除之前繪製的path
    int originY=this.srcBitmap.getHeight()/2;
    int halfLength=this.waveLength/2;
    //設置波浪起始點,加上動畫的偏移量,形成動畫效果
    this.path.moveTo(-this.waveLength+dx,originY-dy);
    //循環設置整個屏幕+waveLength長的波浪
    for(int i=-this.waveLength;i<=getWidth()+this.waveLength;i+=this.waveLength){
        //兩句代碼組成一個波長,中間到波峯在到中間是第一個rQuadTo,中間到波谷到中間是第二rQuadTo
        this.path.rQuadTo(halfLength/2,-50,halfLength,0);
        this.path.rQuadTo(halfLength/2,50,halfLength,0);
    }
    //閉合區域
    this.path.lineTo(this.srcBitmap.getWidth(),this.srcBitmap.getHeight());
    this.path.lineTo(0,this.srcBitmap.getHeight());
    this.path.close();
}

這裏面的註釋也很多,但是如果你還不理解貝濟埃曲線,可以前往該專欄第三篇《Android自定義控件(三)——貝濟埃曲線與水波紋動畫》那裏,詳細原理那裏都有。接着該把實現的水波紋以及文字都繪製到屏幕上,下面我們實現OnDraw()函數,代碼如下:

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    drawWavePath();//繪製波紋
    Canvas c=new Canvas(this.dstBitmap);
    c.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
    c.drawPath(this.path,this.paint);//將波紋繪製到目標圖像上
    canvas.drawBitmap(this.srcBitmap,0,0,this.paint);//繪製源圖像
    //離屏繪製的代碼在canvas.save與canvas.restoreToCount中間
    int layerId=canvas.saveLayer(0,0,getWidth(),getHeight(),null,Canvas.ALL_SAVE_FLAG);
    canvas.drawBitmap(this.dstBitmap,0,0,this.paint);//首先繪製目標圖像
    this.paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//設置畫筆的圖像模式
    canvas.drawBitmap(this.srcBitmap,0,0,this.paint);//繪製源圖像
    this.paint.setXfermode(null);//設置畫筆的圖像模式爲空
    canvas.restoreToCount(layerId);
}

備註:Xfermode的混合模式,先後畫出目標圖層與源圖層,記住,這個順序不能變,不管是SRC源圖像模式,還是DST目標圖像模式,這個都是永恆不變的。

最後就是XML代碼,無非也就是想引用其他控件一樣直接使用自定義控件,代碼如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.liyuanjinglyj.textwaveapplication.TextWaveView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

Github下載地址:點擊下載

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