1. 程式人生 > >Android群英傳之Android動畫機制與使用技巧

Android群英傳之Android動畫機制與使用技巧

1、檢視動畫

檢視動畫定義了透明度AlphaAnimation、旋轉RotateAnimation、縮放ScaleAnimation、位移TranslateAnimation四種基本動畫,還提供AnimationSet動畫集合,混合使用多種動畫。

原理
1. 每次繪製時,View所在的ViewGroup中的drawChild函式獲取該View的Animation的Transformation值
2. 呼叫canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀
3. 如果一次繪製結束,動畫沒有完成,就繼續呼叫invalidate,啟動下次繪製,知道動畫繪製完成
另外


Animation也提供了對應得監聽回撥,監聽動畫開始、結束、重複事件

2、屬性動畫

檢視動畫改變的只是顯示,並不能響應事件。而屬性動畫也可以讓控制元件的對事件的監聽轉移位置。最常使用的就是AnimatorSet和ObjectAnimator。

1)ObjectAnimator

一般形式:

ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 300);
animator.setDuration(1000);
animator.start();

ObjectAnimator使用靜態工廠方法生成動畫物件,第一個引數為要控制的物件,第二個引數為要控制的屬性值(該屬性必須有get和set方法

,因為實現原理就是通過Java的反射機制呼叫set函式修改物件屬性值),第三個引數該屬性變化的取值(也可以是陣列)

常用的可以直接使用屬性動畫的屬性包括

  1. translationX和translationY:控制view從它佈局容器左上角座標偏移的位置;
  2. rotation、rotationX和rotationY:控制view圍繞支點進行2D和3D旋轉;
  3. scaleX和scaleY:控制view圍繞著它的支點進行2D縮放;
  4. pivotX和pivotY:控制支點位置,圍繞這個支點進行旋轉和縮放處理。預設情況下,支點是view的中心點;
  5. x和y:控制view在它的容器中的最終位置,它是最初的左上角座標和translationX、translationY的累計和;
  6. alpha:控制透明度,預設是1(不透明)。

如果一個屬性沒有get、set方法怎麼辦?

a)自定義屬性類或包裝類,新增get、set方法

public class WrapperView {

    private View mView;

    public WrapperView(View mView){
        this.mView = mView;
    }

    public int getWidth(){
        return mView.getLayoutParams().width;
    }

    public void setWidth(int width){
        mView.getLayoutParams().width = width;
        mView.requestLayout();
    }
}

b)通過ValueAnimator實現
本節後續會介紹

2)ValueAnimator

ObjectAnimator就是繼承自ValueAnimator的,它是屬性動畫的核心,ValueAnimator不提供任何動畫效果,它就是一個數值產生器,用來產生具有一定規律的數字,從而讓呼叫者來控制動畫的實現過程,控制的方式是使用AnimatorUpdateListener來監聽數值的變換。

ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float value = (Float) animation.getAnimatedValue();
        //do the animation!
    }
});

3)動畫事件的監聽

一個完整的動畫有Start、Repeat、End、Cancle四個過程,Android提供介面監聽這四個事件

animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

大多數時候,只需要關心動畫什麼時候結束,就可以使用Android的簡易介面卡AnimatorListenerAdapter,其實它就是實現了介面AnimatorListener的抽象類,這樣具體想監聽那個具體事件就繼承並重寫那個方法即可

animator1.addListener(new AnimatorListenerAdapter() {
  @Override
   public void onAnimationEnd(Animator animation) {
       super.onAnimationEnd(animation);
   }
});

3)使用多個屬性動畫效果

a)PropertyValuesHolder

PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("rotation", 360);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(propertyBt, pvh1, pvh2, pvh3).setDuration(1000).start();

b)AnimatorSet

屬性動畫集合AnimatorSet:控制多個動畫的協同工作方式,常用方法animatorSet.play().with().before().after()、playTogether、playSequentially等方法來精確控制動畫播放順序。

ObjectAnimator animator1 = ObjectAnimator.ofFloat(animBt, "rotation", 360);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(animBt, "scaleX", 1f, 0, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(animBt, "scaleY", 1f, 0, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playSequentially(animator1, animator2, animator3);
set.start();

更推薦使用AnimatorSet,既可以與PropertyValuesHolder一樣實現幾個屬性動畫同時使用,也可以定義幾個動畫的先後順序

4)在xml中使用屬性動畫

在animator資料夾下定義屬性動畫

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:app="http://schemas.android.com/apk/res/android"
    app:duration="1000"
    app:propertyName="scaleX"
    app:valueFrom="1.0"
    app:valueTo="2.0"
    app:valueType="floatType">

</objectAnimator>

在程式碼中使用

Animator anim = AnimatorInflater.loadAnimator(this, R.animator.anim);
anim.setTarget(xmlBt);
anim.start();

5)View的animate方法

屬性動畫的簡寫方式

imageView.animate().alpha(0).y(100).setDuration(1000)
        .setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        }).start();

3、Android佈局動畫

ViewGroup增加View時的動畫,使用以下程式碼開啟系統預設的動畫

android:animateLayoutChanges="true"

自定義佈局動畫

 LinearLayout ll = (LinearLayout) findViewById(R.id.layout_anim);
 ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
 sa.setDuration(2000);
 LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f);
 lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
 ll.setLayoutAnimation(lac);
  • LayoutAnimationController.ORDER_NORMAL順序
  • LayoutAnimationController.ORDER_RANDOM順序隨機
  • LayoutAnimationController.ORDER_REVERSE反序

4、Interpolators(差值器)

定義動畫變化速率,類似加速度。

5、自定義動畫

建立自定義動畫就是要實現它的applyTransformation的邏輯,不過通常還需要覆蓋父類的initialize方法來實現初始化工作。

applyTransformation(float interpolatedTime, Transformation t)

第一個引數interpolatedTime差值器的時間因子
第二個引數Transformation,矩陣封裝類,一般使用此類獲取當前的矩陣物件:

final Matrix matrix = mTransformation.getMartix()

通過改變matrix物件,可將動畫效果顯示出來,matrix的變化基本可實現任何動畫效果
模擬電視關閉動畫

public class CustomTV extends Animation {

    private int mCenterWidth;
    private int mCenterHeight;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(1000);// 設定預設時長
        setFillAfter(true);// 動畫結束後保留狀態
        setInterpolator(new AccelerateInterpolator());// 設定預設插值器
        mCenterWidth = width / 2;
        mCenterHeight = height / 2;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final Matrix matrix = t.getMatrix();
        matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight);
    }
}

3D動畫
使用android.graphics.Camera中的Camera類,它封裝了OpenGL的3D動畫。可以把Camera想象成一個真實的攝像機,當物體固定在某處時,只要移動攝像機就能拍攝到具有立體感的影象,因此通過它可以實現各種3D效果。

public class CustomAnim extends Animation {

    private int mCenterWidth;
    private int mCenterHeight;
    private Camera mCamera = new Camera();
    private float mRotateY = 0.0f;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(2000);// 設定預設時長
        setFillAfter(true);// 動畫結束後保留狀態
        setInterpolator(new BounceInterpolator());// 設定預設插值器
        mCenterWidth = width / 2;
        mCenterHeight = height / 2;
    }

    // 暴露介面-設定旋轉角度
    public void setRotateY(float rotateY) {
        mRotateY = rotateY;
    }

    @Override
    protected void applyTransformation( float interpolatedTime, Transformation t) {
        final Matrix matrix = t.getMatrix();
        mCamera.save();
        mCamera.rotateY(mRotateY * interpolatedTime);// 使用Camera設定旋轉的角度
        mCamera.getMatrix(matrix);// 將旋轉變換作用到matrix上
        mCamera.restore();
        // 通過pre方法設定矩陣作用前的偏移量來改變旋轉中心
        matrix.preTranslate(mCenterWidth, mCenterHeight);
        matrix.postTranslate(-mCenterWidth, -mCenterHeight);
    }
}

6、Android 5.X SVG向量動畫機制

挖坑待填-_-