首語
- 這是Android動畫系列的目錄,有興趣的可以學習:Android動畫。
補間動畫
補間動畫指的是做FLASH動畫時,在兩個關鍵幀中間需要做“補間動畫”,才能實現圖畫的運動;插入補間動畫後兩個關鍵幀之間的插補幀是由計算機自動運算而得到的。
實際上,Android 的補間動畫也是由我們指定動畫開始、動畫結束2個關鍵點,中間部分的動畫由系統完成。
- 補間動畫又叫View動畫。上一章的幀動畫和補間動畫都屬於視圖動畫。View動畫的作用對象是View,它支持四種動畫效果,分別爲平移動畫、縮放動畫、旋轉動畫和透明度動畫。同時也就對應着Animation的四個子類:
TranslateAnimation
、ScaleAnimation
、RotateAnimation
、AlphaAnimation
。具體如下表所示。
名稱 | 標籤 | 子類 | 效果 |
---|---|---|---|
平移動畫 | <translate> | TranslateAnimation | 移動View |
縮放動畫 | <scale> | ScaleAnimation | 放大或縮小View |
旋轉動畫 | <rotate> | RotateAnimation | 旋轉View |
透明度動畫 | <alpha> | AlphaAnimation | 改變View的透明度 |
- 補間動畫可以通過兩種方式實現,XML實現和代碼實現。建議採用XML來實現,因爲XML格式的動畫可讀性更好。
插值器
- 在動畫實現之前,瞭解一下插值器的知識。插值器用來控制動畫的變化速度,可以理解成動畫渲染器,當然我們也可以自己實現Interpolator 接口,自行來控制動畫的變化速度,而Android中已經爲我們提供了五個可供選擇的實現類。
LinearInterpolator:
動畫以均勻的速度改變AccelerateInterpolator:
在動畫開始的地方改變速度較慢,然後開始加速AccelerateDecelerateInterpolator:
在動畫開始、結束的地方改變速度較慢,中間時加速CycleInterpolator:
動畫循環播放特定次數,變化速度按正弦曲線改變: Math.sin(2 * mCycles * Math.PI * input)DecelerateInterpolator:
在動畫開始的地方改變速度較快,然後開始減速AnticipateInterpolator:
反向,先向相反方向改變一段再加速播放AnticipateOvershootInterpolator:
開始的時候向後然後向前甩一定值後返回最後的值BounceInterpolator:
跳躍,快到目的值時值會跳躍,如目的值100,後面的值可能依次爲85,77,70,80,90,100OvershottInterpolator:
回彈,最後超出目的值然後緩慢改變到目的值
- XML實現中,屬性是:
android:interpolator
, 而上面對應的值是:@android:anim/linear_interpolator
,其實就是駝峯命名法變下劃線而已AccelerateDecelerateInterpolator
對應:@android:anim/accelerate_decelerate_interpolator
!
XML實現
- 補間動畫的XML文件位置在
res/anim
目錄中。
平移動畫
<!--fromXDelta/fromYDelta:動畫起始位置的X/Y座標。-->
<!--toXDelta/toYDelta:動畫結束位置的X/Y座標。-->
<!--duration:動畫播放的速度。-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="320"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="2000"/>
縮放動畫
<!--fromXScale/fromYScale:沿着X軸/Y軸縮放的起始比例。-->
<!--toXScale/toYScale:沿着X軸/Y軸縮放的結束比例。-->
<!--pivotX/pivotY:縮放的中軸點X/Y座標,即距離自身左邊緣的位置,比如50%就是以圖像的 中心爲中軸點。-->
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="0.2"
android:toXScale="1.5"
android:fromYScale="0.2"
android:toYScale="1.5"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"/>
旋轉動畫
<!--fromDegrees/toDegrees:旋轉的起始/結束角度。-->
<!--repeatCount:旋轉的次數,默認值爲0,代表一次,假如是其他值,比如3,則旋轉4次 另外,值爲-1或者infinite時,表示動畫永不停止。-->
<!--repeatMode:設置重複模式,默認restart,但只有當repeatCount大於0或者infinite或-1時 纔有效。還可以設置成reverse,表示偶數次顯示動畫時會做方向相反的運動。-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="360"
android:duration="1000"
android:repeatCount="1"
android:repeatMode="reverse"/>
透明度動畫
<!--fromAlpha :起始透明度。-->
<!--toAlpha:結束透明度。-->
<!--透明度的範圍爲:0-1,完全透明-完全不透明。-->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="2000"/>
動畫組合
<!--<set>標籤表示動畫集合,對應AnimationSet類,它可以包含若干動畫。-->
<!-- android:shareInterpolator 表示集合中的動畫是否和集合共享一個插值器,如果集合不指定插值器,那麼子動畫就需要單獨指定所需的插值器或者使用默認值-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:shareInterpolator="true" >
<scale
android:duration="2000"
android:fromXScale="0.2"
android:fromYScale="0.2"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.5"
android:toYScale="1.5" />
<rotate
android:duration="1000"
android:fromDegrees="0"
android:repeatCount="1"
android:repeatMode="reverse"
android:toDegrees="360" />
<translate
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="320"
android:toYDelta="0" />
<alpha
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
</set>
代碼調用
Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
imageView.startAnimation(alphaAnimation);
代碼實現
平移動畫
//Animation.RELATIVE_TO_SELF 相當於自身
// Animation.RELATIVE_TO_PARENT 相當於屏幕
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
-1, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 1);
translateAnimation.setDuration(2000);
translateAnimation.setRepeatCount(1);//重複次數
translateAnimation.setRepeatMode(Animation.RESTART);//重複模式
translateAnimation.setFillAfter(true);//是否填充在結束的位置上
tweeniv.startAnimation(translateAnimation);
縮放動畫
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 2, 0.1f, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setRepeatCount(1);
scaleAnimation.setRepeatCount(Animation.REVERSE);
scaleAnimation.setDuration(2000);
scaleAnimation.setFillAfter(true);//填充動畫的結束位置
tweeniv.startAnimation(scaleAnimation);
旋轉動畫
RotateAnimation rotateAnimation = new RotateAnimation(20, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
rotateAnimation.setRepeatCount(1);
rotateAnimation.setRepeatMode(Animation.REVERSE);
tweeniv.startAnimation(rotateAnimation);
透明度動畫
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setRepeatCount(1);
alphaAnimation.setDuration(2000);
tweeniv.startAnimation(alphaAnimation);
動畫組合
AnimationSet animationSet = new AnimationSet(false);//false表示使用動畫的校對器,true表示使用集合的校對器
animationSet.setDuration(2000);
translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
-1, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 1);
rotateAnimation = new RotateAnimation(20, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
alphaAnimation = new AlphaAnimation(0, 1);
scaleAnimation = new ScaleAnimation(0.5f, 2, 0.1f, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
tweeniv.startAnimation(animationSet);
動畫監聽
//translateAnimation 動畫對象
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//動畫開始
}
@Override
public void onAnimationEnd(Animation animation) {
//動畫結束
}
@Override
public void onAnimationRepeat(Animation animation) {
//動畫重複
}
});
自定義View動畫
- 我們派生出一種新動畫只需要集成
Animation
這個抽象類,然後重寫它的initialize
和applyTransformation
方法,在initialize中做一些初始化工作。在applyTransformation
中進行相應的矩陣變換即可。因爲自定義View動畫的過程主要是矩陣變換過程。
public RotateAnimation() {
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
}
View動畫的特殊使用場景
LayoutAnimation
LayoutAnimation
作用於ViewGroup
,爲ViewGroup
指定一個動畫,這樣它的子元素出場都會具有這種動畫效果。例如ListView
每個item都以一定的動畫形式出現就是使用LayoutAnimation
。
使用步驟
- 定義
LayoutAnimation
<!--目錄:res/anim/-->
<!--android:delay表示子元素開始動畫的時間延遲,比如子元素入場動畫的時間週期爲300ms,那麼0.5表示每個子元素都需要延遲150ms才能播放入場動畫。
總體來說,第一一個子元素延遲150ms開始播放入場動畫,第2個子元素延遲300ms開始播放入場動畫,依次類推。-->
<!--android:animationOrder表示子元素動畫的順序,有三種選項:normal(順序顯示),reverse(逆向顯示),random(隨機顯示)。-->
<!--android:animation爲子元素指定具體的動畫-->
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/anim_item"
android:animationOrder="normal"
android:delay="0.5"/>
- 爲子元素指定具體動畫
<!--目錄:res/anim/-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:interpolator="@android:anim/decelerate_interpolator"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<translate
android:fromXDelta="500"
android:toXDelta="0" />
</set>
- 爲
ViewGroup
指定android:layoutAnimation
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/anim_layout"
android:divider="@color/colorAccent"
android:cacheColorHint="@color/colorPrimaryDark"
android:listSelector="@color/colorAccent"
/>
補充: 除了在XML中指定android:layoutAnimation
,還可以通過LayoutAnimationController
來實現。
ListView listView=(ListView) layout.findViewById(R.id.list);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);
Activity的切換效果
- Activity有默認的切換效果,我們自定義效果可以通過
overridePendingTransition(int enterAnim, int exitAnim)
方法,這個方法必須在startActivity()
;或finish()
之後調用纔有效。
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
//參數一:新Activity進場時的動畫;參數二:舊Activity退場時的動畫
overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
Fragment的過渡動畫
- 我們可以調用
FragmentTransaction
對象的setTransition(int transit)
爲Fragment
指定標準的過場動畫,transit
的可選值如下:TRANSIT_NONE
:無動畫TRANSIT_FRAGMENT_OPEN
:打開形式的動畫TRANSIT_FRAGMENT_CLOSE
:關閉形式的動畫
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =fragmentManager.beginTransaction();
fragmentTransaction.setTransition(TRANSIT_NONE);
- 上面的標準過程動畫是兩個都可以調用的,而不同的地方則在於自定義轉場動
setCustomAnimations()
方法!- app包下的
Fragment
:setCustomAnimations(int enter, int exit, int popEnter, int popExit)
分別是添加,移除,入棧,以及出棧時的動畫! 另外要注意一點的是,對應的動畫類型是:屬性動畫(Property),就是動畫文件 的根標籤要是:<objectAnimator>
,<valueAnimator>
或者是前面兩者放到一個裏; - v4包下的
Fragment
: v4包下的則支持兩種setCustomAnimations()
- app包下的
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.push_right_in,R.anim.push_right_out,R.anim.push_left_in,R.anim.push_left_out);//設置進入,退出動畫
- 注意: 要在
fragmentTransaction
add
、replace
或commit
方法前設置動畫,否則動畫將不會運行。 - 我們自定義好動畫後,有時候需要判斷動畫是否開始、結束,這時需要對動畫狀態進行監聽,我們重寫Fragment中的
onCreateAnimation
或onCreateAnimator
方法 Fragment v4
包
public Animation onCreateAnimation(int transit,boolean enter,int nextAnim)
Fragment app
包
public Animator onCreateAnimator(int transit,boolean enter,int nextAnim)