前言
??最近這段時(shí)間對(duì)彈性動(dòng)畫比較感興趣宁昭,空閑就做了一下彈性動(dòng)畫的實(shí)現(xiàn)骤菠。網(wǎng)上對(duì)彈性動(dòng)畫的實(shí)現(xiàn)其實(shí)是有3種铃肯,屬性動(dòng)畫設(shè)置spring插值器为朋、facebook出的rebound以及google出的SpringAnimation臂拓。考慮到android的google背景以及想重溫一下屬性動(dòng)畫的使用习寸,本博實(shí)現(xiàn)了第一種和第三種胶惰。
最終實(shí)現(xiàn)效果
??注意上述動(dòng)態(tài)圖界面的title,第一個(gè)界面是屬性動(dòng)畫差值器的實(shí)現(xiàn)霞溪,第二個(gè)界面是SpringAnimation的實(shí)現(xiàn)孵滞。每一種實(shí)現(xiàn)都做了四種常見(jiàn)的動(dòng)畫操作:縮放、平移鸯匹、旋轉(zhuǎn)坊饶、淡入淡出。
思路及代碼
??所謂“彈性動(dòng)畫”殴蓬,其實(shí)就是控件的某個(gè)屬性值在到達(dá)某個(gè)值之后在該值的左右來(lái)回變化(變得比改之大匿级,或變得比該值小),最終穩(wěn)定在該值的效果痘绎。這種變化的動(dòng)畫很像彈簧津函,所以就叫做“彈性動(dòng)畫”。這種變化作用在view的縮放參數(shù)(scaleX孤页、scaleY)尔苦、平移參數(shù)(transactionX、transactionY)散庶、旋轉(zhuǎn)參數(shù)(rotation)、透明度參數(shù)(alpha)上會(huì)有物理運(yùn)動(dòng)的那種平滑過(guò)渡的效果凌净,比直接到達(dá)該值的那種生硬好很多很多悲龟,這也是“彈性動(dòng)畫”的意義了。
??插值器實(shí)現(xiàn)
??屬性動(dòng)畫的彈性效果實(shí)現(xiàn)冰寻,是利用插值器须教。而選擇合適的插值器函數(shù)至關(guān)重要,網(wǎng)上的一篇文章直接給出了函數(shù):pow(2, -10 * x) * sin((x - factor / 4) * (2 * PI) / factor) + 1斩芭,我們就可以利用這個(gè)函數(shù)創(chuàng)建自己的插值器實(shí)現(xiàn)此效果:
public class SpringInterpolator implements Interpolator {
private float factor;
public SpringInterpolator(float factor) {
this.factor = factor;
}
@Override
public float getInterpolation(float input) {
//factor = 0.4
// pow(2, -10 * x) * sin((x - factor / 4) * (2 * PI) / factor) + 1
return (float) (Math.pow(2, -10 * input) * Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
}
}
??需要注意的是轻腺,此插值器除了在0~1之間線性變化的input這個(gè)輸入?yún)?shù)外,還有一個(gè)factor的輸入?yún)?shù)划乖。那此參數(shù)是做什么的呢贬养?我們可以做一個(gè)實(shí)驗(yàn),做實(shí)驗(yàn)的地方是在這個(gè)網(wǎng)站琴庵,此處的Library選擇Spring误算,然后Equation中的內(nèi)容就變成了我們上面說(shuō)的那個(gè)方程。我們看到當(dāng)factor為0.4時(shí)迷殿,曲線圖是這樣的:
??我們修改factor的值為0.1儿礼,曲線圖變成了這樣:
??再次修改factor的值為0.9,曲線圖是這樣:
??由上述三圖就可以得出結(jié)論:factor的值越小庆寺,值來(lái)回變化的次數(shù)越多蚊夫,對(duì)應(yīng)到具體的動(dòng)畫就是:factor值越小,view來(lái)回縮放的次數(shù)越多懦尝,平移到指定位置后在指定位置上下或左右擺動(dòng)的次數(shù)也越多知纷,旋轉(zhuǎn)和淡入淡出類似。
??下面看一下屬性動(dòng)畫的實(shí)現(xiàn)部分陵霉,因?yàn)閷傩詣?dòng)畫的使用都是差不多屈扎,這里只列出其中的一次使用:
//創(chuàng)建兩個(gè)對(duì)象動(dòng)畫的實(shí)例和將這個(gè)實(shí)例組合起來(lái)的組合對(duì)象實(shí)例
ObjectAnimator objectAnimator0 = null;
ObjectAnimator objectAnimator1 = null;
AnimatorSet animatorSet = new AnimatorSet();
//指定修改view的哪個(gè)屬性及屬性的起始值和結(jié)束值
objectAnimator0 = ObjectAnimator.ofFloat(imageview, "scaleX", 1.0f, 2.0f);
objectAnimator1 = ObjectAnimator.ofFloat(imageview, "scaleY", 1.0f, 2.0f);
//指定兩個(gè)對(duì)象動(dòng)畫的執(zhí)行順序
animatorSet.playTogether(objectAnimator0, objectAnimator1);
//指定兩個(gè)動(dòng)畫組合之后的執(zhí)行時(shí)間
animatorSet.setDuration(2500);
//指定插值器
animatorSet.setInterpolator(new SpringInterpolator(0.3f));
//啟動(dòng)動(dòng)畫
animatorSet.start();
??屬性動(dòng)畫插值器值得說(shuō)的就這么多(插值器函數(shù)中factor的作用、屬性動(dòng)畫的基本使用)撩匕,后面會(huì)給出完整源碼鹰晨。
??SpringAnimation實(shí)現(xiàn)
??Google有專門的一個(gè)包用于實(shí)現(xiàn)此彈性效果,在gradle腳本文件中添加"compile 'com.android.support:support-dynamic-animation:25.+'"引入此包。這個(gè)包的使用也很簡(jiǎn)單模蜡,這里給出一個(gè)其中一種動(dòng)畫的實(shí)現(xiàn)代碼:
//創(chuàng)建兩個(gè)彈性動(dòng)畫對(duì)象
SpringAnimation springAnimation0 = null;
SpringAnimation springAnimation1 = null;
//指定處理view的哪個(gè)屬性漠趁,以及view此屬性的最終值(2.0f)
springAnimation0 = new SpringAnimation(imageview, new FloatPropertyCompat<ImageView>("scaleX") {
@Override
public float getValue(ImageView object) {
float scaleX = object.getScaleX();
return scaleX;
}
@Override
public void setValue(ImageView object, float value) {
object.setScaleX(value);
}
}, 2.0f);
springAnimation1 = new SpringAnimation(imageview, new FloatPropertyCompat<ImageView>("scaleY") {
@Override
public float getValue(ImageView object) {
float scaleY = object.getScaleY();
return scaleY;
}
@Override
public void setValue(ImageView object, float value) {
object.setScaleY(value);
}
}, 2.0f);
//作一些設(shè)置,要不然肉眼看不出來(lái)生效
springAnimation0.setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_ALPHA);
springAnimation1.setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_ALPHA);
//指定此彈性動(dòng)畫的彈性阻尼
springAnimation0.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
//指定此彈性動(dòng)畫的彈性生硬度
springAnimation0.getSpring().setStiffness(SpringForce.STIFFNESS_VERY_LOW);
//如上
springAnimation1.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
springAnimation1.getSpring().setStiffness(SpringForce.STIFFNESS_VERY_LOW);
//啟動(dòng)動(dòng)畫
springAnimation0.start();
springAnimation0.start();
??需要說(shuō)的幾個(gè)點(diǎn):
- 此處的彈性動(dòng)畫只指定了屬性的最終值忍疾,而沒(méi)有指定屬性的起始值闯传。因?yàn)樵摪鼤?huì)根據(jù)當(dāng)前view的位置自動(dòng)獲取起始值,所以無(wú)需我們指定卤妒;
- FloatPropertyCompat甥绿,雖然代碼量看著多,其實(shí)不難则披。構(gòu)造函數(shù)中傳入相關(guān)view屬性共缕,兩個(gè)抽象方法完成對(duì)此屬性的讀寫;
- springAnimation0.setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_ALPHA);在做縮放動(dòng)畫時(shí)士复,setMinimumVisibleChange方法的調(diào)用是必須的图谷,如果不調(diào)用縮放就沒(méi)有彈性效果。我也是看了一部分此包的實(shí)現(xiàn)源碼才發(fā)現(xiàn)這點(diǎn)的阱洪。后面的完整代碼里會(huì)針對(duì)不同的動(dòng)畫給出不同的setMinimumVisibleChange方法調(diào)用便贵;
- setDampingRatio,就是設(shè)置摩擦力的冗荸,摩擦力越大彈起來(lái)越費(fèi)勁承璃,摩擦力越小彈起來(lái)越輕松;
- setStiffness蚌本,這個(gè)是設(shè)置彈性生硬度的绸硕。顯示中彈簧給人的感覺(jué)是,如果它鋼性越強(qiáng)彈起來(lái)也越費(fèi)勁鋼性不那么強(qiáng)的彈起來(lái)輕松魂毁;
- 查了一篇資料玻佩,資料中說(shuō),dampingRatio(即摩擦力)越大席楚,擺動(dòng)次數(shù)越少咬崔,反之則越多;stiffness(即生硬度烦秩、鋼性)越大垮斯,擺動(dòng)時(shí)間越短,反之則越長(zhǎng)只祠。通俗解釋兜蠕,可感知。
總結(jié)
??使用插值器實(shí)現(xiàn)彈性動(dòng)畫抛寝,最核心的是找到彈性插值器的函數(shù)熊杨,而次函數(shù)已經(jīng)是前人栽樹后人乘涼了曙旭,查資料可以查得;而SpringAnimation的實(shí)現(xiàn)晶府,重點(diǎn)是要懂SpringAnimation的基本使用和知道怎么使用setMinimumVisibleChange使彈性效果肉眼可見(jiàn)桂躏。
這里是完整源碼