MotionLayout 是 ConstrainLayout 2.0 庫中被引入的一個新類扁远,幫助安卓開發(fā)者關(guān)聯(lián)手勢和組件動畫。接下來的文章將介紹會如何在應(yīng)用中添加和使用 MotionLayout 驶鹉。
第一章將介紹MotionLayout的基礎(chǔ):
- MotionLayout 是什么?
- 將 ConstrainLayout 2.0 和 MotionLayout 添加到項目中
- 如何使用 MotionLayout
- ConstraintSets
- MotionScene
- 示例1: 關(guān)聯(lián)已有的布局文件
- 處理 OnSwipe
- 示例2: 自包含的 MotionScene
- MotionLayout 屬性
- 總結(jié)
你可以在這里查看示例的源碼 ConstraintLayout examples github repositor
MotionLayout 是什么榨呆?
安卓系統(tǒng)框架中已經(jīng)提供下面幾種方法在應(yīng)用中使用動畫:
- Animated Vector Drawable
- Property Animation framework
- LayoutTransition animations
- Layout transitions with TransitionManager
- CoordinatorLayout
這一部分將介紹 MotionLayout 與這些動畫的不同倦炒。
MotionLayout 就像它的名字一樣,首先它是一個布局刁卜,可以放置組件志电。其次它還是 ConstrainLayout 的子類,內(nèi)置豐富的功能蛔趴。
創(chuàng)建 MotionLayout 的目的是用于降低布局過渡動畫和復(fù)雜的手勢處理之間的難度挑辆,你可以認為它擁有綜合屬性動畫,TransitionManager, 和 CoordinatorLayout 的功能夺脾。
它擁有綜合屬性動畫之拨,TransitionManager, 和 CoordinatorLayout 的功能
使用 MotionLayout 你可以像 TransitionManager 一樣通過兩個布局文件描述布局的過渡動畫,但是可以使用任何屬性(不僅僅局限于 layout attribute). 還有它支持可循跡的過渡咧叭,就像 CoordinatorLayout ( 可以通過滑動即刻響應(yīng)過渡動畫 ) 。它支持通過滑動和關(guān)鍵幀自定義過渡動畫烁竭。
MotionLayout 是完全聲明式的
MotionLayout 的另外一個關(guān)鍵區(qū)別是菲茬,它是完全聲明式的。只需要 XML 文件就可以描述一個復(fù)雜的過渡動畫(如果你像通過代碼來描述動畫,系統(tǒng)提供的屬性完全可以滿足需求)婉弹。
MotionLayout 工具
我們相信這種聲明式的規(guī)范將簡化過渡動畫睬魂,同時也有助于為 Android Studio 提供更好的圖形化工具。(我們現(xiàn)在正在積極的開發(fā)這樣的工具镀赌,它現(xiàn)在還不可用氯哮。)
最后,作為 ConstrainLayout 2.0 的一部分商佛,它最低支持安卓 API 14喉钢,99.8%的設(shè)備都可以使用。
限制
不同于 TransitionManager 良姆,MotionLayout 只能用于他的直接子組件肠虽。
何時使用MotionLayout
我們設(shè)想到的使用 MotionLayout 的使用場景: 當(dāng)你需要移動,縮放或者動畫 實際的 UI 組件 (button玛追,title bar 等) 來提供與用戶的互動時税课。
將 ConstrainLayout 2.0 和 MotionLayout 添加到項目中
只需要將下面的代碼添加到 Gradle 文件中即可
dependencies {
implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta1'
}
如何使用 MotionLayout
MotionLayout 是 ConstrainLayout 的子類,因此你可以把它當(dāng)作一個普通的布局痊剖。 將已經(jīng)存在的 ConstrainLayout 布局轉(zhuǎn)換成 MotionLayout 布局 只需要將類名從:
<android.support.constraint.ConstraintLayout .../>
替換成
<android.support.constraint.motion.MotionLayout .../>
ConstrainLayout 和 MotionLayout 的主要不同是 MotionLayout 不是必須將實際描述信息包含在 XML 布局文件中韩玩。MotionLayout 通常將這些信息保存在一個單獨的 XML 文件 ( MotionScene) 中并關(guān)聯(lián)到布局文件, 通過這種方式布局文件只需要包含 View 和它們的屬性陆馁,無需包含位置信息和動畫啸如。
ConstraintSets
通常 ConstrainSet 將包含布局文件中的所有的位置信息規(guī)則; 你可以使用多個 ConstrainSet, 你可以決定將那些規(guī)則應(yīng)用到布局中氮惯,在應(yīng)用時這些 View 不會被重建叮雳,只會修改他們的位置和大小。結(jié)合 TransitionManager 使用可以很容易的創(chuàng)建 ConstrainLayout 的動畫妇汗。
MotionLayout 實際上也是源于這種思想帘不,并添加了更豐富的功能。
MotionScene
MotionLayout 的規(guī)范保存在一個單獨的 MotionScene XML文件中杨箭,該文件存儲在 res / xml 目錄中寞焙。
一個 MotionScene 文件可以包含動畫所需的所用內(nèi)容:
- 包含的 ConstraintSets
- 這些 ConstraintSet 之間的轉(zhuǎn)換(transition)
- 關(guān)鍵幀, 事件處理
例如互婿,你可以將一個 View 從屏幕的一側(cè)拖拽到另一側(cè):
示例1: 關(guān)聯(lián)布局文件
你需要使用 ConstrainLayout 創(chuàng)建兩個 ConstrainSet 一個是初始位置(組件在屏幕的左面)一個是結(jié)束位置(組件在屏幕的右邊)
初始位置:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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: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:layout_marginStart="8dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
結(jié)束位置:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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: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:layout_marginEnd="8dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
使用這兩個布局文件可以初始化兩個 ConstrainSet 捣郊,并使用他們(如果使用 TransitionManager 會有動畫的平滑過渡)。這種方式有一個問題是轉(zhuǎn)化一旦開始就不會結(jié)束慈参,你也不能告訴系統(tǒng)將轉(zhuǎn)換挺在某個位置 (你不能通過輸入事件控制轉(zhuǎn)換) 呛牲。
MotionLayout 解決了這些問題。你可以使用 MotionLayout 做同樣的事驮配,并且復(fù)用已存在的布局文件來初始化狀態(tài)娘扩。首先需要為組件創(chuàng)建一個 MotionLayout 文件(motion_01_basic.xml ):
<?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:id="@+id/motionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/scene_01"
tools:showPaths="true">
<View
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:background="@color/colorAccent"
android:text="Button"
tools:layout_editor_absoluteX="147dp"
tools:layout_editor_absoluteY="230dp" />
</androidx.constraintlayout.motion.widget.MotionLayout>
布局文件中引用了一個 MotionScene 文件scene_01
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetStart="@layout/motion_01_cl_start"
motion:constraintSetEnd="@layout/motion_01_cl_end"
motion:duration="1000">
<OnSwipe
motion:touchAnchorId="@+id/button"
motion:touchAnchorSide="right"
motion:dragDirection="dragRight" />
</Transition>
</MotionScene>
scene_01
設(shè)置了默認的轉(zhuǎn)換着茸,設(shè)置了開始和結(jié)束 ConstrainSet (motion_01_cl_start
和 motion_01_cl_end
),并為轉(zhuǎn)換設(shè)置了OnSwipe
處理琐旁。
OnSwipe handler
在scene_01.xml
文件中我們在 Transition
中設(shè)置了 OnSwipe
處理器涮阔。處理器通過匹配用戶的輸入事件控制轉(zhuǎn)換。
有一些屬性你需要了解:
touchAnchorId
: 需要跟蹤的對象
touchAnchorSide
: 跟蹤手指的一側(cè)(right / left / top / bottom)
dragDirection
: 跟蹤手指運動的方向 ( dragRight / dragLeft / dragUp / dragDown 將決定進度值的變化0-1)
示例2: 自包含的 MotionScene
示例1展示了如何快速的創(chuàng)建一個 MotionLayout灰殴,最終使用了已存在的布局文件敬特。MotionLayout 還支持直接在 MotionScene 文件中定義 ConstraintSet 。這樣做有有以下好處:
- 一個文件可以包含多個 ConstraintSet
- 除了已有的功能外牺陶,還可以處理其他的屬性和自定義屬性
- 面向未來:即將到來的 Android Studio MotionEditor 可能只支持自包含 MotionScene 文件
插值屬性
MotionScene 文件中 ConstraintSet 元素可以使用的屬性不僅包含常用的布局屬性伟阔,除了位置和邊距下面的屬性也可以在 MotionLayout 中使用:
alpha
visibility
elevation
rotation
,rotation[X
/Y]
translation[X
/Y
/Z]
scaleX
/Y
讓我們?yōu)槭纠?重新創(chuàng)建一個新的自包含的 MotionScene 文件。 MotionLayout 文件除了引用了新的 scene_02.xml
和實例1中沒有區(qū)別:
<?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_02"
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:text="Button" />
</android.support.constraint.motion.MotionLayout>
MotionScene 文件中有明顯的區(qū)別义图, Transition
的設(shè)置相同减俏,但是我們把 Start
和End
直接定義在了 XML 文件中。 和普通布局文件相比主要的區(qū)別是我們沒有指定具體的組件碱工,而是把限定屬性寫在了Constraint
元素中娃承。
<?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/button"
motion:touchAnchorSide="right"
motion:dragDirection="dragRight" />
</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" />
</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" />
</ConstraintSet>
</MotionScene>
ConstraintSet
只需要將了解 ConstrainSet 是如何工作的,新的屬性將替換到關(guān)聯(lián)的組件上怕篷。 只需將需要替換的屬性全部包含到Constraint
中历筝。通常這會清除組件上的所用屬性并將新的屬性賦值到組件上。
MotionLayout 的屬性
在開發(fā)中你可能會用到 MotionLayout 的下列屬性:
app:layoutDescription=”reference” 指定 MotionScene XML 文件
app:applyMotionScene=”boolean” 是否應(yīng)用 MotionScene [default=true]
app:showPaths=”boolean” 是否顯示路徑 [default=false]. 記得在發(fā)布版本中關(guān)閉
app:progress=”float” 指定轉(zhuǎn)換的進度 [0-1]
app:currentState=”reference” 指定一個 ConstraintSet
總結(jié)
第一篇文章包含了 MotionLayout 的基礎(chǔ)功能廊谓, 你可以在這里查看源碼ConstraintLayout examples github repository
接下來的文章中我們將包含更多的講解: