Android動畫之旅(六)----放大鏡的特效動畫

放大鏡特效動畫

動畫核心:
1.主要考驗動畫的拆分,然後分析動畫.

2.判斷一個動畫好與壞,主要是看動畫的平滑程度,而能解決動畫不平滑需要做很多處理,這就考驗做動畫的人的能力.

3.mPaint.setStrokeCap(Paint.Cap.ROUND)畫筆的筆刷 是方形 還是圓形,看平滑程度.

4.兩種控制動畫的手段
(1) onDraw{
    switch(status){
        case 0 :
            break;
        case 0 :
            break;
        case 0 :
            break;
        case 0 :
            break;
        case 0 :
            break;
    }
}

(2)onDraw{
    if(mFraction> 0.3){

    }else{

    }
}

5.上述兩種方式可以搭配工具類使用.會更好.

6.主要將動畫分解,然後學會動畫.
package com.example.administrator.animationworkdemo.views;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * Created by SuperD on 2017/2/28.
 * Demo10中的View
 */

public class SearchAnimView2 extends View implements View.OnClickListener {
    private static final int LINE_WIDTH = 9;
    private static final int LINE_COLOR = Color.BLACK;
    private static final int DEFAULT_POINT_SIZE = 3;
    private static final int DEFAULT_DURATION = 3000;

    private Paint mPaint;
    private Paint mArcPaint;

    private boolean isDotShowing = true;

    //基本的數據參數
    private float mWidth;
    private float mHeight;
    private float mCenterX;
    private float mCenterY;
    //圓的半徑
    private float mCircleRadius;
    //顯示圓的範圍
    private RectF mRectF;
    //整體的路徑
    private Path mPath;
    //外圈的粘性部分
    private Path mArcPath;
    private PathMeasure mPathMeasure;
    private float mPathLength;
    private float mCurrentPos[] = new float[2];
    private float mCurrentTan[] = new float[2];

    private ValueAnimator mAnim;
    //當前動畫播放的進度
    private float mFraction;


    public SearchAnimView2(Context context) {
        this(context, null);
    }

    public SearchAnimView2(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SearchAnimView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //設置筆刷的圖形樣式,以下筆刷爲圓形樣式.
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(LINE_WIDTH);
        mPaint.setColor(LINE_COLOR);

        mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mArcPaint.setStyle(Paint.Style.FILL);
        mArcPaint.setColor(Color.WHITE);

        mPath = new Path();
        mPathMeasure = new PathMeasure();
        mArcPath = new Path();

        mAnim = ValueAnimator.ofFloat(1f, 100f);
        mAnim.setDuration(DEFAULT_DURATION);
        mAnim.setInterpolator(new LinearInterpolator());
        mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mFraction = animation.getAnimatedFraction();
                invalidate();
            }
        });
        setOnClickListener(this);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        mCenterX = mWidth / 2;
        mCenterY = mHeight / 2;
        mCircleRadius = mWidth / 4;
        //繪製圓弧的範圍
        mRectF = new RectF(
                mCenterX - 0.95f * mCircleRadius,
                mCenterY - 0.95f * mCircleRadius,
                mCenterX + 0.95f * mCircleRadius,
                mCenterY + 0.95f * mCircleRadius);
        //移動到圓柄的尾部
        mPath.moveTo(mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2),
                mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2));
        mPath.lineTo(mCenterX, mCenterY);
        //形成R 根號3 R 2R的直角三角形
        mPath.lineTo(mCenterX - 0.45f * mCircleRadius * (float) Math.sqrt(3),
                mCenterY + 0.45f * mCircleRadius);
        //取對稱點
        mPath.lineTo(mCenterX - 0.45f * mCircleRadius * (float) Math.sqrt(3),
                mCenterY - 0.45f * mCircleRadius);
        mPath.lineTo(mCenterX + 0.45f * mCircleRadius * (float) Math.sqrt(3),
                mCenterY);
        //回到原點
        mPath.lineTo(mCenterX, mCenterY);
        mPath.lineTo(mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2),
                mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2));
        mPathMeasure.setPath(mPath, false);
        mPathLength = mPathMeasure.getLength();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float sin45 = (float) Math.sin(Math.PI / 4);
        //通過mFraction來控制動畫的時間階段.
        if (mFraction <= 0.2) { //放大鏡手柄收縮
            //在0.2f的路程內手柄從 1 到 0 消失成點
            canvas.drawCircle(mCenterX, mCenterY, mCircleRadius - mCircleRadius * mFraction, mPaint);
            canvas.drawLine(mCenterX + mCircleRadius * sin45 + 1.2f * mCircleRadius * sin45 * mFraction / 0.2f,
                    mCenterY + mCircleRadius * sin45 + 1.2f * mCircleRadius * sin45 * mFraction / 0.2f,
                    mCenterX + 2.2f * mCircleRadius * sin45,
                    mCenterY + 2.2f * mCircleRadius * sin45,
                    mPaint);
        } else if (mFraction <= 0.8) {
            //取 0.2f -0.6f的path的點
            mPathMeasure.getPosTan(0 + mPathLength * (mFraction - 0.2f) / 0.6f, mCurrentPos, mCurrentTan);
            //在圓心左右R/3處閃爍小球,形成閃爍效果.
            if (mCurrentPos[1] == mCenterY &&
                    mCurrentPos[0] <= mCenterX + mCircleRadius / 3 &&
                    mCurrentPos[0] >= mCenterX - mCircleRadius / 3) {
                if (isDotShowing) {
                    isDotShowing = false;
                } else {
                    //在軌跡中的小球
                    canvas.drawCircle(mCurrentPos[0], mCurrentPos[1], DEFAULT_POINT_SIZE, mPaint);
                    isDotShowing = true;
                }
            } else {
                canvas.drawCircle(mCurrentPos[0], mCurrentPos[1], DEFAULT_POINT_SIZE, mPaint);
            }
            //小球從外部回來的過程, 圓的半徑需要回復圓狀
            if (mFraction <= 0.3) {
                canvas.drawCircle(mCenterX, mCenterY,
                        0.8f * mCircleRadius + mCircleRadius * 2 * (mFraction - 0.2f), mPaint);
            } else {
                canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mPaint);
            }
            //就是一層白色的背景效果,在小球進入圓的時候做了一層效果
            if (mFraction <= 0.35 && mFraction > 0.3) {
                canvas.drawArc(mRectF, 45 - 55 * (mFraction - 0.3f) / 0.05f,
                        110 * (mFraction - 0.3f) / 0.05f, false, mArcPaint);
            } else if (mFraction <= 0.4 && mFraction > 0.35) {
                canvas.drawArc(mRectF, 45 - 55 / 0.05f * (0.4f - mFraction),
                        110 / 0.05f * (0.4f - mFraction), false, mArcPaint);
            }

            //外圈的粘性部分,在小球出去的時候 繪製一條彈力的貝塞爾曲線.
            if (mFraction <= 0.75 && mFraction > 0.7) {
                mArcPath.reset();
                mArcPath.moveTo(mCenterX + mCircleRadius, mCenterY);
                mArcPath.cubicTo(mCenterX + mCircleRadius + 8 * (mFraction - 0.7f) / 0.05f,
                        mCenterY + mCircleRadius / 2 + 8 * (mFraction - 0.7f) / 0.05f,
                        mCenterX + mCircleRadius / 2 + 8 * (mFraction - 0.7f) / 0.05f,
                        mCenterY + mCircleRadius + 8 * (mFraction - 0.7f) / 0.05f,
                        mCenterX,
                        mCenterY + mCircleRadius);
                canvas.drawPath(mArcPath, mPaint);
            } else if (mFraction <= 0.8 && mFraction > 0.75) {
                mArcPath.reset();
                mArcPath.moveTo(mCenterX + mCircleRadius, mCenterY);
                mArcPath.cubicTo(mCenterX + mCircleRadius + 8 * (0.8f - mFraction) / 0.05f,
                        mCenterY + mCircleRadius / 2 + 8 * (0.8f - mFraction) / 0.05f,
                        mCenterX + mCircleRadius / 2 + 8 * (0.8f - mFraction) / 0.05f,
                        mCenterY + mCircleRadius + 8 * (0.8f - mFraction) / 0.05f,
                        mCenterX,
                        mCenterY + mCircleRadius);
                canvas.drawPath(mArcPath, mPaint);
            }
        } else { //放大鏡手柄伸長
            canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mPaint);
            canvas.drawLine(mCenterX + 2.2f * mCircleRadius * sin45 - 1.2f * mCircleRadius * sin45 * (mFraction - 0.8f) / 0.2f,
                    mCenterY + 2.2f * mCircleRadius * sin45 - 1.2f * mCircleRadius * sin45 * (mFraction - 0.8f) / 0.2f,
                    mCenterX + 2.2f * mCircleRadius * sin45,
                    mCenterY + 2.2f * mCircleRadius * sin45
                    , mPaint);
        }


    }

    @Override
    public void onClick(View v) {
        if (!mAnim.isRunning()) {
            mAnim.start();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章