0. 源碼地址
https://github.com/wutongke/AndroidSkinAnimator
1. 引子
動(dòng)畫效果是一個(gè)非常棒的用戶體驗(yàn)颠毙,Android 加入Material Design,app賞心悅目了不少带斑,關(guān)鍵還完全沒有增加開發(fā)者的負(fù)擔(dān)全跨。不需要多寫哪怕一行代碼河闰,用戶體驗(yàn)已經(jīng)提升了很多。
但是在界面中動(dòng)態(tài)刪除一個(gè)View,或者更新View顯示時(shí)痕钢,界面還是存在抖動(dòng)的現(xiàn)象香到,過渡不夠平滑鱼冀。所以是否能有一種方法對(duì)開發(fā)者透明的高效動(dòng)畫實(shí)現(xiàn)呢?幾天前看到有個(gè)同學(xué)實(shí)現(xiàn)了Android-skin-support Android換膚框架悠就,主要原理就是在執(zhí)行onCreate
之前通過setFactory(LayoutInflater inflater, LayoutInflaterFactory factory)
方法替換系統(tǒng)View為自定義的View千绪,從而自如切換View的一些屬性。仔細(xì)想想理卑,利用這種方式可以實(shí)現(xiàn)太多的功能了翘紊。
2. 思路
其實(shí)我們需要實(shí)現(xiàn)的動(dòng)畫主要是View在Visible,Gone
或者內(nèi)容更新的時(shí)候可以平滑切換:
[圖片上傳失敗...(image-eb3007-1609400981041)]
如圖中的第一個(gè)TextView在由text1更新到text1_change時(shí)藐唠,如果有動(dòng)畫是漸隱變化的帆疟,無(wú)動(dòng)畫時(shí)則比較生硬。
我們實(shí)現(xiàn)Animation everywhere主要就是實(shí)現(xiàn)Visible 宇立、Gone踪宠、Update
動(dòng)畫,其它動(dòng)畫不夠通用妈嘹,如果需要可以手動(dòng)實(shí)現(xiàn)柳琢。我們采用的方式也是在setFactory(LayoutInflater inflater, LayoutInflaterFactory factory)
方法中替換系統(tǒng)View,這樣可以保證對(duì)開發(fā)透明润脸,不需要在布局文件中作出改動(dòng)柬脸。
自定義View主要是修改View自身的setVisibility()
和更新內(nèi)容的一些方法,如TextView 的setText()
的方法毙驯。
3. 存在的問題
替換原生View是一個(gè)比較有風(fēng)險(xiǎn)的事情倒堕,因此應(yīng)該提供選項(xiàng),某些Activity中選擇原生View爆价,在有需求的地方再選擇Animator View垦巴。
同時(shí)媳搪,由于并不是所有時(shí)候都需要?jiǎng)赢嫞缡状渭虞d界面的時(shí)候骤宣,如果每個(gè)View都執(zhí)行一次動(dòng)畫秦爆,不僅耗費(fèi)資源,也很奇怪憔披。因此需要提供開啟動(dòng)畫和關(guān)閉動(dòng)畫的選項(xiàng)等限,在需要的時(shí)候開啟動(dòng)畫。
4. 代碼實(shí)現(xiàn)
4.1 功能概要
- 自定義View活逆,覆蓋原生
setVisibility()
等方法 - 實(shí)現(xiàn)多種Animator
- 實(shí)現(xiàn)配置View可用動(dòng)畫的架構(gòu)
4.2 細(xì)節(jié)實(shí)現(xiàn)
- 自定義View
覆蓋setVisibility
方法:
@Override
public void setVisibility(int visibility) {
if (AnimatorManager.getConfig().getTextViewVisibleAnimationType() == ViewAnimatorType.None) {
super.setVisibility(visibility);
} else {
this.visibleStatus = visibility;
if (visibility == GONE) {
ViewAnimatorUtil.executeAnimator(this, AnimatorManager.getConfig().getTextViewVisibleAnimationType(), visibleAction);
} else {
visibleAction.action();
}
}
}
主要是判斷如果不執(zhí)行動(dòng)畫精刷,那么執(zhí)行父類方法即可。
- 實(shí)現(xiàn)多種Animator
這個(gè)主要實(shí)現(xiàn)三類動(dòng)畫蔗候,出現(xiàn)怒允、消失、更新锈遥,可以放置在不同的文件夾中纫事。這里使用了Enum值表示不同的動(dòng)畫,方便配置使用:
ROTATE3{
@Override
public void apply(View view, Action action) {
SkinRotateAnimator3.getInstance().apply(view, action).start();
}
},
-
實(shí)現(xiàn)配置View可用動(dòng)畫的架構(gòu)
這個(gè)主要通過兩個(gè)類來(lái)實(shí)現(xiàn)所灸,一個(gè)提供動(dòng)畫操作接口丽惶,一個(gè)提供動(dòng)畫配置接口:
動(dòng)畫配置使用build的方式,操作方法:
new AnimatorConfig.Builder()
.textviewTextAnimationType(ViewAnimatorType.AlphaUpdateAnimator)
.textviewVisibleAnimationType(ViewAnimatorType.TranslationAlphaHideAnimator)
.imageviewVisibleAnimationType(ViewAnimatorType.TranslationAlphaHideAnimator)
.build())
以上就是實(shí)現(xiàn)animator everywhere 的思路和基本的代碼結(jié)構(gòu)爬立,源碼可以參考AndroidSkinAnimator
4.3 框架使用:
1.繼承
SkinCompatActivity
, 同時(shí)支持了換膚功能2.如果Activity需要支持全局動(dòng)畫钾唬,覆蓋方法:
@Override
protected boolean needAnimator() {
return true;
}
如果不需要,則不用理會(huì)
- 3.在Activity中設(shè)置動(dòng)畫配置:
setAnimatorConfig(new AnimatorConfig
.Builder()
.textviewTextAnimationType(ViewAnimatorType.AlphaUpdateAnimator)
.textviewVisibleAnimationType(ViewAnimatorType.TranslationAlphaHideAnimator)
.build());
在其它地方設(shè)置配置:
AnimatorManager.setConfig(new AnimatorConfig.Builder()
.textviewVisibleAnimationType(ViewAnimatorType.TranslationAlphaHideAnimator)
.textviewTextAnimationType(ViewAnimatorType.AlphaUpdateAnimator)
.build());
- 4.在需要的地方打個(gè)關(guān)閉動(dòng)畫:
AnimatorManager.openAnimator();
AnimatorManager.closeAnimator();
5. 換膚動(dòng)畫
感覺動(dòng)畫寫起來(lái)還是挺好玩的侠驯,于是對(duì)換膚過程也寫了幾個(gè)動(dòng)畫:
其實(shí)實(shí)現(xiàn)起來(lái)都比較簡(jiǎn)單抡秆,主要就是把動(dòng)畫進(jìn)行分解,通過組合使用平移吟策、旋轉(zhuǎn)儒士、大小變化等基本動(dòng)畫,就可以做出比較好動(dòng)畫檩坚。