概述
屬性動畫踩麦,顧名思義-動態(tài)改變對象的屬性佛猛,以此變化來產(chǎn)生某種效果制妄。 這里的對象可是任何對象祠锣,并不限定是View控件酷窥。
-
屬性動畫是Android 3.0(API 11)增加的,為何增加伴网?有何意義蓬推?
- 你一定還記得在view animation 中,交互不友好(比如view的位置改變了澡腾,但是點擊事件還在原來的位置)
- view animation 能讓view動起來的效果有限沸伏,屬性動畫可是打著能改變?nèi)魏螌ο蟮娜魏螌傩猿鰣龅模@樣就可以實現(xiàn)復(fù)雜高級效果了动分。
-
系統(tǒng)為我們提供了屬性動畫哪些用法毅糟?出了具體表現(xiàn)在這些類,也支持XML中定義使用澜公。
- ObjectAnimator
- PropertyHolder
- ValueAnimator
- AnimatorSet
- Animator.AnimatorListener
- ValueAnimator.AnimatorUpdateListener
屬性動畫中也要用到view動畫中的差值器等API姆另,也獨有估值器
ObjectAnimator
在這個類中,通過調(diào)用ObjectAnimator的工廠方法坟乾,傳入對應(yīng)的參數(shù)即可迹辐,舉個簡單的用法來看具體怎么使用
這樣的效果用屬性動畫也是非常容易實現(xiàn)的
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
// 指定一個時間差值器(TimeInpolator),ObjectAnimator默認的是LinearInpolator
objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator1.setDuration(1000);
objectAnimator1.start();
關(guān)于ofFloat(Object target, String propertyName, float... values)
第一個參數(shù)是要操縱的對象,第二個是操縱對象的屬性名甚侣,第三個是一個可變數(shù)組參數(shù)右核,表示屬性的取值變化的過程
列舉view的一些常見可以直接用的屬性值
view偏移量: translationX 、translationY
view2D和3D旋轉(zhuǎn)角度: rotation渺绒、rotationX贺喝、rotationY
view的2D縮放比例: scaleX、 scaleY
view的旋轉(zhuǎn)和縮放的中心點宗兼,默認是view的中心點:pivotX躏鱼、pivotY
view的坐標: x 、y
view的透明度: alpha
值得注意的是ObjectAnimator
:
- 操縱的屬性必須具有
set<propertyName>()
,因為ObjectAnimator
在動態(tài)改變屬性的過程中殷绍,會去通過set方法來改變這個屬性染苛。如果操縱的屬性沒有set方法,官方給出三種建議:- 如果你有權(quán)限的話就去給這個屬性添加一個set方法
- 可以通過自定義一個屬性類或者包裝類,來間接給這個屬性增加set方法
- 使用
ValueAnimator
來代替
- 對于這個可變參數(shù)茶行,
values...
如果僅僅設(shè)置了一個參數(shù)躯概,會被認為這個值是變化過程的結(jié)束值。此刻ObjectAnimator
會自動去通過get<propertyName>()
來獲得變化的起始值畔师,這時就要求操作的屬性必須具有g(shù)et方法
這里我們舉個例子娶靡,操作一個自定義的對象
public class Person {
private int age;
public void setAge(int age) {
this.age = age;
Log.d("age", "set年齡" + age);
}
public int getAge() {
Log.d("age", "get年齡" + age);
return age;
}
}
這個時候我們?nèi)赢嫷母淖兯?/p>
ObjectAnimator objectAnimator;
// 1.屬性動畫可以對任意一個對象的屬性動態(tài)改變
objectAnimator = ObjectAnimator.ofInt(new Person(), "age",5, 8);
objectAnimator.start();
觀察這個時候的log
和我們預(yù)想的一樣,動態(tài)改變了這個年齡值看锉,哈哈
如果我們對可變參數(shù)只設(shè)置一個參數(shù)呢姿锭?
ObjectAnimator objectAnimator;
// 1.屬性動畫可以對任意一個對象的屬性動態(tài)改變
objectAnimator = ObjectAnimator.ofInt(new Person(), "age", 4);
objectAnimator.start();
這個時候的log 顯示表明調(diào)用了get方法獲得初始值
雖然上面這個改變屬性值沒有實際意義,但是很清晰的展示了屬性動畫的魅力和變化過程伯铣。
你對為什么一個數(shù)值打印那么多遍感到很奇怪呻此?
其實這就是屬性動畫中有估值器(Evaluator)這個概念,這里我給采用的是ofInt
對應(yīng)的其實是IntEvaluator
腔寡,這是ObjectAnimator內(nèi)部會去判斷,可以去源碼中查看焚鲜。
同理如果ofFloat
對應(yīng)的就是FloatEvaluator
當然你也可以ofObject
傳入自己想要的估值器
那么這個時候你把Person
的age
屬性改成float, 并且動畫采用ofFloat
,結(jié)果你會發(fā)現(xiàn)會一步一步接近最后的值放前。
PropertyValuesHolder
如果同時改變多個屬性呢?
可以直接構(gòu)造多個ObjetAnimator
然后調(diào)用start
. 因為他們是異步的犀斋,這些動畫會同時執(zhí)行
objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator1.setDuration(1000);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
objectAnimator2.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator2.setDuration(1000);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
objectAnimator3.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator3.setDuration(2000);
objectAnimator1.start();
objectAnimator2.start();
objectAnimator3.start();;
還可以使用PropertyValuesHolder
贝乎,然后調(diào)用的ObjectAnimator.ofPropertyValuesHolder
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0f,imageview.getWidth());
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationY",0f,imageview.getHeight());
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("rotationX",0f,360f);
ObjectAnimator.ofPropertyValuesHolder(imageview, p1,p2,p3).setDuration(2000).start();
在上面的例子中,那如果我想控制他們的播放順序呢叽粹?
AnimatorSet
這個效果是先同時x和y方向平移動畫览效,然后在執(zhí)行旋轉(zhuǎn)
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
AnimatorSet set = new AnimatorSet();
set.setDuration(2000);
set.setInterpolator(new LinearInterpolator());
//set.playTogether(objectAnimator1,objectAnimator2, objectAnimator3);
//set.playSequentially(objectAnimator1,objectAnimator2, objectAnimator3);
set.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3); objectAnimator3);
set.start();
可以將注釋部分觀察效果。AnimatorSet
需要說明幾點:
-
playSequentially
是單獨順序播放 -
play
配合with
虫几、before
锤灿、after
來按照這些規(guī)則播放動畫 -
playTogether
動畫同時播放
ValueAnimator的使用
通過上面的那個類關(guān)系圖,ValueAnimator
是ObjectAnimator
的父類辆脸,實際上ObjectAnimator
是更加具體化了ValueAnimator
但校,實現(xiàn)了一系列的既定效果,更加方便的使用啡氢。那么上文提到如果一個屬性沒有set方法可以用ValueAnimator
來代替.
什么意思呢状囱?其實就是說ValueAnimator
,它并不要求你非要指定什么屬性倘是,注重的是值的變化亭枷,然后可以監(jiān)聽這些值的變化過程,從而自己來根據(jù)這些值搀崭,產(chǎn)生你自己需要的效果叨粘。比如你要做一個計時器,這個時候你可以ofInt在監(jiān)聽里面去設(shè)置UI 顯示倒計時的數(shù)值即可。
這里看一下如何監(jiān)聽等常規(guī)思路:
ValueAnimator valueAnimator = ValueAnimator.ofInt(1,15);// ValueAnimator ,ofInt,ofFloat,ofObject
// valueAnimator.setEvaluator(new IntEvaluator()); // 設(shè)置估值器
valueAnimator.setEvaluator(new TypeEvaluator<Integer>() {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
// 這里自定義了一個估值器升敲,就是在int估值器的基礎(chǔ)上加一個1
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt)+1);
}
});
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.d("smart","變化的值:" +animation.getAnimatedValue());
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
估值器
-
系統(tǒng)定義的估值器:
- IntEvaluator 計算整型
- FloatEvaluator 計算float型
- ArgbEvaluator 計算顏色
- TypeEvaluator 是一個接口答倡,自定義估值器需要實現(xiàn)它
-
如何自定義一個估值器
public interface TypeEvaluator<T> { public T evaluate(float fraction, T startValue, T endValue); }
實現(xiàn)這個接口,確定泛型的返回值T驴党。
至此 瘪撇,屬性動畫的基本概念敘述完畢!