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方法
常用的可以直接使用屬性動畫的屬性包括:
- translationX和translationY:控制view從它佈局容器左上角座標偏移的位置;
- rotation、rotationX和rotationY:控制view圍繞支點進行2D和3D旋轉;
- scaleX和scaleY:控制view圍繞著它的支點進行2D縮放;
- pivotX和pivotY:控制支點位置,圍繞這個支點進行旋轉和縮放處理。預設情況下,支點是view的中心點;
- x和y:控制view在它的容器中的最終位置,它是最初的左上角座標和translationX、translationY的累計和;
- 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向量動畫機制
挖坑待填-_-