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

這是我這個系列的目錄,有興趣的可以看下: android 動畫系列 - 目錄

專場動畫大家熟悉吧,效果絕對炫酷,也是產(chǎn)品汪們動腦筋考研我們的地方,第一效果要炫酷,第二不要卡,簡單的專場動畫沒什么,但是產(chǎn)品要是給你一個復雜的專場動畫,那就考驗技術(shù)功底了,效果要好,速度又要快,真的是有點難度的,所以今天我們來看看這個專場動畫,不要有僥幸心理啊,這部分是逃不過去的,必回必備必精的部分。

廢話不多說,開始啦,先來理論

何為專場動畫

轉(zhuǎn)場動畫就是在頁面切換時,前一個和后一個頁面之間的動畫過度,說起來很簡單,相信打擊也很熟悉,那么我們來說下大家不熟悉的地方。

專場動畫的4個狀態(tài):

  • enter :進入動畫
  • exit : 退出動畫
  • reenter : 再次進入動畫
  • return : 頁面關(guān)閉動畫

舉例:
從 A -> B 頁面,一個很熟悉的場景吧:

  • 對于 A 來說是 exit 動畫,因為這時是 A 啟動 B ,A 就要切換到后臺去,所以是退出動畫,注意不是關(guān)閉動畫
  • 對于 B 來說,此時 B 是一個新創(chuàng)建的頁面,所以 B 是 enter 進入動畫

從 B -> A 頁面,點擊返回鍵,回到上個頁面

  • 對于 A 來說是 reenter 再次進入動畫,因為 A 是從后臺切換到前臺。
  • 對于 B 來說是 return 關(guān)閉動畫,因為這時候 B 頁面是要銷毀的,所以是關(guān)閉動畫

清楚了上面轉(zhuǎn)場動畫的4個狀態(tài),下面再去看就清楚多了。


4.X 時代的傳統(tǒng)寫法

4.x 時代的傳統(tǒng)寫法,大家一定太熟悉了把 ,操作的是 view 動畫

 public void overridePendingTransition(int enterAnim, int exitAnim)

現(xiàn)在再去看這里面的 enter 和 exit 應該就明白是啥意思了吧,之前這里的確是有很多人不清楚的,包括我也是的。

注意點:

  • overridePendingTransition方法必須在startActivity()或者finish()方法的后面
  • 如果參數(shù)是0,表示沒有動畫,盡量不要傳0,enter 傳0,會是一個黑屏的效果,親測
startActivity(intent);
overridePendingTransition(R.anim.bottom_top_anim, R.anim.alpha_hide);

---

finish();
overridePendingTransition(R.anim.alpha_show, R.anim.top_bottom_anim);

另外使用主題也是可以的,注意操作的同樣是 view 動畫

 <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>

    用這個屬性去設(shè)置
    <item name="android:windowAnimationStyle">@style/ActivityTransitionAnimatoin</item>

這里買的 open 表示 A -> B , close 表示 B -> A

4.x 時代的專場動畫沒啥好說的,是最簡單好用的,產(chǎn)品沒什么特殊設(shè)計用這個方式就好了。缺點嘛,就是不夠靈活,大家發(fā)現(xiàn)沒,動畫添加到誰身上了,是添加到 activity 身上的,所以我們只能給整個頁面添加一個統(tǒng)一的動畫,而不能針對頁面中的控件進行操作。

最簡單的我們可以直接使用 android 系統(tǒng)以及給你定義好的動畫資源

overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);

windowAnimation和ActivityAnimation的區(qū)別

上面我們使用 activityOpenAnimation / activityCloseAnimation 這是在 activity 身上做動畫,我們其實還可以在 window 身上做動畫,并且window 的級別高于 activity ,兩者同時存在,以 window 動畫為準。window 的動畫我們可以在 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 動畫寫起來還方便,不用再鍵一個 style 出來,不過注意啊,只能設(shè)置 下一個頁面的動畫,因為這里我們只能設(shè)置 enter / exit 的動畫,具體使用哪種看大家具體需求把。


MD 時代

5.X 的時代我們迎來了革命性的 MD ,google 在 apple 的壓力下重新優(yōu)化了 android 系統(tǒng)上的交互體驗,最大的改變是帶給了 android 很炫酷的交互體驗,這些體驗是多方位的,知識點也是很多,這里咱們就來看看新的頁面專場動畫

不就知道大家聽過 transition 變換動畫沒有,這是 API 19時添加的一種動畫,叫過度動畫,MD 帶給我們的心得炫酷的專場動畫就是用 transition 變換動畫實現(xiàn)的,transition 本身是比較復雜的,本篇我們不說,下篇再介紹。這里簡單說下,transition 是對一個 viewgroup 中所有的 view 做動畫,transition 是可以設(shè)置這個 viewgroup 是哪個的,我們用 transition 作頁面轉(zhuǎn)場動畫,就是把 transition 中的視圖設(shè)置為 頁面的根視圖。

MD 提供了幾個 transition 變換動畫的默認實現(xiàn):

  • Explode :爆炸效果
  • Slide : 側(cè)滑效果
  • fade : 淡入效果
  • Share Element : 共享元素效果

這幾個是 MD 默認提供的專場動畫效果,是 transition 的子類或間接子類,本質(zhì)是生成 animator 動畫。

那么我們怎么使用呢,我們需要結(jié)合 window 來使用了,API 19 添加了 transition 動畫后,我們可以給 window 設(shè)置進入和退出4種狀態(tài)對用的動畫:

  • setExitTransition() :A中的View退出場景的transition
  • setEnterTransition() :使B中的View進入場景的transition
  • setReturnTransition() - 當B 返回 A時,使B中的View退出場景的transition
  • setReenterTransition() - 當B 返回 A時,使A中的View進入場景的transition

也可以在theme中定義如下style:

  • android:windowExitTransition
  • android:windowEnterTransition
  • android:windowReturnTransition
  • android:windowReenterTransition


    1159344-1f795b3129360658.jpeg

Explode

我們需要 new 一個 transition 動畫對象,就是這個 Explode 類,然后設(shè)置進 window 就好了

啟動頁面

 Intent intent = new Intent(this, ExplodeTransitionActivity.class);
        Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
        startActivity(intent, options);

在后一個頁面設(shè)置切換動畫

 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ù)視圖層次自動決定 view 動畫的方向是向上還是向下, Explode 類有幾個可以設(shè)置的屬性:


Snip20171225_8.png

看上圖,可以設(shè)置時間,插值器,延遲時間,其他的都是涉及到 transition 比較很細你的知識了,需要去詳細學習 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 這個動畫效果可玩的比較多啊,我們來看看都可以怎么玩


Snip20171225_10.png

除了時間,插值器,延遲時間外,我們還可以設(shè)置滑動方向

  Slide slide = new Slide(Gravity.LEFT);
        slide.setDuration(500);

Fade

和 Explode ,Slide 是使用上都是一樣的,沒什么特殊的設(shè)置選項

 Fade fade = new Fade();
        getWindow().setEnterTransition(fade);
        getWindow().setExitTransition(fade);
ezgif.com-video-to-gif.gif

Explode ,Slide,F(xiàn)ade 共同點

為啥我要特意說一下呢,因為這3個 MD 內(nèi)置效果可以看到用法都一樣,都是基于 transition 技術(shù)實現(xiàn)頁面專場動畫的最簡單使用。

這里有一個點還要說一下,transition 的轉(zhuǎn)場動畫是對頁面根節(jié)點視圖中所有 view 都執(zhí)行動畫,我們可以設(shè)置忽略的 view 的 id,那么這個 view 就不會執(zhí)行轉(zhuǎn)場動畫了

忽略底部導航欄 view
slide.excludeTarget(android.R.id.navigationBarBackground, true);
忽略底部狀態(tài)欄 view
slide.excludeTarget(android.R.id.statusBarBackground, true);

也可以直接在style中設(shè)置動畫

<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)欄以及底部的導航欄不執(zhí)行動畫-->
    <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

共享元素動畫是 MD 中最吸引人的專場動畫效果了,這個 apple 絕對沒有啊,這個做好了看著絕對上檔次,目前也是有很多 app 都集成進來了,但是想做好真不容易,在實際開發(fā)中,遇到的問題也是很多啊,我這里也是很欠缺的,比如點擊列表的一個 item 跳到一個頁,跳到的新的頁面里面還是列表,然后在這個心得列表里面點擊另一個 item再切回來,怎么正確的關(guān)聯(lián)前后頁面的共享元素是個大問題啊。

說簡單點就是頁面切換的動畫是從前一個頁面的某些元素開始,漸變到整個第二個頁面的,廢話不多說,看看效果就知道了


ezgif.com-video-to-gif.gif

上面的例子里我們關(guān)聯(lián)了前一個頁面和后一個頁面中的那個機器人圖標的 imageview。說來使用起來也是很簡單的:

  • 在 xml 中設(shè)置相同的 transitionName 標記用于執(zhí)行共享元素動畫的 view
android:transitionName="imageView"
  • 啟動activity B,在啟動頁面的 bundle 參數(shù)中傳入共享元素 view 和 transitionName 標記
        Intent intent = new Intent(this, ShadeTransitionActivity.class);
        Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(this, view_image, view_image.getTransitionName()).toBundle();
        startActivity(intent, bundle);
  • 在B中設(shè)置共享元素動畫,這里必要時不設(shè)置的話也沒事用的是默認的動畫樣式
 @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);
    }

簡單學下原理:創(chuàng)建出 B 頁面對象和 window 后,B 頁面解析標簽,解析初共享元素,然后和 B 頁面的共享元素關(guān)聯(lián),然后計算出動畫的初始參數(shù)和結(jié)束參數(shù),然后生成動畫對象,然后 A 頁面隱藏,關(guān)閉,B 頁面執(zhí)行這個動畫,其中的技術(shù)實現(xiàn)是使用 transition 來實現(xiàn)的。

多個共享元素:

 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)建的這個 bundle 對象,推薦還是用這個兼容類好。


Fragment 的頁面切換動畫

4513808-97ee8c40279a79eb.jpg

enter,exit,reenter,return 這4個位置的動畫大家看過上面應該知道都是對應哪個位置的了把,fragment 的替換我們一般來說我們有2種常用的方式:

  • replace 替換
    我們使用上面的圖中的方式,加入返回棧就可以實現(xiàn)頁面切換的動畫
  • show,hint
    這種方式,我們可以使用添加 transition 的方式實現(xiàn) 頁面切換動畫
 @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 動畫,我試了下,show,hint 觸發(fā)的都是 enter,exit 動畫,reenter,return 沒有觸發(fā),這里就麻煩了,要知道 enter,exit,reenter,return 這4個狀態(tài)是個整個效果,涉及到前后2個頁面,這里 reenter,return 觸發(fā)不出來怎么辦,只能讓前后2個頁面的 enter,exit 執(zhí)行相反方向的動畫了,比如 slide 這個效果,A 頁面 left,B 頁面 right。

更多的我還得再去找找資料,不過基本的操作就是這樣了,fragment 的頁面切換我們單純用的不多,多數(shù)使用場景還是在 viewpager 中,vp 的頁面切換原理就不是本文寫的方式了,是實現(xiàn) ViewPager.PageTransformer 的這個接口,具體的看這里:ViewPager學習(1) - transformer 頁面切換


最后啦

最后了簡單的吐槽下吧,這個代碼啊,不看不會,不寫不明白啊。之前零零散散的關(guān)于專場動畫這塊也是看了還幾次了,時間也是花了一些的,時間久一點忘了,就真是一點都不記得了,必須要寫 demo,必須要寫博客才行,這次看了不少,總算是看全了,以后忘了,10分鐘就想起來了。

貼一下本項目的 demo 地址:ActivityTransitionDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容