原文連接html
MotionLayout 是一個來自 ConstraintLayout 2.0 的專一於動畫的新佈局。本系列的前幾篇文章對該系統進行了很好的概述。我強烈建議你在閱讀本文前先去查看它們。android
MotionLayout 動畫系統經過在兩種狀態之間插入值(一般是控件的位置/大小)來工做,這些值是使用 ConstraintLayout 的約束系統 (ConstranitSets) 以及視圖屬性來指定的。這兩種狀態之間的轉換也能夠徹底由觸摸事件驅動。這個系統一般會爲你的過渡提供很好的效果。git
除了上面說的狀態以外,MotionLayout 還支持關鍵幀(在本系列的第二部分中簡單介紹過),咱們將在本文中深刻介紹這些關鍵幀。注意,雖然關鍵幀很好,可是它絕對是一個更專業的工具;你可能不須要或者偶爾纔會用到。github
請記住,在應用中添加的動畫應該有它的意義;不要濫用!工具
可是,若是須要對你的過渡效果添加額外的功能,那麼關鍵幀能夠幫助你擴展 MotionLayout 的功能。如你所見,這裏有不少內容須要覆蓋:佈局
從較高的層次上看,關鍵幀能夠對你的兩個狀態之間的插值進行一個修改。動畫
MotionLayout 支持不一樣的關鍵幀:google
KeyPosition
KeyAttribute
KeyCycle
KeyTimeCycle
注意,每種類型的關鍵幀都是獨立於其餘類型的關鍵幀的——也就是說,你不須要在相同的點上定義全部的關鍵幀(可是你不能在相同的點上定義相同類型的多個關鍵幀)spa
全部關鍵幀(位置、屬性、循環、週期)都有一些關鍵的通用屬性:3d
motion:framePosition
: 關鍵幀在過渡中(從0到100)的做用時機motion:target
: 哪一個對象受該關鍵幀影響motion:transitionEasing
: 使用哪一種插值器(默認爲線性)motion:curveFit
: 樣條(默認)或線形——使用哪一個曲線擬合關鍵幀。默認狀況下是單調樣條曲線,這使得過渡更加平滑,固然你也能夠決定使用線性 (linear) 擬合。位置關鍵幀多是你最常使用到通用關鍵幀。它容許你修改控件在過渡期間在屏幕上的路徑。舉例,讓咱們在 MotionLayout 中爲其中的一個控件作動畫:
咱們有一個起始狀態(左下)和結束狀態(右上),過渡過程就是控件在這兩種狀態之間的線性 (linear interpoltion) 直線運動。
經過引入位置關鍵幀,咱們能夠將運動路徑變成曲線運動:
添加更多的關鍵幀容許你建立複雜的運動路徑。
<KeyFrameSet>
<KeyPosition motion:keyPositionType="pathRelative" motion:percentX="0.75" motion:percentY="-0.3" motion:framePosition="25" motion:target="@id/button"/>
<KeyPosition motion:keyPositionType="pathRelative" motion:percentY="-0.4" motion:framePosition="50" motion:target="@id/button"/>
<KeyPosition motion:keyPositionType="pathRelative" motion:percentX="0.25" motion:percentY="-0.3" motion:framePosition="75" motion:target="@id/button"/>
</KeyFrameSet>
複製代碼
若是 ConstraintSets 已經容許你以很是靈活的方式擺放控件,那麼你也許會問本身定位關鍵幀的意義是什麼。緣由以下:
注意:在一個 MotionScene 中定義多個 ConstraintSets 是有可能的,因此若是你有一個多步驟的動做,其中這些步驟是有效的「靜止」狀態,那麼你可使用它們而不是關鍵幀。狀態到狀態的轉換必須在代碼中完成(可使用改動監聽器(change listeners))。
關鍵幀存在於 <KeyFrameSet>
屬性中,<KeyFrameSet>
則存在於 MotionScene 文件中的 <Transition>
,而且至少包含:
target
: 被關鍵幀影響的控件framePosition
: 關鍵幀使用時機,(0-100)keyPositionType
: 所使用的座標系 相對父容器(parentRelative), 三角定位(deltaRelative), 相對路徑(pathRelative)
percentX / percentY
:位置的 (x,y) 座標<Transition ...>
<KeyFrameSet>
<KeyPosition motion:keyPositionType="parentRelative" motion:percentY="0.25" motion:framePosition="50" motion:target="@+id/button"/>
</KeyFrameSet>
</Transition>
複製代碼
在 MotionLayout 中的起始狀態和結束狀態容許複雜的定位。對於 ConstraintSets,它們可使用 ConstraintLayout 的全部功能。系統將根據密度 (density) 、屏幕方向(screen orientation)、語言(language) 等變化,正確的處理這些狀態。
要使關鍵幀在這樣的系統中發揮做用,咱們須要它們可以以相似自適應的方式進行佈局——而不是簡單的使用固定的位置。
爲了解決這個問題,同時保持關鍵幀系統的輕量級,咱們提出了一種靈活的方法——在給定的座標系中,每一個關鍵幀的位置用(x,y)座標對 (pair) 表示:
motion:percentX=」<float>」
motion:percentY=」<float>」
這個座標的含義取決於所使用的座標系類型:parentRelative
, deltaRelative
, or pathRelative
.
注意:每一個關鍵幀的位置都是單獨存在——每一個關鍵幀的位置均可以用它們本身相對的座標系表示。
座標是根據相對父容器表示的。這是一種很是直接和直觀的方式來表達關鍵幀的位置,一般就足夠了。一般狀況下,你用它來作與父容器相關的大範圍運動。
因爲這個座標系只基於父容器維度,而不是移動的控件的開始/結束位置,您可能會遇到這樣的狀況,即最後的關鍵幀位置以次優位置結束(相對於開始/結束位置)。(原文: you may encounter situations where the resulting keyframe position ends in a suboptimal position (relative to the start/end positions).)
第二個座標系經過使用開始/結束位置定義來解決這個問題。座標表示起點和終點之間的百分比。
和相對父容器座標系有點像,這是一個相對直觀的座標系統,通常也會給出很好的結果。當你但願控件以水平或垂直運動開始或結束時,它十分有用。
它有一個潛在的問題——由於它是根據控件從開始到結束位置之間的差別定義的額,若是差別很是小(或者沒有)關鍵幀將不會在對應軸上發生變化。例如,若是控件在屏幕從左向右移動,而保持在相同的高度,那麼對位置關鍵幀使用 deltarelative
percentY
將不會產生任何效果。
最後一個座標系定義了一個相對於從開始狀態到結束狀態的直線路徑。它能夠解決 deltaRelative 座標系中的問題——當一個控件沒有在垂直軸移動的狀況下,使用 pathRelative 將容許將位置關鍵幀設置爲偏離路徑。注意,它也支持負座標。它是一個更特殊的座標系,可是在處理時間上特別有用。下面有一個例子是實現一個曲線形狀(好比「S」形),即便端點發生變化,它也會保持不變。
在 Material Design 中使用的一種典型的運動類型是圓弧運動(arc motion)。使用 MotionLayout 建立圓弧運動的一種方法是在起始位置和結束位置之間添加正確放置的位置關鍵幀,如前一節所述。
在 ConstraintLayout 2.0.0 alpha 2 中,咱們引入了一種實現完美元弧運動的新方案——並且它更加容易使用。你只須要將motion:pathMotionArc
屬性添加到起始的 ConstraintSet ,從而讓默認的線形運動 (linear motion) 切換到弧線運動 (arc motion) 。
讓咱們來看一個簡單的例子,開始狀態是屏幕的右下,結束的位置是屏幕的頂部而且水平居中。添加下面這個屬性就能夠產生弧線運動:
motion:pathMotionArc=」startHorizontal」
若是把屬性換成:
motion:pathMotionArc=」startVertical」
就會改變弧線的方向:
你仍然可使用位置關鍵幀來創造更復雜的弧線路徑。下面是結果:
它是經過在動畫中添加一個垂直居中的位置關鍵幀來實現的:
<KeyPosition motion:keyPositionType="parentRelative" motion:percentY="0.5" motion:framePosition="50" motion:target="@id/button"/>
複製代碼
經過設置 motion:pathMotionArc
屬性,還能夠在該場景中使用關鍵幀來更改圓弧的方向。屬性能夠是flip
(翻轉當前的圓弧方向)、none
(還原爲線性運動),也能夠是startHorizontal
或startVertical
。
<KeyPosition motion:keyPositionType="parentRelative" motion:pathMotionArc="flip" motion:percentY="0.5" motion:framePosition="50" motion:target="@id/button"/>
複製代碼
<KeyPosition motion:keyPositionType="parentRelative" motion:pathMotionArc="none" motion:percentY="0.5" motion:framePosition="50" motion:target="@id/button"/>
複製代碼
在前幾節中,咱們介紹了各類機制幫助你定義一個運動路徑。對於一個動畫,不只僅須要選擇合適的路徑;時間也是相當重要的。
因爲位置關鍵幀能夠由時間指定,你可使用它們來定義控件移動的快慢,具體取決於移動的空間。
可是在一個單獨片斷內——開始和結束狀態之間,或者在關鍵幀之間——時間插值器是線形的。(the time interpolation is linear)
你可使用motion:transitionEasing
屬性來指定一個緩和曲線來修改它。你能夠將這個屬性使用在ConstraintSets
或 關鍵幀,它接受這些值:
cubic(float, float , float, float)
, x1,y1,x2,y2 表示一個從 0,0 到 1,1 的三次貝塞爾方程的控制點standard
, accelerate
, decelerate
, 預約義的曲線相似 Material Design definitions.一般用於在非觸摸驅動的動畫中。它最適合於開始和結束都是靜止狀態的元素。
加速一般用於一個元素移出屏幕。
減速一般用於一個元素進入屏幕。
屬性關鍵幀容許你在動畫過程當中指定控件的屬性在給定時間點的更改——換句話說,它們與位置關鍵幀相似,但做用於屬性而不是位置。
上面的例子經過在 MotionScene 文件中添加 KeyAttribute 元素來實現:
<KeyFrameSet>
<KeyAttribute android:scaleX="2" android:scaleY="2" android:rotation="-45" motion:framePosition="50" motion:target="@id/button" />
</KeyFrameSet>
複製代碼
相比於KeyPostion
,咱們須要指定framePosition
(關鍵幀應用時機)和目標(哪一個對象受到影響)。
一些你開箱即用的 View 屬性:
android:visibility
, android:alpha
, android:elevation
, android:rotation
, android:rotationX
, android:rotationY
, android:scaleX
, android:scaleY
, android:translationX
, android:translationY
, android:translationZ
受到應用程序的 SDK level 限制,其中一些屬性將不起做用:
android:elevation
android:translationZ
你能夠經過添加 <CustionAttribute>
子節點在 ConstraintSets 和 KeyAttribute 節點中聲明自定義屬性。這個節點須要一個屬性名(attributeName
),它是getter/setter
的名稱(除去set/get前綴)和要傳入或使用的值類型,屬性類型指定爲下方其中一個:
customColorValue
: 顏色值customColorDrawableValue
: 顏色值 DrawablecustomIntegerValue
: IntegercustomFloatValue
: FloatcustomStringValue
: StringcustomDimension
: 尺寸customBoolean
: Boolean舉例,這面是對應上面動畫的 XML:
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/button" ...>
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/button" ...>
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF"/>
</Constraint>
</ConstraintSet>
複製代碼
本文介紹了 MotionLayout 中 最多見的關鍵幀和路徑規範。咱們將在本系列的第五部分討論 循環(KeyCycle)和 週期(KeyTimeCycle),它們介紹了一種很是強大的方法,能夠將擾動(相似波形)添加到屬性(基於路徑或基於時間),容許各類有趣但可預測的循環效果(反彈(bounce)、抖動(shaking)、脈動(pulsations)等)。
使用 MotionLayout 的各類示例能夠在 ConstraintLayout examples github repository查看。