一、前言
本篇是續(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)效果饮寞,注意圖片在工具欄幾乎快要完全折疊之前是不會開始漸變到主色彩動畫的:
現(xiàn)在我們看看 MotionLayout 的實現(xiàn),我們會發(fā)現(xiàn)圖片漸變在整個過渡動畫中是統(tǒng)一穩(wěn)定的列吼。也就是說:隨著工具欄折疊動畫的開始幽崩,圖片便立刻發(fā)生漸變,一直持續(xù)到工具欄完全到達折疊狀態(tài):
這個問題實際上很容易解決寞钥,這要感謝 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% 折疊時完全透明。
現(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é)束的時候直接回落到正確的位置上:
雖然這只是棄用 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 控件(中心位置):
值得注意的是鳞青,我們在文本控件上添加的關(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é)不成才