【翻譯】MotionLayout實現(xiàn)折疊工具欄(Part 2)

motionlayout_part2.jpg

一、前言

本篇是續(xù)集,第一篇翻譯直達鏈接:【翻譯】MotionLayout實現(xiàn)折疊工具欄(Part 1)

本文特點:沒有 Kotlin/Java 代碼,講解部分全為 XML 代碼钻注,閱讀時間短,獲取技能: MotionLayout 的入門和使用配猫!發(fā)布時間: 8 月 17 號 幅恋,作者: Mark Allison ,原文鏈接: https://blog.stylingandroid.com/motionlayout-collapsing-toolbar-part-2/

二泵肄、正文

谷歌 IO 2018 發(fā)布了 ConstraintLayout 2.0 版本捆交,其中最重要的部分就是 MotionLayout 了,這玩意就是一個全新的腐巢、超牛的布局動畫工具品追! Nicolas Roard 哥們早已發(fā)布了一個關(guān)于 MotionLayout 的完美詳情介紹,我強烈推薦大家去閱讀一下系忙,從中理解 MotionLayout 組件的基礎(chǔ)架構(gòu)诵盼。本系列教程中,我會講解如何使用 MotionLayout 來創(chuàng)建一個我們已經(jīng)非常熟悉的動畫行為:一個折疊工具欄動畫( a Collapsing Toolbar )银还。

通過上一篇文章我們了解了基本的折疊工具欄動畫行為风宁,使用的是 MotionLayout ,第一次嘗試的效果與在 CoordinatorLayout 中使用 CollapsingToolbarLayout 的效果非常接近蛹疯。不過有一個細(xì)微的小動畫在 MotionLayout 中沒有實現(xiàn)出來戒财。移動和縮放動畫在文字上表現(xiàn)確實已經(jīng)非常接近,但是背景圖片的漸變在最邊緣上卻沒有完全相同捺弦。讓我們先看下 CoordinatorLayout 版本的實現(xiàn)效果饮寞,注意圖片在工具欄幾乎快要完全折疊之前是不會開始漸變到主色彩動畫的:

motionlayout_part2_traditional.gif

現(xiàn)在我們看看 MotionLayout 的實現(xiàn),我們會發(fā)現(xiàn)圖片漸變在整個過渡動畫中是統(tǒng)一穩(wěn)定的列吼。也就是說:隨著工具欄折疊動畫的開始幽崩,圖片便立刻發(fā)生漸變,一直持續(xù)到工具欄完全到達折疊狀態(tài):

motionlayout_part2_motion_basic.gif

這個問題實際上很容易解決寞钥,這要感謝 MotionLayout 的另一個非常重要的特性:關(guān)鍵幀慌申。我們已經(jīng)討論過 MotionLayout 是如何在 ConstraintSets 中所定義的固定布局之間進行過渡動畫了。而關(guān)鍵幀允許我們在兩個固定布局之間定義一個中間點理郑,并對此點的屬性值進行操作控制蹄溉。

我們之前在 ImageView 控件上定義的關(guān)于 imageAlpha 屬性的過渡動畫,設(shè)定的是從展開位置的值 255 到折疊位置的值 0 之間進行您炉,同時 MotionLayout 在動畫過程中會進行插值運算柒爵。因此我們得到的是一個非常平滑的過渡動畫,從工具欄開始發(fā)生折疊一直到工具欄完全達到折合狀態(tài)為止赚爵。這也很好的解釋了我們所看到的在 MotionLayout 中對動畫行為的實現(xiàn)棉胀。

利用關(guān)鍵幀特性我們甚至可以做到修改相關(guān)的行為動畫,使得這些行為動畫時間在整個過渡動畫中往后延遲冀膝。為了實現(xiàn)這個目標(biāo)膏蚓,我們首先需要在展開狀態(tài) ConstraintSet 的定義中刪除自定義屬性 imageAlpha 字段:

  <ConstraintSet android:id="@+id/expanded">
    <Constraint
      android:id="@id/toolbar_image"
      android:layout_height="200dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

同時也需要在折疊狀態(tài) ConstraintSet 的定義中進行同樣的操作:

  <ConstraintSet android:id="@+id/collapsed">
    <Constraint
      android:id="@id/toolbar_image"
      android:layout_height="?attr/actionBarSize"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

這樣同時把透明度的漸變動畫一起刪除了,不過接下來我們會使用一個 KeyFrameSet 來代替它畸写,這個關(guān)鍵幀設(shè)置 KeyFrameSet 字段是作為過渡元素的一個子元素:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto">
 
  <Transition
    app:constraintSetEnd="@id/collapsed"
    app:constraintSetStart="@id/expanded">
 
    <OnSwipe
      app:dragDirection="dragUp"
      app:touchAnchorId="@id/recyclerview"
      app:touchAnchorSide="top" />
 
    <KeyFrameSet>
      <KeyAttribute
        app:framePosition="60"
        app:target="@id/toolbar_image">
        <CustomAttribute
          app:attributeName="imageAlpha"
          app:customIntegerValue="255" />
      </KeyAttribute>
      <KeyAttribute
        app:framePosition="90"
        app:target="@id/toolbar_image">
        <CustomAttribute
          app:attributeName="imageAlpha"
          app:customIntegerValue="0" />
      </KeyAttribute>
    </KeyFrameSet>
  </Transition>
  ...
</MotionScene>

這里 KeyFrameSet 包含了兩個 KeyAttribute 字段驮瞧,每一個字段分別定義了指定位置下的一個狀態(tài),第一個位于第 60 幀枯芬,也就是說整個過渡動畫過程中的 60% 的位置论笔,而第二個在 90 的位置,同樣的道理千所,這意味著位于過渡動畫的 90% 的位置狂魔。這兩個字段通過設(shè)置 ID 分別指定作用目標(biāo)控件對象(在這里兩個字段都是指定的 @id/toolbar_image )。每一個字段還定義了一個 CustomAttribute 元素淫痰,它的意思和我們之前在開頭最楷、結(jié)尾狀態(tài)中定義的意思是一樣的。

目前來說,發(fā)生的情況是:圖片的透明度在過渡動畫還沒有達到 60% 之前是不會發(fā)生變化的(也就是至少超過一半的折疊狀態(tài)下不發(fā)生變化)籽孙,接下來會慢慢開始淡出烈评,直到工具欄達到 90% 折疊時完全透明。

motionlayout_part2_motion_offset_fade.gif

現(xiàn)在已經(jīng)更加接近我們所見到的 CoordinatorLayout 所實現(xiàn)的標(biāo)準(zhǔn)動畫了犯建。不過仍然并非完全一樣讲冠,但是至少我們能看到,通過這種方式我們可以取得對動畫過渡的更好的控制權(quán)适瓦,如果使用 CoordinatorLayout 來進行這樣的調(diào)整那會非常的麻煩竿开。

事實上關(guān)鍵幀是非常非常強大的, Nicolas Roard 已經(jīng)對此作了一個深入介紹玻熙。我們在此不會重復(fù) Nicolas Roard 所介紹的那樣否彩,相反我們來嘗試一些其他的方式并投入使用。

首先我們并不局限于目前僅使用兩個關(guān)鍵幀的限制嗦随,事實上我們可以創(chuàng)建更多精細(xì)動畫列荔。甚至使用關(guān)鍵幀我們都能夠創(chuàng)建出自定義的漸進曲線來(對于安卓開發(fā)者來說也就是所謂的插值)。舉個例子称杨,假設(shè)我們設(shè)置 imageAlpha 的開始和結(jié)束值分別是 255 和 0 肌毅,然后在 25% 的位置添加一個關(guān)鍵幀,設(shè)置值為 205 姑原,在 75% 的位置設(shè)置另一個關(guān)鍵幀值為 50 悬而。結(jié)果會給我們實現(xiàn)一個和加速-減速插值器一樣的效果。

更牛逼的是锭汛,我們可以在動畫進行時對動畫進行動態(tài)更改笨奠。標(biāo)題文字的移動和縮放在整個過渡動畫中是同時進行的,但是通過添加一個單獨關(guān)鍵幀后我們可以做到在不更改 ConstraintSets 代碼的前提下唤殴,也不用改變縮放速度就能讓標(biāo)題文本更快地到達動畫最終位置:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto">
 
  <Transition
    app:constraintSetEnd="@id/collapsed"
    app:constraintSetStart="@id/expanded">
 
    <OnSwipe
      app:dragDirection="dragUp"
      app:touchAnchorId="@id/recyclerview"
      app:touchAnchorSide="top" />
 
    <KeyFrameSet>
      <KeyAttribute
        app:framePosition="60"
        app:target="@id/toolbar_image">
        <CustomAttribute
          app:attributeName="imageAlpha"
          app:customIntegerValue="255" />
      </KeyAttribute>
      <KeyAttribute
        app:framePosition="90"
        app:target="@id/toolbar_image">
        <CustomAttribute
          app:attributeName="imageAlpha"
          app:customIntegerValue="0" />
      </KeyAttribute>
      <KeyPosition
        app:type="pathRelative"
        app:framePosition="50"
        app:target="@id/title"
        app:percentX="0.9" />
    </KeyFrameSet>
  </Transition>

以上代碼能實現(xiàn)在 50% 的過渡動畫進程中完成 90% 的移動效果般婆。最終標(biāo)題文本會走在工具欄折疊動畫之前,接著在折疊完全結(jié)束的時候直接回落到正確的位置上:

motionlayout_part2_motion_key_position.gif

雖然這只是棄用 CoordinatorLayout 過渡動畫的一個開始朵逝,但是恰恰通過這個例子告訴了我們蔚袍,如何使用關(guān)鍵幀來幫助我們動態(tài)地進行過渡動畫修改,實現(xiàn)在同樣的過渡中產(chǎn)生不同的動畫效果配名。

最后值得一提的是:有時候它還能幫我們實現(xiàn)過渡動畫的可視化啤咽,我們可以通過開啟布局中的 showPaths 屬性來實現(xiàn):

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layoutDescription="@xml/collapsing_toolbar"
  tools:context=".MainActivity"
  tools:showPaths="true"
  app:showPaths="true">
  ...
</androidx.constraintlayout.motion.widget.MotionLayout>

這里的 tools:showPaths="true" 設(shè)置如果在 Android Studio 編輯器里配合使用會更爽(這個功能應(yīng)該會出現(xiàn)在 Android Studio 3.4 的 alpha 版本中)。但是在目前來說渠脉,添加 tools:showPaths="true" 這段代碼能夠讓 MotionLayout 計算并顯示這三個被過渡動畫所影響的視圖控件的軌跡路線:標(biāo)題文本控件(頂部宇整,中心左側(cè)),工具欄的海灘小排屋圖片(頂部中心)芋膘,以及列表 RecyclerView 控件(中心位置):

motionlayout_part2_motion_show_paths.gif

值得注意的是鳞青,我們在文本控件上添加的關(guān)鍵幀就是位于左邊路徑頂部下方的那一個紅點霸饲。如果你仔細(xì)查看標(biāo)題文本的移動,你會清楚的看到這一行軌跡始終穿行在字母 n 和 g 之間臂拓,并且它到達關(guān)鍵點位置要相對快些厚脉。這種顯示路徑的方式有助于我們理解剛才創(chuàng)建的關(guān)鍵幀是如何影響到過渡動畫的特定部分的。你只需要記得在最終發(fā)布版本中要關(guān)閉這個功能——我建議定義一個布爾值資源埃儿,在布局中使用器仗,然后你就可以在發(fā)布版本時總能設(shè)置它為 false 就可以了融涣。

好吧童番,這次就到這里。即使如此威鹿,我相信大多數(shù)人還是會認(rèn)同 MotionLayout 不僅靈活剃斧、強大,而且還為設(shè)計用戶交互控制的布局動畫開辟了一個非常有趣的可能性哦忽你。 :sunglasses:

三幼东、總結(jié)

本篇的源代碼請移步這里

? 2018 科雳, Mark Allison 根蟹。保留所有版權(quán)。

我的博客地址: http://liuqingwen.me 糟秘,歡迎關(guān)注我的微信公眾號:

IT自學(xué)不成才

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末简逮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子尿赚,更是在濱河造成了極大的恐慌散庶,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凌净,死亡現(xiàn)場離奇詭異悲龟,居然都是意外死亡,警方通過查閱死者的電腦和手機冰寻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門须教,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斩芭,你說我怎么就攤上這事轻腺。” “怎么了秒旋?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵约计,是天一觀的道長。 經(jīng)常有香客問我迁筛,道長煤蚌,這世上最難降的妖魔是什么耕挨? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮尉桩,結(jié)果婚禮上筒占,老公的妹妹穿的比我還像新娘。我一直安慰自己蜘犁,他們只是感情好翰苫,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著这橙,像睡著了一般奏窑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屈扎,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天埃唯,我揣著相機與錄音,去河邊找鬼鹰晨。 笑死墨叛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的模蜡。 我是一名探鬼主播漠趁,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼忍疾!你這毒婦竟也來了闯传?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤膝昆,失蹤者是張志新(化名)和其女友劉穎丸边,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荚孵,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡妹窖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了收叶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骄呼。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖判没,靈堂內(nèi)的尸體忽然破棺而出蜓萄,到底是詐尸還是另有隱情,我是刑警寧澤澄峰,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布嫉沽,位于F島的核電站,受9級特大地震影響俏竞,放射性物質(zhì)發(fā)生泄漏绸硕。R本人自食惡果不足惜堂竟,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玻佩。 院中可真熱鬧出嘹,春花似錦、人聲如沸咬崔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垮斯。三九已至郎仆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甚脉,已是汗流浹背丸升。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工铆农, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留牺氨,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓墩剖,卻偏偏與公主長得像猴凹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子岭皂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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