前言:
前面初步認識了Android的Property Animation(屬性動畫)Android動畫效果之初識Property Animation(屬性動畫)(三),並且利用屬性動畫簡單了補間動畫能夠實現的動畫效果,今天重點學習下Property Animation基本原理及高階使用。本章先通過餘額寶的數字動畫小例子來學習屬性動畫基本原理。具體效果如下:
其他幾種動畫效果:
- Android動畫效果之Tween Animation(補間動畫)
- Android動畫效果之Frame Animation(逐幀動畫)
- Android動畫效果之初識Property Animation(屬性動畫)
- Android動畫效果之Property Animation進階(屬性動畫)
- Android動畫效果之自定義ViewGroup新增布局動畫
ValueAnimator(差值動畫)
上篇文章一直使用的ObjectAnimator來實現屬性動畫,單純從字面上理解的話ObjectAnimator作用於某個實際的物件,而ValueAnimator是ObjectAnimator的父類,它繼承自抽象類Animator,它作用於一個值,將其由一個值變化為另外一個值,然後根據值的變化,按照一定的規則,動態修改View的屬性,比如View的位置、透明度、旋轉角度、大小等,即可完成了動畫的效果。直接看下上面的數字動畫是怎麼實現的?
ValueAnimator valueAnimator =ValueAnimator.ofFloat( 0f, 126512.36f); valueAnimator.setDuration(2000); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float money= (float) animation.getAnimatedValue(); mTextView.setText(String.format("%.2f", money)); } }); valueAnimator.start();
這裡通過ofFloat()方法構造一個ValueAnimator例項,除此之外還提供了其他函式ofInt()、ofObject()、ofPropertyValuesHolder()函式,api 21之後又提供了ofArgb(),每個函式都是可以傳入多個改變值。
Interpolator(插值器)
Interpolator插值器用於控制動畫的變化速率,也可以簡單的理解成用於控制動畫的快慢,插值器目前都只是對動畫執行過程的時間進行修飾,並沒有對軌跡進行修飾。系統提供的插值器有以下幾種:
插值器名字 | 解說 | 對應的xml |
AccelerateInterpolator | 加速,開始時慢中間加速 | @android:anim/accelerate_interpolator |
DecelerateInterpolator | 減速,開始時快然後減速 | @android:anim/decelerate_interpolator |
AccelerateDecelerateInterolator | 先加速後減速,開始結束時慢,中間加速 | @android:anim/accelerate_decelerate_interpolator |
AnticipateInterpolator | 反向 ,先向相反方向改變一段再加速播放 | @android:anim/anticipate_interpolator |
AnticipateOvershootInterpolator | 反向加超越,先向相反方向改變,再加速播放,會超出目的值然後緩慢移動至目的值 | @android:anim/anticipate_overshoot_interpolator |
BounceInterpolator | 跳躍,快到目的值時值會跳躍,如目的值100,後面的值可能依次為85,77,70,80,90,100 | @android:anim/bounce_interpolator |
CycleIinterpolator | 迴圈,動畫迴圈一定次數,值的改變為一正弦函式:Math.sin(2* mCycles* Math.PI* input) | @android:anim/cycle_interpolator |
LinearInterpolator | 線性,線性均勻改變 | @android:anim/linear_interpolator |
OvershootInterpolator | 超越,最後超出目的值然後緩慢改變到目的值 | @android:anim/overshoot_interpolator |
通過上面的名字大家是不是很眼熟,是的和補間動畫的插值器是一致的。Android的動畫插值器採用策略設計模式,都是實現了Interpolator這個介面,而Interpolator又是繼承自一個叫做TimeInterpolator的介面(從3.0開始,增加了TimeInterpolator這個介面,並把原先的Interpolator介面的抽象方法移到了其中,3.0後的Interpolator介面也就什麼也沒做,只是對父類改了個名字,達到向下相容)。
package android.animation; public interface TimeInterpolator { float getInterpolation(float input); }
在Interpolator的實現類裡面,都實現了一個float getInterpolator(float input)的方法,傳入引數是正常執行動畫的時間點,返回值是使用者真正想要它執行的時間點。上面的數字動畫使用了勻速插值器LinearInterpolator其程式碼實現如下:
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; } /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactoryHelper.createLinearInterpolator(); } }
可以看出float getInterpolator(float input)返回的值就是當前要執行的時間點實現勻速執行動畫。
如何自定義一個插值器?舉例:我們實現一個先減速後加速插值器,程式碼如下
public class DecelerateAccelerateInterpolator implements Interpolator { @Override public float getInterpolation(float input) { float result; if (input <= 0.5f) { result = (float) (Math.sin(Math.PI * input)) / 2.0f; } else { result = (float) (2 - Math.sin(Math.PI * input)) / 2.0f; } return result; } }
TypeEvaluator(估值器)
TypeEvaluator用於根據當前屬性改變的百分比來計算改變後的屬性值,系統提供瞭如下幾種估值器
-
IntEvaluator 針對整型屬性
-
IntArrayEvaluator 針對整型屬性集合
-
FloatEvaluator 針對浮點型屬性
-
FloatArrayEvaluator 針對浮點型屬性集合
-
ArgbEvaluator 針對Color屬性
-
RectEvaluator 針對Rect屬性
-
PointFEvaluator 針對PointF屬性
TypeEvaluator設計也是採用策略設計模式,都實現TypeEvaluator介面,原始碼如下:
package android.animation; public interface TypeEvaluator<T> { public T evaluate(float fraction, T startValue, T endValue); }
介面提供了evaluate(float fraction, T startValue, T endValue);動畫在執行過程中Interpolator自動計算出動畫執行的百分比fraction,然後TypeEvaluator根據fraction計算出當前動畫的屬性值。以FloatEvaluator 程式碼為例:
public class FloatEvaluator implements TypeEvaluator<Number> { public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); } }
如何自定義TypeEvaLuator?比如我們要實現一個錢的增加,字型顏色越紅的動畫,我們現在都知道可以使用ofArgb(),但是ofArgb()需要api 21以上才能使用,所以需要我們自定義一個ArgbEvaLuator,這裡為了演示自定義TypeEvaluator直接把api 21中提供的ArgbEvaluator原始碼拿來使用,如下:
public class TextArgbEvaluator implements TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { int startInt = (Integer) startValue; int startA = (startInt >> 24) & 0xff; int startR = (startInt >> 16) & 0xff; int startG = (startInt >> 8) & 0xff; int startB = startInt & 0xff; int endInt = (Integer) endValue; int endA = (endInt >> 24) & 0xff; int endR = (endInt >> 16) & 0xff; int endG = (endInt >> 8) & 0xff; int endB = endInt & 0xff; return (int) ((startA + (int) (fraction * (endA - startA))) << 24) | (int) ((startR + (int) (fraction * (endR - startR))) << 16) | (int) ((startG + (int) (fraction * (endG - startG))) << 8) | (int) ((startB + (int) (fraction * (endB - startB)))); } }
呼叫方式:
AnimatorSet animatorSet = new AnimatorSet(); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 126512.36f); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float money = (float) animation.getAnimatedValue(); Log.e("Interpolator", "money---->" + money); mTextView.setText(String.format("%.2f", money)); } }); int startColor = Color.parseColor("#FCA3AB"); int endColor = Color.parseColor("#FB0435"); ValueAnimator colorAnimator = ValueAnimator.ofObject(new TextArgbEvaluator(),startColor, endColor); colorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int color = (int) animation.getAnimatedValue(); Log.e("Interpolator", "color---->" + color); mTextView.setTextColor(color); } }); animatorSet.playTogether(valueAnimator,colorAnimator); animatorSet.setDuration(5000); animatorSet.setInterpolator(new LinearInterpolator()); animatorSet.start();
執行效果:
ObjectAnimator
上篇我們簡單了學習了ObjectAnimator動畫,並且通過ObjectAnimator實現了幾種簡單的動畫效果,ObjectAnimator繼承自ValueAnimator,所以主體方法還是ValueAnimator裡實現的。先來回顧一下上篇的一個旋轉動畫例子。
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f); objectAnimator.setDuration(500); objectAnimator.setRepeatCount(1); objectAnimator.setRepeatMode(ValueAnimator.REVERSE); objectAnimator.start();
這個例子很簡單,針對view的屬性rotation進行持續時間為500ms的0到360的角度變換。屬性名字rotation在View中有對應setRotation(),否則沒有任何效果,而且引數型別必須為float型,否則沒有任何效果。view常見可操作的引數有:x/y;scaleX/scaleY;rotationX/ rotationY;transitionX/ transitionY等等。現在問題來了,我們本篇例子是為TextView 賦值一個float型的值,我們檢視TextView的函式並不找不到setText(float f),這時該怎麼處理呢?如何為不具有get/set方法的屬性提供修改方法呢?莫著急!谷歌為此提供了兩種方法,第一種就是使用ValueAnimator來實現,就是上面所說的方式,另外一種方式通過自己寫一個包裝類,來為該屬性提供get/set方法。
public class MoneyTextView extends TextView { public MoneyTextView(Context context, AttributeSet attrs) { super(context, attrs); } public void setText(float money) { setText(String.format("%.2f", money)); } }
然後就可以通過ObjectAnimator實現上面的數字動畫效果了。
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView, "text", 0f, 126512.36f); objectAnimator.setDuration(2000); objectAnimator.setInterpolator(new LinearInterpolator()); objectAnimator.start();
其他有關ObjectAnimator的使用方式請參考上篇文章Android動畫效果之初識Property Animation(屬性動畫)(三)。
總結:
本篇主要簡單學習了屬性動畫的基本原理,屬性動畫使用了比較常見的策略設計模式,感興趣的話可以看下這篇文章Java設計模式之策略模式(Strategy),下篇文章將藉助自定義ViewGroup學習一下佈局動畫。