android 動(dòng)畫系列 (6) - 轉(zhuǎn)場動(dòng)畫

這是我這個(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);
    }
ezgif.com-video-to-gif.gif

可以看到二打,Explode 根據(jù)視圖層次自動(dòng)決定 view 動(dòng)畫的方向是向上還是向下县忌, Explode 類有幾個(gè)可以設(shè)置的屬性:


Snip20171225_8.png

看上圖,可以設(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);
ezgif.com-video-to-gif.gif

Slide 這個(gè)動(dòng)畫效果可玩的比較多啊,我們來看看都可以怎么玩


Snip20171225_10.png

除了時(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);
ezgif.com-video-to-gif.gif

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è)頁面的迟几,廢話不多說,看看效果就知道了


ezgif.com-video-to-gif.gif

上面的例子里我們關(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)畫

4513808-97ee8c40279a79eb.jpg

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旺罢,一起剝皮案震驚了整個(gè)濱河市旷余,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扁达,老刑警劉巖正卧,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異跪解,居然都是意外死亡炉旷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窘行,“玉大人饥追,你說我怎么就攤上這事」蘅” “怎么了但绕?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翘骂。 經(jīng)常有香客問我壁熄,道長,這世上最難降的妖魔是什么碳竟? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任草丧,我火速辦了婚禮,結(jié)果婚禮上莹桅,老公的妹妹穿的比我還像新娘昌执。我一直安慰自己,他們只是感情好诈泼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布懂拾。 她就那樣靜靜地躺著,像睡著了一般铐达。 火紅的嫁衣襯著肌膚如雪岖赋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天瓮孙,我揣著相機(jī)與錄音唐断,去河邊找鬼。 笑死杭抠,一個(gè)胖子當(dāng)著我的面吹牛脸甘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播偏灿,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼丹诀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翁垂?” 一聲冷哼從身側(cè)響起铆遭,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沿猜,沒想到半個(gè)月后枚荣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡邢疙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年棍弄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疟游。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呼畸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出颁虐,到底是詐尸還是另有隱情蛮原,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布另绩,位于F島的核電站儒陨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏笋籽。R本人自食惡果不足惜蹦漠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望车海。 院中可真熱鬧笛园,春花似錦、人聲如沸侍芝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽州叠。三九已至棵红,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間咧栗,已是汗流浹背逆甜。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楼熄,地道東北人忆绰。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像可岂,于是被迫代替她去往敵國和親错敢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355