背景
MotionLayout的设计是为了连接布局过渡与复杂的手势处理。你可以把它想象成属性动画框架、过渡动画管理和CoordinatorLayout三种能力集于一身的框架。
它可以能够描述两个布局之间的过渡( 就像TransitionManager的功能一样),但是它又和TransitionManager不一样的地方在于,在转换的过程中,任何属性都能以动画的形式过渡(不仅仅是已有的属性,自定义属性也可以)。更屌的是,它本身就支持可见的转换,就像CoordinatorLayout一样(这种转换完全由触摸驱动,并且立即转换到任意点)。它支持触摸处理和关键帧(keyFrames),允许开发者非常容易的定制元素之间的过渡。
MotionLayout另一个不同点就是完全是声明式的,你完全可以用xml写一个复杂的转换(如果想用代码,当时也是非常可以的)
MotionLayout非常有特色的将所有的信息保存在了一个独立的XML文件中,保存在XML文件中的信息优先级将会比layout文件中要高。
MotionLayout的限制
MotionLayout只能对其直属的子View提供各种变换功能,这一点相对于可以作用布局层级和Activity之间转换的TransitionManager来说,的确是一个劣势。
MotionLayout官方使用场景
- 平移、缩放、旋转
- 属性动画(支持自定义属性)
- 自定义路径动画
- 配合CoordinatorLayout动画
- 配合DrawLayout
MotionLayout属性
- layoutDescription:动画布局xml引用
- applyMotionScene:布尔类型,表示是否应用 MotionScene,默认值为 true。
- showPaths:布尔类型,表示在运动进行时是否显示运动路径。默认值为 false
- progress:float类型,可以明确指定转换进度(取值0.0~1.0)
- currentState:reference类型,可指定具体的 ConstraintSet
- motionDebug:可显示与运动有关的其他调试信息。可取值有:SHOW_PROGRESS、SHOW_PATH或SHOW_ALL。
运动描述文件详解
描述文件组成元素
<MotionScene>:描述文件的根节点元素。
<ConstraintSet>:声明所有的视图控件在运动过程中,特定关键点的位置和属性。
<Constraint>:声明单个视图控件在运动过程中,特定关键点的位置和属性。
<Transition>:声明运动过程中的开始和结束状态,包括所有预期的过度状态、用户的触发的交互等。
<onClick>:声明当用户触摸特定的视图控件时所要执行的动作。
<onSwipe>:声明当用户在布局中滑动时所要执行的动作。
<KeyFrameSet>:声明在运动过程中视图控件的位置和属性。
<KeyPosition>:声明在运动过程中特定时刻视图控件的位置。
<KeyAttribute>:声明在运动过程中特定时刻视图控件的属性。
元素详解
- <MotionScene>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto"
motion:defaultDuration="500">
......
</MotionScene>
<MotionScene>是运动场景文件的根元素,必须包含一个或多个 <Transition> 元素,<Transition>元素用于定义运动序列的开始和结束状态,以及这两种状态之间的转换。
必须包含的元素
<Transition>:指定运动场景需要的动画序列,可以有多个,每一个指定需要执行的运动序列。如果 <MotionScene> 包含多个 <Transition> 元素,MotionLayout 会根据用户的互动选择最合适的 <Transition> 元素,但是要注意防止冲突。
可以包含的元素
<ConstraintSet>:运动的状态布局集,为 <Transition> 元素指定开始或结束状态。 MotionLayout 关联的 <MotionScene>可以没有 <ConstraintSet> 子元素,因为 <Transition>可指向 XML 布局,而不是指向<ConstraintSet>布局集。
属性
- defaultDuration:所有动画的默认持续时间(以毫秒为单位)。用于给未指定持续时间的 <Transition> 指定一个默认的持续时间。
- <ConstraintSet>
<ConstraintSet android:id="@+id/start">
...
</ConstraintSet>
<ConstraintSet> 元素是用来指定视图在动画序列中某一点上的位置和属性(可同时指定多个视图),也叫约束条件集合。通常,一个 <Transition> 元素可指向两个 <ConstraintSet> 元素,其中一个定义动画序列的开始,另一个定义动画序列的结束。
必须包含的元素
<Constraint>:必须包含一个或者多个 <Constraint> 元素,描述动画在特定时刻视图的位置和属性。
属性
- android:id:集合的 ID,在 <Transition> 中通过此 ID 来引用该序列
- deriveConstraintsFrom:(可选)值为另一个 ConstraintSet 的 ID。如果指定这个属性,ID 对应约束集合内的所有约束条件都将应用于此集合,除非此集明确替换它们。
- <Constraint>
<Constraint
android:id="@+id/view"
attributes >
</Constraint>
属性
- android:id:视图 ID,约束视图的 ID ;
- 其他在 ConstraintLayout 中用来约束视图位置的属性;
- <Transition>
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
</Transition>
该元素是用来声明运动过程中的开始和结束状态,包括所有预期的过度状态、用户的触发的交互等。
属性
- motion:constraintSetStart:运动序列的初始状态。可以是 <ConstraintSet> 的 ID (属性值设置为“@+id/constraintSetId”),也可以是布局(属性值设置为"@layout/layoutName”)。
- motion:constraintSetEnd:运动序列的最终状态。可以是 <ConstraintSet> 的 ID (属性值设置为“@+id/constraintSetId”),也可以是布局(属性值设置为"@layout/layoutName”)。
- motion:duration:运动序列的时长(单位:毫秒,可选)。如果未指定,则使用 <ConstraintSet> 元素中的 defaultDuration 属性值。
包含的元素
- <OnClick>:表示运动序列是由用户轻触触发的。
- <OnSwipe>:表示运动序列是由用户滑动触发的。
- <KeyFrameSet>:用于为运动序列中的元素指定一个或多个中间位置或属性设置。
- <OnClick>
<OnClick motion:targetId="@+id/view"
motion:clickAction="transitionToEnd"/>
该元素用于指定当用户点按特定视图时要执行的操作,用于 <Transition> 元素内部,指定当用户点击视图时触发动画序列,在一个 <Transition> 内部只能有一个 <OnClick> 元素。
属性
- motion:targetId:点击的视图的 ID。
- motion:clickAction:点击时触发的操作,enum 类型,可选值有
- <OnSwipe>
<OnSwipe
motion:touchAnchorId="@+id/view"
motion:touchAnchorSide="right"
motion:dragDirection="dragRight"
motion:dragScale="1.1"
motion:maxVelocity="2"
motion:maxAcceleration="3"
motion:onTouchUp="autoComplete"/>
该元素用于指定当用户在不居中滑动时需要执行的操作。动画序列的速度和目标视图的动画,受滑动的速度和方向影响,滑动的速度和方向是通过可选参数配置来控制的。
属性
- motion:touchAnchorId:滑动时需要移动的视图 ID。
- motion:touchAnchorSide:滑动所关联到的目标视图的锚点边,MotionLayout 会尝试在该锚点与用户手指之间保持恒定的距离。(可取值有: left、right、top 和 bottom)。
- motion:dragDirection:用户滑动的方向,如果设定了该值,这个 <OnSwipe> 将仅支持向特定的方向滑动(可取值有:dragLeft、dragRight、dragUp 和 dragDown)
- motion:dragScale:控制目标视图的滑动距离和用户手指滑动距离的相对比例,默认值是1。取值小于1时目标视图的移动速度小于手指滑动速度,取值大于1时目标视图的移动速度大于手指的滑动速度。
- motion:maxVelocity:目标视图的最大速度。
- motion:maxAcceleration:目标视图的最大加速度。
- motion:onTouchUp:触摸收起时的动作,可选值有:stop(停止动画)、autoComplete(自动完成动画)、autoCompleteToEnd(自动完成到结束状态)、autoCompleteToStart(自动完成到开始状态)、decelerate(减速停止动画)、decelerateAndComplete(减速并完成动画)
- <KeyFrameSet>
<KeyFrameSet>
<KeyPosition/>
<KeyAttribute/>
</KeyFrameSet>
前面提到,动画的声明是有 “开始状态” 和 “结束状态” 两个点,目标控件在这两个点之间移动,前面的例子都是直线的动画,显然这个实际使用中需要更复杂的动画。<KeyFrameSet> 就是提供声明更加复杂动画的元素,他声明了动画运动轨迹的关键点集合,它可包含 <KeyPosition> 和 <KeyAttribute>,通过这些元素,可以在动画的 “开始状态” 和 “结束状态” 添加 “中间点”,动画将平滑地移动到每个中间点,完成更复杂的动画。
- <KeyPosition>
<KeyPosition
motion:motionTarget="@id/view"
motion:framePosition="30"
motion:keyPositionType="deltaRelative"
motion:percentX="0.1"
motion:percentY="0.2"/>
该元素用于指定视图在运动过程中,在特定的时刻的位置。换句话说就是运动轨迹上的关键点的位置。在一个 <KeyFrameSet> 中可以添加多个 <KeyPosition> 用来添加多个不同的关键点位置。
属性
- motion:motionTarget:当前关键点位置控制的目标视图的 ID。
- motion:framePosition:关键帧位置,用百分比表示,取值为 0~100 之间的整数。(例如:取值20,表示该关键帧在运动轨迹的 20% 位置处 ),这个点将运动时间一分为二,两边的时间是相等的,如果运动轨迹长度不一样,那么将会造成运动速度不一样。但需要注意的是,关键帧的位置并不是关键点的位置。
- motion:keyPositionType:关键点的类型,不同的类型会对 motion:percentX 和 motion:percentY 的值做出不一样的解析。取值有 parentRelative 、 deltaRelative 和pathRelative。
- motion:percentX:X 轴方向的属性取值百分比,取值范围为0.0~1.0。
- motion:percentY:Y 轴方向的属性取值百分比,取值范围为0.0~1.0。
关键点类型详细说明
- parentRelative :父容器关系型,即关键点的位置是相对于整个父容器中的相对位置来指定,percentX 和 percentY 分别表示 X 轴和Y轴相对位置,取值为 -1.0~1.0(负数时目标视图将移动到父容器外面)。需要注意的是:关键点的位置是相对父容器来指定,跟 “开始点” 和 “结束点” 位置无关。
- deltaRelative:三角区域关系型,在目标视图整个运动序列移动的区域组成一个坐标轴,X 为横轴,Y 为纵轴,原点为 “开始点”,视图移动的方向为坐标的正方向。percentX 和 percentY 分别为 X 轴和 Y 轴上的数值,控制关键点的位置,取值范围是 -1.0 ~ 1.0之间,负数表示在坐标轴的负值方向位置。framePosition 一样控制的是轨迹弧顶的位置。
- pathRelative:路径关系型,即关键点的位置是相对于路径相对指定的,路径是指 “开始点” 和 “结束点” 的直线路径(构成 X 轴),percentX 表示在 X 轴相对位置,0 表示在开始点, 1表示在结束点;percentY 表示垂直于 X 轴(Y 轴)的相对位置,正数在 X 轴左侧,负数在 X 轴右侧。 |percentY 取值范围为-1.0~1.0,Y 轴距离是以 “开始点” 和 “结束点”之间的距离为基数的百分比(也就是说 Y 轴的最大距离就是开始点和结束点直线距离的最大值,如果该值取0,弧度为0,则轨迹为直线)。另外, framePosition 控制的是轨迹弧顶的位置(而不是关键点的位置),大于 50 时偏向起始点,小于50时偏向结束点,弧顶两端轨迹,运动时间是相等的,如果取了不对等的值(非50),就可以实现快慢变化的效果。
- <KeyAttribute>
<KeyAttribute
motion:motionTarget="@+id/view"
motion:framePosition="50"/>
- android:alpha:视图的透明度
- android:elevation:视图的 Z 轴深度(在 API Level 21开始才有,像素单位,如dp)
- android:rotation:视图的旋转角度(默认方向)
- android:rotationX:视图 X 轴方向旋转角度
- android:rotationY:视图 Y 轴方向旋转角度
- android:scaleX:视图 X 轴方向缩放
- android:scaleY:视图 Y 轴方向缩放
- android:translationX:视图 X 轴方向的平移量(像素单位,如dp)
- android:translationY:视图 Y 轴方向的平移量(像素单位,如dp)
- android:translationZ:视图 Z 轴方向的平移量(在 API Level 21开始才有,像素单位,如dp)
- <CustomAttribute>
在 <Constraint> 元素中,您可以使用 <CustomAttribute> 元素设置属性,自定义属性不仅仅可以设置标准属性,也可以设置非标准的相关属性(例如:backgroundColor 背景色),但是必须要注意一点,设置的自定义属性,必须是在 View 中定义了 getter 和 setter 方法的,而且属性值的类型必须准确。
一个 <CustomAttribute> 元素必须包含两个属性:
- motion:attributeName:属性名(必须)
- 必须包含以下含类型的属性值的一个:
motion:customColorValue: 适用于颜色
motion:customIntegerValue:适用于整数
motion:customFloatValue:适用于浮点值
motion:customStringValue:适用于字符串
motion:customDimension:适用于尺寸
motion:customBoolean:适用于布尔值
结语
MotionLayout 在动画处理方面的能力非常强大,完全配置化,如果需要在布局中使用到动画的同学可以试试这个强大的布局。