四汪疮、Content Transition實(shí)現(xiàn)非共享元素轉(zhuǎn)場(chǎng)

1. 梗概

!!! 拆分一個(gè)頁(yè)面的不同元素view,實(shí)現(xiàn)不同的animation...但是元素是 非共享的 !!!

content transition決定了非共享view元素在activity和fragment切換期間是如何進(jìn)入或者退出場(chǎng)景的峭火。根據(jù)google最新的Material Design設(shè)計(jì)語(yǔ)言,content transition讓我們毫不費(fèi)力的去協(xié)調(diào)Activity/Fragment切換過(guò)程中view的進(jìn)入和退出智嚷,讓這個(gè)過(guò)程更流暢卖丸。在5.0之后content transition可以通過(guò)調(diào)用Window和Fragment的如下代碼來(lái)設(shè)置:

setExitTransition()     //當(dāng)A start B時(shí),使A中的View退出場(chǎng)景的transition

setEnterTransition()   //當(dāng)A start B時(shí)盏道,使B中的View進(jìn)入場(chǎng)景的transition

setReturnTransition()  //當(dāng)B 返回 A時(shí)稍浆,使B中的View退出場(chǎng)景的transition

setReenterTransition() //當(dāng)B 返回 A時(shí),使A中的View進(jìn)入場(chǎng)景的transition

//也可以直接在xml設(shè)置,通常都這么做
        <item name="android:windowEnterTransition"></item>
        <item name="android:windowExitTransition"></item>
        <item name="android:windowReenterTransition"></item>
        <item name="android:windowReturnTransition"></item>

以下圖為例猜嘱,演示了google play Games app如何通過(guò)content transition實(shí)現(xiàn)activity之間的平滑切換衅枫。當(dāng)?shù)诙€(gè)activity開(kāi)始的時(shí)候,enter transition讓用戶(hù)的頭像從底部邊緣慢慢滑入朗伶。而在activity退出的時(shí)候弦撩,屏幕被分成兩半,各自消失在上下邊緣论皆。


Content Transition 例子

2. 那么怎么使用Content Transition呢?

2.1 xml實(shí)現(xiàn)

  1. 定義 界面指定元素的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
    三益楼、定義 界面指定元素 或界面間共享元素 的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)基礎(chǔ)

  2. 在Manifest.xml為相應(yīng)的Activity設(shè)置相對(duì)于的style

    <style name="BaseAnimationAppTheme" parent="android:Theme.Material">
        <!-- 1. 開(kāi)啟過(guò)渡效果-->
        <item name="android:windowContentTransitions">true</item>

        <!-- 2. 指定 界面元素 進(jìn)入/退出的動(dòng)畫(huà)效果,可以不全部實(shí)現(xiàn)(當(dāng)然可以在代碼中設(shè)置,前文已提)-->
        <item name="android:windowEnterTransition">@anim/search_enter</item>
        <item name="android:windowExitTransition">...</item>
        <item name="android:windowReenterTransition">...</item>
        <item name="android:windowReturnTransition">...</item>

    
        /**還可以設(shè)置是否同步執(zhí)行還是順序執(zhí)行
        *默認(rèn)情況下,material主題的應(yīng)用中enter/return的content transition
        *會(huì)在exit/reenter的content transitions結(jié)束之前開(kāi)始播放(只是稍微早于)
        */
        <!--A退出的動(dòng)畫(huà)和B進(jìn)入的動(dòng)畫(huà)同步進(jìn)行,代碼中setWindowAllowEnterTransitionOverlap()實(shí)現(xiàn)-->
        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <!--B返回的動(dòng)畫(huà)和A重新進(jìn)入的動(dòng)畫(huà)同步進(jìn)行,代碼中setWindowAllowReturnTransitionOverlap()實(shí)現(xiàn)-->
        <item name="android:windowAllowReturnTransitionOverlap">true</item>

    </style>
  1. 啟動(dòng)Activity
ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(this);
ActivityCompat.startActivity(this, intent, optionsCompat.toBundle());

4.退出時(shí)調(diào)用finishAfterTransition()

注意
1点晴、Material主題默認(rèn)會(huì)將exit的transition設(shè)置成null偏形,enter的transition設(shè)置成Fade 。
2觉鼻、如果reenter 或者 return transition沒(méi)有明確設(shè)置俊扭,則將用exit 和enter的共享元素transition替代

2.2 Java代碼實(shí)現(xiàn)(不推薦)

1、activity的style中開(kāi)啟內(nèi)容過(guò)渡效果,并設(shè)置相應(yīng)的theme

 <item name="android:windowContentTransitions">true</item>

    <!--A退出的動(dòng)畫(huà)和B進(jìn)入的動(dòng)畫(huà)同步進(jìn)行-->
    <item name="android:windowAllowEnterTransitionOverlap">true</item>
    <!--B返回的動(dòng)畫(huà)和A重新進(jìn)入的動(dòng)畫(huà)同步進(jìn)行-->
    <item name="android:windowAllowReturnTransitionOverlap">true</item

2.啟動(dòng)activity B

ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(this);
ActivityCompat.startActivity(this, intent, optionsCompat.toBundle());

3坠陈、在B中使用內(nèi)容變換

Slide slide=new Slide(Gravity.BOTTOM);
        slide.setDuration(500);
        //內(nèi)容變換萨惑,不包括底部導(dǎo)航欄和狀態(tài)欄
        slide.excludeTarget(android.R.id.navigationBarBackground, true);
        slide.excludeTarget(android.R.id.statusBarBackground, true);
        slide.excludeTarget(R.id.appBarLayout, true);
        getWindow().setEnterTransition(slide);
        getWindow().setReturnTransition(slide);


//也可以在xml文件設(shè)置transition,使用TransitionInflater得到Transition仇矾,如下:
Transition slide=TransitionInflater.from(this).inflateTransition(R.transition.slide_anim);
slide.setDuration(500);
slide.excludeTarget(R.id.appBarLayout, true);
getWindow().setEnterTransition(slide);
getWindow().setReturnTransition(slide);

4.return時(shí)調(diào)用finishAfterTransition() :非強(qiáng)制的


3. 深入分析

3.1 Activity A 調(diào)用startActivity()

1.framework遍歷A的View樹(shù)庸蔼,確定當(dāng)A的exit transition運(yùn)行時(shí)哪些view會(huì)退出場(chǎng)景(即哪些view是transitioning view)。

2.A的exit transition捕獲A中transitioning view的開(kāi)始狀態(tài)贮匕。

3.framework將A中所有的transitioning view設(shè)置為INVISIBLE姐仅。

4.A的exit transition捕獲到A中transitioning view的結(jié)束狀態(tài)。

5.A的exit transition比較每個(gè)transitioning view的開(kāi)始和結(jié)束狀態(tài)刻盐,然后根據(jù)前后狀態(tài)的區(qū)別創(chuàng)建一個(gè)Animator掏膏。Animator開(kāi)始運(yùn)行,同時(shí)transitioning view退出場(chǎng)景敦锌。

3.2 Activity B啟動(dòng)

1.framework遍歷B的View樹(shù)馒疹,確定當(dāng)B的enter transition運(yùn)行時(shí)哪些view會(huì)進(jìn)入場(chǎng)景,transitioning view會(huì)被初始化為INVISIBLE乙墙。

2.B的enter transition捕獲B中transitioning view的開(kāi)始狀態(tài)颖变。

3.framework將B中所有的transitioning view設(shè)置為VISIBLE生均。

4.B的enter transition捕獲到B中transitioning view的結(jié)束狀態(tài)。

5.B的enter transition比較每個(gè)transitioning view的開(kāi)始和結(jié)束狀態(tài)腥刹,然后根據(jù)前后狀態(tài)的區(qū)別創(chuàng)建一個(gè)Animator马胧。Animator開(kāi)始運(yùn)行,同時(shí)transitioning view進(jìn)入場(chǎng)景衔峰。

通過(guò)在每個(gè)transitioning view中來(lái)回切換INVISIBLE 和VISIBLE漓雅,framework確保content transition得到創(chuàng)建animation(期望的animation)所需的狀態(tài)信息。

3.3 監(jiān)聽(tīng)動(dòng)畫(huà)的變化過(guò)程

 //當(dāng)然也可以監(jiān)聽(tīng) Return,Exit,Reenter時(shí)的動(dòng)畫(huà)
        getWindow().getEnterTransition().addListener(new Transition.TransitionListener() {
            @Override
            public void onTransitionStart(Transition transition) {
                
            }

            @Override
            public void onTransitionEnd(Transition transition) {

            }

            @Override
            public void onTransitionCancel(Transition transition) {

            }

            @Override
            public void onTransitionPause(Transition transition) {

            }

            @Override
            public void onTransitionResume(Transition transition) {

            }
        });

下面來(lái)看一個(gè)簡(jiǎn)單的實(shí)現(xiàn),先看效果


GIFtransitionelements.gif
//AndroidManifest.xml
        <activity
            android:name=".ContentTransitionElementsActivity"
            android:label="ContentTransitionElements"
            android:theme="@style/AppTheme.ContentTransition" />

//style.xml
    <style name="AppTheme.ContentTransition">
        <item name="android:windowContentTransitions">true</item>
        <item name="android:windowActivityTransitions">true</item>
        <item name="android:windowEnterTransition">@transition/enter_content_transition</item>
        <item name="android:windowReturnTransition">@transition/return_content_transition</item>
    </style>

enter_content_transition.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">

    <targets >
        <target android:excludeId="@android:id/statusBarBackground"/>  <!--狀態(tài)欄-->
        <target android:excludeId="@android:id/navigationBarBackground"/> <!--導(dǎo)航欄-->
    </targets>

<!--    <fade android:duration="500">
        <targets>
            <target android:targetId="@android:id/statusBarBackground"/>
        </targets>
    </fade>-->

    <slide android:slideEdge="left"  android:startDelay="500">
        <targets >
            <target android:targetId="@id/tv_show"/>
        </targets>
    </slide>

    <slide android:startDelay="700">
        <targets >
            <target android:targetId="@id/iv_left"/>
        </targets>
    </slide>

    <slide android:startDelay="900">
        <targets >
            <target android:targetId="@id/iv_right"/>
        </targets>
    </slide>

</transitionSet>

return_content_transition.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="800">

    <slide android:slideEdge="top">
        <targets>
            <target android:targetId="@id/relay_flag" />
            <!--<target  android:targetId="@id/fab"/>
            <target android:targetId="@id/icon_gg"/>
            <target android:targetId="@id/image_bg"/>-->

        </targets>
    </slide>

    <slide android:slideEdge="bottom">
        <targets>
            <target android:targetId="@id/bottom_container" />
            <target android:targetId="@id/tv_show"/>
            <target android:targetId="@id/iv_left"/>
            <target android:targetId="@id/iv_right"/>
        </targets>
    </slide>


        <fade>
            <targets >
                <target android:targetId="@android:id/statusBarBackground"/>
            </targets>
        </fade>
</transitionSet>
public class ContentTransitionElementsActivity extends AppCompatActivity {

    FloatingActionButton fab;
    View image_bg;
    ImageView icon_gg;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_content_transition);
        fab=findViewById(R.id.fab);
        image_bg=findViewById(R.id.image_bg);
        icon_gg=findViewById(R.id.icon_gg);

        getWindow().getEnterTransition().addListener(new Transition.TransitionListener() {
            @Override
            public void onTransitionStart(Transition transition) {
                Animator circularReveal = ViewAnimationUtils.createCircularReveal(image_bg, image_bg.getWidth() / 2, image_bg.getHeight() / 2
                        , icon_gg.getWidth()/2, Math.max(image_bg.getWidth(), image_bg.getHeight()));
                image_bg.setBackgroundColor(Color.BLACK);
                circularReveal.setDuration(600);
                circularReveal.start();
            }

            @Override
            public void onTransitionEnd(Transition transition) {
                fab.animate()
                        .scaleY(1)
                        .scaleX(1)
                        .start();
            }

            @Override
            public void onTransitionCancel(Transition transition) {

            }

            @Override
            public void onTransitionPause(Transition transition) {

            }

            @Override
            public void onTransitionResume(Transition transition) {

            }
        });

    }

    @Override
    public void onBackPressed() {
        finishAfterTransition();
        super.onBackPressed();

    }
}

由此可見(jiàn) :動(dòng)畫(huà)效果都在XML中實(shí)現(xiàn)了,Activity只要加載先關(guān)布局即可

代碼:animatedTransitionsLearn-master

Transition系列文章
一朽色、初識(shí)Transition—實(shí)現(xiàn)兩個(gè)場(chǎng)景的變換
二邻吞、番外篇 Transition之ViewOverlay
三、定義 界面指定元素 或界面間共享元素 的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)基礎(chǔ)
四葫男、Content Transition實(shí)現(xiàn)非共享元素轉(zhuǎn)場(chǎng)
五抱冷、SharedElementTransition之Activity間的轉(zhuǎn)場(chǎng)
六、SharedElementTransition之Fragment間的轉(zhuǎn)場(chǎng)
七梢褐、番外篇- 自定義Visibility
八旺遮、5.0以下實(shí)現(xiàn)共享轉(zhuǎn)場(chǎng)


本篇參考 :
深入理解Content Transition :建議去了解一下
animatedTransitionsLearn-master
Android轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市盈咳,隨后出現(xiàn)的幾起案子耿眉,更是在濱河造成了極大的恐慌,老刑警劉巖鱼响,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸣剪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡丈积,警方通過(guò)查閱死者的電腦和手機(jī)筐骇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)江滨,“玉大人铛纬,你說(shuō)我怎么就攤上這事』;” “怎么了告唆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)晶密。 經(jīng)常有香客問(wèn)我擒悬,道長(zhǎng),這世上最難降的妖魔是什么惹挟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任茄螃,我火速辦了婚禮缝驳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘到逊。我一直安慰自己只恨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布拼弃。 她就那樣靜靜地躺著,像睡著了一般摇展。 火紅的嫁衣襯著肌膚如雪吻氧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,874評(píng)論 1 314
  • 那天咏连,我揣著相機(jī)與錄音盯孙,去河邊找鬼。 笑死祟滴,一個(gè)胖子當(dāng)著我的面吹牛振惰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播垄懂,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼骑晶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了草慧?” 一聲冷哼從身側(cè)響起桶蛔,我...
    開(kāi)封第一講書(shū)人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漫谷,沒(méi)想到半個(gè)月后仔雷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舔示,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年朽寞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斩郎。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脑融,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缩宜,到底是詐尸還是另有隱情肘迎,我是刑警寧澤,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布锻煌,位于F島的核電站妓布,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宋梧。R本人自食惡果不足惜匣沼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捂龄。 院中可真熱鬧释涛,春花似錦加叁、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至窖认,卻和暖如春豫柬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扑浸。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工烧给, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喝噪。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓创夜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親仙逻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驰吓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,348評(píng)論 25 707
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料系奉? 從這篇文章中你...
    hw1212閱讀 12,754評(píng)論 2 59
  • 假設(shè)檬贰,兩個(gè)有Activity A和B A啟動(dòng)B: A發(fā)生exit動(dòng)畫(huà),B發(fā)生enter動(dòng)畫(huà) B返回A:B發(fā)生ret...
    i冰點(diǎn)閱讀 17,277評(píng)論 7 42
  • 晨起鳥(niǎo)鳴路人行缺亮,醒來(lái)囫圇急無(wú)影翁涤。 裊裊細(xì)煙眾車(chē)堵,漫漫拼搏誰(shuí)人顧萌踱。
    愛(ài)懵的兔子閱讀 123評(píng)論 2 1
  • 前端調(diào)微信接口->微信調(diào)后臺(tái)->后臺(tái)獲取openid->返回openid給前端
    zhangtaiwei閱讀 375評(píng)論 0 1