Android動畫之旅(五)----容器的填充動畫

容器充滿動畫

動畫思路:

1.首先波浪形的加載,就是貝塞爾曲線加上動畫,給上下方向和左右方向設置動畫就OK.

2.讓一個東西顯示在某張圖片或圖形之上,需要給畫筆設置PorterDuffXfermode這個類.讓其繪製公共區域,詳情參加安卓羣英傳.

        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

3.需要用到畫布和繪製Bitmap的一些相關知識.

4.爲了動畫效果當快要充滿的時候,波浪的峯值需要遞減到一定程度.
package com.example.administrator.animationworkdemo.views;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.View;

import com.example.administrator.animationworkdemo.R;

/**
 * Created by SuperD on 2017/2/23.
 */

public class WaveLoadingView2 extends View {

    // Xfermode
    private PorterDuffXfermode porterDuffXfermode;
    // 畫筆
    private Paint paint;
    // 源圖片
    private Bitmap bitmap;
    // 控件寬高
    private int width, height;
    // 畫貝塞爾曲線Path
    private Path path;
    // 在該畫布上繪製目標圖片
    private Canvas mCanvas;
    // 目標圖片
    private Bitmap bg;
    // 貝塞爾曲線控制點,使用三階貝塞爾曲線曲線,需要兩個控制點,兩個控制點都在該變量基礎上生成
    private float controlX, controlY;
    // 上升的高度
    private float waveY;
    // 用於控制控制點水平移動
    private boolean isIncrease;

    /**
     * @param context
     */
    public WaveLoadingView2(Context context) {
        this(context, null);
    }

    /**
     * @param context
     * @param attrs
     */
    public WaveLoadingView2(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * @param context
     * @param attrs
     * @param defStyle
     */
    public WaveLoadingView2(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    /**
     * 初始化變量
     */
    private void init() {
        // 初始化畫筆
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.parseColor("#ffc9394a"));
        // 獲得資源文件
        bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        // 設置寬高爲圖片的寬高
        width = bitmap.getWidth();
        height = bitmap.getHeight();
        // 初始狀態值
        waveY = 7 / 8F * height;
        controlY = 17 / 16F * height;
        // 初始化Xfermode
        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        // 初始化path
        path = new Path();
        // 初始化畫布
        mCanvas = new Canvas();
        // 創建bitmap
        bg = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        // 將新建的bitmap注入畫布
        mCanvas.setBitmap(bg);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 畫目標圖,存在bg上
        drawTargetBitmap();
        // 將目標圖繪製在當前畫布上,起點爲左邊距,上邊距的交點
        canvas.drawBitmap(bg, getPaddingLeft(), getPaddingTop(), null);
        invalidate();
    }

    private void drawTargetBitmap() {
        // 重置path
        path.reset();
        // 擦除像素
        bg.eraseColor(Color.parseColor("#00ffffff"));
        // 當控制點的x座標大於或等於終點x座標時更改標識值
        if (controlX >= width + 1 / 2 * width) {
            isIncrease = false;
        }
        // 當控制點的x座標小於或等於起點x座標時更改標識值
        else if (controlX <= -1 / 2 * width) {
            isIncrease = true;
        }
        // 根據標識值判斷當前的控制點x座標是該加還是減
        controlX = isIncrease ? controlX + 10 : controlX - 10;
        if (controlY >= 0) {
            // 波浪上移
            controlY -= 1;
            waveY -= 1;
        } else {
            // 超出則重置位置
            waveY = 7 / 8F * height;
            controlY = 17 / 16F * height;
        }
        // 貝塞爾曲線的生成
        path.moveTo(0, waveY);
        // 兩個控制點通過controlX,controlY生成
        path.cubicTo(controlX / 2, waveY - (controlY - waveY),
                (controlX + width) / 2, controlY, width, waveY);
        // 與下下邊界閉合
        path.lineTo(width, height);
        path.lineTo(0, height);
        // 進行閉合
        path.close();
        // 畫慕課網logo
        mCanvas.drawBitmap(bitmap, 0, 0, paint);
        // 設置Xfermode
        paint.setXfermode(porterDuffXfermode);
        // 畫三階貝塞爾曲線
        mCanvas.drawPath(path, paint);
        // 重置Xfermode
        paint.setXfermode(null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 獲得寬高測量模式和大小
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        // 保存測量結果
        int width, height;
        if (widthMode == MeasureSpec.EXACTLY) {
            // 寬度
            width = widthSize;
        } else {
            // 寬度加左右內邊距
            width = this.width + getPaddingLeft() + getPaddingRight();
            if (widthMode == MeasureSpec.AT_MOST) {
                // 取小的那個
                width = Math.min(width, widthSize);
            }
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            // 高度
            height = heightSize;
        } else {
            // 高度加左右內邊距
            height = this.height + getPaddingTop() + getPaddingBottom();
            if (heightMode == MeasureSpec.AT_MOST) {
                // 取小的那個
                height = Math.min(height, heightSize);
            }
        }
        // 設置高度寬度爲logo寬度和高度,實際開發中應該判斷MeasureSpec的模式,進行對應的邏輯處理,這裏做了簡單的判斷測量
        setMeasuredDimension(width, height);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章