標籤: 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);
}
}