Android 自定義View----屬性動畫(如何在自定義view中添加動畫)

自定義view難免會接觸到動畫,不然很多效果做不出來,動畫分爲幾種,今天主要用到的是屬性動畫;

上面這個效果分上下兩部分完成,在繪製的時候先繪製下半部分,具體代碼如下,裏面有詳細註釋:

public class CameraAnimatorView extends View {

    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    // 圖片左上padding值
    private int mPadding = 300;
    // 圖片寬高
    private int mLength = 800;

    // 上面翻的度數 (因爲要做動畫,所以先全部設置爲0,然後設置get,set方法爲動畫做準備)
    float topFlip = 0;
    // 下面翻的度數
    float bottomFlip = 0;
    // 旋轉度數
    float flipRotation = 0;

    /*
    android.graphics.Camera ( 是這個並不是相機,相機是android.hardware.Camera )
    官方介紹:A camera instance can be used to compute 3D transformations and generate a matrix that can be applied, for instance, on aCanvas.
              (自己隨便翻譯吧)
    Camera對象可以用來計算3D變換,並將計算結果封裝進一個Matrix矩陣,之後便進行應用
     */
    Camera camera = new Camera();

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

    {
        /*
        默認0,0,-8  ( 8 英寸 = 8 * 72 像素 )
        每個手機分辨率不同,所以需要做適配 ,getResources().getDisplayMetrics().density
         */
        camera.setLocation(0, 0, -6 * getResources().getDisplayMetrics().density);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 先繪製下半部分,再繪製上半部分(直接複製)
        /*********************************繪製上半部分*******************************************/
        canvas.save();
        canvas.translate(mPadding + mLength / 2, mPadding + mLength / 2);
        canvas.rotate(-flipRotation);
        camera.save();
        // 以X軸爲軸心旋轉*°
        camera.rotateX(topFlip);
        camera.applyToCanvas(canvas);
        camera.restore();
        canvas.clipRect(-mLength , -mLength , mLength, 0);
        canvas.rotate(flipRotation);
        canvas.translate(-(mPadding + mLength / 2), -(mPadding + mLength / 2));
        canvas.drawBitmap(getAvatar(mLength), mPadding, mPadding, mPaint);
        canvas.restore();

        /**********************************繪製下半部分(倒着繪製)******************************/
        canvas.save();
        /*
        投射原點再0,0位置,如果不移動畫布,映射出來的是變形的圖片(歪的),所以需要先移動再旋轉再挪回來
        挪動位置:padding + 圖片寬高的一半
         */
        canvas.translate(mPadding + mLength / 2, mPadding + mLength / 2);
        canvas.rotate(-flipRotation);

        // 保存狀態
        camera.save();
        // 以X軸爲軸心旋轉*°
        camera.rotateX(bottomFlip);
        // 應用到畫布  根據當前的變換計算出相應的矩陣,然後應用到制定的畫布上
        camera.applyToCanvas(canvas);
        // 回滾狀態
        camera.restore();

        // 只要下半部分,旋轉前切割  因爲涉及到旋轉,所以切割範圍要變大
        canvas.clipRect(-mLength, 0, mLength, mLength);

        // 旋轉20°
        canvas.rotate(flipRotation);

        // 將畫布移回來
        canvas.translate(-(mPadding + mLength / 2), -(mPadding + mLength / 2));

        // 繪製圖片
        canvas.drawBitmap(
                getAvatar(mLength),
                mPadding, mPadding,
                mPaint
        );
        canvas.restore();

    }

    // 自定義動畫配置 topFlip,bottomFlip,FlipRotation
    public float getTopFlip() {
        return topFlip;
    }

    public void setTopFlip(float topFlip) {
        this.topFlip = topFlip;
        invalidate();
    }

    public float getBottomFlip() {
        return bottomFlip;
    }

    public void setBottomFlip(float bottomFlip) {
        this.bottomFlip = bottomFlip;
        invalidate();
    }

    public float getFlipRotation() {
        return flipRotation;
    }

    public void setFlipRotation(float flipRotation) {
        this.flipRotation = flipRotation;
        invalidate();
    }

    Bitmap getAvatar(int width) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        // inJustDecodeBounds爲true,不返回bitmap,只返回這個bitmap的尺寸
        options.inJustDecodeBounds = true;
        // 從資源中讀取(比較浪費資源,所以上面設置爲true,只獲取圖片寬高)
        BitmapFactory.decodeResource(getResources(), R.drawable.ysdry, options);
        // 再設置爲false,最後要返回bitmap
        options.inJustDecodeBounds = false;
        // 根據縮放比例重新計算寬高
        options.inDensity = options.outWidth;
        options.inTargetDensity = width;
        return BitmapFactory.decodeResource(getResources(), R.drawable.ysdry, options);
    }

}

下面是開啓動畫

       /*
        屬性動畫 大概分爲兩種,ViewPropertyAnimator 和 ObjectAnimator
                 前者是系統提供好的,可做一些簡單的平移,縮放,旋轉,漸變
                 後者是自定義屬性動畫,比較靈活
         */
        CameraAnimatorView mCameraAnimatorView = findViewById(R.id.mCameraAnimatorView);

        // bottomFlip對應CameraAnimatorView裏面的bottomFlip,45代表bottomFlip要變化的值
        ObjectAnimator bottomAnimator=ObjectAnimator.ofFloat(mCameraAnimatorView,"bottomFlip",45);
        // 設置時長
        bottomAnimator.setDuration(1500);

        ObjectAnimator flipRotationAnimator=ObjectAnimator.ofFloat(mCameraAnimatorView,"flipRotation",270);
        flipRotationAnimator.setDuration(1500);

        ObjectAnimator topFlipAnimator=ObjectAnimator.ofFloat(mCameraAnimatorView,"topFlip",-45);
        flipRotationAnimator.setDuration(3300);

        // 多個動畫,分先後順序填寫到playSequentially方法中
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playSequentially(bottomAnimator,flipRotationAnimator,topFlipAnimator);
        // 延遲動畫啓動的時間
        animatorSet.setStartDelay(2000);
        animatorSet.start();

 

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