MotionLayout的背景
简介
MotionLayout 提供了一个丰富的动画系统来协调多个视图之间的动画效果。MotionLayout 基于 ConstraintLayout,并在其之上进行了扩展,允许你在多组约束 (或者 ConstraintSets) 之间进行动画的处理。你可以对视图的移动、滚动、缩放、旋转、淡入淡出等一系列动画行为进行自定义,甚至可以定义各个动画本身的自定义属性。它还可以处理手势操作所产生的物理移动效果,以及控制动画的速度。使用 MotionLayout 构建的动画是可追溯且可逆的,这意味着可以随意切换到动画过程中任意一个点,甚至可以倒着执行动画效果。
Android Studio 集成了 Motion Editor (动作编辑器),可以利用它来操作 MotionLayout 对动画进行生成、预览和编辑等操作。这样一来,在协调多个视图的动画时,就可以做到对各个细节进行精细操控。
动画的演进
目前的动画主要分为三种:View动画、属性动画、过渡动画。
View动画 Animation 是在API 1很早就已经出现,但现在也基本比较少使用它们,因为使用属性动画也可以完全实现同样的效果。比如 AlphaAnimation、ScaleAnimation 等。
属性动画是在API 11时出现,是目前最常见和使用的动画,可以很方便的实现控件的透明度、平移、缩放、旋转等动画效果。
过渡动画是在API 18时引入,它主要是用于在两种场景或两种状态之间的切换。
属性动画与过渡动画的对比
先用属性动画实现一个简单的例子,代码如下:
1 | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
1 | final View root = findViewById(R.id.root); |
效果如下所示:

功能非常简单,点击时使用属性动画将ImageView从左边移动到右边,使用属性动画实现这个动画经过了两个步骤:计算图片从左边移动到右边的距离、创建属性动画执行动画。
如果我们想直接通过改变ImageView的属性实现这个效果,代码和效果如下:
1 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) image.getLayoutParams(); |

修改了ImageView的 gravity 属性,但是这样是没有动画效果的,会直接闪现过去,再加上一句代码:
1 | // 添加这句代码,在修改控件参数之前 |
运行程序可以发现实现效果和属性动画一样有了平移动画的效果。通过加上一句 TransitionManager.beginDelayedTransiton() 就实现了过渡动画的平移效果,从一个状态过渡到另一个状态。
下面再看一个例子:
1 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
1 | // 属性动画 |
属性动画效果如下:

过渡动画效果如下:

过渡动画的实现本质可以简单分为两个步骤:
- 定义两个场景之间的过渡,有开始场景和结束场景,会记录两个场景控件的各种参数;
- 创建动画并执行动画,有了上一步记录的控件参数,就可以创建执行动画的参数。
过渡动画的限制
看如下过渡动画的示例:

相关代码如下:
activity_film.xml:
1 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
film_start_scene.xml:
1 | <merge xmlns:android="http://schemas.android.com/apk/res/android" |
film_end_scene.xml:
1 | <merge xmlns:android="http://schemas.android.com/apk/res/android" |
1 | public class FilmActivity extends AppCompatActivity implements View.OnClickListener { |
如果使用之前讲的 TransitionManager.beginDelayedTransition() 实现上面的处理将会是比较麻烦的事情,你需要通过代码对控件各个参数属性进行修改。
这个示例将控件的开始场景和结束场景分别用 film_start_scene.xml 和 film_end_scene.xml 两个布局文件管理,再用 TransitionManager.go() 将场景装载。但缺点也比较明显:
- 每次场景切换都会移除控件替换并需要重新绑定,调用 bindData();
- 场景之间有一些控件参数并不需要但还是要加上。比如结束场景最终展示只需要 FloatinActionButton 、封面 ImageView 和一个背景 View,但还是得加上开始场景那些控件,否则会抛出异常。
有没有一种办法可以实现:既可以在xml添加修改属性管理,又可以不重复绑定添加控件?使用 ConstraintLayout 作为根布局可以解决这个问题。
ConstraintLayout场景过渡
相关代码如下:
activity_start_scene.xml:
1 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
activity_end_scene.xml:
1 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
1 | //关键代码如下: |
实现的效果和上面使用 TransitionManager.go() 相同。
在 ConstraintLayout 通过 ConstraintSet.clone() 后调用 ConstraintSet.applyTo() 就可以实现场景的切换。虽然解决了上面提出的问题,但这种方式实现场景过渡还是不够完美:
- 不能停留在任意位置,applyTo() 设置了结束场景后就只能执行完成;
- 不支持触摸反馈,根据手指的拖动伸缩;
- 定义的两个xml文件有很多重复的控件属性,需要两个xml布局文件放在layout目录管理。
根据上面探讨的问题,能解决这些问题的动画框架 MotionLayout 就诞生了。
MotionLayout场景过渡
下面使用 MotionLayout 实现上面的效果:
1 | <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" |
在 res/xml 目录定义 MotionLayout 使用的动画执行场景:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
效果如下:

第一个实例
MotionLayout 布局必须要有一个MotionScene 文件,需要在 MotionLayout 标签中使用app:layoutDescription配置,如果你忘记配置,Android Sudio 会提示配置,按照提示会自动创建 MotionScene 文件并配置。
选择创建后,会在res/xml文件夹下生成.xml(我的名字是activity_motionlayout_scene)文件。类似如下代码:
1 |
|
根标签MotionScene有一个defaultDuration属性,表示所有未指定时间的动画的默认时间,默认为300毫秒。
此时在布局文件中的MotionLayout标签会多一个layoutDescription=”@xml/aactivity_motionlayout_scene”属性。
在布局文件中增加一个id 为view_start_status的正方形View。并在根标签MotionLayout添加showPaths=”true”属性,用来显示正方形运动的路径。代码如下:
1 | <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" |
将activity_motionlayout_scene.xml文件中Constraint标签的id值修改成正方形的id,即view_start_status。Constraint标签的id属性值需要与开始动画效果的View的id保持一致,这样Constraint标签的所有属性都会作用于该View。Constraint标签的属性与ConstraintLayout的属性是一致的,为此,给正方形开始状态增加一些属性,使其位置水平居中,距离顶部50dp。详细代码如下:
1 | <ConstraintSet android:id="@+id/start"> |
因为id为start的ConstraintSet标签关联到Transition标签的constraintSetStart属性,所以它作为动画(目前只有一个动画)的起始状态。而id为end的ConstraintSet标签关联到Transition标签的constraintSetEnd属性,所以它将作为动画的结束状态。结束状态我们将正方形设置水平居中,距离底部50dp。代码如下:
1 | <ConstraintSet android:id="@+id/end"> |
给Transition标签增加onClick子标签,表示点击触发动画。onClick标签增加clickAction属性,值为toggle,表示重复点击时,动画循环效果;增加targetId属性,值为@id/view_start_status,表示点击正方形视图触发过渡动画。
activity_motionlayout_scene.xml完整代码如下:
1 |
|
运行结果:
标签与属性
Transition标签
Transition标签主要用来指定Motion场景中一个或多个动画。即关联到动画对应的各种状态和用户交互动作,描述两个状态或约束集之间的过渡。
常用属性
- id=”reference” Transition描述的ID;
- constraintSetStart=”reference” 使用ConstraintSet描述的用作开始约束或布局文件作为开始约束(例如:@id/start(ConstraintSet描述)或者@layout/start(布局文件)),指定动画初始状态;
- constraintSetEnd=”reference” 使用ConstraintSet描述的用作最终约束或布局文件作为最终约束(例如:@id/end(ConstraintSet描述)或者@layout/end(布局文件)),指定动画结束状态;
- duration=”float” 执行过渡动画所需的时间;
- staggered=”float” 交错移动物体的快速方法;
- autoTransition=”none|jumpToStart|jumpToEnd|animateToStart|animateToEnd” 设置动画自动执行效果,无需用户触发(点击或移动)动画。
- animateToStart 过渡到初始状态、执行过渡动画到开始约束的效果;
- animateToEnd 过渡到结束状态、执行过渡动画到最终约束的效果;
- jumpToEnd 跳到结束状态、直接到最终约束效果;
- jumpToStart 跳到初始状态、直接到开始约束效果;
- none 不开始状态。默认情况下是none,当设为其它值时,不用和用户交互即自动开启动画。
- motionInterpolator=”easeInOut|easeIn|easeOut|linear|bounce” 插值器,取值有linear线性、bounce弹簧、easeIn淡入、easeOut淡出、easeInOut淡入淡出;
- transitionDisable=”boolean” 允许动画功能;
- layoutDuringTransition =”honorRequest|ignoreRequest” 动画过程中,MotionLayout子View调用reqeustLayout,是否做出响应。取值honorRequest响应、ignoreRequest忽略;
用户交互的子标签
Transition标签通过一些子标签,实现与用户交互的行为。例如上文的OnClick子标签表示用户的点击行为。
OnClick标签
点击场景中某个视图,开始动画效果,可选参数,增加了对触发处理的支持。
- targetId=”reference” 设置用来触发过渡动画的 View 的 Id;
- clickAction=”toggle|transitionToEnd|transitionToStart|jumpToEnd|jumpToStart” 点击时视图执行的动作;
- toggle 在 Start 场景和 End 场景之间循环的切换;
- transitionToEnd 过渡到 End 场景;
- transitionToStart 过渡到 Start 场景;
- jumpToEnd 不执行过渡动画跳到 End 场景;
- jumpToStart 不执行过渡动画跳到 Start 场景;
OnSwipe标签
表示在布局上滑动时要执行的操作。可选参数,增加了对触摸处理的支持,一个<Transition> 标签下可以包含多个<OnSwipe>
- touchAnchorId=”reference” 视图的Id,滑动此视图外的区域,能响应滑动效果;
- touchRegionId=”reference” 视图的Id,滑动此视图内的区域,能响应滑动效果;
- touchAnchorSide=”top|left|right|bottom|middle|start|end” 用户滑动界面时MotionLayout将尝试在touchAnchorId指定的视图和手指之间保持一个恒定的距离,而此属性指定的是手指和View的哪一侧保持恒定的距离(left、right、top、buttom);
- maxVelocity=”float” 目标视图的最大速度,单位为秒,当滑动一定速度,目标视图会按照惯性继续运作,进行先加速后减速运行(默认情况)。如果视图运动过程中加速到了我们设置的最大值,那么就是先加速,然后按最大速度匀速运动,最后再减速运动;
- dragDirection=”dragUp|dragDown|dragLeft|dragRight|dragStart|dragEnd” 滑动的方向,设置之后只会在特定的方向生效;
- dragUp(手指从下往上拖动(↑))
- dragDown(手指从上往下拖动(↓))
- dragLeft(手指从右往左拖动(←))
- dragRight(手指从左往右拖动(→))
- maxAcceleration=”float” 目标视图的最大加速度,如果想让视图运动更快,则加大其值。默认值1.2;
- dragScale=”float” 控制视图相对于滑动长度的移动距离。默认值1.0(视图移动的距离应与滑动距离一致),当值小于1时,视图移动的距离会远远小于滑动距离(例如dragScale值为0.5 , 如果滑动了2dp,目标视图会移动1dp),当值大于1时,视图移动的距离会大于滑动距离(例如dragScale值为1.5 , 如果滑动了2dp,目标视图会移动3dp);
- moveWhenScrollAtTop=”boolean” boolean类型,如果滑动是滚动的,并且View(例如RecyclerView或NestedScrollView)同时滚动和过渡;
- onTouchUp=”decelerateAndComplete|decelerate|stop|autoCompleteToEnd|autoCompleteToStart|autoComplete”
- decelerateAndComplete 减速直到最近的状态
- decelerate 减数
- stop 停止动画
- autoCompleteToEnd 自动过渡到结束状态
- autoCompleteToStart 自动过渡到开始状态
- autoComplete 自动过渡到最近的状态
- nestedScrollFlags=”disablePostScroll|disableScroll|none” 嵌套滚动标记;
- limitBoundsTo 编制滑动边缘;
- dragThreshold 触发滑动的门阀,即滑动多长距离才会触发动画;
关键帧子标签
在上文中,默认情况下过渡动画Transition标签会关联一个开始状态和一个结束状态的TransitionSet标签。但Transition标签不仅可以创建初始状态和结束状态,还可以创建中间状态。这些中间状态则由关键帧来构成,以实现更复杂的动画效果。
KeyFrameSet标签用来指定某个中间状态的位置和属性。其实和过渡动画的关键帧是一样的概念。KeyFrameSet标签含有KeyPosition和KeyAttribute两个子标签,这些共同构成过渡动画过程中某特殊状态的位置和属性。
位置关键帧
KeyPosition标签用来定义整个运动动画中某个状态的位置,相比于静态的TransitionSet标签来说,更加灵活。
- motionTarget=”reference” 修改路径的视图id,实现过渡动画的视图id;
- framePosition=”integer” 表示动画的进度,当前关键帧的位置,把整个运动动画分成100个位置,取值0到100(可取负值)时,那么初始状态的位置就是0,结束状态就是100,30就表示动画进度执行30%的地方;
- transitionEasing=”standard|accelerate|decelerate|linear” 使用的插值器,standard标准、accelerate加速、decelerate减速、linear线性;
- pathMotionArc=”none|startVertical|startHorizontal|flip” 动画以弧形运行,需要在起始的 ConstraintSet 也要加入pathMotionArc属性,此时关键帧处加入pathMotionArc也能生效;
- none 直线运行,还原为线性运动;
- startVertical 纵向弧形,沿垂直方向开始弧形运动;
- startHorizontal 横向弧形,沿水平方向开始弧形运动;
- flip 当前弧形翻转,翻转当前的圆弧方向;
正常不添加关键帧,只是控制View的约束位置,不设置其它参数,代码入下:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
执行效果如下直线效果:

此时,在起始的 ConstraintSet 加入 pathMotionArc,代码如下:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
效果如下:


此时加入一个关键帧,代码如下(keyPositionType属性后面说明):
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
效果如下:

在关键帧处设置pathMotionArc=”startHorizontal”,代码入下:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
效果如下:

在关键帧处设置pathMotionArc=”none”:

在关键帧处设置pathMotionArc=”flip:

- keyPositionType=”deltaRelative|pathRelative|parentRelative” 参考坐标系的选择,决定了percentX和percentY属性取值的结果。
parentRelative
相对父容器。表示坐标系基于父视图,看如下代码:
1 | <KeyFrameSet> |

左图为相对与MotionLayout布局建立坐标系,可以看出实际的P点与坐标系中坐标相交点略微偏差。那是因为建立坐标系需要依赖视图本身的中心点为依据,如果你的视图足够小,小到为一个点,此时这种坐标系就是左图情况。而实际上视图不可能那样小,实际状况如右图,依赖控件本身的中心点建立坐标系,此时的P点正好为坐标系中的位置。
deltaRelative
三角定位。
1 | <KeyFrameSet> |

此方式是以动画起始状态视图中心点为坐标系(0,0)点,动画结束状态为(1,1)建立坐标系,p点为设置的percentX、percentY具体坐标。
pathRelative
相对路径。
1 | <KeyFrameSet> |

此方式为以动画起始状态视图中心点(0,0),动画结束状态视图中心点(1,0)建立x轴,x顺时针90度建立y轴,y轴1.0长度与x轴相同,长度都等于路径的长度,此时y轴就有正负之分。p点为设置的percentX、percentY具体坐标。
- percentX=”float” 相对参考系的横向的比例(0-1);
- percentY=”float” 相对参考系的纵向的比例(0-1) ;
- sizePercent=”float” 如果视图更改大小,则这将控制大小的增长方式。(对于固定大小的对象,请使用
scaleX / Y);
例如设置一个约束起始宽度、高度为50dp ,终止宽度、高度为100dp,代码如下:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
如果不设置sizePercent比例效果如下:

如果设置sizePercent为0.3,代码如下:
1 | <KeyPosition |
效果如下:

如果设置sizePercent为0.9,效果如下:

- 宽度变化的百分比,如果宽度没有变化,则此属性无效。将会覆盖sizePercent。
例如设置一个约束起始宽度为50dp ,终止宽度为100dp,代码如下:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
如果不设置percentWidth比例效果如下:

如果设置percentWidth为0.3,代码如下:
1 | <KeyPosition |
效果如下:

如果设置percentWidth为0.9,效果如下:

- percentHeight=”float” 高度变化的百分比,如果高度没有变化,则此属性无效。percentWidth和percentHeight属性都会导致sizePercent属性失效。具体效果同percentWidth。
- curveFit=”spline|linear” 设置动画运动路径,spline(曲线,默认)、linear(直线)
如果不设置curveFit属性或设置curveFit=”spline”(它将是曲线运行)
代码如下:
1 | <KeyPosition |
效果如下:

如果设置curveFit=“linear”(它将是直线运行)
代码如下:
1 | <KeyPosition |
效果如下:

- drawPath=”none|path|pathRelative|deltaRelative|asConfigured|rectangles” 调试使用,绘制布局动画路径及参考线。
例如设置drawPath=”pathRelative”代码如下:
1 | <KeyPosition |
效果如下:

设置drawPath=”rectangles”效果如下:

设置drawPath=”deltaRelative”效果如下:

属性关键帧
KeyAttribute相对于位置关键帧,属性关键帧更注重的是属性,在动画期间控制布局属性,例如实现View在移动过程中自身的缩放、透明度、旋转等属性的改变。
基本属性
如下代码:
1 | <KeyFrameSet> |
效果如下:

- motionTarget=”reference” 修改属性的视图id;
- framePosition=”integer” 表示动画的进度;
- transitionEasing 动画速度;
- curveFit 选择基于直线的路径或基于单一速率的路径;
- motionProgress 设置动画进度;
- scaleX=”float” 视图的宽度变化比例,X轴缩放;
- scaleY=”float” 视图的高度变化比例,Y轴缩放;
- rotation=”float” 视图旋转的角度(以度为单位);
- rotationX 视图绕x轴旋转的角度(以度为单位);
- rotationY 视图绕y轴旋转的角度(以度为单位);
- transformPivotX 旋转或缩放的中心点X坐标;
- transformPivotY 旋转或缩放的中心点Y坐标;
- alpha=”float” 视图的透明度变化(0-1)
- elevation=”dimension” 视图基于Z轴的高度;
- translationX=”dimension” 视图在X轴上位移的距离;
- translationY=”dimension” 视图在Y轴上位移的距离;
- translationZ=”dimension” 视图在Z轴上位移的距离。
自定义属性
CustomAttribute标签必须通过attributeName属性指定一个属性名,通过反射调用设置的“名称”方法。
例如在关键帧处改变背景色,代码如下:
1 | <KeyFrameSet> |
效果如下:

- attributeName=”string” 属性的名称,区分大小写(BackgroundColor将寻找方法setBackgroundColor(…));
- customColorValue=”color” 反射的属性为一个颜色值的属性;
- customColorDrawableValue 颜色值的Drawable类型;
- customIntegerValue=”integer” 反射的属性为一个integer值的属性;
- customFloatValue=”float” 反射的属性为一个float值的属性;
- customStringValue=”string” 反射的属性为一个string值的属性;
- customDimension=”dimension” 反射的属性为一个dimension值的属性;
- customPixelDimension Pixel尺寸类型;
- customBoolean=”boolean” 反射的属性为一个boolean(true/false)值的属性;
KeyCycle
控制动画过程中做周期性。
例如实现View在移动动画使用正弦函数模式进行属性改变:
1 | <KeyFrameSet> |
效果如下:

- motionTarget=”reference” 修改属性的视图id;
- framePosition=”integer” 表示动画的进度,当前关键帧的位置,把整个运动动画分成100个位置,取值0到100(可取负值)时,那么初始状态的位置就是0,结束状态就是100,30就表示动画进度执行30%的地方;
- waveOffset=”float” 偏移值已添加到属性;
- wavePeriod=”float” 在该区域附近循环的循环数;
- waveShape=”sin|square|triangle|sawtooth|reverseSawtooth|cos|bounce” 产生设置的波的形状,如上面的正弦波;
下面是其它的波形效果图:






常用相关属性参数及<CustomAttribute> 参考 <KeyAttribute> 即可。
KeyTimeCycle
控制动画在帧上做周期性,例如在View未移动时也显示周期性动画,当View移动时同时也执行周期性动画,代码如下:
1 | <KeyFrameSet> |
效果如下:

- rotation=”float” 视图旋转的角度(以度为单位);
- wavePeriod=”float” 在该区域附近循环的循环数;
- motionTarget=”reference” 修改属性的视图id;
- framePosition=”integer” 表示动画的进度,取值范围为[0,100]。50就表示动画进度执行50%的地方;
其它参数同<KeyCycle>
KeyTrigger
在动画过程中的固定点触发回调到代码中,例如在动画执行过程中,监听动画执行进度,类似如下效果:

实现步骤:
1、定义KeyTrigger:
1 | <KeyFrameSet> |
- motionTarget=”reference” 目标视图id(这里是自定义视图,因为方法写在了自定义视图里);
- framePosition=”integer” 表示动画的进度,取值范围为[0,100]。50就表示动画进度执行50%的地方
- onCross=”string” 方法名称,与自定义视图中方法名一一对应。不管动画是正向还是反向,只要到达设置的framePosition 就会执行函数;
- onPositiveCross=”string” 方法名称,与自定义视图中方法名一一对应。只有正向执行动画是到达设置的framePosition 才会执行函数;
- onNegativeCross=”string” 方法名称,与自定义视图中方法名一一对应。只有反向执行动画是到达设置的framePosition 才会执行函数;
三者效果如下所示:

- triggerSlack=”float” 如果动画位置未离开framePosition触发点,则不会重复调用触发器(值越大重复率越低);
- triggerId=”reference” 使用此ID回调TransitionListener监听中的onTransitionTrigger中方法;
2、自定义视图:
代码如下:
1 | public class MyText extends AppCompatTextView { |
3、使用自定义视图:
1 | <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" |
ConstraintSet标签
描述约束集,约束集主要用来定义多个属性集合,并通过id被Transition标签引用,作为运动动画过程的起始或结束状态。
Constraint标签
在 MotionLayout 配置文件中,可以将 Constraint 理解为在对应 ConstraintSet 场景下的View控件,只是在配置文件中是不会认ImageView或TextView等等,都用 Constraint 代替,类似如下代码:
1 | <MotionScene> |
Layout标签
Layout 是 Constraint 的子节点,主要是声明控件的布局属性。
1 | <MotionScene> |
相比直接将布局属性写在 Constraint 节点,使用 Layout 会更加合理。
Motion标签
Motion 是 Constraint 的子节点,可以指定控件的运动轨迹,默认是直线运动轨迹,通过它可以很方便的将运动轨迹修改为曲线。
1 | <MotionScene> |
相关属性详见位置关键帧一节。
CustomAttribute标签
CustomAttribute 是 Constraint 的子节点,在该节点声明控件背景、文本颜色等其他自定义属性。
1 | <MotionScene> |
相关属性详见自定义属性一节。
Transform标签
Transform 是 Constraint 的子节点,可以指定从开始场景到结束场景之间添加动画效果,比如缩放、旋转等。
1 | <MotionScene> |
相关属性详见属性关键帧中的基本属性。
代码如下:
1 | <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" |
效果如下:

MotionLayout常用API
- setDebugMode(int debugMode) 设置运动进行时是否显示运动路径,用来调试动画,与MotionLayout xml中app:motionDebug对应,在xml 也可以使用app:showPaths=”true”来控制是否显示运动路径;
代码中设置可选参数如下:
1 | public static final int DEBUG_SHOW_NONE = 0;//不显示路径及进度 |
xml设置可选参数如下:
1 | <enum name="NO_DEBUG" value="0"/>//不显示路径及进度 |
- loadLayoutDescription(int motionScene) 通过代码加载MotionScene,对应的xml中属性为app:layoutDescription;
- transitionToStart() 切换到动画start状态,默认有过渡效果,如果不需要过渡效果,可以通过setProgress(0);
- transitionToEnd() 切换到动画end状态,默认有过渡效果,如果不需要过渡效果,可以通过setProgress(1);
- setProgress(float pos) 设置动画运动进度(0-1);
- transitionToState(int id) 切换到动画某个状态,可以是start或end状态,参数id指的是ConstraintSet标签定义的id;
- setTransitionListener(MotionLayout.TransitionListener listener) 监听MotionLayout动画执行过程,如下代码所示:
1 | public interface TransitionListener { |
使用AndroidStudio中Motion Editor
预览面板
Motion Editor(Android Studio 4.0 +) 是一款专门针对 MotionLayout 布局类型所构建的可视化编辑器,通过它可以轻松地创建和预览动画效果。当你在一个包含 MotionLayout 的 XML 文件中选择 Design 或 Split 视图时,AndroidStudio 会自动打开 Motion Editor。你可以使用已在布局编辑器中所熟知的交互方式来编辑布局和 Motion Scene 文件,并可以直接在 Android Studio 预览界面中对动画效果进行预览。

预览面板的加入使得在处理动画效果时,能够实现快速编辑并立即获取反馈,当你对动画进行细微调整之后,不用再去重新编译和部署,也能直接预览最终的动画效果。
概览面板
MotionLayout 可以对布局的变化做动画处理,在编辑器中该动画可被指定为 ConstraintSets 中的 Transition 效果,Motion Editor 可以通过概览面板将这些状态的转变可视化(预览面板),要编辑 ConstraintSet 中的约束,点击概览面板中相应的选项即可。

图中start、end是两个<ConstraintSet> ,它们之间有一个<Transition> 效果,可以通过选择start、end来修改视图的状态。
选择面板
选择面板会根据概览面板中的状态显示相应的控件信息,它有三种显示模式。
选中概览面板中 MotionLayout 时的模式:Motion Editor 支持编辑基本的 MotionLayout,当在概览面板中选中 MotionLayout模式之后,你可以选择相应的组件来查看它的约束是否配置正确。

选中概览面板中 ConstraintSet 时的模式:当在概览面板中选中 ConstraintSet 时,选择面板会以列表的形式列出所有组件,组件旁边的选中图标意味着该组件被当前的 ConstraintSet 所约束(下图选中的是start,也可以选end)。

选中概览面板中 Transition 时的模式:当在概览面板中选择 Transition 时,你可以通过动画工具栏来控制动画的播放。当选中某个动画后,点击时间轴上的 ▶按钮,可以预览动画效果。

当在概览面板中选择 Transition 时,你可以通过工具栏中添加关键帧来添加关键帧约束:

属性面板
这里的属性面板同 Layout Editor 的属性面板类似,可以在这里对Constraint 的可视化效果进行预览,对Motion Scene 文件中视图的所有属性效果进行修改和添加。
当选择概览面板的 ConstraintSet 时,选择面板会以列表的形式列出所有组件,选择具体组件,这时属性面板会展示组件基础可选修改选项供修改或添加。

当选择概览面板的 Transition 时,此时属性面板展示<Transition>基础可选属性选项,供修改或添加,下方的选择面板会以列表的形式列出所有动画,选择具体动画,这时属性面板会展示动画基础可选属性选项,供修改或添加。

参考资料:
谷歌开发者 Constraint Layout 2.0 用法详解
新小梦 Constraintlayout 2.0:你们要的更新来了
zping0808 ConstraintLayout2.x使用详解
VincentWei95 MotionLayout