項目需求討論 — 用Transition做一個漂亮的登錄界面

前言

一次在逛Github的時候,看到一個漂亮的登錄界面米酬,用的是Transition做的沛豌。我就直接貼上地址:

MaterialLogin

當然,如果單純的直接拿過來用赃额,沒有任何意義加派。主要還是來看具體如何實現(xiàn)的。我就來寫下具體如何一步步的來實現(xiàn)這個效果跳芳。

我也按照相應的原理寫了個Demo芍锦。最后的效果如下圖所示(其中l(wèi)ayout布局我就直接從github上面拷貝過來了):


基礎

首先我們來看下什么是Transition。大家看仔細是Transition飞盆,而不是Translate娄琉。我們直接看翻譯:

而Translate通常我們指的是平移的動畫操作。

Transition:

所以我們知道了用的是過渡的方式來做吓歇,那什么是過渡呢孽水?

Android 4.4:

Android對于開發(fā)者提供了越來越多的動畫API支持。從API 1就存在的Drawable Animation和View Animation照瘾,以及API 11(Android 3.0)以后加入的Property Animation匈棘。而過渡動畫Transition是在API 19(Android 4.4.2)中加入的丧慈。

基礎知識我就不說了析命,直接看其他文章傳送門:

Android 過渡(Transition)動畫解析之基礎篇

所以初步我們可以理解為(可能這么說明有不對,可以提出):

場景(scenes)和變換(transitions)逃默。場景(scenes)定義了當前的UI狀態(tài)鹃愤,變換(transitions)則定義了在不同場景之間動畫變化的過程。

當一個場景改變的時候完域,transition主要負責:

(1)捕捉每個View在開始場景和結束場景時的狀態(tài)软吐。

(2)根據(jù)兩個場景(開始和結束)之間的區(qū)別創(chuàng)建一個Animator。

Android 5.0

Android 5.0中Transition可以被用來實現(xiàn)Activity或者Fragment切換時的異常復雜的動畫效果吟税。

雖然在以前的版本中凹耙,已經(jīng)可以使用Activity的overridePendingTransition() 和 FragmentTransaction的setCustomAnimation()來實現(xiàn)Activity或者Fragment的動畫切換,但是他們僅僅局限與將整個視圖一起動畫變換肠仪。新的Lollipop api更進了一步肖抱,讓單獨的view也可以在進入或者退出其布局容器中時發(fā)生動畫效果,甚至還可以在不同的activity/Fragment中共享一個view异旧。

還是上面那個圖意述,只是變成了二個Activity界面:

我們在跳轉到第二個Activity的時候,我們會有個過場動畫。會第一個Activity的按鈕移動到第二個Activity的按鈕荤崇。效果如下所示:


所以我們再回頭看下面這種效果拌屏,是不是就知道怎么實現(xiàn)了,用的是Activity的過渡動畫了术荤。

大家也可以看看下面的相關文章鏈接:

Activity和Fragment Transition介紹

深入理解Content Transition

深入理解共享元素變換(Shared Element Transition)-上


正文

我們先準備第一個Activity倚喂,界面如下:
[圖片上傳中...(1515553694(1).png-7b7bdf-1515572604428-0)]

第一步:fab按鈕的移動:

我們讓那個按鈕"+"能移動到頂部:

我們由前面的demo說明已經(jīng)知道了,啟動第二個Activity瓣戚,我們我們先讓第二個Activity的界面如下所示:

我們設置第二個Activity的主題為:

<style name="Translucent" parent="Theme.AppCompat.Light.NoActionBar">
    //第一個activity的狀態(tài)欄顏色為#0288D1
    <item name="colorPrimaryDark">#0288D1</item>
    //第二個activity的背景為透明务唐,
    //這樣可以看得到第一個Activity的界面
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowIsTranslucent">true</item>
</style>

沒錯,我們在第二個界面先寫上一個按鈕"X"带兜,這樣我們啟動第二個Activity的時候就蓋在了第一個Activity的上面枫笛,同時這個fab按鈕也有了動畫的效果:

代碼很簡單,只要讓第一個Activity的按鈕的android:transitionName與第二個Activity的按鈕的android:transitionName一樣就可以刚照。我們稱這個為共享元素刑巧。

FloatingActionButton btn = findViewById(R.id.fab);;

ActivityOptionsCompat optionsCompat
    = ActivityOptionsCompat.makeSceneTransitionAnimation(LoginMainActivity.this,btn,btn.getTransitionName());
startActivity(new Intent(LoginMainActivity.this,RegisterMainActivity.class),optionsCompat.toBundle());

然后通過ActivityOptionsCompat來記錄當前這個Activity的這個fab按鈕的狀態(tài)。然后在startActivity的時候无畔,通過optionsCompat.toBundle()把內(nèi)容帶到了第二個Activity中啊楚。第二個Activity就會讓現(xiàn)在的相同trasitionName的fab按鈕,以傳過來的第一個Activity的按鈕相同位置的為起始點浑彰,然后通過動畫到了最終的地方恭理。(所以動畫是在第二個Activity中完成的,只是按鈕的起始狀態(tài)是以第一個Activity傳過來的按鈕的狀態(tài)信息相同郭变,然后到最終用戶設置的位置颜价。)

我們可以看到,共享元素變換并不是真正實現(xiàn)了兩個activity或者Fragment之間元素的共享诉濒,實際上我們看到的幾乎所有變換效果中(不管是B進入還是B返回A),共享元素都是在B中繪制出來的周伦。Framework沒有真正試圖將A中的某個元素傳遞給B,而是采用了不同的方法來達到相同的視覺效果未荒。A傳遞給B的是共享元素的狀態(tài)信息专挪。B利用這些信息來初始化共享View元素,讓它們的位置片排、大小寨腔、外觀與在A中的時候完全一致。當變換開始的時候率寡,B中除了共享元素之外迫卢,所有的其他元素都是不可見的。隨著動畫的進行勇劣,framework 逐漸將B的activity窗口顯示出來靖避,當動畫完成潭枣,B的窗口才完全可見。

并且其實動畫是繪制在ViewOverlay上面幻捏,可以看看這篇文章:ViewOverlay與animation介紹

第二步讓fab按鈕通過曲線路徑變化:

我們直接不做任何處理盆犁,默認是fab按鈕的位置變化是直線。
我們更希望是:

我們可以設置共享元素的進入動畫:

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

    <changeBounds>
        <arcMotion
            android:maximumAngle="0"
            android:minimumHorizontalAngle="60"
            android:minimumVerticalAngle="90" />
    </changeBounds>
</transitionSet>
//獲取過渡動畫
Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.fabtransition);
設置共享元素的進入動畫
getWindow().setSharedElementEnterTransition(transition);

這里使用的是arcMotion來做的曲線路徑.

ArcMotion文檔

里面的介紹我用的谷歌翻譯翻譯的篡九,大致應該是這個意思:
PathMotion在包含兩個點的假想圓上沿圓弧生成曲線路徑谐岁。 如果點之間的水平距離小于垂直距離,則圓的中心點將與終點水平對齊榛臼。 如果垂直距離小于水平距離伊佃,則圓的中心點將與終點垂直對齊。
當兩點接近水平或垂直時沛善,運動的曲線將會變小航揉,因為圓的中心距兩點都很遠。 要強制路徑的曲率金刁,可以使用setMinimumHorizontalAngle(float)和setMinimumVerticalAngle(float)來設置兩點之間的弧的最小角度帅涂。

其他參考文章:

曲線運動-1

曲線運動 - 2

第三步fab按鈕動畫結束后出現(xiàn)注冊界面:

我們上一步對fab按鈕設置了過渡的動畫。我們可以對這個過渡動畫設置結束的監(jiān)聽尤蛮,然后其他我們的注冊界面的出現(xiàn):

Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.fabtransition);
getWindow().setSharedElementEnterTransition(transition);
transition.addListener(new Transition.TransitionListener() {
            
    .....
    .....
            
    @Override
    public void onTransitionEnd(Transition transition) {
        transition.removeListener(this);
        
        
        /*我們可以在動畫結束后媳友,
            可以在這里寫上代碼,
            讓注冊界面出現(xiàn)
        */
        .....
        .....
       
    }
});

這是我們的第二個Activity的布局變成了這樣:

只不過默認這個注冊界面是不可見的产捞,等到我們的fab按鈕動畫結束后醇锚,我們再讓注冊界面可見就可以了。

這里我們可以直接在上面fab按鈕動畫結束的時候坯临,直接讓注冊界面出現(xiàn)(因為這個注冊界面是用CardView寫的焊唬,所以這里直接用cardView來指這個實例),我們可以在上面的結束監(jiān)聽里面直接設置:

@Override
public void onTransitionEnd(Transition transition) {
    transition.removeListener(this);
    //設置可見
    cardView.setVisibility(View.VISIBLE);
}

效果如下:

我們發(fā)現(xiàn)尿扯,直接突然出現(xiàn)求晶,雖然功能實現(xiàn)了焰雕,但我們還是希望有更好看的效果衷笋,就像文章開頭那樣,這個注冊界面是慢慢展開的矩屁。所以我們在fab按鈕過渡動畫結束后辟宗,不是簡單的對cardView設置View.VISIBLE就可以。我們使用揭露動畫來實現(xiàn):

Animator mAnimator = ViewAnimationUtils.createCircularReveal(cardView,cardView.getWidth()/2
    ,0,0,cardView.getHeight());
mAnimator.setDuration(500);
mAnimator.setInterpolator(new AccelerateInterpolator());
mAnimator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
        cardView.setVisibility(View.VISIBLE);
    }
});
mAnimator.start();

揭露動畫參考文章:

使用Circular Reveal為你的應用添加揭露動畫效果

所以我們這么使用后效果變成了:


第四步返回登錄界面:

這里有二種方式:

  1. 按了手機上的返回鍵
  2. 按了那個fab按鈕返回

我們的fab鍵從左邊移動到了上邊吝秕,然后如果你按返回鍵泊脐,你會發(fā)現(xiàn)自動fab鍵會先執(zhí)行相應的自動回去動畫,然后activity再關閉烁峭。比如你直接對fab鍵設置了點擊事件:

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
       finish();
    }
});

直接調用finish()方法的話容客,你就會發(fā)現(xiàn)秕铛,沒有fab鍵返回的動畫,而是直接第二個activity關閉缩挑,顯示第一個activity的見面但两。這樣很不友善。

我們知道默認按返回鍵是調用了:

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

說明調用onBackPressed會調用退出動畫效果后再finish();

參考文章:

最常用的Activity的onBackPressed()與finish()的區(qū)別.

所以我們知道了供置,我們點擊fab鍵返回的時候不能直接finish谨湘,而是最后一步是調用super.onBackPressed();

所以我們最終是先讓注冊界面慢慢消失芥丧,消失后調用super.onBackPressed();紧阔。

//覆寫返回鍵操作,
//執(zhí)行注冊界面消失動畫续担,
//然后再執(zhí)行super.onBackPressed();
@Override
public void onBackPressed() {
    animateRevealClose();
}
//fab的點擊事件與上面一樣
btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        animateRevealClose();
    }
});
//注冊界面界面慢慢消失擅耽,然后調用super.onBackPressed()
//然后fab鍵會執(zhí)行動畫回到原始位置,然后第二個Activity關閉物遇。
//然后顯示了第一個Activity
public void animateRevealClose(){
    
    Animator mAnimator = ViewAnimationUtils.createCircularReveal(cardView,cardView.getWidth()/2
            ,0,cardView.getHeight(),0);
    mAnimator.setDuration(500);
    mAnimator.setInterpolator(new AccelerateInterpolator());
    mAnimator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            cardView.setVisibility(View.GONE);
            btn.setImageResource(R.drawable.plus);
            RegisterMainActivity.super.onBackPressed();
        }
    });
    mAnimator.start();
}

最后實現(xiàn)就是這樣子了:


結語

哪里錯誤了秫筏,大家留言回復哦,多謝支持挎挖。o( ̄︶ ̄)o

大佬如果能幫我解答下下面二個問題这敬,非常感謝:

  1. 我在使用arcMotion的時候,小米5(6.0)與華為(7.0)蕉朵,呈現(xiàn)的曲線效果差別很大崔涂,(gif圖是小米的,所以fab鍵移動的時候更像是直線始衅,但是華為就很明顯的是曲線)不知道是什么原因冷蚂,知道的可以告訴我下。


網(wǎng)上的文章清一色都是要求app的主題設置里面這個屬性要是true汛闸,但是我設成了false蝙茶,為什么也是沒問題的。比如activity之間的共享元素動畫也是一樣執(zhí)行的诸老。測試手機是小米5(6.0)與華為(7.0)隆夯。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市别伏,隨后出現(xiàn)的幾起案子蹄衷,更是在濱河造成了極大的恐慌,老刑警劉巖厘肮,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愧口,死亡現(xiàn)場離奇詭異,居然都是意外死亡类茂,警方通過查閱死者的電腦和手機耍属,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門托嚣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厚骗,你說我怎么就攤上這事注益。” “怎么了溯捆?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵丑搔,是天一觀的道長。 經(jīng)常有香客問我提揍,道長啤月,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任劳跃,我火速辦了婚禮谎仲,結果婚禮上,老公的妹妹穿的比我還像新娘刨仑。我一直安慰自己郑诺,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布杉武。 她就那樣靜靜地躺著辙诞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轻抱。 梳的紋絲不亂的頭發(fā)上飞涂,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音祈搜,去河邊找鬼较店。 笑死,一個胖子當著我的面吹牛容燕,可吹牛的內(nèi)容都是我干的梁呈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蘸秘,長吁一口氣:“原來是場噩夢啊……” “哼官卡!你這毒婦竟也來了?” 一聲冷哼從身側響起秘血,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤味抖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后灰粮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡忍坷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年粘舟,在試婚紗的時候發(fā)現(xiàn)自己被綠了熔脂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡柑肴,死狀恐怖霞揉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晰骑,我是刑警寧澤适秩,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站硕舆,受9級特大地震影響秽荞,放射性物質發(fā)生泄漏。R本人自食惡果不足惜抚官,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一扬跋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凌节,春花似錦钦听、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卒煞,卻和暖如春余指,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跷坝。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工酵镜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柴钻。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓淮韭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贴届。 傳聞我的和親對象是個殘疾皇子靠粪,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

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