1. 程式人生 > >Android動畫系列之屬性動畫

Android動畫系列之屬性動畫

> 原文首發於微信公眾號:jzman-blog,歡迎關注交流! 屬性動畫相較幀動畫和補間動畫更強大,幀動畫和補間動畫只能應用於 View 及其子類,而屬性動畫可以修改任何物件的屬性值,屬性值可在指定的一段時間內自動改變,根據物件屬性值的變化進而實現更復雜的動畫。 1. 屬性動畫的常用設定 2. ValueAnimator 3. ObjectAnimator 4. 關鍵幀 5. 插值器和估值器 #### 屬性動畫的常用設定 下面是屬性動畫的常用設定,具體如下: ```java //設定屬性動畫持續時間 animator.setDuration(2000); //設定屬性插值器 animator.setInterpolator(new AccelerateInterpolator()); //設定屬性動畫重複播放模式 animator.setRepeatMode(ValueAnimator.REVERSE); //設定屬性動畫重複播放次數 animator.setRepeatCount(0); //設定屬性動畫延時播放的時間 animator.setStartDelay(0); //設定屬性動畫估值器,用於控制最終屬性值(API22) animator.setCurrentFraction(0.5f); //設定當前播放時間,其值在Duration範圍之內 animator.setCurrentPlayTime(1000); //設定屬性動畫估值器,用於控制最終屬性值 animator.setEvaluator(new IntEvaluator()); //設定屬性動畫監聽 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Log.i(TAG, animation.getAnimatedValue() + ""); // } }); //... ``` #### ValueAnimator ValueAnimator 提供了一個簡單的計時引擎,用於執行動畫時根據設定的時長以及其他屬相完成動畫值的計算,然後就可以將動畫值設定到合適的目標物件上,使用的插值器預設時 AccelerateDecelerateInterpolator,表示動畫開始和結束時較慢,中間加速完成動畫,下面是原始碼中預設的插值器,具體如下: ```java // The time interpolator to be used if none is set on the animation private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); ``` 在 ValueAnimator 中已經內部處理了一些估值器 IntEvaluator 和 FloatEvaluator,也就是說如果使用的時 ofInt 和 ofFloat 方法作為動畫的屬性值,那麼 ValueAnimator 會自動處理 int 和 float 值的變化,在原始碼中找了一下,這部分內容在 PropertyValuesHolder 這個類中,具體如下: ```java void init() { if (mEvaluator == null) { // We already handle int and float automatically, but not their Object // equivalents mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : (mValueType == Float.class) ? sFloatEvaluator : null; } if (mEvaluator != null) { // KeyframeSet knows how to evaluate the common types - only give it a custom // evaluator if one has been set on this class mKeyframes.setEvaluator(mEvaluator); } } ``` ValueAnimator 可以使用程式碼建立,也可以使用 xml 建立,下面以平移動畫為例說明 ValueAnimator 的使用方式,其他如縮放、旋轉等使用方式類似。 ##### 使用程式碼建立 ```java private void translation(){ ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100); valueAnimator.setDuration(2000); valueAnimator.setInterpolator(new AccelerateInterpolator()); valueAnimator.setRepeatMode(ValueAnimator.REVERSE); valueAnimator.setRepeatCount(0); valueAnimator.setStartDelay(0); // valueAnimator.setCurrentFraction(0.5f); // valueAnimator.setCurrentPlayTime(1000); valueAnimator.setEvaluator(new IntEvaluator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Log.i(TAG, animation.getAnimatedValue() + ""); int x = (int) animation.getAnimatedValue(); ivImage.setTranslationX(x); ivImage.setTranslationY(x); } }); valueAnimator.start(); } ``` ##### 使用xml建立 在 res/animator 資料夾下建立 test_animator.xml 檔案,檔案內容如下: ```xml ``` 然後在 Activity 中獲取 ValueAnimator,設定目標物件,啟動動畫即可,具體如下: ```java private void translation(){ ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.test_animator); animator.setTarget(ivImage); animator.start(); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Log.i(TAG, animation.getAnimatedValue() + ""); int x = (int) animation.getAnimatedValue(); ivImage.setTranslationX(x); ivImage.setTranslationY(x); } }); } ``` ##### 測試效果 這裡使用 ValueAnimator 來實現平移動畫,測試效果如下: ![ValueAnimator](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11faa91a9?w=354&h=434&f=gif&s=49881) #### ObjectAnimator ObjectAnimator 是 ValueAnimator 的子類,可在目標物件上支援動畫屬性的設定,在其構造方法中通過引數指定目標物件以及所對應動畫屬性的名稱,然後會相應的執行對應的動畫屬性的 setter 方法來最終完成動畫的執行,也就是說屬性動畫 ObjectAnimator 最終呼叫目標物件的 setter 方法完成目標物件屬性值的變化,然後相應的改變目標物件的屬性,從而實現目標物件的動畫效果,下面以透明度變化來介紹 ObjectAnimator 的基本使用,程式碼參考如下: ``` private void alpha(){ ObjectAnimator animator = ObjectAnimator.ofFloat(ivImage,"alpha",1f,0,1f); animator.setDuration(3000); //其他屬性動畫設定 //... animator.start(); } ``` 下面是測試效果,如下圖所示: ![屬性動畫-透明度](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11f436579?w=385&h=330&f=gif&s=89466) 至於平移、旋轉、縮放動畫實現方式基本如上,這裡不再贅述,其對應的 setter 方法對應關係如下: 屬性|作用|對應方法 ---|---|--- Alpha|控制View的透明度|setAlpha TranslationX|控制X方向的位移|setTranslationX TranslationY|控制Y方向的位移|setTranslationY ScaleX|控制X方向的縮放倍數|setScaleX ScaleY|控制Y方向的縮放倍數|setScaleY Rotation|控制以螢幕方向為軸的旋轉度數|setRotation RotationX|控制以X軸為軸的旋轉度數|setRotationX RotationY|控制以Y軸為軸的旋轉度數|setRotationY ObjectAnimator 提供了很多的 ofXxx() 方法來方面設定屬性動畫,如下圖所示: ![屬性動畫-ofXxx()](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11fb107ed?w=1161&h=652&f=jpeg&s=112262) 可根據不同的動畫需求使用 ObjectValueAnimator 不同 ofXxx() 方法來實現相應的動畫。 #### 關鍵幀 這裡簡單說一下關鍵幀的使用,顧名思義關鍵幀就是在某個固定時刻上定義具體的屬性值,為定義的將按照估值器返回的值返回屬性值,屬性動畫中的關鍵幀使用方式如下: ```java /** * 關鍵幀的使用 */ private void keyFrame(){ Keyframe keyframe1 = Keyframe.ofFloat(0,0); Keyframe keyframe2 = Keyframe.ofFloat(0.25f,300); //每個KeyFrame可設定自己的插值器 keyframe2.setInterpolator(new AccelerateInterpolator()); Keyframe keyframe3 = Keyframe.ofFloat(0.75f,100); Keyframe keyframe4 = Keyframe.ofFloat(1,400); PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4); ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(ivImage,holder); animator.setDuration(3000); animator.start(); } ``` 看一下新增關鍵幀之後對普通平移動畫的改變,實現測試效果如下: ![keyFragme.gif](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11f5709b9?w=386&h=328&f=gif&s=117675) #### 插值器和估值器 - 插值器(TimeInterpolator) 表示的是整個動畫期間動畫的變化規律,如加速、減速等。 Android 內建許多插值器,這些插值器基本涵蓋了實際開發中的大部分情況,具體如下: ![插值器](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11f0afd5f?w=926&h=444&f=png&s=82857) 如果內建的插值器不滿足需求,也可以自定義插值器。 - 估值器(TypeEvaluator)表示的是在整個動畫期間各時刻屬性值的具體變化。 這裡自定義一個估值器來實現一個 View 沿正弦曲線運動,自定義估值器如下: ```java /** * 自定義估值器 * Point封裝了座標x和y */ public class SineTypeValue implements TypeE