補間動畫和屬性動畫主要區別:
-
作用對象不同,補間動畫只能作用在view上,屬性動畫可以作用在所有對象上。
-
屬性變化不同,補間動畫只是改變顯示效果,不會改變view的屬性,比如位置、寬高等,而屬性動畫實際改變對象的屬性。
-
動畫效果不同,補間動畫只能實現位移、縮放、旋轉和透明度四種動畫操作,而屬性動畫還能實現補間動畫所有效果及其他更多動畫效果。
新引入的屬性動畫機制已經不再是針對於 view 來設計的,也不限定於只能實現位移、縮放、旋轉和透明度這幾種動畫操作,同時也不再只是一種視覺上的動畫效果。它實際上是一種不斷地對值進行操作的機制,並將值賦值到指定對象的指定屬性上,可以是任意對象的任意屬性。我們只需要告訴系統動畫的運行時長,需要執行哪種類型的動畫,以及動畫的初始值和結束值,剩下的工作就可以全部交給系統去完成了。
ValueAnimator
ValueAnimator是整個屬性動畫機制當中最核心的一個類,前面我們已經提到了,屬性動畫的運行機制是通過不斷地對值進行操作來實現的,而初始值和結束值之間的動畫過渡就是由ValueAnimator這個類來負責計算的。它的內部使用一種時間循環的機制來計算值與值之間的動畫過渡,我們只需要將初始值和結束值提供給ValueAnimator,並且告訴它動畫所需運行的時長,那么ValueAnimator就會自動幫我們完成從初始值平滑地過渡到結束值這樣的效果。除此之外,ValueAnimator還負責管理動畫的播放次數、播放模式、以及對動畫設置監聽器等,確實是一個非常重要的類。
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(
300
);
anim.start();
|
用法就是這么簡單,現在如果你運行一下上面的代碼,動畫就會執行了。可是這只是一個將值從0過渡到1的動畫,又看不到任何界面效果,我們怎樣才能知道這個動畫是不是已經真正運行了呢?這就需要借助監聽器來實現了,如下所示:
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"
,
"cuurent value is "
+ currentValue);
}
});
anim.start();
|
ObjectAnimator
相比於ValueAnimator,ObjectAnimator可能才是我們最常接觸到的類,因為ValueAnimator只不過是對值進行了一個平滑的動畫過渡,但我們實際使用到這種功能的場景好像並不多。而ObjectAnimator則就不同了,它是可以直接對任意對象的任意屬性進行動畫操作的,比如說View的alpha屬性。
不過雖說ObjectAnimator會更加常用一些,但是它其實是繼承自ValueAnimator的,底層的動畫實現機制也是基於ValueAnimator來完成的,因此ValueAnimator仍然是整個屬性動畫當中最核心的一個類。那么既然是繼承關系,說明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它們的用法也非常類似,這里如果我們想要將一個TextView在5秒中內從常規變換成全透明,再從全透明變換成常規,就可以這樣寫:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview,
"alpha"
, 1f, 0f, 1f);
animator.setDuration(
5000
);
animator.start();
|
可以看到,我們還是調用了ofFloat()方法來去創建一個ObjectAnimator的實例,只不過ofFloat()方法當中接收的參數有點變化了。這里第一個參數要求傳入一個object對象,我們想要對哪個對象進行動畫操作就傳入什么,這里我傳入了一個textview。第二個參數是想要對該對象的哪個屬性進行動畫操作,由於我們想要改變TextView的不透明度,因此這里傳入"alpha"。后面的參數就是不固定長度了,想要完成什么樣的動畫就傳入什么值,這里傳入的值就表示將TextView從常規變換成全透明,再從全透明變換成常規。之后調用setDuration()方法來設置動畫的時長,然后調用start()方法啟動動畫。
到目前為止,ObjectAnimator的用法還算是相當簡單吧,但是我相信肯定會有不少朋友現在心里都有同樣一個疑問,就是ofFloat()方法的第二個參數到底可以傳哪些值呢?
-
translationX、translationY:這兩個屬性作為一種增量來控制着View對象從它布局容器的左上角坐標開始的位置。
-
rotation、rotationX、rotationY:這三個屬性控制着View對象圍繞它的支點進行2D和3D的旋轉。
-
scaleX和scaleY:這兩個屬性控制着View對象圍繞它的支點進行2D縮放。
-
pivotX和pivotY:這兩個屬性控制着View對象的支點位置,圍繞這個支點進行旋轉和縮放變換處理。默認情況下,該支點的位置就是View對象的中心點。
-
alpha:它表示View對象的alpha透明度。
-
x、y:這是兩個簡單的實用的屬性,它描述了View對象在它的容器中最終的位置。
以上只是view中常用的動畫操作,為什么會是這些勒?
其實ObjectAnimator內部的工作機制並不是直接對我們傳入的屬性名進行操作的,而是會去尋找這個屬性名對應的get和set方法。
比如第二個參數為alpha,那么該對象一定有setAlpha和getAlpha方法,而且 set方法參數為float類型,get方法返回值為float類型。使用Android Studio 開發時如果該值錯誤,不符合以上條件,會自動檢測提醒錯誤。
至於后面的參數含義可以查找對應的set方法來理解。比如ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f) 就是循環調用該對象的setAlpha方法。
動畫實踐
1、平移動畫代碼如下:
ObjectAnimator.ofFloat(view,
"translationX"
, 0f, 200f)
.setDuration(
500
)
.start();
|
2、透明度動畫代碼如下:
ObjectAnimator.ofFloat(view,
"alpha"
, 1f, 0f)
.setDuration(
1500
)
.start();
|
3、旋轉動畫代碼如下:
ObjectAnimator.ofFloat(view,
"scaleX"
, 1f, 0f)
.setDuration(
1000
)
.start();
|
4、位移動畫代碼如下:
ObjectAnimator.ofFloat(view,
"translationX"
,
0
, view.getWidth())
.setDuration(
1000
)
.start();
|
5、背景顏色漸變代碼如下:
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// API 必須代碼 23 才能使用ofArgb
ObjectAnimator animator = ObjectAnimator.ofArgb(view,
"backgroundColor"
,
0xffff00ff
,
0xffffff00
,
0xffff00ff
);
animator.setDuration(
4000
);
animator.start();
}
|
6、組合動畫-----伸縮、透明度動畫同時開始代碼如下:
AnimatorSet animatorSet =
new
AnimatorSet();
//組合動畫
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view,
"scaleX"
, 1f, 0f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view,
"scaleY"
, 1f, 0f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(view,
"alpha"
, 1f, 0f);
animatorSet.setDuration(
2000
);
animatorSet.setInterpolator(
new
DecelerateInterpolator());
animatorSet.play(scaleX).with(scaleY).with(alpha);
//動畫同時開始
animatorSet.start();
|
7、組合動畫-----縮放、透明度動畫先后開始代碼如下:
AnimatorSet animatorSet =
new
AnimatorSet();
//組合動畫
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view,
"scaleX"
, 1f, 2f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view,
"scaleY"
, 1f, 2f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(view,
"alpha"
, 1f, 0f);
ObjectAnimator scaleX2 = ObjectAnimator.ofFloat(view,
"scaleX"
, 2f, 0f);
ObjectAnimator scaleY2 = ObjectAnimator.ofFloat(view,
"scaleY"
, 2f, 0f);
animatorSet.setDuration(
2000
);
animatorSet.setInterpolator(
new
DecelerateInterpolator());
animatorSet.play(scaleX).with(scaleY).before(alpha).before(scaleX2).before(scaleY2);
//alpha 動畫后執行
animatorSet.start();
|
-
after(Animator anim) :將現有動畫插入到傳入的動畫之后執行
-
after(long delay) :將現有動畫延遲指定毫秒后執行
-
before(Animator anim): 將現有動畫插入到傳入的動畫之前執行
-
with(Animator anim) :將現有動畫和傳入的動畫同時執行
在動畫執行前,還可以為動畫添加監聽事件
animatorSet.addListener(
new
Animator.AnimatorListener() {
@Override
public
void
onAnimationStart(Animator animation) {
//動畫開始的時候調用
}
@Override
public
void
onAnimationEnd(Animator animation) {
//畫結束的時候調用
}
@Override
public
void
onAnimationCancel(Animator animation) {
//動畫被取消的時候調用
}
@Override
public
void
onAnimationRepeat(Animator animation) {
//動畫重復執行的時候調用
}
});
|
有時候,我們只想監聽其中的某個事件,其他的我們並不關心。官方還是很人性化得為我們提供了另一個類:AnimatorListenerAdapter,在這個類中,只要重寫我們想要的監聽事件就可以了。
animatorSet.addListener(
new
AnimatorListenerAdapter() {
@Override
public
void
onAnimationStart(Animator animation) {
}
});
|
8、按鈕控件寬度增加動畫代碼如下:
ObjectAnimator animator = ObjectAnimator.ofInt(v,
"width"
, v.getWidth(), v.getWidth() *
2
);
animator.setDuration(
1000
);
animator.start();
|
9、拋物線動畫代碼如下:
ValueAnimator valueAnimator =
new
ValueAnimator();
valueAnimator.setDuration(
1500
);
valueAnimator.setObjectValues(
new
PointF(
0
,
100
));
valueAnimator.setInterpolator(
new
LinearInterpolator());
valueAnimator.setEvaluator(
new
TypeEvaluator<PointF>() {
@Override
public
PointF evaluate(
float
fraction, PointF startValue, PointF endValue) {
/**x方向200px/s ,則y方向0.5 * 200 * t**/
PointF point =
new
PointF();
point.x =
200
* fraction *
3
;
point.y =
0
.5f *
200
* (fraction *
3
) * (fraction *
3
);
return
point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
v.setX(point.x);
v.setY(point.y);
}
});
|