高逼格Android轉(zhuǎn)場動畫

前言

轉(zhuǎn)場動畫在交互上非常有優(yōu)勢,本文從轉(zhuǎn)場動畫的使用場景和方法起,最后是實現(xiàn)掘金中用戶頭像的轉(zhuǎn)場動畫怀各。

轉(zhuǎn)場動畫適用的版本

Activity transition APIs 只有在Android 5.0(API 21)或者更高的版本上能使用壳影。所以在使用之前需要進(jìn)行版本判斷虑润。當(dāng)版本API 大于21時使用轉(zhuǎn)場動畫戒祠,否則不使用骇两。

// Check if we're running on Android 5.0 or higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Apply activity transition
} else {
    // Swap without transition
}

還需要配置允許window content transitions 。也就是字段:android:windowActivityTransitions姜盈〉颓В可以在activity的style文件中進(jìn)行如下配置。

<style name="BaseAppTheme" parent="android:Theme.Material">
  <!-- enable window content transitions -->
  <item name="android:windowActivityTransitions">true</item>
</style>

也可以在代碼中動態(tài)的配置如下:

// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// set an exit transition
getWindow().setExitTransition(new Explode());

轉(zhuǎn)場動畫的使用場景

Android中的轉(zhuǎn)場動畫主要有三種場景:
1馏颂、在兩個activity之間切換時界面的過渡效果示血。

2、兩個activity或者Fragment之間shared elements 切換效果救拉。

3难审、同一個activity中的view的動畫效果。
下面分別詳細(xì)的介紹這三種方式亿絮。

1告喊、兩個activity之間切換時界面的過渡效果

兩個activity切換時的,有兩個動畫派昧,如下圖黔姜,從activity A 切換到activity B時,會有A的退出動畫和B的進(jìn)入動畫蒂萎。

activity主要的進(jìn)場和出場方法:

  • Window.setEnterTransition() 設(shè)置進(jìn)場動畫

  • Window.setExitTransition() 設(shè)置出場動畫

  • Window().setReturnTransition() 設(shè)置返回activity時動畫

  • Window().setReenterTransition() 設(shè)置重新進(jìn)入時動畫
    如下圖:


    在Google提供的android.transition.Transition包中從activity A切換到activity B有三種方式:Explode, Slide 和Fade秆吵。
    1、Explode:從屏幕的中間進(jìn)入或退出岖是。
    2帮毁、Slide:從屏幕的一邊向另一邊進(jìn)入或退出。
    3豺撑、Fade:通過改變透明度來出現(xiàn)或消失烈疚。

    效果如下圖所示:

    上面的三種動畫有兩種實現(xiàn)方式:

1、通過xml聲明聪轿。

在res目錄下新建transition文件夾在transition文件夾下新建activity_fade.xml文件爷肝。
res/transition/activity_fade.xml

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

res/transition/activity_slide.xml

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

ActivityA的代碼如下:因為從ActivityA切換到ActivityB,所以ActivityA是退出動畫使用的方法是:getWindow().setExitTransition(slide);

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        setupWindowAnimations();
    }

    private void setupWindowAnimations() {
        Slide slide = TransitionInflater.from(this).inflateTransition(R.transition.activity_slide);
        getWindow().setExitTransition(slide);
    }

ActivityB是進(jìn)入動畫使用方法:getWindow().setEnterTransition(fade);,ActivityB的代碼如下

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        setupWindowAnimations();
    }

    private void setupWindowAnimations() {
        Fade fade = TransitionInflater.from(this).inflateTransition(R.transition.activity_fade);
        getWindow().setEnterTransition(fade);
    }
2陆错、代碼方式實現(xiàn)灯抛。

ActivityA代碼如下:實現(xiàn)一個Slide對象并且設(shè)置時間為1000毫秒。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        setupWindowAnimations();
    }

    private void setupWindowAnimations() {
        Slide slide = new Slide();
        slide.setDuration(1000);
        getWindow().setExitTransition(slide);
    }

ActivityB中實現(xiàn)一個Fide對象并且設(shè)置時間為1000毫秒音瓷。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        setupWindowAnimations();
    }

    private void setupWindowAnimations() {
        Fade fade = new Fade();
        fade.setDuration(1000);
        getWindow().setEnterTransition(fade);
    }

上面兩種方式最終的實現(xiàn)效果如下:


上面的動畫過程分析:
1对嚼、Activity A 啟動Activity B
2、Transition FrameWork層得到Activity A的退出動畫slide并且應(yīng)用到全部可見的view中绳慎。
3纵竖、Transition FrameWork層得到Activity B的進(jìn)入動畫fade并且應(yīng)用到全部可見的view中漠烧。
4、當(dāng)從Activity B返回到Activity A的時候會分別執(zhí)行Enter和Exit相反的動畫(沒有設(shè)置returnTransition靡砌,和reenterTransition時)已脓。

ReturnTransition & ReenterTransition
Return 和Reenter Transition是enter 和exit相反的過程。當(dāng)從Activity A進(jìn)入到Activity B時會執(zhí)行 exit和enter當(dāng)從Activity B退回到Activity A時會執(zhí)行Return Transition和Reenter Transition通殃。

  • EnterTransition <--> ReturnTransition

  • ExitTransition <--> ReenterTransition
    如果沒有定義Return 或者 Reenter度液,那么Android會反向執(zhí)行Enter和Exit變換。如下圖從Activity B退回到Activity A:



    給Activity A增加了ReturnTransition的代碼如下:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        setupWindowAnimations();
    }

    private void setupWindowAnimations() {
        Fade fade = new Fade();
        fade.setDuration(1000);
        getWindow().setEnterTransition(fade);

        Slide slide = new Slide();
        slide.setDuration(1000);
        getWindow().setReturnTransition(slide);        
    }

增加了返回動畫和沒有增加返回動畫的對比效果如下:


2画舌、 Shared elements between Activities

Shared elements轉(zhuǎn)換確定兩個Activity之間共享的視圖如何在這兩個Activity之間轉(zhuǎn)換堕担。例如,如果兩個Activity在不同的位置和大小中具有相同的圖像骗炉,則通過Shared elements轉(zhuǎn)換會在這兩個Activity之間平滑地轉(zhuǎn)換和縮放圖像照宝。

主要方法


如下圖,當(dāng)從Activity A跳轉(zhuǎn)到Activity B時句葵,ActivityA厕鹃, ActivityB中的兩個item有動畫變化,但是要注意的時ActivityA 乍丈,ActivityB中的item是兩個獨立的item剂碴。


shared elements轉(zhuǎn)換包括以下幾種:
  • changeBounds 改變目標(biāo)布局中view的邊界
  • changeClipBounds 裁剪目標(biāo)布局中view的邊界
  • changeTransform 實現(xiàn)旋轉(zhuǎn)或者縮放動畫
  • changeImageTransform 實現(xiàn)目標(biāo)布局中ImageView的旋轉(zhuǎn)或者縮放動畫
    實現(xiàn)上面的效果需要三個步驟:
1、 Enable Window Content Transition

設(shè)置styles.xml文件轻专,允許windowContentTransitions如下:
value/style.xml

<style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:windowContentTransitions">true</item
    ...
</style>
2忆矛、定義一個相同的transition名稱

分別在Activity A 和Activity B的布局文件中定義item,這兩個item的屬性可以不一樣请垛,但是android:transitionName必須一樣催训。如下:
layout/activity_a.xml

<ImageView
        android:id="@+id/small_blue_icon"
        style="@style/MaterialAnimations.Icon.Small"
        android:src="@drawable/circle"
        android:transitionName="@string/blue_name" />

layout/activity_b.xml

<ImageView
        android:id="@+id/big_blue_icon"
        style="@style/MaterialAnimations.Icon.Big"
        android:src="@drawable/circle"
        android:transitionName="@string/blue_name" />
3、在activity中啟動shared element

使用ActivityOptions.makeSceneTransitionAnimation()方法
ActivityA.java

blueIconImageView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent i = new Intent(MainActivity.this, SharedElementActivity.class);

        View sharedView = blueIconImageView;
        String transitionName = getString(R.string.blue_name);

        ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
        startActivity(i, transitionActivityOptions.toBundle());
    }
});

效果如下:


Start an activity with multiple shared elements

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
       Pair.create(view1, "agreedName1"),
       Pair.create(view2, "agreedName2"));

Fragment之間Shared elements
Fragment之間的Shared elements的使用過程和Activity之間的類似宗收,分為三個步驟:

1漫拭、允許windowContentTransitions
<style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:windowContentTransitions">true</item>
    ...
</style>
2、定義一個共同的變換名稱

layout/fragment_a.xml

<ImageView
        android:id="@+id/small_blue_icon"
        style="@style/MaterialAnimations.Icon.Small"
        android:src="@drawable/circle"
        android:transitionName="@string/blue_name" />

layout/fragment_b.xml

<ImageView
        android:id="@+id/big_blue_icon"
        style="@style/MaterialAnimations.Icon.Big"
        android:src="@drawable/circle"
        android:transitionName="@string/blue_name" />
3混稽、使用FragmentTransaction
FragmentB fragmentB = FragmentB.newInstance(sample);

// Defines enter transition for all fragment views
Slide slideTransition = new Slide(Gravity.RIGHT);
slideTransition.setDuration(1000);
sharedElementFragment2.setEnterTransition(slideTransition);

// Defines enter transition only for shared element
ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds);
fragmentB.setSharedElementEnterTransition(changeBoundsTransition);

getFragmentManager().beginTransaction()
        .replace(R.id.content, fragmentB)
        .addSharedElement(blueView, getString(R.string.blue_name))
        .commit();

效果如下圖


設(shè)置是否允許動畫重疊

可以通過設(shè)置setAllowEnterTransitionOverlap(overlap);中的overlap的值為true或者false來允許或者不允許進(jìn)場動畫和出場動畫重疊采驻。

FragmentB fragmentB = FragmentB.newInstance(sample);

// Defines enter transition for all fragment views
Slide slideTransition = new Slide(Gravity.RIGHT);
slideTransition.setDuration(1000);
sharedElementFragment2.setEnterTransition(slideTransition);

// Defines enter transition only for shared element
ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds);
fragmentB.setSharedElementEnterTransition(changeBoundsTransition);

// Prevent transitions for overlapping
fragmentB.setAllowEnterTransitionOverlap(overlap);
fragmentB.setAllowReturnTransitionOverlap(overlap);

getFragmentManager().beginTransaction()
        .replace(R.id.content, fragmentB)
        .addSharedElement(blueView, getString(R.string.blue_name))
        .commit();

想學(xué)習(xí)更多Android知識,或者獲取相關(guān)資料請加入Android開發(fā)交流群:1018342383匈勋。 有面試資源系統(tǒng)整理分享礼旅,Java語言進(jìn)階和Kotlin語言與Android相關(guān)技術(shù)內(nèi)核,APP開發(fā)框架知識洽洁, 360°Android App全方位性能優(yōu)化痘系。Android前沿技術(shù),高級UI饿自、Gradle汰翠、RxJava临谱、小程序、Hybrid奴璃、 移動架構(gòu)師專題項目實戰(zhàn)環(huán)節(jié)、React Native城豁、等技術(shù)教程苟穆!架構(gòu)師課程、NDK模塊開發(fā)唱星、 Flutter等全方面的 Android高級實踐技術(shù)講解雳旅。還有在線答疑

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市间聊,隨后出現(xiàn)的幾起案子攒盈,更是在濱河造成了極大的恐慌,老刑警劉巖哎榴,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件型豁,死亡現(xiàn)場離奇詭異,居然都是意外死亡尚蝌,警方通過查閱死者的電腦和手機(jī)迎变,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來飘言,“玉大人衣形,你說我怎么就攤上這事∽撕瑁” “怎么了谆吴?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長苛预。 經(jīng)常有香客問我句狼,道長,這世上最難降的妖魔是什么碟渺? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任鲜锚,我火速辦了婚禮,結(jié)果婚禮上苫拍,老公的妹妹穿的比我還像新娘芜繁。我一直安慰自己,他們只是感情好绒极,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布骏令。 她就那樣靜靜地躺著,像睡著了一般垄提。 火紅的嫁衣襯著肌膚如雪榔袋。 梳的紋絲不亂的頭發(fā)上周拐,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機(jī)與錄音凰兑,去河邊找鬼妥粟。 笑死,一個胖子當(dāng)著我的面吹牛吏够,可吹牛的內(nèi)容都是我干的勾给。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼锅知,長吁一口氣:“原來是場噩夢啊……” “哼播急!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起售睹,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤桩警,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后昌妹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捶枢,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年飞崖,在試婚紗的時候發(fā)現(xiàn)自己被綠了柱蟀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚜厉,死狀恐怖长已,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情昼牛,我是刑警寧澤术瓮,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贰健,受9級特大地震影響胞四,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伶椿,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一辜伟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脊另,春花似錦导狡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诉植。三九已至秕噪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間花履,已是汗流浹背睡腿。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工继找, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留捍歪,地道東北人畅姊。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像卢肃,于是被迫代替她去往敵國和親谓松。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

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