內(nèi)容如下:
- 屬性動畫與補間動畫的不同
- 屬性動畫工作原理
- API 概述
- 計算器 Evaluators
- 插值器 Interpolators
- 使用ValueAnimator
- 使用ObjectAnimator
- AnimatorSet
- 動畫監(jiān)聽
- 視圖容器中布局的動畫改變
- 使用TypeEvaluator
- 使用插值器 (Interpolators)
- 關(guān)鍵幀
- ViewPropertyAnimator
- 聲明XML
屬性動畫與補間動畫的不同
補間動畫只提供了運動可視對象的能力,如果你想操作非可視對象,就不得不自己用代碼實現(xiàn)。實際上,補間動畫具有局限性,它只能夠使一個視圖對象的幾個方面做運動,比如:視圖的縮放、旋轉(zhuǎn),而不能操作背景顏色等等。
補間動畫另一個缺點是:它只能夠改變視圖繪制的位置,并不能改變它的真實位置。例如:你在屏幕中運動一個按鈕,按鈕將被正確的繪制,但是當你點擊當前位置的按鈕時,按鈕并不會有任何改變。所以你不得不通過實現(xiàn)自己的邏輯來操作它。
對于屬性動畫而言,這些限制被全部移除。你能夠使任何對象(可視和非可視)的任何屬性運動,并且對象自身被修改。屬性動畫就是通過不停修改屬性值實現(xiàn)動畫效果的。屬性動畫在實現(xiàn)動畫方面更加強大。你可以根據(jù)需求將動畫分派給對象的屬性,比如:顏色、位置、大??;你也可以定義動畫的差值器以及多動畫的同步。
不管怎樣,補間動畫的創(chuàng)建可以用更少的時間和更少的代碼。如果補間動畫能夠完成你需要的每件事,或者代碼中已存在的補間動畫代碼能夠?qū)崿F(xiàn)你的需求。你就沒必要使用屬性動畫。通過不同的使用場景來確定使用兩種動畫系統(tǒng)的哪一種。
屬性動畫工作原理
圖1描述了一個假想的對象,沿x軸運動,表示它在屏幕上的水平位置。在40ms內(nèi)運動40px,每10毫秒(默認幀刷新率),對象水平移動10像素。到40ms時,動畫結(jié)束。對象停在40px處。這是一個線性插值動畫的例子,表示對象勻速運動。

還可以指定具有非線性插值的動畫。圖2假設(shè)一個對象,在動畫開始時加速,然后減速動畫結(jié)束時。該對象仍然在40ms移動40px,但非線性。

屬性動畫系統(tǒng)的重要組件如何計算上面提到的動畫:

ValueAnimator 對象保持跟蹤動畫的時間,比如動畫的已運動時間和動畫的當前值。
TimeInterpolator 定義動畫的插值器。
TypeEvaluator 定義如何計算動畫屬性的值。
開始一個動畫:
- 創(chuàng)建一個ValueAnimator并給它的開始屬性值、結(jié)束屬性值以及動畫的持續(xù)時間。
- 調(diào)用start()開始動畫。
- ValueAnimator計算一個在0和1之間的逝去分數(shù),基于動畫的持續(xù)時間和經(jīng)過的多少時間。該分數(shù)表示動畫完成的時間百分比,0表示0%,1表示100%。
- 當ValueAnimator完成計算一個逝去分數(shù),它調(diào)用當前設(shè)置的TimeInterpolator計算插值分數(shù)。
- 當插值分數(shù)計算完成,ValueAnimator調(diào)用合適的TypeEvaluator,計算該屬性的值,基于插值分數(shù)、起始值和動畫結(jié)束值。
API 概述
ValueAnimator 屬性動畫的計時引擎,通過屬性值進行動畫處理。包括計算動畫值的核心功能,動畫隨時間變化的細節(jié),動畫重復(fù)監(jiān)聽以及更新時間,自定義evaluate。屬性動畫包括兩部分:1.計算動畫值;2.對正在進行動畫的對象設(shè)置這些值。ValueAnimator不能直接完成第二部分,所以必須在UpdateListener中更新屬性值。
ObjectAnimator ValueAnimator的子類,可以直接設(shè)置目標對象和屬性進行動畫。ObjectAnimator使用起來更方便,也有限制,對于進行的動畫的屬性必須要有setter,getter的訪問方法。
AnimatorSet 提供一種將多動畫分組并使之關(guān)聯(lián)運行的機制。可以使動畫同時執(zhí)行,順序執(zhí)行,延時執(zhí)行。
估算器 Evaluators
- IntEvaluator 計算int型屬性
- FloatEvaluator 計算float型屬性
- ArgbEvaluator 計算16進制的顏色值
- TypeEvaluator 自定義計算器(更多見下文)
插值器 Interpolators
- AccelerateDecelerateInterpolator 先加速后減速
- AccelerateInterpolator 加速
- AnticipateInterpolator 向相反運動一小段后再開始運行
- AnticipateOvershootInterpolator 前后都超出一小段
- BounceInterpolator 結(jié)束時振動結(jié)束
- CycleInterpolator 往返運行動畫
- DecelerateInterpolator 減速運行
- LinearInterpolator 勻速運行
- OvershootInterpolator 結(jié)束時超出一小段
- TimeInterpolator 自定義
使用ValueAnimator
通過調(diào)用ofInt(),ofFloat(),ofObject()方法獲得一個ValueAnimator,如下:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
還可以通過以下操作指定一個自定義類型來進行動畫:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue,
endPropertyValue);
animation.setDuration(1000);
animation.start();
上述代碼,當調(diào)用start()時,ValueAnimator 將在1s內(nèi)計算0-1之間的動畫值。它只是在計算一個值并沒有影響到一個具體的對象。你需要實現(xiàn)ValueAnimator.AnimatorUpdateListener這個接口,通過調(diào)用getAnimatedValue()方法可以獲得特定幀的計算值,通過這個值可以對目標對象進行需要的變換。
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator updatedAnimation) {
// You can use the animated value in a property that uses the
// same type as the animation. In this case, you can use the
// float value in the translationX property.
float animatedValue = (float)updatedAnimation.getAnimatedValue();
textView.setTranslationX(animatedValue);
}
});
使用ObjectAnimator
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();
擁有setter,getter方法的屬性都可以進行動畫操作。
經(jīng)常操作的屬性:
"alpha" 透明度;
"translationY" 沿Y軸平移;
"translationX" 沿X軸平移;
"scaleX" 橫向縮放;
"scaleY" 縱向縮放;
"rotation" 平面旋轉(zhuǎn);
"rotationX" 關(guān)于X軸旋轉(zhuǎn);
"rotationY" 關(guān)于Y軸旋轉(zhuǎn);
AnimatorSet
你可以使用AnimatorSet控制多個Animator的播放順序,同時播放,順序播放,誰在前誰在后等。可以嵌套使用。例:
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
常用方法:
playSequentially (Animator...) 順序播放;
playTogether (Animator...) 一起播放;
Builder方式:
play(Animator a);
創(chuàng)建一個Builder對象;
例1:有四個動畫anim1, amin2, anim3,anim4。anim1和anim2同時播放;當anim2播放結(jié)束時播放anim3;當anim3播放結(jié)束時播放anim4。
AnimatorSet s = new AnimatorSet();
s.play(anim1).with(anim2);
s.play(anim2).before(anim3);
s.play(anim4).after(anim3);
動畫監(jiān)聽
Animator.AnimatorListener
- onAnimationStart() 動畫開始時
- onAnimationEnd() 動畫結(jié)束時
- onAnimationRepeat() 動畫重復(fù)時
- onAnimationCancel() 動畫取消時,同時調(diào)用onAnimationEnd()
ValueAnimator.AnimatorUpdateListener
- onAnimationUpdate() 每幀動畫都將被調(diào)用
通過getAnimatedValue()方法獲取動畫值。
AnimatorListenerAdapter
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
)};
視圖容器中布局的動畫改變
使用TypeEvaluator
如果你想以系統(tǒng)未知的方式運動,你可以通過實現(xiàn)TypeEvaluator接口來創(chuàng)建。實現(xiàn)TypeEvaluator接口只需要實現(xiàn)一個方法evaluate()。如下:
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
例:使TextView沿正弦曲線運動
創(chuàng)建包裝類:
private class TextHolder
private TextView view;
public TextHolder(TextView textView){
view=textView;
}
public XYHolder getXY() {
return new XYHolder(view.getX(),view.getY());
}
public void setXY(XYHolder xyHolder) {
view.setX(xyHolder.getX());
view.setY(xyHolder.getY());
}
}
估值器:
public class SineTypeEvaluator implements TypeEvaluator<XYHolder> {
@Override
public XYHolder evaluate(float fraction, XYHolder startValue, XYHolder endValue) {
float xHolder=startValue.getX()+fraction*(endValue.getX()-startValue.getX());
float yHolder=(float) (300*Math.sin(xHolder/100)+endValue.getY());
return new XYHolder(xHolder,yHolder );
}
}
開始動畫:
ObjectAnimator objectAnimator=ObjectAnimator.ofObject(new TextHolder(mText1),"xY",new
SineTypeEvaluator(),new XYHolder(0f,400f),new XYHolder(628f,400f));
objectAnimator.setDuration(2000);
objectAnimator.start();
使用插值器
一個隨時間計算動畫值的函數(shù)
AccelerateDecelerateInterpolator
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
LinearInterpolator
public float getInterpolation(float input) {
return input;
}
關(guān)鍵幀
例如:
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
ViewPropertyAnimator
ViewPropertyAnimator提供一種更簡單的多屬性運動的方式。如下對比:
使用多個ObjectAnimator:
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
使用一個ObjectAnimator:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
使用ViewPropertyAnimator:
myView.animate().x(50f).y(100f);</pre>
聲明XML
將xml文件保存在res/animator/ 目錄下
動畫類與xml標簽的對應(yīng)關(guān)系:
ValueAnimator - <animator>
ObjectAnimator - <objectAnimator>
AnimatorSet- <set>
下面的示例依次播放兩組對象動畫,第一個動畫集合同時播放兩個對象動畫:
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
運行上述動畫:
AnimatorSet set = (AnimatorSet)
AnimatorInflater.loadAnimator(myContext,R.anim.property_animator);
set.setTarget(myObject);
set.start();
在XML中聲明ValueAnimator:
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:valueType="floatType"
android:valueFrom="0f"
android:valueTo="-100f" />
ValueAnimator必須實現(xiàn)AnimatorUpdateListener,如下:
ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator updatedAnimation) {
float animatedValue = (float)updatedAnimation.getAnimatedValue();
textView.setTranslationX(animatedValue);
}
});
xmlAnimator.start();