MotionLayout 是一种布局类型,可帮助您管理应用中的动作和微件动画。MotionLayout 是 ConstraintLayout 的子类,在其丰富的布局功能基础之上构建而成。作为 ConstraintLayout 库的一部分,MotionLayout 可用作支持库。
MotionLayout 缩小了布局转换与复杂运动处理之间的差距,同时在属性动画框架、TransitionManager 和 CoordinatorLayout 之间提供了各种功能。
除了描述布局之间的转换之外,MotionLayout 还能够让您为任何布局属性添加动画效果。此外,它本身就支持可搜索转换。也就是说,您可以根据某个条件(例如触控输入)立即显示转换中的任意点。MotionLayout 还支持关键帧,从而实现完全自定义的转换以满足您的需求。
MotionLayout 是完全声明性的,也就是说您可以使用 XML 描述任何转换,无论复杂程度如何。
设计考虑事项
MotionLayout 旨在移动与用户交互的界面元素(例如按钮和标题栏),以及对其调整大小和添加动画效果。请勿在应用中将动作用作无意义的特殊效果。您可以使用它来帮助用户了解您的应用在做什么。如需详细了解如何设计包含动画的应用,请参阅 Material Design 有关了解动画的部分。
开始使用
请按照以下步骤开始在您的项目中使用 MotionLayout。
- 
    添加 ConstraintLayout依赖项:如需在项目中使用MotionLayout,请将ConstraintLayout2.0 依赖项添加到应用的build.gradle文件中。如果您使用了 AndroidX,请添加以下依赖项:Groovydependencies { implementation "androidx.constraintlayout:constraintlayout:2.2.1" // To use constraintlayout in compose implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1" } Kotlindependencies { implementation("androidx.constraintlayout:constraintlayout:2.2.1") // To use constraintlayout in compose implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1") } 
- 
    创建 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属性引用一个 motion scene。运动场景是一个 XML 资源文件。在其<MotionScene>根元素中,动作场景包含相应布局的所有动作描述。为了将布局信息与动作描述分开,每个MotionLayout都引用一个单独的动作场景。MotionScene 中的定义优先于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"垂直居中。 在水平方向上,端点位于屏幕最左侧和最右侧。
 如需详细了解 MotionScene 支持的各种元素,请参阅 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 03.2 进行高级 Android 开发:使用 MotionLayout 实现动画效果
- MotionLayout 示例
- GitHub 上的 MotionLayout/ConstraintLayout 示例
- MotionLayout 简介(第 I 部分)
- MotionLayout 简介(第 II 部分)
- MotionLayout 简介(第 III 部分)
- MotionLayout 简介(第 IV 部分)
 
  