重要結(jié)論:
既可以通過重寫插值器
改變數(shù)值進(jìn)度
來改變數(shù)值位置酿联,
也可以通過改變Evaluator
中數(shù)值進(jìn)度所對應(yīng)的具體數(shù)值
來改變數(shù)值位置兄淫。
自定義Interpolator
與自定義Evaluator
预厌,
這兩種方法都可以成為屬性動(dòng)畫的驅(qū)動(dòng)力!!!
本文完整項(xiàng)目代碼敬請見GitHub
系統(tǒng)插值器種類
1.AccelerateDecelerateInterpolator
加速減速插值器继效,
表示在開始與結(jié)束的地方速率改變比較慢,在中間的時(shí)候加速装获。
- 整幅圖像表示的是
動(dòng)畫進(jìn)行的時(shí)刻(x軸)
與進(jìn)行的程度(y軸)
的關(guān)系圖,
y軸的值域
為0 ~ 100
穴豫,表示動(dòng)畫進(jìn)行的程度
凡简;
最左側(cè)(線的點(diǎn)坐標(biāo) y = 0)表示動(dòng)畫進(jìn)度為0,即動(dòng)畫剛開始精肃;
最右側(cè)(線的點(diǎn)坐標(biāo) y = 100)表示動(dòng)畫完成秤涩,進(jìn)度為1;
線上的每一個(gè)點(diǎn)
表示在某個(gè)時(shí)間點(diǎn)
的動(dòng)畫進(jìn)行的程度
司抱。
所以某個(gè)點(diǎn)
的切線斜率
就表示
該點(diǎn)對應(yīng)的時(shí)間點(diǎn)的動(dòng)畫
的速率
筐眷;
該點(diǎn)的切線斜率越大
,
該點(diǎn)對應(yīng)的時(shí)間點(diǎn)的動(dòng)畫的速率
則越大习柠;
下面就用這種圖來演繹諸中系統(tǒng)插值器的特性匀谣;
2.AccelerateInterpolator
- 加速插值器,表示在動(dòng)畫開始的地方速率改變比較慢资溃;
-
動(dòng)畫一直加速武翎,在停止時(shí)是突然停止的,
而不像AccelerateDecelerateInterpolator先減速再停止溶锭;
3.DecelerateInterpolator
是減速插值器宝恶,
表示在動(dòng)畫開始的一瞬間加速到最大值,然后逐漸變慢
4.LinearInterpolator
線性插值器,也稱勻速加速器卑惜,很顯然膏执,它的速率是保持恒定的
5.BounceInterpolator
彈跳插值器,模擬了控件自由落地后回彈的效果
- 上面的4幅圖像雖然速率有變化露久,
但是隨著時(shí)間的推移更米,動(dòng)畫進(jìn)度一直是增長的:
而在這幅圖像中,在結(jié)束部分毫痕,
隨著時(shí)間的推移征峦,動(dòng)畫進(jìn)度會(huì)回退。
這也就是出現(xiàn)回彈效果的原因消请,它把動(dòng)畫進(jìn)度回退了栏笆。
6. AnticipateInterpolator
初始偏移插值器,表示在動(dòng)畫開始的時(shí)候向前偏移一段距離臊泰,然后應(yīng)用動(dòng)畫蛉加。
- AnticipateInterpolator還有一個(gè)構(gòu)造函數(shù)。
public AnticipateInterpolator(float tension)
參數(shù)float tension
對應(yīng)的XML屬性為android:tension
缸逃,表示張力值
针饥,默認(rèn)值為2,
值越大需频,初始的偏移量越大丁眼,而且速度越快;
當(dāng)直接使用new AnticipateInterpolator()
構(gòu)造時(shí)昭殉,使用的是tension的默認(rèn)值2苞七。
下圖展示了當(dāng)tension(圖中的T)分別取0.5、2挪丢、4時(shí)的數(shù)學(xué)圖像蹂风。
7.OvershootInterpolator
結(jié)束偏移插值器,表示在動(dòng)畫結(jié)束時(shí)乾蓬,沿動(dòng)畫方向繼續(xù)運(yùn)動(dòng)一段距離后再結(jié)束動(dòng)畫硫眨。- OvershootInterpolator也有另一個(gè)構(gòu)造函數(shù)。
public OvershootInterpolator(float tension)
參數(shù)float tension
對應(yīng)的XML屬性為android:tension
巢块,
表示張力值礁阁,默認(rèn)值為2,值越大族奢,結(jié)束時(shí)的偏移量越大姥闭,而且速度越快;
8. AnticipateOvershootInterpolator
AnticipateInterpolator與OvershootInterpolator的合體越走,
- AnticipateOvershootInterpolator也有其他的構(gòu)造函數(shù)
表示張力值铜跑,默認(rèn)值為2门怪,
值越大,起始和結(jié)束時(shí)的偏移量越大锅纺,而且速度越快掷空。
參數(shù)float extraTension對應(yīng)的XML屬性為android:extraTension,
表示額外張力值囤锉,默認(rèn)值為1.5坦弟。
9. CycleInterpolator
循環(huán)插值器,表示動(dòng)畫循環(huán)播放特定的次數(shù)官地,速率沿正弦曲線改變酿傍。- 其構(gòu)造函數(shù):
public CycleInterpolator(float cycles)
參數(shù)cycles
表示循環(huán)次數(shù); - android:fillAfter="true"屬性
對于CycleInterpolator而言沒有影響驱入。
案例:鏡頭由遠(yuǎn)及近效果
- 實(shí)現(xiàn)其實(shí)就是一個(gè)ScaleAnimation縮放動(dòng)畫而已赤炒,
再配合一下插值器; - 完整項(xiàng)目代碼敬請見GitHub
......
case 6:
ImageView cameraStretchView = new ImageView(this);
cameraStretchView.setBackgroundResource(R.drawable.imagetest1);
ll_nextParent.addView(cameraStretchView, layoutParams);
ScaleAnimation scaleAnimation = getTheCameraStretchAnim();
cameraStretchView.startAnimation(scaleAnimation);
break;
default:
}
}
private ScaleAnimation getTheCameraStretchAnim() {
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.2f, 1.0f, 1.2f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setFillAfter(true);
scaleAnimation.setInterpolator(new BounceInterpolator());
scaleAnimation.setDuration(6000);
return scaleAnimation;
}
自定義插值器
前言
通過
ofInt(0亏较,400)
定 義 了 動(dòng) 畫 的 區(qū) 間 值 是 0~400莺褒,
然后通過添加AnimatorUpdateListener
來監(jiān)聽動(dòng)畫的實(shí)時(shí)變化。那么
0~400
的值
是怎么變化的呢宴杀?
插值器就是用來控制動(dòng)畫的區(qū)間值如何被計(jì)算出來的。
比如
LinearInterpolator插值器表示勻速返回區(qū)間內(nèi)的值拾因;
而DecelerateInterpolator插值器則表示開始變化快旺罢,后期變化慢;
其他插值器與此類似绢记。在 ValueAnimator 中使用插值器很簡單扁达,
直接調(diào)用ValueAnimator.setInterpolator(TimeInterpolator value)
即可。
先看看系統(tǒng)自帶的插值器是如何實(shí)現(xiàn)的蠢熄,比如LinearInterpolator
- LinearInterpolator 實(shí)現(xiàn)了 Interpolator 接口跪解,
而 Interpolator 接口則直接繼承自TimeInterpolator,
而且并沒有添加任何其他的方法签孔。
看看TimeInterpolator接口都有哪些函數(shù)
- 里面只有一個(gè)函數(shù)
float getInterpolation(float input)
叉讥。
該函數(shù)
的含義如下。
參數(shù)input:
input參數(shù)是Float類型的饥追,它的取值范圍是0~1图仓,
表示當(dāng)前動(dòng)畫的進(jìn)度,
取0時(shí)表示動(dòng)畫剛開始但绕,
取1時(shí)表示動(dòng)畫結(jié)束救崔,
取0.5時(shí)表示動(dòng)畫中間的位置惶看,其他以此類推。返回值(
getInterpolation()
的return
返回的東西):
表示當(dāng)前實(shí)際想要顯示的進(jìn)度六孵;
取值可以超過1纬黎,也可以小于0。
超過1表示已經(jīng)超過目標(biāo)值劫窒,小于0表示小于開始位置本今。
getInterpolation(flaot input)
中的input參數(shù)
代表一個(gè)勻速增加的當(dāng)前動(dòng)畫的進(jìn)度,
這個(gè)進(jìn)度是自然進(jìn)度烛亦,自然的诈泼,沒有經(jīng)過修改的,
區(qū)分于實(shí)際顯示的動(dòng)畫進(jìn)度煤禽,
與任何設(shè)置無關(guān)铐达,隨著時(shí)間的推移,
動(dòng)畫的進(jìn)度自然會(huì)從0到1逐漸增加檬果。input參數(shù)相當(dāng)于時(shí)間的概念瓮孙,
正如我們生活中參照時(shí)鐘來知曉時(shí)間,
這里我們參照勻速选脊、自然杭抠、不可改變的自然進(jìn)度input
(input
類似于數(shù)學(xué)函數(shù)意義
中勻速增長
的自變量 x
),
通過向各種數(shù)學(xué)計(jì)算
輸入input
(各種數(shù)學(xué)計(jì)算
則類似于數(shù)學(xué)函數(shù)意義
中的函數(shù)關(guān)系f()
)恳啥,
以輸出各種變化速率的數(shù)值
作為返回值
(最后作為getInterpolation(flaot input)
的return返回值的數(shù)值
偏灿,
則類似于因變量y
,y = f ( x )
)钝的,
從而實(shí)現(xiàn)各種形式的插值器
(插值器
就是基于函數(shù)規(guī)則
翁垂,
把勻速增長的自變量input
,
計(jì)算轉(zhuǎn)換
成具有函數(shù)規(guī)則
的輸出返回值
)input參數(shù)與任何我們設(shè)定的值沒有關(guān)系硝桩,
只與時(shí)間有關(guān)沿猜,隨著時(shí)間的推移,動(dòng)畫的進(jìn)度也自然地增加碗脊,
input參數(shù)就代表了當(dāng)前動(dòng)畫的自然進(jìn)度
啼肩,
而返回值則表示當(dāng)前動(dòng)畫顯示的數(shù)值進(jìn)度
。
-
返回值(
getInterpolation()
的return
返回的東西)
則表示動(dòng)畫的數(shù)值顯示進(jìn)度衙伶,
它可以通過Evaluator的計(jì)算祈坠,得到一個(gè)對應(yīng)的數(shù)值范圍,
對應(yīng)的數(shù)值范圍是我們通過ofInt()矢劲、ofFloat()函數(shù)來指定的颁虐。
在添加了AnimatorUpdateListener的監(jiān)聽事件以后卧须,
通過在監(jiān)聽函數(shù)中調(diào)用animation.getAnimatedValue()函數(shù)另绩,
就可以得到當(dāng)前的值儒陨。
當(dāng)前的值=100+(400-100)× 顯示進(jìn)度
(這個(gè)公式其實(shí)就模擬了Evaluator的計(jì)算過程,Evaluator的內(nèi)容稍后會(huì)進(jìn)行詳解)
其中笋籽,
100和400就是我們設(shè)置的ofInt(100蹦漠,400)中的值,
而顯示進(jìn)度车海,就是返回值(getInterpolation()
的return
返回的東西) -
通過上面的講解笛园,
下面看看LinearInterpolator是如何重寫TimeInterpolator的:
我們知道了input參數(shù)與getInterpolation()函數(shù)返回值的關(guān)系(y = f(x)),
以上侍芝,
LinearInterpolator在getInterpolation()函數(shù)中直接把input值返回研铆,
即以當(dāng)前動(dòng)畫進(jìn)度作為動(dòng)畫的數(shù)值進(jìn)度,
這也就表示當(dāng)前動(dòng)畫的數(shù)值進(jìn)度與動(dòng)畫的時(shí)間進(jìn)度一致州叠。
由于動(dòng)畫進(jìn)度是隨時(shí)間勻速前進(jìn)的棵红,
所以LinearInterpolator的數(shù)值進(jìn)度也是勻速增加的,
這便是基于LinearInterpolator的動(dòng)畫進(jìn)度是勻速進(jìn)行的原理咧栗;
自定義Interpolator
自定義插值器其實(shí)很容易逆甜,
只需實(shí)現(xiàn)TimeInterpolator接口,
重寫getInterpolation()
致板,
在里面返回自己需要的計(jì)算值和方式
即可:下面例程交煞,
自定義插值器的getInterpolation()
函數(shù)中,
將進(jìn)度反轉(zhuǎn)過來斟或,
當(dāng)傳入0的時(shí)候素征,讓它的數(shù)值進(jìn)度在完成的位置;
當(dāng)完成的時(shí)候萝挤,讓它的數(shù)值進(jìn)度在開始的位置御毅。
public class MyInterpolator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
return 1 - input;
}
}
-
使用:GitHub文件目錄
private void startAnimationTestInterpolator() {
ValueAnimator animator = ValueAnimator.ofInt(0, 400);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv_text.layout(tv_text.getLeft(),curValue,
tv_text.getRight(), curValue+tv_text.getHeight());
}
});
animator.setDuration(1000);
animator.setInterpolator(new MyInterpolator());
animator.start();
}
接下來筆記Evaluator
Evaluator
-
下圖講述了
得到當(dāng)前動(dòng)畫所對應(yīng)數(shù)值的整個(gè)過程:
從定義動(dòng)畫的數(shù)值區(qū)間到在AnimatorUpdateListener中
ofInt(0,400):表示指定動(dòng)畫的數(shù)值區(qū)間平斩,從0運(yùn)動(dòng)到400亚享。
插值器:
在動(dòng)畫開始后
通過插值器會(huì)返回當(dāng)前動(dòng)畫進(jìn)度所對應(yīng)的數(shù)值進(jìn)度咽块,
這個(gè)數(shù)值進(jìn)度是以小數(shù)表示的绘面,如0.2。Evaluator:
我們通過監(jiān)聽器拿到的是當(dāng)前動(dòng)畫所對應(yīng)的具體數(shù)值侈沪,
而不是用小數(shù)表示的數(shù)值揭璃。
那么必須有一個(gè)地方會(huì)根據(jù)當(dāng)前的數(shù)值進(jìn)度
將其轉(zhuǎn)換為對應(yīng)的數(shù)值
,
這個(gè)地方就是Evaluator
亭罪。
Evaluator用于將
從插值器返回的數(shù)值進(jìn)度(小數(shù)瘦馍,0 - 1.0)
轉(zhuǎn)換成對應(yīng)的數(shù)值
。監(jiān)聽器返回:
在AnimatorUpdateListener
監(jiān)聽器中
使用animation.getAnimatedValue()
函數(shù)
拿到Evaluator
中返回的數(shù)值应役。
插值器
返回的小數(shù)值表示的是當(dāng)前動(dòng)畫的數(shù)值進(jìn)度情组,
這對于無論是使用ofFloat()
函數(shù)
還是使用ofInt()
函數(shù)定義的動(dòng)畫都是適用的燥筷。
因?yàn)闊o論是什么動(dòng)畫,它的進(jìn)度必然在0~1
之間院崇。
0表示還沒開始肆氓,1表示動(dòng)畫結(jié)束
,這對于任何動(dòng)畫都是適用的底瓣。而
Evaluator
則不一樣谢揪,
它把插值器返回的小數(shù)進(jìn)度轉(zhuǎn)換成當(dāng)前數(shù)值進(jìn)度所對應(yīng)的值。
如果使用ofInt()
函數(shù)來定義動(dòng)畫捐凭,
動(dòng)畫中的值應(yīng)該都是Integer類型的拨扶,
所對應(yīng)的Evaluator在返回值時(shí),必然返回Integer類型的值茁肠;
如果使用ofFloat()
函數(shù)來定義動(dòng)畫患民,
動(dòng)畫中的值都是Float類型的,
Evaluator在返回值時(shí)官套,必然返回Float類型的值酒奶。所以,每種定義方式所對應(yīng)的Evaluator必然是它專用的奶赔。
Evaluator專用的原因
在于動(dòng)畫數(shù)值類型
不一樣惋嚎,
在通過Evaluator返回時(shí)會(huì)報(bào)強(qiáng)轉(zhuǎn)錯(cuò)誤,
所以只有在動(dòng)畫數(shù)值類型一樣時(shí)站刑,所對應(yīng)的Evaluator才能通用另伍。
ofInt()
函數(shù)對應(yīng)的Evaluator類名為IntEvaluator
,
而ofFloat()
函數(shù)對應(yīng)的Evaluator類名為FloatEvaluator
绞旅。
- 通過
animator.setEvaluator()函數(shù)
來設(shè)置Evaluator
摆尝,
(下面例程第三行)
private void startAnimationArgbEvaluator() {
ValueAnimator animator = ValueAnimator.ofInt(0xffffff00, 0xff0000ff);
animator.setEvaluator(new ArgbEvaluator());//設(shè)置Evaluator
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (Integer) animation.getAnimatedValue();
tv_text.setBackgroundColor(curValue);
}
});
animator.start();
}
可以使用ValueAnimator.ofInt()函數(shù)構(gòu)造ValueAnimator,
顯式設(shè)置了它所對應(yīng)的IntEvaluator因悲,
用來計(jì)算數(shù)值進(jìn)度所對應(yīng)的數(shù)值堕汞。
但其實(shí),
ofInt()
和ofFloat()
都是系統(tǒng)直接提供的函數(shù)晃琳,
所以會(huì)有默認(rèn)的插值器和Evaluator可供使用讯检。
ofInt()
函數(shù)的默認(rèn)Evaluator 是IntEvaluator
,
而ofFloat()
函數(shù)的默認(rèn)Evaluator則是FloatEvaluator
卫旱。
-
Ctrl + 左鍵 看一下IntEvaluator的源碼
package android.animation;
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
在IntEvaluator中
只有一個(gè)函數(shù)
evaluate(float fraction人灼,Integer startValue,Integer endValue)
fraction
參數(shù)就是插值器中的返回值顾翼,
表示當(dāng)前動(dòng)畫的數(shù)值進(jìn)度投放,以百分制的小數(shù)表示。
startValue
和endValue
分別對應(yīng)
ofInt(int start适贸,int end)
函數(shù)中start
和end
的數(shù)值灸芳。
假設(shè)當(dāng)我們定義的動(dòng)畫ofInt(100涝桅,400)
進(jìn)行到數(shù)值進(jìn)度20%
的時(shí)候,
那么此時(shí)在evaluate()
函數(shù)中烙样,
fraction
的值就是0.2
苹支,
startValue
的值是100
,
endValue
的值是400
误阻。
返回值
(即return (int)(startInt + fraction * (endValue - startInt));
)
就是當(dāng)前數(shù)值進(jìn)度
所對應(yīng)的具體數(shù)值
债蜜,
這個(gè)數(shù)值就是
我們在AnimatorUpdateListener
監(jiān)聽器中
通過animation.getAnimatedValue()
函數(shù)得到的數(shù)值。
evaluate(float fraction究反,Integer startValue寻定,Integer endValue)
函數(shù)
根據(jù)return (int)(startInt + fraction * (endValue - startInt));
,
也就是根據(jù)進(jìn)度數(shù)值來計(jì)算出具體數(shù)值精耐,
這跟前面插值器中提到的當(dāng)前的值=100+(400-100)× 顯示進(jìn)度
是相對應(yīng):
結(jié)論:
既可以通過重寫插值器改變數(shù)值進(jìn)度
來改變數(shù)值位置狼速,
也可以通過改變Evaluator中數(shù)值進(jìn)度所對應(yīng)的具體數(shù)值
來改變數(shù)值位置。
這兩種方法都可以成為屬性動(dòng)畫的驅(qū)動(dòng)力X酝!O蚝!
自定義Evaluator
public class MyEvaluator implements TypeEvaluator<Integer> {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int) (200 + startInt + fraction * (endValue - startInt));
}
}
首先實(shí)現(xiàn)TypeEvaluator接口惊完;(注意這里的理解泛型的概念)僵芹;
這里實(shí)現(xiàn)TypeEvaluator時(shí),指定它的泛型是Integer類型的小槐,
這樣就可以在ofInt()函數(shù)中使用這個(gè)Evaluator了拇派。注意:
只有定義動(dòng)畫時(shí)的數(shù)值類型與Evaluator的返回值類型一樣,
才能使用這個(gè)Evaluator凿跳。
很顯然件豌,ofInt()函數(shù)定義的數(shù)值類型是Integer,
這里定義的MyEvaluator只能適用于ofInt()
函數(shù)了控嗜。
同理茧彤,
如果把實(shí)現(xiàn)的TypeEvaluator
接口泛型
設(shè)置為Float類型,
那么這個(gè)Evaluator也就只能適用于ofFloat()
函數(shù)了疆栏。然后簡單實(shí)現(xiàn)其中的
evaluate()
函數(shù):在IntEvaluator的基礎(chǔ)上修改了一下曾掂,
讓它返回值時(shí)增加了200。
所以承边,
當(dāng)我們定義的區(qū)間是ofInt(0遭殉,400)時(shí)石挂,
它的實(shí)際返回值區(qū)間應(yīng)該是(200博助,600)。
使用自定義的Evaluator
private void startAnimation() {
ValueAnimator animator = ValueAnimator.ofInt(0, 400);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv_text.layout(tv_text.getLeft(),curValue,
tv_text.getRight(), curValue+tv_text.getHeight());
}
});
animator.setDuration(1000);
animator.setEvaluator(new MyEvaluator());
animator.start();
}
-
自定義Evaluator實(shí)現(xiàn)倒序輸出
- 除
IntEvaluator
和FloatEvaluator
外富岳,
在android.animation
包下還有另一個(gè)Evaluator
,
名為ArgbEvaluator
窖式,它是用來實(shí)現(xiàn)顏色值過渡轉(zhuǎn)換的。
-
ArgbEvaluator
的實(shí)現(xiàn)原理 - 這段代碼分為三部分:
第一部分根據(jù)startValue
求出A萝喘、R淮逻、G、B中各個(gè)色彩的初始值阁簸;
第二部分根據(jù)endValue
求出A、R启妹、G、B中各個(gè)色彩的結(jié)束值饶米;
第三部分根據(jù)當(dāng)前動(dòng)畫的百分比進(jìn)度求出對應(yīng)的數(shù)值桨啃。
注意0xff是八個(gè)二進(jìn)制位而已,剛好留下一個(gè)色彩的值C适洹照瘾!
-
使用ArgbEvaluator
private void startAnimationArgbEvaluator() {
ValueAnimator animator = ValueAnimator.ofInt(0xffffff00, 0xff0000ff);
animator.setEvaluator(new ArgbEvaluator());//設(shè)置Evaluator
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (Integer) animation.getAnimatedValue();
tv_text.setBackgroundColor(curValue);
}
});
animator.start();
}
本文完整項(xiàng)目代碼敬請見GitHub