(一)簡介
屬性動畫是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<PointBean> {
@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<String> {
//僅支持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度)。