《Android羣英傳》---讀書筆記5

標籤: android中級 讀書筆記


Android動畫機制與使用技巧

包括:
Android視圖動畫
Android屬性動畫
還包括下一篇的 Android5.X引入的 SVG 矢量動畫

7.1 Android View動畫框架

Animation框架定義了透明度,旋轉,縮放和位移幾種常見的動畫,而且控制的是整個View
視圖動畫使用很簡單,提供了AlphaAnimation,RotateAnimation,TranslateAnimation,ScaleAnimation四種動畫方式,並且提供了AnimationSet動畫集合,混合使用多種動畫
可以使用XML文件來描述一個動畫過程,同樣也可以使用代碼來控制整個動畫過程

透明度動畫
AlphaAnimation aa=new AlphaAnimation(0,1);
aa.setDuration(1000);
view.starAnimation(aa);

旋轉動畫
RotateAnimation ra=new RotateAnimation(0,360,100,100);
ra.setDuration(1000);
view.startAnimation(ra);
也可以將旋轉中心設置爲自身中心點
RotateAnimation ra=new RotateAnimation(0,360,RorateAnimation,RELATIVE_TO_SELF,0.5F,RELATIVE_TO_SELF,0.5F);

位移動畫
TranslateAnimation ta=new TranslateAnimation(0,200,0,300);
ta.setDuration(1000);
view.startAnimation(ta);

縮放動畫
ScaleAnimation sa=new ScaleAnimation(0,2,0,2);
sa.setDuration(1000);
view.startAnimation(sa);
也可以設置旋轉中心爲自身中心

動畫集合
AnimationSet as=new AnimationSet(true);
as.setDuration(1000);

AlphaAnimation aa=new AlphaAnimation(0,1);
aa.setDuration(1000);
as.addAnimation(aa);

TranslateAnimation ta=new TranslateAnimation(0,100,0,200);
ta.setDuration(1000);
as.addAnimation(ta);

view.startAnimation(as);

對於動畫事件,可以設置對應的監聽回調
animation.setAnimationListener(new Animation.AnimationListener(){
@Override
public void onAnimationStart(Animation animation){
}
@Override
public void onAnimationEnd(Animation animation){
}
@Override
public void onAnimationRepeat(Animation animation){
}
});

7.2 Android屬性動畫分析

Animation(即視圖動畫)存在的一些侷限性—例如改變的只是顯示,不能相應事件,所以引入了屬性動畫
Animator框架中使用最多就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator進行更加精細化的控制。而且可以調用setFrameDelay(longframDelay)設置動畫幀之間的間隙時間,減少CPU資源的消耗。

7.2.1 ObjectAnimator
使用ObjectAnimator控制的對象的相應屬性,該屬性必須具有get和set函數。
ObjectAnimator animator =ObjectAnimator.ofFloat(view,”translationX”,300);
animator.setDuration(300);
animator.start();

常用的屬性動畫的屬性值:
translateX和translationY:控制着View對象從它佈局容器的左上角座標的偏移量
rotation,rotationX和rotationY:控制View對象圍繞支點進行2D和3D旋轉
scaleX和scaleY:圍繞支點進行2D縮放
pivotX和pivotY:控制View對象的支點位置,圍繞這個支點進行旋轉和縮放變換處理。默認情況下就是View對象的中心點
x和y:描述了View對象在它的容器中的最終位置,它是translationX,translationY值得累計和
alpha:表示View對象的alpha透明度

如果一個屬性沒有get,set方法,可以採用包裝類的方式,或者使用ValueAnimator來實現

private static WrapperView{
private View mTarget;
public WrapperView(View target){
    mTarget=target;
}
public int getWidth(){
return mTarget.getLayoutParams().width;
}
public void setWidth(){
    mTarget.getLayoutParams().width=width;
    mTarget.requestLayout();
}
}
然後 就可以通過包裝類來間接使用ObjectAnimator來使用屬性動畫
ViewWrapper wrapper=new ViewWrapper(mButton);
ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();

7.2.2 PropertyValuesHolder
類似於視圖動畫中的AnimationSet,在屬性動畫中,可以使用PropertyValuesHolder來實現對同一個對象的多個屬性,同時作用多種動畫。例如在平移動畫中,在平移的過程中同時改變X,Y軸的縮放

PropertyValuesHolder phv1=PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder phv2=PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
PropertyValuseHolder.ofFloat("scaleY",1f,0,1f);
ObjectAnimator.ofPropertyValuesHolder(view,phv1,phv2,phv3).setDuration(1000).start();

7.2.3 ValueAnimator
ValueAnimator本身不提供任何動畫效果,它更像一個數值發生器,用來產生具有一定規律的數值從而讓調用者來控制動畫的實現過程

ValueAnimator animator=ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(3000).start();
animator.addUpdateListener(new AnimatorUpdateListener(){
@Override
public void onAnimatorUpdate(ValueAnimator animation){
Float value=(Float)animation.getAnimatedValue();
//TODO use the value
}
});

7.2.4 動畫事件的監聽
一個完整的動畫具有 Start, Repeat,End,Cancel四個過程,

ObjectAnimator anim=ObjectAnimator.ofFloat(view,"alpha",0.5f);
anim.addListener(new AnimatorListener(){
//some Methods to Override...
});

不過大多數時候我們只關心onAnimationEnd事件,所以只需要通過AnimatorListenerAdapter進行監聽就行

anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){

}
});

7.2.5 AnimatorSet
AnimatorSet相比PropertyValuesHolder能實現更加精確的控制

ObejectAnimator animator1=ObjectAnimator.ofFloat(view,"translationX",300f);
ObejectAnimator animator2=ObjectAnimator.ofFloat(view,"scaleX",1f,0f,1f);
ObejectAnimator animator3=ObjectAnimator.ofFloat(view,"scaleY",1f,0f,1f);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.playTogether(animator1,animator2,animator3);
set.start();

AnimatorSet可以通過playTogether(), playSequentially(), animSet.play().with(), before(), after()這些方法來控制多個動畫的協同工作方式

7.2.6 在XML中使用屬性動畫

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

然後直接在程序中使用
public void scaleX(View view){
Animator anim=Animator.loadAnimator(this,R.animator.scalex);
anim.setTarget(mMv);
anim.start();
}

7.2.7 View的animate方法
Android 3.0之後,可以使用View的animate方法直接驅動屬性動畫

view.animate().alpha(0).y(300).setDuration(300).withStartAction(new Runable(){
@Override
public void run(){  }
}).withEndAction(new Runable(){
@Override
 public void run(){ 
    runOnUiThread(new Runable(){
        @Override
         public void run(){  }
         }
    });
    }
}).start();

7.3 Android佈局動畫

佈局動畫就是指ViewGroup增加View時添加一個動畫過度效果。
最簡單的佈局動畫就是在ViewGroup的XML中,使用以下代碼來打開佈局動畫,從而實現默認的動畫效果
android:animateLayoutChanges=”true”

另外還可以使用LayoutAnimationController類來自定義一個子View的過度效果

LinerLayout ll=(LinearLayout)findViewById(R.id.ll);
//設置過度動畫
ScaleAnimation sa=new ScaleAnimation(0,1,0,1);
sa.setDuration(2000);
//設置佈局動畫的顯示屬性
LayoutAnimatorController lac=new LayoutAnimationController(sa,0.5f);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
//爲ViewGroup設置佈局動畫
ll.setLayoutAnimation(lac);

LayoutAnimationController的第一個參數是需要作用的動畫,第二個參數是每個子View顯示的delay時間。當delay不爲0時,可以設置子View的顯示順序

Interpolators(插值器)

通過插值器可以定義動畫的變換速率,非常類似於物理中的加速度,其主要作用是控制目標變量的變化值進行對應的變化。在不同的插值器的作用下同一個動畫的起始值,每個單位時間內所達到的變化值是不一樣的。

7.5 自定義動畫、

創建自定義動畫非常簡單,只需要實現它的applyTransformation的邏輯就可以了,不過通常情況下,還需要覆蓋父類的initialize方法來進行一些初始化工作。

applyTransformation(float interpolateTime,Transformation t)//第一個參數爲時間因子,取值範圍0到1.0;第二個參數爲一個矩陣的封裝類,一般通過這個類來獲得當前的矩陣對象:final Matrix matrix=t.getMatrix();
通過改變獲得的matrix對象,就可以將動畫效果實現出來

下面的代碼示例實現一個類似於電視機關閉的動畫

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class CustomTV 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(1000);
    // 動畫結束後保留狀態
    setFillAfter(true);
    // 設置默認插值器
    setInterpolator(new AccelerateInterpolator());
    mCenterWidth = width / 2;
    mCenterHeight = height / 2;
}

// 暴露接口-設置旋轉角度
public void setRotateY(float rorateY) {
    mRotateY = rorateY;
}

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

也可以結合矩陣,並使用Camera類來實現一個自定義的3D動畫。
這裏的Camera類指的是android.graphics.Camera中的Camera類,它封裝課openGL的3D動畫,從而可以非常方便的創建3D動畫效果

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.Transformation;

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();
    // 使用Camera設置旋轉的角度
    mCamera.rotateY(mRotateY * interpolatedTime);
    // 將旋轉變換作用到matrix上
    mCamera.getMatrix(matrix);
    mCamera.restore();
    // 通過pre方法設置矩陣作用前的偏移量來改變旋轉中心
    matrix.preTranslate(mCenterWidth, mCenterHeight);
    matrix.postTranslate(-mCenterWidth, -mCenterHeight);
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章