原文連接: Introduction to MotionLayout (part II)php
這是系列文章「MotionLayout 介紹」的 part II。閱讀以前請先查看 part I! (中文點這)android
在文本中,咱們將繼續經過各類示例揭露基本的 MotionLayout 特性,介紹自定義屬性 (custom attribute)、圖像操做 (image operations) 和關鍵幀 (keyframes)。git
在part I的最後,咱們建立了一個引用MotionScene
的MotionLayout
(self-contained MotionScene)。咱們能夠進一步利用它,來實現其餘屬性的過渡。github
事實上,最初的ConstraintSet
只封裝了佈局規則;可是爲了豐富動畫效果,咱們常常須要作些別的事(好比背景顏色)。在 ConstraintLayout 2.0,ConstraintSet
也能夠存儲自定義屬性狀態。查看下方動畫,背景顏色跟着移動過程發生了改變。app
之前,你不得不在代碼中處理此問題。如今,你能夠直接經過 XML 指定屬性:ide
<Constraint android:id="@+id/button" ...>
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/>
</Constraint>
複製代碼
這是這個動畫修改後的MotionScene
文件工具
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@+id/start" motion:duration="1000" motion:interpolator="linear">
<OnSwipe motion:dragDirection="dragRight" motion:touchAnchorId="@+id/button" motion:touchAnchorSide="right" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF" />
</Constraint>
</ConstraintSet>
</MotionScene>
複製代碼
自定義屬性是用屬性名字 (attributeName) 來指定的,屬性名字須要和對象中的getter/setter
方法對應:佈局
getName
(e.g. getBackgroundColor)setName
(e.g. setBackgroundColor)另外還須要指定屬性值的類型:post
customColorValue
customIntegerValue
customFloatValue
customStringValue
customDimension
customBoolean
最後當咱們定義一個自定義屬性,你須要同時定義開始 (start) 和結束 (end) 的ConstraintSet
動畫
當咱們處理複雜的過渡時,經常須要對圖像進行一些操做,而且對他們進行動畫處理。ConstraintLayout2.0 引入了名爲 ImageFilterView (繼承與AppCompatImageView)的一個有用的工具類來輕鬆實現這一點。
下面是咱們在兩張圖片之間作的淡入淡出 (cross-fade) 效果:
首先咱們須要建立一個包含 ImageFilterView 的 MotionLayout 文件。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/motionLayout" app:layoutDescription="@xml/scene_04" android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.constraint.utils.ImageFilterView android:id="@+id/image" android:background="@color/colorAccent" android:src="@drawable/roard" app:altSrc="@drawable/hoford" android:layout_width="64dp" android:layout_height="64dp"/>
</android.support.constraint.motion.MotionLayout>
複製代碼
它與 ImageView 的主要區別在於altSrc
屬性
<android.support.constraint.image.ImageFilterView android:id="@+id/image" ... android:src="@drawable/roard" app:altSrc="@drawable/hoford"/>
複製代碼
在MotionScene 文件中使用對應的淡入淡出屬性(crossfade
)
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@+id/start" motion:duration="1000" motion:interpolator="linear">
<OnSwipe motion:dragDirection="dragRight" motion:touchAnchorId="@+id/image" motion:touchAnchorSide="right" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="crossfade" motion:customFloatValue="0" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="crossfade" motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
</MotionScene>
複製代碼
ImageFilterView 也提供了更多的功能:
飽和度 saturation : 0 = grayscale, 1 = original, 2 = hyper saturated 對比度 contrast : 1 = unchanged, 0 = gray, 2 = high contrast 色溫 warmth : 1 = neutral, 2 = warm (red tint), 0.5 = cold (blue tint) 淡入淡出 crossfade (with
app:altSrc
)
這裏有另一個例子顯示怎麼使用濾鏡飽和度:
簡單的指定自定義屬性就能夠操做飽和度:
<CustomAttribute motion:attributeName="saturation" motion:customFloatValue="1" />
複製代碼
這裏是這個例子使用的 MotionLayout 文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/motionLayout" app:layoutDescription="@xml/scene_05" android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.constraint.utils.ImageFilterView android:id="@+id/image" android:src="@drawable/sunset2" android:scaleType="centerCrop" android:layout_width="match_parent" android:layout_height="300dp" />
</android.support.constraint.motion.MotionLayout>
複製代碼
這裏是對應的場景(Scene)文件:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000">
<OnSwipe motion:touchAnchorId="@+id/image" motion:touchAnchorSide="top" motion:dragDirection="dragUp" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/image" android:layout_width="match_parent" android:layout_height="300dp" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="saturation" motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/image" android:layout_width="match_parent" android:layout_height="300dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent">
<CustomAttribute motion:attributeName="saturation" motion:customFloatValue="0" />
</Constraint>
</ConstraintSet>
</MotionScene>
複製代碼
大多數狀況下,MotionLayout 是使用「靜止狀態」 (resting states) 的 ConstraintSets 實現的。這種方式下,咱們知道最終的佈局結果將適應不一樣的屏幕尺寸:從本質上來講,MotionLayout的表現像一個典型的 ConstraintLayout。
原文:The general idea for MotionLayout is that 「resting states」 are implemented as ConstraintSets. This way, we know that the resulting layouts will correctly adapt to different screen sizes: essentially, MotionLayout will behave like a typical ConstraintLayout.
在某些狀況,你可能但願有一箇中間狀態——一個要通過的狀態(a state to go through),而不是要停留的狀態(not a state to stay in)。固然你能夠指定兩個以上的 ConstraintSets 來解決,可是更好的作法是使用 Keyframes。
關鍵幀能夠應用於位置或屬性值。它們主要讓你在轉換期間指定一個時間節點上的改變。
舉個栗子,你可能想讓一個控件在過渡進行到 25% 的時候轉換變成紅色。或者在過渡中的 50% 時,改成向上移動。
有多種設置位置關鍵幀 (KeyPosition) 的方法 (pathRelative、deltaRelative、parentRelative),咱們將在本系列的第4部分詳細介紹。
簡單介紹位置關鍵幀 (position keyframes),這裏指定了在過渡進行到 50% 的時候,位置在屏幕高度的 25%處。
<Transition ...>
<KeyFrameSet>
<KeyPosition motion:keyPositionType="parentRelative" motion:percentY="0.25" motion:framePosition="50" motion:target="@+id/button"/>
</KeyFrameSet>
</Transition>
複製代碼
最終的效果以下:
和以往同樣,MotionLayout 文件仍然很是簡單:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/motionLayout" app:layoutDescription="@xml/scene_06" android:layout_width="match_parent" android:layout_height="match_parent">
<View android:id="@+id/button" android:background="@color/colorAccent" android:layout_width="64dp" android:layout_height="64dp" />
</android.support.constraint.motion.MotionLayout>
複製代碼
MotionScene 文件與咱們以前看到的很是類似,只是添加了一個KeyPosition
元素:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000" motion:interpolator="linear">
<OnSwipe motion:touchAnchorId="@+id/button" motion:touchAnchorSide="right" motion:dragDirection="dragRight" />
<KeyFrameSet>
<KeyPosition motion:keyPositionType="parentRelative" motion:percentY="0.25" motion:framePosition="50" motion:target="@+id/button"/>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF"/>
</Constraint>
</ConstraintSet>
</MotionScene>
複製代碼
相似位置關鍵幀,你能夠在過渡中的特定的指定屬性值(使用KeyAttribute
)。
例如,咱們可能須要操縱對象在 50% 位置的時候,指定執行縮放和旋轉,效果以下:
這能夠經過在KeyFrameSet
中添加一個KeyAttribute
元素來實現:
<KeyFrameSet>
<KeyAttribute android:scaleX="2" android:scaleY="2" android:rotation="-45" motion:framePosition="50" motion:target="@id/button" />
</KeyFrameSet>
複製代碼
MotionLayout 文件與前一個例子相同,惟一不一樣的是 MotionScene 文件中添加了KeyAttribute
:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000" motion:interpolator="linear">
<OnSwipe motion:touchAnchorId="@+id/button" motion:touchAnchorSide="right" motion:dragDirection="dragRight" />
<KeyFrameSet>
<KeyAttribute android:scaleX="2" android:scaleY="2" android:rotation="-45" motion:framePosition="50" motion:target="@id/button" />
<KeyPosition motion:keyPositionType="screenRelative" motion:percentY="0.2" motion:framePosition="50" motion:target="@id/button"/>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF"/>
</Constraint>
</ConstraintSet>
</MotionScene>
複製代碼
第二章介紹了 MotionLayout 更高級的功能,給出瞭如何利用自定義屬性和關鍵幀建立更引入注目的動畫示例。
你能夠在ConstraintLayout examples github repository查看這些示例的源碼。
在本系列文章中還有更多內容: