摘要:HenCoder Android 自定义 View 1-7:属性动画 Property Animation(进阶篇)
上期的內(nèi)容,對(duì)于大多數(shù)簡(jiǎn)單的屬性動(dòng)畫場(chǎng)景已經(jīng)夠用了。這期的內(nèi)容主要針對(duì)兩個(gè)方面:
1. 針對(duì)特殊類型的屬性來做屬性動(dòng)畫;
2. 針對(duì)復(fù)雜的屬性關(guān)系來做屬性動(dòng)畫。
TypeEvaluator
關(guān)于 ObjectAnimator,上期講到可以用 ofInt() 來做整數(shù)的屬性動(dòng)畫和用 ofFloat() 來做小數(shù)的屬性動(dòng)畫。這兩種屬性類型是屬性動(dòng)畫最常用的兩種,不過在實(shí)際的開發(fā)中,可以做屬性動(dòng)畫的類型還是有其他的一些類型。當(dāng)需要對(duì)其他類型來做屬性動(dòng)畫的時(shí)候,就需要用到 TypeEvaluator 了。
ArgbEvaluator
TypeEvaluator 最經(jīng)典的用法是使用 ArgbEvaluator 來做顏色漸變的動(dòng)畫。
ObjectAnimator animator = ObjectAnimator.ofInt(view, “color”, 0xffff0000, 0xff00ff00);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
另外,在 Android 5.0 (API 21) 加入了新的方法 ofArgb(),所以如果你的 minSdk 大于或者等于 21(哈哈哈哈哈哈哈哈),
你可以直接用下面這種方式:
ObjectAnimator animator = ObjectAnimator.ofArgb(view, “color”, 0xffff0000, 0xff00ff00);
animator.start();
自定義 Evaluator
如果你對(duì) ArgbEvaluator 的效果不滿意,或者你由于別的什么原因希望寫一個(gè)自定義的 TypeEvaluator,你可以這樣寫:
// 自定義 HslEvaluator
private class HsvEvaluator implements TypeEvaluator {
float[] startHsv = new float[3];
float[] endHsv = new float[3];
float[] outHsv = new float[3];
// 使用自定義的 HslEvaluator
animator.setEvaluator(new HsvEvaluator());
animator.start();
ofObject()
借助于 TypeEvaluator,屬性動(dòng)畫就可以通過 ofObject() 來對(duì)不限定類型的屬性做動(dòng)畫了。方式很簡(jiǎn)單:
為目標(biāo)屬性寫一個(gè)自定義的 TypeEvaluator
使用 ofObject() 來創(chuàng)建 Animator,并把自定義的 TypeEvaluator 作為參數(shù)填入
private class PointFEvaluator implements TypeEvaluator {
PointF newPoint = new PointF();
}
ObjectAnimator animator = ObjectAnimator.ofObject(view, “position”,
new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
animator.start();
另外在 API 21 中,已經(jīng)自帶了 PointFEvaluator 這個(gè)類,所以如果你的 minSdk 大于或者等于 21(哈哈哈哈哈哈哈哈),上面這個(gè)類你就不用寫了,直接用就行了。
ofMultiInt() ofMultiFloat()
在 API 引入的新的方法還有 ofMultiInt() 和 ofMultiFloat() 等,用法也很簡(jiǎn)單,不過實(shí)用性就低了一些。你有興趣的話可以去做一下了解,這里不在多做介紹。
以上這些就是對(duì) TypeEvaluator 的介紹。它的作用是讓你可以對(duì)同樣的屬性有不同的解析方式,對(duì)本來無法解析的屬性也可以打造出你需要的解析方式。有了 TypeEvaluator,你的屬性動(dòng)畫就有了更大的靈活性,從而有了無限的可能。
TypeEvaluator 是本期的第一部分內(nèi)容:針對(duì)特殊的屬性來做屬性動(dòng)畫,它可以讓你「做到本來做不到的動(dòng)畫」。接下來是本期的第二部分內(nèi)容:針對(duì)復(fù)雜的屬性關(guān)系來做動(dòng)畫,它可以讓你「能做到的動(dòng)畫做起來更簡(jiǎn)單」。
PropertyValuesHolder 同一個(gè)動(dòng)畫中改變多個(gè)屬性
很多時(shí)候,你在同一個(gè)動(dòng)畫中會(huì)需要改變多個(gè)屬性,例如在改變透明度的同時(shí)改變尺寸。如果使用 ViewPropertyAnimator,你可以直接用連寫的方式來在一個(gè)動(dòng)畫中同時(shí)改變多個(gè)屬性:
view.animate()
.scaleX(1)
.scaleY(1)
.alpha(1);
而對(duì)于 ObjectAnimator,是不能這么用的。不過你可以使用 PropertyValuesHolder 來同時(shí)在一個(gè)動(dòng)畫中改變多個(gè)屬性。
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat(“scaleX”, 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat(“scaleY”, 1);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat(“alpha”, 1);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)
animator.start();
PropertyValuesHolder 的意思從名字可以看出來,它是一個(gè)屬性值的批量存放地。所以你如果有多個(gè)屬性需要修改,
可以把它們放在不同的 PropertyValuesHolder 中,然后使用 ofPropertyValuesHolder() 統(tǒng)一放進(jìn) Animator。
這樣你就不用為每個(gè)屬性單獨(dú)創(chuàng)建一個(gè) Animator 分別執(zhí)行了。
AnimatorSet 多個(gè)動(dòng)畫配合執(zhí)行
有的時(shí)候,你不止需要在一個(gè)動(dòng)畫中改變多個(gè)屬性,還會(huì)需要多個(gè)動(dòng)畫配合工作,比如,在內(nèi)容的大小從 0 放大到 100% 大小后開始移動(dòng)。這種情況使用 PropertyValuesHolder 是不行的,因?yàn)檫@些屬性如果放在同一個(gè)動(dòng)畫中,需要共享動(dòng)畫的開始時(shí)間、結(jié)束時(shí)間、Interpolator 等等一系列的設(shè)定,這樣就不能有先后次序地執(zhí)行動(dòng)畫了。
這就需要用到 AnimatorSet 了。
// 兩個(gè)動(dòng)畫依次執(zhí)行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();
使用 playSequentially(),就可以讓兩個(gè)動(dòng)畫依次播放,而不用為它們?cè)O(shè)置監(jiān)聽器來手動(dòng)為他們監(jiān)管協(xié)作。
AnimatorSet 還可以這么用:
// 兩個(gè)動(dòng)畫同時(shí)執(zhí)行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();
以及這么用:
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式來精確配置各個(gè) Animator 之間的關(guān)系
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();
有了 AnimatorSet ,你就可以對(duì)多個(gè) Animator 進(jìn)行統(tǒng)一規(guī)劃和管理,讓它們按照要求的順序來工作。
PropertyValuesHolders.ofKeyframe() 把同一個(gè)屬性拆分
除了合并多個(gè)屬性和調(diào)配多個(gè)動(dòng)畫,你還可以在 PropertyValuesHolder 的基礎(chǔ)上更進(jìn)一步,通過設(shè)置 Keyframe (關(guān)鍵幀),把同一個(gè)動(dòng)畫屬性拆分成多個(gè)階段。例如,你可以讓一個(gè)進(jìn)度增加到 100% 后再「反彈」回來。
// 在 0% 處開始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 時(shí)間經(jīng)過 50% 的時(shí)候,動(dòng)畫完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 時(shí)間見過 100% 的時(shí)候,動(dòng)畫完成度倒退到 80%,即反彈 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe(“progress”, keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();
第二部分,「關(guān)于復(fù)雜的屬性關(guān)系來做動(dòng)畫」,就這么三種:
1. 使用 PropertyValuesHolder 來對(duì)多個(gè)屬性同時(shí)做動(dòng)畫;
2. 使用 AnimatorSet 來同時(shí)管理調(diào)配多個(gè)動(dòng)畫;
3. PropertyValuesHolder 的進(jìn)階使用:使用 PropertyValuesHolder.ofKeyframe() 來把一個(gè)屬性拆分成多段,執(zhí)行更加精細(xì)的屬性動(dòng)畫。
ValueAnimator 最基本的輪子
額外簡(jiǎn)單說一下 ValuesAnimator。很多時(shí)候,你用不到它,只是在你使用一些第三方庫的控件,而你想要做動(dòng)畫的屬性卻沒有 setter / getter 方法的時(shí)候,會(huì)需要用到它。
除了 ViewPropertyAnimator 和 ObjectAnimator,還有第三個(gè)選擇是 ValueAnimator。ValueAnimator 并不常用,因?yàn)樗墓δ芴A(chǔ)了。ValueAnimator 是 ObjectAnimator 的父類,實(shí)際上,ValueAnimator 就是一個(gè)不能指定目標(biāo)對(duì)象版本的 ObjectAnimator。ObjectAnimator 是自動(dòng)調(diào)用目標(biāo)對(duì)象的 setter 方法來更新目標(biāo)屬性的值,以及很多的時(shí)候還會(huì)以此來改變目標(biāo)對(duì)象的 UI,而 ValueAnimator 只是通過漸變的方式來改變一個(gè)獨(dú)立的數(shù)據(jù),這個(gè)數(shù)據(jù)不是屬于某個(gè)對(duì)象的,至于在數(shù)據(jù)更新后要做什么事,全都由你來定,你可以依然是去調(diào)用某個(gè)對(duì)象的 setter 方法(別這么為難自己),也可以做其他的事,不管要做什么,都是要你自己來寫的,ValueAnimator 不會(huì)幫你做。功能最少、最不方便,但有時(shí)也是束縛最少、最靈活。比如有的時(shí)候,你要給一個(gè)第三方控件做動(dòng)畫,你需要更新的那個(gè)屬性沒有 setter 方法,只能直接修改,這樣的話 ObjectAnimator 就不靈了啊。怎么辦?這個(gè)時(shí)候你就可以用 ValueAnimator,在它的 onUpdate() 里面更新這個(gè)屬性的值,并且手動(dòng)調(diào)用 invalidate()。
所以你看,ViewPropertyAnimator、ObjectAnimator、ValueAnimator 這三種 Animator,它們其實(shí)是一種遞進(jìn)的關(guān)系:從左到右依次變得更加難用,也更加靈活。但我要說明一下,它們的性能是一樣的,因?yàn)?ViewPropertyAnimator 和 ObjectAnimator 的內(nèi)部實(shí)現(xiàn)其實(shí)都是 ValueAnimator,ObjectAnimator 更是本來就是 ValueAnimator 的子類,它們?nèi)齻€(gè)的性能并沒有差別。它們的差別只是使用的便捷性以及功能的靈活性。所以在實(shí)際使用時(shí)候的選擇,只要遵循一個(gè)原則就行:盡量用簡(jiǎn)單的。能用 View.animate() 實(shí)現(xiàn)就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。
總結(jié)
以上是生活随笔為你收集整理的摘要:HenCoder Android 自定义 View 1-7:属性动画 Property Animation(进阶篇)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈Junit4和TestNG中的参数化
- 下一篇: android sina oauth2.