Android:屬性動畫詳解
(一)簡介
屬性動畫是Android 3.0中提供了新功能,便於對任意元素進行“平滑的過渡”。眾所周知,Android 之前提供的補間動畫如AlphaAnimation、TranslateAnimation等都只能應用在View上,並且幾乎沒有任何可擴充的地方。並且,使用原來的動畫無法實現色彩坡形效果,算是一個遺憾。
屬性動畫徹底打破了這種設計方式,不再將這些動畫強制的放在View上,而是僅僅產生一系列的值,由開發人員自行使用這些值。例如,屬性動畫可產生1~0平滑過渡的值,把這些值應用在View的alpha上就可以實現透明度漸層了。
同時,屬性動畫可以直接用來改變View的屬性。例如,不斷的setTranslationX,便可實現水平方向的平移。
(二)代碼示範
1.ValueAnimator:產生某個範圍內平滑過渡的值。
//屬性動畫,0~1漸層 public void simpleValueAnimator(View view) { ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(300); //動畫過程的監聽 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //回調方法在主線程執行 float currentValue = (float) animation.getAnimatedValue(); Log.d(TAG, "current value is " + currentValue); } }); anim.start(); }(1)該方法可以通過設定多個值來實現更複雜的“平滑過渡”,例如實現0~5~3~10的過渡效果:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);
(2)設定啟動延時、重複次數、重複模式:
//設定啟動延時 anim.setStartDelay(1000); //設定重複次數(也可以設定成無限次數) anim.setRepeatCount(3); //設定重複模式:重新執行動畫(也可以設定成倒序) anim.setRepeatMode(ValueAnimator.RESTART);
(3)監聽動畫開始、結束、重複狀態:
//監聽動畫的狀態(開始/結束/重複/取消) anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); Log.d(TAG, "onAnimationStart"); } @Override public void onAnimationRepeat(Animator animation) { super.onAnimationRepeat(animation); Log.d(TAG, "onAnimationRepeat"); } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); Log.d(TAG, "onAnimationEnd"); } });2.ObjectAnimator:平滑的改變任意對象的屬性值。
(1)平滑改變TextView的不透明度:
public void changeAlphaValue(View view) { TextView textView = (TextView) findViewById(R.id.main_text1); //ObjectAnimator繼承自ValueAnimator //animator會調用textView的setAlpha方法。如果該方法不存在則會出現警告異常。 ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "alpha", 1f, 0f, 1f); animator.setDuration(3000); animator.start(); }該動畫並非直接改變textView的alpha屬性(事實上,textView甚至它的父組件View都沒有alpha屬性),而是調用textView的setAlpha方法,然後傳入1~0~1平滑漸層的值作為參數,從而實現了不透明度漸層效果。
類似的,可以通過傳遞參數rotation、translationX(translationY)等實現旋轉、平移等效果。
3.使用AnimatorSet將各個動畫進行組合:
public void animatorSet(View view) { TextView textView = (TextView) findViewById(R.id.main_text1); ObjectAnimator moveIn = ObjectAnimator.ofFloat(textView, "translationX", -500f, 0f); ObjectAnimator rotate = ObjectAnimator.ofFloat(textView, "rotation", 0f, 360f); ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textView, "alpha", 1f, 0.2f, 1f); //先平移,然後在旋轉的同時進行alpha漸層 AnimatorSet animSet = new AnimatorSet(); animSet.play(rotate).with(fadeInOut).after(moveIn); animSet.setDuration(5000); animSet.start(); }animSet.play會產生一個Animator.Builder對象,然後可以使用with,after,before等方法進行動畫疊加。
4.自訂Evaluator,實現任意兩個對象之間的“平滑過渡”。
ValueAnimator的ofInt,ofFloat方法很簡單,無非是產生一些平滑過渡的數值。不過,ValueAnimator還有一個ofObject方法,可以實現兩個Object之間的平滑過渡。顯然,系統不可能知道應該怎麼過渡,因此需要我們指定它。
例如定義了一個類表示點的座標:
public class PointBean { private float x; private float y; public PointBean(float x, float y) { this.x = x; this.y = y; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; }}然後,我們希望實現兩個點之間的平滑過渡(通過它就可以實現View的平移了),就需要定義兩個PointBean之間是如何過渡的。當然此處的實現很簡單:
public class PointEvaluator implements TypeEvaluator { @Override public PointBean evaluate(float fraction, PointBean startValue, PointBean endValue) { float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX()); float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY()); return new PointBean(x, y); }}參數fraction表示動畫完成度(0.0~1.0的一個值),startValue表示開始點,endValue表示結束點,該方法需要返回從startValue過渡到endValue、完成比例是fraction時的結果。
然後,通過兩個PointBean的過渡實現平移效果(此處僅為示意,實際情境中可以直接使用ObjectAnimator):
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint); animator.setDuration(2000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointBean current = (PointBean) animation.getAnimatedValue(); imageView.setTranslationX(current.getX()); imageView.setTranslationY(current.getY()); } }); animator.start();5.實現色彩坡形
與上述內容相似,實現紅色~綠色~藍色的漸層:
ValueAnimator animator = ValueAnimator.ofObject(new ColorEvaluator(), "#ffff0000", "#ff00ff00", "#ff0000ff"); animator.setDuration(5000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { String currentColor = (String) animation.getAnimatedValue(); textView.setBackgroundColor(Color.parseColor(currentColor)); } }); animator.start();顯然此處的重點是ColorEvaluator,即指定顏色值是如何漸層的。例如, #ffff0000是如何過渡到#ff00ff00的。
public class ColorEvaluator implements TypeEvaluator { //僅支援AARRGGBB模式 @Override public String evaluate(float fraction, String startValue, String endValue) { if (!startValue.startsWith("#") || !endValue.startsWith("#")) { throw new IllegalArgumentException("color must started with '#'."); } if (startValue.length() != 9 || endValue.length() != 9) { throw new IllegalArgumentException("startValue and endValue must be '#AARRGGBB'."); } int start_a, start_r, start_g, start_b; int end_a, end_r, end_g, end_b; //start start_a = getIntValue(startValue, 1, 3); start_r = getIntValue(startValue, 3, 5); start_g = getIntValue(startValue, 5, 7); start_b = getIntValue(startValue, 7, 9); //end end_a = getIntValue(endValue, 1, 3); end_r = getIntValue(endValue, 3, 5); end_g = getIntValue(endValue, 5, 7); end_b = getIntValue(endValue, 7, 9); return "#" + getHexString((int) (start_a + fraction * (end_a - start_a))) + getHexString((int) (start_r + fraction * (end_r - start_r))) + getHexString((int) (start_g + fraction * (end_g - start_g))) + getHexString((int) (start_b + fraction * (end_b - start_b))); } //從原始#AARRGGBB顏色值中指定位置截取,並轉為int. private int getIntValue(String hexValue, int start, int end) { return Integer.parseInt(hexValue.substring(start, end), 16); } private String getHexString(int value) { String a = Integer.toHexString(value); if (a.length() == 1) { a = "0" + a; } return a; }}6.設定Interpolator,控制動畫進行的方式,如勻速、逐漸加速、逐漸減速或先加速後減速等效果。此處和傳統的動畫很相似。同樣,可以自訂Interpolator的實現。
anim.setInterpolator(new AccelerateInterpolator()); //逐漸加速的動畫
7.ViewPropertyAnimator:使用屬性動畫為View設定動畫效果的一種簡便方式。
testImageView.animate().setDuration(2000).alpha(0.3f).rotationBy(360).yBy(160);
上述代碼錶示將testImageView的不透明度漸層至0.3,同時旋轉360度、向下移動160px。
這裡的方法都有兩種形式,如rotation(360)表示旋轉至360度的位置(不管起始狀態是多少度,都旋轉至360度),而rotationBy(360)表示旋轉360度(如果起始位置不是0度,則結束時依然不是0度)。