MotionLayout
是一种布局类型,可帮助您管理应用中的运动和小部件动画。MotionLayout
是 ConstraintLayout
的子类,并构建在其丰富的布局功能之上。作为 ConstraintLayout
库的一部分,MotionLayout
可作为支持库使用。
MotionLayout
弥合了布局转换和复杂运动处理之间的差距,提供了 属性动画框架、TransitionManager
和 CoordinatorLayout
之间功能的混合。
除了描述布局之间的转换外,MotionLayout
还允许您为任何布局属性设置动画。此外,它本身支持可寻址转换。这意味着您可以根据某些条件(例如触摸输入)立即显示转换中的任何点。MotionLayout
还支持关键帧,使您可以完全自定义转换以满足您的需求。
MotionLayout
完全是声明性的,这意味着您可以用 XML 描述任何转换,无论多么复杂。
设计注意事项
MotionLayout
用于移动、调整大小和为用户交互的 UI 元素(如按钮和标题栏)设置动画。不要在您的应用中将运动用作无端的特殊效果。使用它来帮助用户了解您的应用正在做什么。有关使用运动设计应用的更多信息,请参阅 Material Design 部分 了解运动。
开始使用
请按照以下步骤开始在您的项目中使用 MotionLayout
。
-
添加
ConstraintLayout
依赖项:要在您的项目中使用MotionLayout
,请将ConstraintLayout
2.0 依赖项添加到应用的build.gradle
文件中。如果您使用的是 AndroidX,请添加以下依赖项Groovy
dependencies { implementation "androidx.constraintlayout:constraintlayout:2.2.0-beta01" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01" }
Kotlin
dependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.0-beta01") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01") }
-
创建
MotionLayout
文件:MotionLayout
是ConstraintLayout
的子类,因此您可以通过替换布局资源文件中的类名称将任何现有的ConstraintLayout
转换为MotionLayout
,如以下示例所示AndroidX
<!-- before: ConstraintLayout --> <androidx.constraintlayout.widget.ConstraintLayout .../> <!-- after: MotionLayout --> <androidx.constraintlayout.motion.widget.MotionLayout .../>
支持库
<!-- before: ConstraintLayout --> <android.support.constraint.ConstraintLayout .../> <!-- after: MotionLayout --> <android.support.constraint.motion.MotionLayout .../>
这是一个
MotionLayout
文件的完整示例,它定义了图 1 中显示的布局AndroidX
<?xml version="1.0" encoding="utf-8"?> <!-- activity_main.xml --> <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" /> </androidx.constraintlayout.motion.widget.MotionLayout>
支持库
<?xml version="1.0" encoding="utf-8"?> <!-- activity_main.xml --> <android.support.constraint.motion.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" /> </android.support.constraint.motion.MotionLayout>
-
创建 MotionScene:在前面的
MotionLayout
示例中,app:layoutDescription
属性引用了运动场景。运动场景是一个 XML 资源文件。在其<MotionScene>
根元素内,运动场景包含对应布局的所有运动描述。为了使布局信息与运动描述分开,每个MotionLayout
都引用一个单独的运动场景。运动场景中的定义优先于MotionLayout
中的任何类似定义。这是一个运动场景文件示例,它描述了图 1 中的基本水平运动
<?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>
请注意以下几点
-
<Transition>
包含运动的基本定义。-
motion:constraintSetStart
和motion:constraintSetEnd
是对运动端点的引用。这些端点在运动场景后面的<ConstraintSet>
元素中定义。 -
motion:duration
指定运动完成所需的时间(以毫秒为单位)。
-
-
<OnSwipe>
允许您为运动创建触摸控制。-
motion:touchAnchorId
指的是用户可以滑动和拖动的视图。 -
motion:touchAnchorSide
表示视图从右侧被拖动。 -
motion:dragDirection
指的是拖动的进度方向。例如,motion:dragDirection="dragRight"
表示当视图向右拖动时进度会增加。
-
-
<ConstraintSet>
用于定义描述运动的各种约束。在此示例中,为运动的每个端点定义了一个<ConstraintSet>
。这些端点使用app:layout_constraintTop_toTopOf="parent"
和app:layout_constraintBottom_toBottomOf="parent"
垂直居中。在水平方向上,端点位于屏幕的最左侧和最右侧。
有关运动场景支持的各种元素的更详细介绍,请参阅 MotionLayout 示例。
-
插值属性
在运动场景文件中,ConstraintSet
元素可以包含在转换期间插值的附加属性。除了位置和边界之外,MotionLayout
还插值以下属性
alpha
visibility
elevation
rotation
、rotationX
、rotationY
translationX
、translationY
、translationZ
scaleX
、scaleY
自定义属性
在 <Constraint>
内,您可以使用 <CustomAttribute>
元素指定不简单地与位置或 View
属性相关的属性的转换。
<Constraint android:id="@+id/button" ...> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60"/> </Constraint>
<CustomAttribute>
包含两个它自己的属性
motion:attributeName
是必需的,并且必须与具有 getter 和 setter 方法的对象匹配。getter 和 setter 必须匹配特定的模式。例如,backgroundColor
受支持,因为视图具有底层的getBackgroundColor()
和setBackgroundColor()
方法。- 您必须提供的另一个属性基于值类型。从以下支持的类型中选择
motion:customColorValue
用于颜色motion:customIntegerValue
用于整数motion:customFloatValue
用于浮点数motion:customStringValue
用于字符串motion:customDimension
用于尺寸motion:customBoolean
用于布尔值
在指定自定义属性时,在开始和结束 <ConstraintSet>
元素中定义端点值。
更改背景颜色
基于前面的示例,假设您希望视图的颜色作为其运动的一部分发生变化,如图 2 所示。
向每个 ConstraintSet
元素添加 <CustomAttribute>
元素,如以下代码片段所示
<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>
其他 MotionLayout 属性
除了前面示例中的属性外,MotionLayout
还有一些您可能想要指定的其他属性
app:applyMotionScene="boolean"
指示是否应用运动场景。此属性的默认值为true
。app:showPaths="boolean"
指示是否在运动运行时显示运动路径。此属性的默认值为false
。app:progress="float"
允许您显式指定转换进度。您可以使用从0
(转换的开始)到1
(转换的结束)的任何浮点值。app:currentState="reference"
允许您指定特定的ConstraintSet
。app:motionDebug
允许您显示有关运动的更多调试信息。可能的值为"SHOW_PROGRESS"
、"SHOW_PATH"
或"SHOW_ALL"
。
其他资源
有关 MotionLayout
的更多信息,请参阅以下资源
- Kotlin 中的高级 Android 03.2:使用 MotionLayout 进行动画
- MotionLayout 示例
- GitHub 上的 MotionLayout/ConstraintLayout 示例
- MotionLayout 简介(第一部分)
- MotionLayout 简介(第二部分)
- MotionLayout 简介(第三部分)
- MotionLayout 简介 (第四部分)