【Transition】Android炫酷的Activity切換效果意荤,共享元素

如果本文幫助到你啊片,本人不勝榮幸,如果浪費(fèi)了你的時間玖像,本人深感抱歉紫谷。
希望用最簡單的大白話來幫助那些像我一樣的人。如果有什么錯誤捐寥,請一定指出笤昨,以免誤導(dǎo)大家、也誤導(dǎo)我握恳。
本文來自:http://www.reibang.com/users/320f9e8f7fc9/latest_articles
感謝您的關(guān)注瞒窒。

本文原項(xiàng)目地址為:
https://github.com/lgvalle/Material-Animations
在文章最后,有我自己對著這個項(xiàng)目手敲的一份乡洼。
代碼基本一模一樣崇裁,只有略微的修改,加了一些注釋束昵,以及將其中大多數(shù)英文翻譯成了中文拔稳。


此篇 API 均為 Android 5.0(API 級別 21) 以上才可支持。
此demo一共分為四部分:

1.1 普通過渡 Transition锹雏;
1.2 Shared Elements Transition 共享元素巴比;
2.0 TransitionManager 控制動畫;
3.0 ViewAnimationUtils 顯示或隱藏效果礁遵。

過渡效果 Transition

Material Design 為應(yīng)用中的切換頁面時匿辩,提供了非常優(yōu)雅的視覺切換效果。
您可為進(jìn)入榛丢、退出轉(zhuǎn)換、頁面之間的共享元素轉(zhuǎn)換設(shè)置特定的動畫挺庞。

1. Transition 動畫都包含哪些晰赞?

Android 5.0(API 級別 21)支持的進(jìn)入與退出轉(zhuǎn)換有三個:

Explode Slide Fade
從中心移入或移出 從邊緣移入或移出 調(diào)整透明度產(chǎn)生漸變

一會看到使用場景的時候,就會發(fā)現(xiàn)上面的三張圖,每張圖都經(jīng)歷了:(此處可以一會再回過頭來看)

退出 -> 進(jìn)入  -> 返回   -> 重新進(jìn)入
Exit -> Enter -> Return -> Reenter

**第一個頁面設(shè)置:**
android:windowExitTransition      啟動新 Activity 掖鱼,此頁面退出的動畫
android:windowReenterTransition   重新進(jìn)入的動畫然走。即第二次進(jìn)入,可以和首次進(jìn)入不一樣戏挡。
**第二個頁面設(shè)置:**
android:windowEnterTransition     首次進(jìn)入顯示的動畫
android:windowReturnTransition    調(diào)用 finishAfterTransition() 退出時芍瑞,此頁面退出的動畫

如此即可達(dá)到以上效果。

explode:從場景的中心移入或移出
slide:從場景的邊緣移入或移出
fade:調(diào)整透明度產(chǎn)生漸變效果

這三個類都繼承于 Transition 褐墅,所有有一些屬性都是共同的拆檬。
常用屬性如下:

// 設(shè)置動畫的時間。類型:long
transition.setDuration();
// 設(shè)置修飾動畫妥凳,定義動畫的變化率竟贯,具體設(shè)置往下翻就看到了
transition.setInterpolator();
// 設(shè)置動畫開始時間,延遲n毫秒播放逝钥。類型:long
transition.setStartDelay();
// 設(shè)置動畫的運(yùn)行路徑
transition.setPathMotion();
// 改變動畫 出現(xiàn)/消失 的模式屑那。Visibility.MODE_IN:進(jìn)入;Visibility.MODE_OUT:退出艘款。
transition.setMode();

// 設(shè)置動畫的監(jiān)聽事件
transition.addListener()

至于例子持际,在下一個給出。
喏哗咆,這不就是了蜘欲。

2. 修飾動畫,定義動畫的變化率(Interpolator)

在 Java 代碼中定義:

Explode transition = new Explode();
transition.setDuration(500);
transition.setInterpolator(new AccelerateInterpolator());

在 Xml 資源定義:

<explode
    android:duration="@integer/anim_duration_long"
    android:interpolator="@android:interpolator/bounce"
    />

可選類型:

AccelerateDecelerateInterpolator 在動畫開始與結(jié)束的地方速率改變比較慢岳枷,在中間的時候加速

AccelerateInterpolator  在動畫開始的地方速率改變比較慢芒填,然后開始加速

AnticipateInterpolator 開始的時候向后然后向前甩

AnticipateOvershootInterpolator 開始的時候向后然后向前甩一定值后返回最后的值

BounceInterpolator   動畫結(jié)束的時候彈起

CycleInterpolator 動畫循環(huán)播放特定的次數(shù),速率改變沿著正弦曲線

DecelerateInterpolator 在動畫開始的地方快然后慢

LinearInterpolator   以常量速率改變

OvershootInterpolator    向前甩一定值后再回到原來位置
3. 設(shè)置 Transition 的時機(jī)

到底該什么時候空繁,設(shè)置什么樣的過渡呢殿衰?

以下為動畫的設(shè)置場景:

首先打開頁面A :
頁面A -> Enter 首次進(jìn)入

從 A 打開 B :
頁面A -> Exit 退出
頁面B -> Enter 首次進(jìn)入

從 B 返回 A :
頁面B -> Return 返回
頁面A -> Reenter 重新進(jìn)入

可設(shè)置的方法如下:

android:windowContentTransitions                允許使用transitions

android:windowAllowEnterTransitionOverlap       是否覆蓋執(zhí)行,其實(shí)可以理解成前后兩個頁面是同步執(zhí)行還是順序執(zhí)行

android:windowAllowReturnTransitionOverlap      與上面相同盛泡。即上一個設(shè)置了退出動畫闷祥,這個設(shè)置了進(jìn)入動畫,兩者是否同時執(zhí)行傲诵。

android:windowContentTransitionManager          引用TransitionManager XML資源凯砍,定義不同窗口內(nèi)容之間的所需轉(zhuǎn)換。



android:windowEnterTransition                   首次進(jìn)入顯示的動畫

android:windowExitTransition                    啟動新 Activity 拴竹,此頁面退出的動畫

android:windowReenterTransition                 重新進(jìn)入的動畫悟衩。即第二次進(jìn)入,可以和首次進(jìn)入不一樣栓拜。

android:windowReturnTransition                  調(diào)用 finishAfterTransition() 退出時座泳,此頁面退出的動畫



android:windowSharedElementsUseOverlay          指示共享元素在轉(zhuǎn)換期間是否應(yīng)使用疊加層惠昔。

android:windowSharedElementEnterTransition      首次進(jìn)入顯示的動畫

android:windowSharedElementExitTransition       啟動新 Activity ,此頁面退出的動畫

android:windowSharedElementReenterTransition    重新進(jìn)入的動畫挑势。即第二次進(jìn)入镇防,可以和首次進(jìn)入不一樣。

android:windowSharedElementReturnTransition     調(diào)用 finishAfterTransition() 退出時潮饱,此頁面退出的動畫

以上為 style 中設(shè)置屬性来氧,在代碼中設(shè)置為:

 getWindow().setEnterTransition(visibility);
 // 其余的都是類似
4. 跳轉(zhuǎn)頁面

至此,用以上知識基本可以設(shè)置出絕大多數(shù)的過渡效果香拉。
然后啦扬,跳轉(zhuǎn)頁面跟普通的跳轉(zhuǎn)也有點(diǎn)不一樣。

跳轉(zhuǎn)頁面:

protected void transitionTo(Intent i) {
    ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
    startActivity(i, transitionActivityOptions.toBundle());
}

退出頁面:

private void closeActivity(){
    // 如果定義了 return transition 缕溉,將使用 定義的動畫過渡
    Visibility returnTransition = buildReturnTransition();
    getWindow().setReturnTransition(returnTransition);

    // 如果沒有 return transition 被定義考传,將使用 反進(jìn)入 的動畫
    finishAfterTransition();
}

注意:退出時,一定要調(diào)用:finishAfterTransition();

通過以上設(shè)置证鸥,就能夠完成一個基本的過渡效果了僚楞。


Shared Elements Transition 共享元素

效果如圖:

Shared Elements Transition

共享元素的各種設(shè)置 與 普通Transition 差不多。
來說說不同的地方枉层。

攜帶需要共享的 View 進(jìn)行跳轉(zhuǎn)

也就是在跳轉(zhuǎn)的參數(shù)中泉褐,增加了要共享的 View控件。

  1. 先在 layout 布局里面給需要共享的元素加上如下字段鸟蜡,這樣兩個 View 就能互通了:
android:transitionName="image"
  1. 然后開始設(shè)置跳轉(zhuǎn)頁面膜赃,代碼如下:
protected void transitionTo(Intent i) {
    // 這里攜帶了兩個 View
    ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
                                                    Pair.create(view1, "agreedName1"),
                                                    Pair.create(view2, "agreedName2"));
    startActivity(i, options.toBundle());
}

增加的參數(shù)的介紹:

Pair.create(
   View view,      // 本頁面要共享的 View
   String resId    // 下一個頁面的 View 的 id,注意是 id 的字符串
)
頁面切換時,動畫的效果設(shè)置

Android 5.0(API 級別 21)支持轉(zhuǎn)換效果如下:

changeBounds - 改變目標(biāo)視圖的布局邊界
changeClipBounds - 裁剪目標(biāo)視圖邊界
changeTransform - 改變目標(biāo)視圖的縮放比例和旋轉(zhuǎn)角度
changeImageTransform - 改變目標(biāo)圖片的大小和縮放比例

設(shè)置代碼:

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

ChangeBounds changeBounds = new ChangeBounds();
changeBounds.setDuration(500);

getWindow().setEnterTransition(slide);
getWindow().setSharedElementEnterTransition(changeBounds);

Shared Elements Transition 就是 特殊的 Transition 用法揉忘,都是一樣的跳座。


TransitionManager 控制動畫

這個框架可以讓一些復(fù)雜的動畫特別簡單的被實(shí)現(xiàn)。

TransitionManager

簡單的說明一下步驟:

  1. 定義需要切換 layout xml頁面泣矛;
  2. 調(diào)用 Scene.getSceneForLayout() 保存每個Layout疲眷;
  3. 調(diào)用 TransitionManager.go(scene1, new ChangeBounds()) 切換。

相當(dāng)于定義了不同的 xml 布局您朽,然后通過簡單的調(diào)用狂丝,就完成了較為復(fù)雜的動畫。

以下為代碼片段:

private void setupLayout() {
    scene0 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene0, this);
    scene1 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene1, this);
    scene2 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene2, this);
    scene3 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene3, this);
    scene4 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene4, this);
    binding.sample3Button1.setOnClickListener(this);
    binding.sample3Button2.setOnClickListener(this);
    binding.sample3Button3.setOnClickListener(this);
    binding.sample3Button4.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.sample3_button1:
            TransitionManager.go(scene1, new ChangeBounds());
            break;
        case R.id.sample3_button2:
            TransitionManager.go(scene2, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds));
            break;
        case R.id.sample3_button3:
            TransitionManager.go(scene3,TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential));
            break;
        case R.id.sample3_button4:
            TransitionManager.go(scene3,TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators));
            break;
    }
}

只需要定義布局哗总,調(diào)用調(diào)轉(zhuǎn)几颜,
就實(shí)現(xiàn)了,點(diǎn)擊四個 Button 讯屈,分別切換四個布局蛋哭。
TransitionManager.go() 中可以設(shè)置各種動畫。


CircularReveal 顯示或隱藏 的效果

ViewAnimationUtils.createCircularReveal()
當(dāng)您顯示或隱藏一組 UI 元素時涮母,Circular Reveal 可為用戶提供視覺連續(xù)性

CircularReveal

參數(shù)說明:

Animator createCircularReveal (View view, // 將要變化的 View
            int centerX,                  // 動畫圓的中心的x坐標(biāo)
            int centerY,                  // 動畫圓的中心的y坐標(biāo)
            float startRadius,            // 動畫圓的起始半徑
            float endRadius               // 動畫圓的結(jié)束半徑
)

顯示 View :

private void animShow() {
    View myView = findViewById(R.id.my_view);
    // 從 View 的中心開始
    int cx = (myView.getLeft() + myView.getRight()) / 2;
    int cy = (myView.getTop() + myView.getBottom()) / 2;
    int finalRadius = Math.max(myView.getWidth(), myView.getHeight());

    //為此視圖創(chuàng)建動畫設(shè)計(起始半徑為零)
    Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
    // 使視圖可見并啟動動畫
    myView.setVisibility(View.VISIBLE);
    anim.start();
}

隱藏 View :

private void animHide() {
    final View myView = findViewById(R.id.my_view);
    int cx = (myView.getLeft() + myView.getRight()) / 2;
    int cy = (myView.getTop() + myView.getBottom()) / 2;

    int initialRadius = myView.getWidth();

    // 半徑 從 viewWidth -> 0
    Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);

    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            myView.setVisibility(View.INVISIBLE);
        }
    });
    anim.start();
}

因?yàn)榫咦常@些炫酷的效果都只支持 API 23 以上准颓,所以在我們常用的 APP 中都還不常見。但是效果真的很不錯棺妓。

值得大家研究一下。
此文是我的一個總結(jié)炮赦。

項(xiàng)目地址:
https://github.com/Wing-Li/Material-Animations-CN

這個項(xiàng)目是我對著原項(xiàng)目手敲的怜跑,
基本一模一樣,只是加了一些注釋吠勘,以及將其中英文翻譯成了中文性芬。
大家可以參考參考。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剧防,一起剝皮案震驚了整個濱河市植锉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌峭拘,老刑警劉巖俊庇,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸡挠,居然都是意外死亡辉饱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門拣展,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彭沼,“玉大人,你說我怎么就攤上這事备埃⌒栈螅” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵按脚,是天一觀的道長于毙。 經(jīng)常有香客問我,道長乘寒,這世上最難降的妖魔是什么望众? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮伞辛,結(jié)果婚禮上烂翰,老公的妹妹穿的比我還像新娘。我一直安慰自己蚤氏,他們只是感情好甘耿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竿滨,像睡著了一般佳恬。 火紅的嫁衣襯著肌膚如雪捏境。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天毁葱,我揣著相機(jī)與錄音垫言,去河邊找鬼。 笑死倾剿,一個胖子當(dāng)著我的面吹牛筷频,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播前痘,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼凛捏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芹缔?” 一聲冷哼從身側(cè)響起坯癣,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎最欠,沒想到半個月后示罗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窒所,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年鹉勒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吵取。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡禽额,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出皮官,到底是詐尸還是另有隱情脯倒,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布捺氢,位于F島的核電站藻丢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏摄乒。R本人自食惡果不足惜悠反,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馍佑。 院中可真熱鬧斋否,春花似錦、人聲如沸拭荤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舅世。三九已至旦委,卻和暖如春奇徒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缨硝。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工摩钙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人追葡。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓腺律,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宜肉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,510評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫翎碑、插件谬返、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,025評論 4 62
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,708評論 22 664
  • 丫頭回來,想著看能不能多做個菜日杈。圍著圍裙出門遣铝,想看看剛才路口賣菜的攤點(diǎn)還在不在。20米遠(yuǎn)的路莉擒,我手抄口袋自顧自朝前...
    知畫秋嬋閱讀 313評論 3 5
  • 盛開的花朵是春雨的答案 羞澀的青果是夏日的答案 秋天的答案在稻穗尖上 冬天的答案融化在雪地里 沒有誰能束縛住誰 愛...
    一言爾閱讀 286評論 5 0