這是我這個(gè)系列的目錄隧土,有興趣的可以看下: android 動(dòng)畫系列 - 目錄
專場動(dòng)畫大家熟悉吧,效果絕對(duì)炫酷攒暇,也是產(chǎn)品汪們動(dòng)腦筋考研我們的地方,第一效果要炫酷敢伸,第二不要卡扯饶,簡單的專場動(dòng)畫沒什么,但是產(chǎn)品要是給你一個(gè)復(fù)雜的專場動(dòng)畫池颈,那就考驗(yàn)技術(shù)功底了尾序,效果要好,速度又要快躯砰,真的是有點(diǎn)難度的每币,所以今天我們來看看這個(gè)專場動(dòng)畫,不要有僥幸心理啊琢歇,這部分是逃不過去的兰怠,必回必備必精的部分。
廢話不多說李茫,開始啦揭保,先來理論
何為專場動(dòng)畫
轉(zhuǎn)場動(dòng)畫就是在頁面切換時(shí),前一個(gè)和后一個(gè)頁面之間的動(dòng)畫過度魄宏,說起來很簡單秸侣,相信打擊也很熟悉,那么我們來說下大家不熟悉的地方宠互。
專場動(dòng)畫的4個(gè)狀態(tài):
- enter :進(jìn)入動(dòng)畫
- exit : 退出動(dòng)畫
- reenter : 再次進(jìn)入動(dòng)畫
- return : 頁面關(guān)閉動(dòng)畫
舉例:
從 A -> B 頁面味榛,一個(gè)很熟悉的場景吧:
- 對(duì)于 A 來說是 exit 動(dòng)畫,因?yàn)檫@時(shí)是 A 啟動(dòng) B 予跌,A 就要切換到后臺(tái)去搏色,所以是退出動(dòng)畫,注意不是關(guān)閉動(dòng)畫
- 對(duì)于 B 來說券册,此時(shí) B 是一個(gè)新創(chuàng)建的頁面频轿,所以 B 是 enter 進(jìn)入動(dòng)畫
從 B -> A 頁面,點(diǎn)擊返回鍵烁焙,回到上個(gè)頁面
- 對(duì)于 A 來說是 reenter 再次進(jìn)入動(dòng)畫略吨,因?yàn)?A 是從后臺(tái)切換到前臺(tái)。
- 對(duì)于 B 來說是 return 關(guān)閉動(dòng)畫考阱,因?yàn)檫@時(shí)候 B 頁面是要銷毀的翠忠,所以是關(guān)閉動(dòng)畫
清楚了上面轉(zhuǎn)場動(dòng)畫的4個(gè)狀態(tài),下面再去看就清楚多了乞榨。
4.X 時(shí)代的傳統(tǒng)寫法
4.x 時(shí)代的傳統(tǒng)寫法秽之,大家一定太熟悉了把 当娱,操作的是 view 動(dòng)畫
public void overridePendingTransition(int enterAnim, int exitAnim)
現(xiàn)在再去看這里面的 enter 和 exit 應(yīng)該就明白是啥意思了吧,之前這里的確是有很多人不清楚的考榨,包括我也是的跨细。
注意點(diǎn):
- overridePendingTransition方法必須在startActivity()或者finish()方法的后面
- 如果參數(shù)是0,表示沒有動(dòng)畫河质,盡量不要傳0冀惭,enter 傳0,會(huì)是一個(gè)黑屏的效果掀鹅,親測
startActivity(intent);
overridePendingTransition(R.anim.bottom_top_anim, R.anim.alpha_hide);
---
finish();
overridePendingTransition(R.anim.alpha_show, R.anim.top_bottom_anim);
另外使用主題也是可以的散休,注意操作的同樣是 view 動(dòng)畫
<style name="ActivityTransitionAnimatoin" parent="@android:style/Animation.Activity">
<item name="android:activityOpenExitAnimation">@anim/translate_buttom_out</item>
<item name="android:activityCloseEnterAnimation">@anim/translate_buttom_in</item>
<item name="android:activityCloseExitAnimation">@anim/translate_top_out</item>
</style>
用這個(gè)屬性去設(shè)置
<item name="android:windowAnimationStyle">@style/ActivityTransitionAnimatoin</item>
這里買的 open 表示 A -> B , close 表示 B -> A
4.x 時(shí)代的專場動(dòng)畫沒啥好說的乐尊,是最簡單好用的戚丸,產(chǎn)品沒什么特殊設(shè)計(jì)用這個(gè)方式就好了。缺點(diǎn)嘛扔嵌,就是不夠靈活限府,大家發(fā)現(xiàn)沒,動(dòng)畫添加到誰身上了痢缎,是添加到 activity 身上的胁勺,所以我們只能給整個(gè)頁面添加一個(gè)統(tǒng)一的動(dòng)畫,而不能針對(duì)頁面中的控件進(jìn)行操作独旷。
最簡單的我們可以直接使用 android 系統(tǒng)以及給你定義好的動(dòng)畫資源
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
windowAnimation和ActivityAnimation的區(qū)別
上面我們使用 activityOpenAnimation / activityCloseAnimation 這是在 activity 身上做動(dòng)畫姻几,我們其實(shí)還可以在 window 身上做動(dòng)畫,并且window 的級(jí)別高于 activity 势告,兩者同時(shí)存在,以 window 動(dòng)畫為準(zhǔn)抚恒。window 的動(dòng)畫我們可以在 theme 上直接加:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowAnimationStyle">@style/ActivityTransitionAnimatoin</item>
<item name="android:windowEnterAnimation">@anim/translate_buttom_in</item>
<item name="android:windowExitAnimation">@anim/translate_buttom_in</item>
</style>
比 activityOpenAnimation / activityCloseAnimation 動(dòng)畫寫起來還方便咱台,不用再鍵一個(gè) style 出來,不過注意啊俭驮,只能設(shè)置 下一個(gè)頁面的動(dòng)畫回溺,因?yàn)檫@里我們只能設(shè)置 enter / exit 的動(dòng)畫,具體使用哪種看大家具體需求把混萝。
MD 時(shí)代
5.X 的時(shí)代我們迎來了革命性的 MD 遗遵,google 在 apple 的壓力下重新優(yōu)化了 android 系統(tǒng)上的交互體驗(yàn),最大的改變是帶給了 android 很炫酷的交互體驗(yàn)逸嘀,這些體驗(yàn)是多方位的车要,知識(shí)點(diǎn)也是很多,這里咱們就來看看新的頁面專場動(dòng)畫
不就知道大家聽過 transition 變換動(dòng)畫沒有崭倘,這是 API 19時(shí)添加的一種動(dòng)畫翼岁,叫過度動(dòng)畫类垫,MD 帶給我們的心得炫酷的專場動(dòng)畫就是用 transition 變換動(dòng)畫實(shí)現(xiàn)的,transition 本身是比較復(fù)雜的琅坡,本篇我們不說悉患,下篇再介紹。這里簡單說下榆俺,transition 是對(duì)一個(gè) viewgroup 中所有的 view 做動(dòng)畫售躁,transition 是可以設(shè)置這個(gè) viewgroup 是哪個(gè)的,我們用 transition 作頁面轉(zhuǎn)場動(dòng)畫茴晋,就是把 transition 中的視圖設(shè)置為 頁面的根視圖陪捷。
MD 提供了幾個(gè) transition 變換動(dòng)畫的默認(rèn)實(shí)現(xiàn):
- Explode :爆炸效果
- Slide : 側(cè)滑效果
- fade : 淡入效果
- Share Element : 共享元素效果
這幾個(gè)是 MD 默認(rèn)提供的專場動(dòng)畫效果,是 transition 的子類或間接子類晃跺,本質(zhì)是生成 animator 動(dòng)畫揩局。
那么我們怎么使用呢,我們需要結(jié)合 window 來使用了掀虎,API 19 添加了 transition 動(dòng)畫后凌盯,我們可以給 window 設(shè)置進(jìn)入和退出4種狀態(tài)對(duì)用的動(dòng)畫:
- setExitTransition() :A中的View退出場景的transition
- setEnterTransition() :使B中的View進(jìn)入場景的transition
- setReturnTransition() - 當(dāng)B 返回 A時(shí),使B中的View退出場景的transition
- setReenterTransition() - 當(dāng)B 返回 A時(shí)烹玉,使A中的View進(jìn)入場景的transition
也可以在theme中定義如下style:
- android:windowExitTransition
- android:windowEnterTransition
- android:windowReturnTransition
-
android:windowReenterTransition
1159344-1f795b3129360658.jpeg
Explode
我們需要 new 一個(gè) transition 動(dòng)畫對(duì)象驰怎,就是這個(gè) Explode 類,然后設(shè)置進(jìn) window 就好了
啟動(dòng)頁面
Intent intent = new Intent(this, ExplodeTransitionActivity.class);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
startActivity(intent, options);
在后一個(gè)頁面設(shè)置切換動(dòng)畫
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Explode explode = new Explode();
getWindow().setEnterTransition(explode);
getWindow().setExitTransition(explode);
setContentView(R.layout.activity_mdtarge);
}
可以看到二打,Explode 根據(jù)視圖層次自動(dòng)決定 view 動(dòng)畫的方向是向上還是向下县忌, Explode 類有幾個(gè)可以設(shè)置的屬性:
看上圖,可以設(shè)置時(shí)間继效,插值器症杏,延遲時(shí)間,其他的都是涉及到 transition 比較很細(xì)你的知識(shí)了瑞信,需要去詳細(xì)學(xué)習(xí) transition 才行厉颤。
Slide
使用方法和 Explode 一樣
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Slide slide = new Slide();
getWindow().setEnterTransition(slide);
getWindow().setExitTransition(slide);
setContentView(R.layout.activity_mdtarge);
Slide 這個(gè)動(dòng)畫效果可玩的比較多啊,我們來看看都可以怎么玩
除了時(shí)間凡简,插值器逼友,延遲時(shí)間外,我們還可以設(shè)置滑動(dòng)方向
Slide slide = new Slide(Gravity.LEFT);
slide.setDuration(500);
Fade
和 Explode 秤涩,Slide 是使用上都是一樣的帜乞,沒什么特殊的設(shè)置選項(xiàng)
Fade fade = new Fade();
getWindow().setEnterTransition(fade);
getWindow().setExitTransition(fade);
Explode ,Slide筐眷,F(xiàn)ade 共同點(diǎn)
為啥我要特意說一下呢黎烈,因?yàn)檫@3個(gè) MD 內(nèi)置效果可以看到用法都一樣,都是基于 transition 技術(shù)實(shí)現(xiàn)頁面專場動(dòng)畫的最簡單使用。
這里有一個(gè)點(diǎn)還要說一下怨喘,transition 的轉(zhuǎn)場動(dòng)畫是對(duì)頁面根節(jié)點(diǎn)視圖中所有 view 都執(zhí)行動(dòng)畫津畸,我們可以設(shè)置忽略的 view 的 id,那么這個(gè) view 就不會(huì)執(zhí)行轉(zhuǎn)場動(dòng)畫了
忽略底部導(dǎo)航欄 view
slide.excludeTarget(android.R.id.navigationBarBackground, true);
忽略底部狀態(tài)欄 view
slide.excludeTarget(android.R.id.statusBarBackground, true);
也可以直接在style中設(shè)置動(dòng)畫
<item name="android:windowExitTransition">@transition/slide_anim</item>
<item name="android:windowEnterTransition">@transition/slide_anim</item>
其中@transition/slide_anim如下
<!-- @transition/slide_anim-->
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
>
<!--頂部的狀態(tài)欄以及底部的導(dǎo)航欄不執(zhí)行動(dòng)畫-->
<targets>
<target android:excludeId="@android:id/statusBarBackground"/>
<target android:excludeId="@android:id/navigationBarBackground"/>
</targets>
<slide android:slideEdge="bottom"
android:duration="1300"/>
<!--<fade />-->
</transitionSet>
Share Element
共享元素動(dòng)畫是 MD 中最吸引人的專場動(dòng)畫效果了必怜,這個(gè) apple 絕對(duì)沒有啊肉拓,這個(gè)做好了看著絕對(duì)上檔次,目前也是有很多 app 都集成進(jìn)來了梳庆,但是想做好真不容易暖途,在實(shí)際開發(fā)中,遇到的問題也是很多啊膏执,我這里也是很欠缺的驻售,比如點(diǎn)擊列表的一個(gè) item 跳到一個(gè)頁,跳到的新的頁面里面還是列表更米,然后在這個(gè)心得列表里面點(diǎn)擊另一個(gè) item再切回來欺栗,怎么正確的關(guān)聯(lián)前后頁面的共享元素是個(gè)大問題啊。
說簡單點(diǎn)就是頁面切換的動(dòng)畫是從前一個(gè)頁面的某些元素開始征峦,漸變到整個(gè)第二個(gè)頁面的迟几,廢話不多說,看看效果就知道了
上面的例子里我們關(guān)聯(lián)了前一個(gè)頁面和后一個(gè)頁面中的那個(gè)機(jī)器人圖標(biāo)的 imageview栏笆。說來使用起來也是很簡單的:
- 在 xml 中設(shè)置相同的 transitionName 標(biāo)記用于執(zhí)行共享元素動(dòng)畫的 view
android:transitionName="imageView"
- 啟動(dòng)activity B类腮,在啟動(dòng)頁面的 bundle 參數(shù)中傳入共享元素 view 和 transitionName 標(biāo)記
Intent intent = new Intent(this, ShadeTransitionActivity.class);
Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(this, view_image, view_image.getTransitionName()).toBundle();
startActivity(intent, bundle);
- 在B中設(shè)置共享元素動(dòng)畫,這里必要時(shí)不設(shè)置的話也沒事用的是默認(rèn)的動(dòng)畫樣式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TransitionSet set = new TransitionSet();
set.addTransition(new ChangeImageTransform());
set.addTransition(new ChangeBounds());
getWindow().setSharedElementEnterTransition(set);
setContentView(R.layout.activity_mdtarge);
}
簡單學(xué)下原理:創(chuàng)建出 B 頁面對(duì)象和 window 后蛉加,B 頁面解析標(biāo)簽蚜枢,解析初共享元素,然后和 B 頁面的共享元素關(guān)聯(lián)针饥,然后計(jì)算出動(dòng)畫的初始參數(shù)和結(jié)束參數(shù)厂抽,然后生成動(dòng)畫對(duì)象,然后 A 頁面隱藏丁眼,關(guān)閉筷凤,B 頁面執(zhí)行這個(gè)動(dòng)畫,其中的技術(shù)實(shí)現(xiàn)是使用 transition 來實(shí)現(xiàn)的户盯。
多個(gè)共享元素:
Intent intent = new Intent(this, ShadeTransitionActivity.class);
Pair<View, String> pair1 = new Pair<View, String>(view_image, ViewCompat.getTransitionName(view_image));
Pair<View, String> pair2 = new Pair<View, String>(tx_text, ViewCompat.getTransitionName(tx_text));
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this, pair1, pair2).toBundle();
startActivity(intent, bundle);
這里使用 ActivityOptionsCompat 創(chuàng)建的這個(gè) bundle 對(duì)象,推薦還是用這個(gè)兼容類好饲化。
Fragment 的頁面切換動(dòng)畫
enter,exit,reenter,return 這4個(gè)位置的動(dòng)畫大家看過上面應(yīng)該知道都是對(duì)應(yīng)哪個(gè)位置的了把莽鸭,fragment 的替換我們一般來說我們有2種常用的方式:
- replace 替換
我們使用上面的圖中的方式,加入返回棧就可以實(shí)現(xiàn)頁面切換的動(dòng)畫 - show,hint
這種方式吃靠,我們可以使用添加 transition 的方式實(shí)現(xiàn) 頁面切換動(dòng)畫
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Slide slide = new Slide(Gravity.LEFT);
Explode explode = new Explode();
setEnterTransition(slide);
setExitTransition(slide);
setReenterTransition( explode );
setReturnTransition( explode );
}
在 fragment 的 onCreate 中添加 transition 動(dòng)畫硫眨,我試了下,show巢块,hint 觸發(fā)的都是 enter,exit 動(dòng)畫礁阁,reenter,return 沒有觸發(fā)巧号,這里就麻煩了,要知道 enter,exit,reenter,return 這4個(gè)狀態(tài)是個(gè)整個(gè)效果姥闭,涉及到前后2個(gè)頁面丹鸿,這里 reenter,return 觸發(fā)不出來怎么辦,只能讓前后2個(gè)頁面的 enter,exit 執(zhí)行相反方向的動(dòng)畫了棚品,比如 slide 這個(gè)效果靠欢,A 頁面 left,B 頁面 right铜跑。
更多的我還得再去找找資料门怪,不過基本的操作就是這樣了,fragment 的頁面切換我們單純用的不多锅纺,多數(shù)使用場景還是在 viewpager 中掷空,vp 的頁面切換原理就不是本文寫的方式了,是實(shí)現(xiàn) ViewPager.PageTransformer 的這個(gè)接口囤锉,具體的看這里:ViewPager學(xué)習(xí)(1) - transformer 頁面切換
最后啦
最后了簡單的吐槽下吧坦弟,這個(gè)代碼啊,不看不會(huì)嚼锄,不寫不明白啊减拭。之前零零散散的關(guān)于專場動(dòng)畫這塊也是看了還幾次了,時(shí)間也是花了一些的区丑,時(shí)間久一點(diǎn)忘了拧粪,就真是一點(diǎn)都不記得了,必須要寫 demo沧侥,必須要寫博客才行可霎,這次看了不少,總算是看全了宴杀,以后忘了癣朗,10分鐘就想起來了。
貼一下本項(xiàng)目的 demo 地址:ActivityTransitionDemo