Android MotionLayout详解

    技术2022-07-12  94

    文章目录

    一、前言二、使用入门2.1 引入依赖2.2 创建 MotionLayout 布局文件2.3 创建 MotionScene(运动描述文件)2.4 在 MotionLayout 中配置运动描述2.5 MotionLayout 的属性详解 三、运动描述文件详解3.1 描述文件组成元素3.2 元素详解3.2.1 <MotionScene>必须包含的元素可以包含的元素属性 3.2.2 <ConstraintSet>语法必须包含的元素父元素属性 3.2.3 <Constraint>语法父元素属性 3.2.4 <Transition>语法属性可以包含的元素父元素 3.2.5 <OnClick>语法属性 3.2.6 <OnSwipe>语法属性父元素 3.2.7 <KeyFrameSet>语法父元素可以包含的元素 3.2.8 <KeyPosition>语法属性父元素 3.2.9 <KeyAttribute>语法属性父元素 3.3 设置视图属性3.3.1 <ConstraintSet>插入标准属性3.3.2 <CustomAttribute> 自定义属性 四、编后语

    一、前言

        MotionLayout 其实是一种布局类型,可帮助您管理动画。MotionLayout 是 ConstraintLayout的子类(关于 ConstraintLayout 的介绍可以参考: Android ConstraintLayout从入门到精通),因此, MotionLayout 拥有者 ConstraintLayout 同样强大的布局功能,它是 ConstraintLayout 库的一部分,可向后兼容 API 级别 14,也就是说,只需要引入 ConstraintLayout 的依赖,就可以使用 MotionLayout 了。

        MotionLayout 将布局转换与复杂动画处理结合在一起,同时也在属性动画框架、TransitionManager 和 CoordinatorLayout 之间提供了各种功能。

        除了描述布局之间的转换之外,MotionLayout 还能够为任何布局属性添加动画效果。此外,它本身就支持可搜索转换。也就是说,可以根据某个条件(例如触控输入)立即显示转换中的任意点。MotionLayout 还支持关键帧,从而实现完全自定义的转换以满足您的需求。

        此外,MotionLayout 是完全声明性的,也就是说可以直接使用 XML 描述任何转换,无论复杂程度如何。

    注意:MotionLayout 仅适用于为其直接子级添加动画,不支持嵌套布局层次结构或 Activity 转换。

    二、使用入门

    2.1 引入依赖

        MotionLayout 是 ConstraintLayout 库的一部分,所以,只需要在程序模块的 build.gradle 文件中增加 ConstraintLayout 库的依赖就可以。

    // support包引入,如果项目使用其他support包,使用这个 implementation 'com.android.support.constraint:constraint-layout:1.1.3' // androidx包引入,如果项目使用androidx时使用,跟support包引入只能选其一,否则会冲突 implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7'

    2.2 创建 MotionLayout 布局文件

        前面提到,MotionLayout 是 ConstraintLayout 的子类,所以,直接将布局中的 ConstraintLayout 类接替换成 MotionLayout 也是完全可以的。

    <?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" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" tools:showPaths="true"> <View android:id="@+id/btn6" android:layout_width="100dp" android:layout_height="100dp" android:background="@color/colorAccent" android:text="Button6"/> </androidx.constraintlayout.motion.widget.MotionLayout>

    2.3 创建 MotionScene(运动描述文件)

        MotionLayout 是完全声明性的,使用 XML 文件描述任何转换,MotionLayout 的转换描述 XML 文件放在 res/xml 目录下,其中包含相应布局的所有运动描述。为了将布局信息与运动描述分开,每个 MotionLayout 都引用一个单独的 MotionScene。

    注意:MotionScene 中的定义的运动描述优先于 MotionLayout 中的任何类似定义。

    <?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/btn6" motion:touchAnchorSide="right" motion:dragDirection="dragRight" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/btn6" 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" motion:layout_constraintVertical_bias="0.5" android:layout_marginLeft="8dp" > <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/btn6" 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="#FFFF00" /> </Constraint> </ConstraintSet> </MotionScene>

    提示:运动描述文件通过预定义的元素,声明运动的各种状态,关于描述文件的详细内容,请参考:运动描述文件详解

    2.4 在 MotionLayout 中配置运动描述

        创建运动描述文件之后,需要在布局文件中添加配置。添加运动描述配置,需要在 MotionLayout 跟节点上,通过 layoutDescription 属性配置。

    <?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" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" app:layoutDescription="@xml/scene_01" tools:showPaths="true"> <View android:id="@+id/btn6" android:layout_width="100dp" android:layout_height="100dp" android:background="@color/colorAccent" android:text="Button6"/> </androidx.constraintlayout.motion.widget.MotionLayout> 效果:

    注意事项:运动描述文件和布局是一一对应的,一个 MotionLayout 需要但对对应一个描述 XML 文件,并且描述文件中的所有控件的 ID 也必须在布局中能找到。

    2.5 MotionLayout 的属性详解

        MotionLayout 除了上述的 layoutDescription 属性以外,还有以下属性: 其他 MotionLayout 属性 除了上述示例中的属性之外,MotionLayout 还包含您可能想要指定的其他属性:

    applyMotionScene:布尔类型,表示是否应用 MotionScene,默认值为 true。showPaths:布尔类型,表示在运动进行时是否显示运动路径。默认值为 false。progress:float类型,可以明确指定转换进度(取值0.0~1.0)currentState:reference类型,可指定具体的 ConstraintSet。motionDebug:可显示与运动有关的其他调试信息。可取值有:SHOW_PROGRESS、SHOW_PATH或SHOW_ALL。

    三、运动描述文件详解

    3.1 描述文件组成元素

    <MotionScene>:描述文件的根节点元素。<ConstraintSet>:声明所有的视图控件在运动过程中,特定关键点的位置和属性。<Constraint>:声明单个视图控件在运动过程中,特定关键点的位置和属性。<Transition>:声明运动过程中的开始和结束状态,包括所有预期的过度状态、用户的触发的交互等。<onClick>:声明当用户触摸特定的视图控件时所要执行的动作。<onSwipe>:声明当用户在布局中滑动时所要执行的动作。<KeyFrameSet>:声明在运动过程中视图控件的位置和属性。<KeyPosition>:声明在运动过程中特定时刻视图控件的位置。<KeyAttribute>:声明在运动过程中特定时刻视图控件的属性。

    3.2 元素详解

    3.2.1 <MotionScene>

        <MotionScene>是运动场景文件的根元素,必须包含一个或多个 <Transition> 元素,<Transition>元素用于定义运动序列的开始和结束状态,以及这两种状态之间的转换。

    语法 <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto" motion:defaultDuration="500"> </MotionScene>

    必须包含的元素

    <Transition>:指定运动场景需要的动画序列,可以有多个,每一个指定需要执行的运动序列。如果 <MotionScene> 包含多个 <Transition> 元素,MotionLayout 会根据用户的互动选择最合适的 <Transition> 元素,但是要注意防止冲突。

    可以包含的元素

    <ConstraintSet>:运动的状态布局集,为 <Transition> 元素指定开始或结束状态。 MotionLayout 关联的 <MotionScene>可以没有 <ConstraintSet> 子元素,因为 <Transition> 可指向 XML 布局,而不是指向<ConstraintSet>布局集。

    属性

    defaultDuration:所有动画的默认持续时间(以毫秒为单位)。用于给未指定持续时间的 <Transition> 指定一个默认的持续时间。

    3.2.2 <ConstraintSet>

        <ConstraintSet> 元素是用来指定视图在动画序列中某一点上的位置和属性(可同时指定多个视图),也叫约束条件集合。通常,一个 <Transition> 元素可指向两个 <ConstraintSet> 元素,其中一个定义动画序列的开始,另一个定义动画序列的结束。

    语法

    <ConstraintSet android:id="@+id/name" [deriveConstraintsFrom="@+id/id_name"]> ... </ConstraintSet>

    必须包含的元素

    <Constraint>:必须包含一个或者多个 <Constraint> 元素,描述动画在特定时刻视图的位置和属性。

    父元素

    <MotionScene>

    属性

    android:id:集合的 ID,在 <Transition> 中通过此 ID 来引用该序列。deriveConstraintsFrom:(可选)值为另一个 ConstraintSet 的 ID。如果指定这个属性,ID 对应约束集合内的所有约束条件都将应用于此集合,除非此集明确替换它们。 示例: <?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" motion:defaultDuration="500"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end2" motion:duration="1000"> <OnSwipe motion:touchAnchorId="@+id/btn6" motion:touchAnchorSide="right" motion:dragDirection="dragRight" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/btn6" 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" motion:layout_constraintHorizontal_bias="0.5" android:layout_marginLeft="8dp" > <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60" /> </Constraint> <Constraint android:id="@+id/btn5" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" android:layout_marginBottom="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" android:layout_marginLeft="8dp" > <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D8FF22" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end2" motion:deriveConstraintsFrom="@+id/end"> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/btn6" 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="#FFFF00" /> </Constraint> <Constraint android:id="@+id/btn5" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" android:layout_marginTop="8dp" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent" > <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#FF00FF" /> </Constraint> </ConstraintSet> </MotionScene>

    以上例子中,ID 为 end2 的 ConstraintSet 包含了 ID 为 end 的 ConstraintSet 中所有的约束。如果在 end2 对同一个视图声明约束(Constraint),那么就会替换掉 end 中声明的对应约束。

    3.2.3 <Constraint>

        <Constraint> 元素用来声明运动序列其中一个视图的位置和属性,也就是视图的约束。

    语法

    <Constraint android:id="@+id/view_id_name" attributes> </Constraint>

    父元素

    <ConstraintSet>

    属性

    android:id:视图 ID,约束视图的 ID ;其他在 ConstraintLayout 中用来约束视图位置的属性;

    3.2.4 <Transition>

        该元素是用来声明运动过程中的开始和结束状态,包括所有预期的过度状态、用户的触发的交互等。

    语法

    <Transition motion:constraintSetStart="@+id/start_constraint_set_id" motion:constraintSetEnd="@+id/end_constraint_set_id" [motion:duration="duration_integer"]> ... [动画触发属性元素] </Transition>

    属性

    motion:constraintSetStart:运动序列的初始状态。可以是 <ConstraintSet> 的 ID (属性值设置为“@+id/constraintSetId”),也可以是布局(属性值设置为"@layout/layoutName”)。motion:constraintSetEnd:运动序列的最终状态。可以是 <ConstraintSet> 的 ID (属性值设置为“@+id/constraintSetId”),也可以是布局(属性值设置为"@layout/layoutName”)。motion:duration:运动序列的时长(单位:毫秒,可选)。如果未指定,则使用 <ConstraintSet> 元素中的 defaultDuration 属性值。

    可以包含的元素

    <OnClick>:表示运动序列是由用户轻触触发的。<OnSwipe>:表示运动序列是由用户滑动触发的。<KeyFrameSet>:用于为运动序列中的元素指定一个或多个中间位置或属性设置。

    父元素

    <MotionScene>

    3.2.5 <OnClick>

        该元素用于指定当用户点按特定视图时要执行的操作,用于 <Transition> 元素内部,指定当用户点击视图时触发动画序列,在一个 <Transition> 内部只能有一个 <OnClick> 元素。

    说明:官方文档中说一个 <Transition> 元素内部可以有多个 <OnClick> 元素,但是笔者实践过程中发现不可行,会编译报错,不知道是否跟版本有关。

    语法

    <OnClick motion:targetId="@+id/view_id" motion:clickAction="actionName" />

    属性

    motion:targetId:点击的视图的 ID。motion:clickAction:点击时触发的操作,enum 类型,可选值有: 取值说明备注transitionToStart从当前状态转变到 <Transition> 元素中 motion::constraintSetStart 属性指定的状态,转变过程有动画效果-transitionToEnd从当前状态转变到 <Transition> 元素中 motion:constraintSetEnd 属性指定的k状态,转变过程有动画效果。-jumpToStart从当状态转变到 <Transition> 元素中 motion::constraintSetStart 属性指定的状态,转变过程无动画效果-jumpToEnd从当状态转变到 <Transition> 元素中 motion:constraintSetEnd 属性指定的状态,转变过程无动画效果-toggle在 <Transition> 元素中 motion::constraintSetStart 和 motion:constraintSetEnd 两个属性指定的两个状态中相互转换,转变过程有动画效果只要在非这两个状态下,触发都会向目标状态的相反状态转变。例如:当动画执行到中间状态时,触发时,将不会到达当前动画的目标状态,而是立刻向当前动画的目标状态的相反状态转变

    3.2.6 <OnSwipe>

        该元素用于指定当用户在不居中滑动时需要执行的操作。动画序列的速度和目标视图的动画,受滑动的速度和方向影响,滑动的速度和方向是通过可选参数配置来控制的。

    说明:官方文档中说一个 <Transition> 元素内部可以有多个 <OnSwipe> 元素,但是笔者实践过程中发现不可行,会编译报错,不知道是否跟版本有关。

    语法

    <onSwipe motion:touchAnchorId="@id/target_view" motion:touchAnchorSide="side" [ motion:dragDirection="direction" ] [ motion:dragScale="scale" ] [ motion:maxVelocity="maxVelocity" ] [ motion:maxAcceleration="maxAcceleration" ] [ motion:onTouchUp="action" ] />

    属性

    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(减速并完成动画)、

    父元素

    <Transition>

    3.2.7 <KeyFrameSet>

        前面提到,动画的声明是有 “开始状态” 和 “结束状态” 两个点,目标控件在这两个点之间移动,前面的例子都是直线的动画,显然这个实际使用中需要更复杂的动画。<KeyFrameSet> 就是提供声明更加复杂动画的元素,他声明了动画运动轨迹的关键点集合,它可包含 <KeyPosition> 和 <KeyAttribute>,通过这些元素,可以在动画的 “开始状态” 和 “结束状态” 添加 “中间点”,动画将平滑地移动到每个中间点,完成更复杂的动画。

    语法

    <KeyFrameSet> [ <KeyPosition/>... ] [ <KeyAttribute/>...] </KeyFrameSet>

    父元素

    <Transition>

    可以包含的元素

    <KeyPosition><KeyAttribute>

    3.2.8 <KeyPosition>

        该元素用于指定视图在运动过程中,在特定的时刻的位置。换句话说就是运动轨迹上的关键点的位置。在一个 <KeyFrameSet> 中可以添加多个 <KeyPosition> 用来添加多个不同的关键点位置。

    语法

    <KeyPosition motion:motionTarget="@id/targetView" motion:framePosition="frame position percentage" motion:keyPositionType="position type" motion:percentX="xOffset" motion:percentY="yOffset" />

    属性

    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),就可以实现快慢变化的效果。

    deltaRelative示例

    示例代码 <?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" motion:defaultDuration="2000"> <Transition motion:constraintSetStart="@+id/btn7_start" motion:constraintSetEnd="@+id/btn7_end"> <KeyFrameSet> <KeyPosition motion:motionTarget="@+id/btn7" motion:framePosition="25" motion:keyPositionType="deltaRelative" motion:percentX="0.5" motion:percentY="-0.2"/> <KeyPosition motion:motionTarget="@+id/btn7" motion:framePosition="75" motion:keyPositionType="deltaRelative" motion:percentX="0.4" motion:percentY="0.6"/> </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/btn7_start"> <Constraint android:id="@+id/btn7" android:layout_width="80dp" android:layout_height="80dp" motion:layout_constraintTop_toTopOf="parent" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintLeft_toLeftOf="parent"/> </ConstraintSet> <ConstraintSet android:id="@+id/btn7_end"> <Constraint android:id="@+id/btn7" android:layout_width="80dp" android:layout_height="80dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" /> </ConstraintSet> </MotionScene> 效果(虚线为运动轨迹,中间的方点为关键点)

    父元素

    <KeyFrameSet>

    3.2.9 <KeyAttribute>

        <KeyAttribute> 元素是用来在运动序列的特定时刻,设置视图的任何 标准属性。必须注意的是,只能设置标准属性。

    语法

    <KeyAttribute motion:motionTarget="@+id/targetViewId" motion:framePosition="frame position percentage" [ attributeName = value ] />

    属性

    motion:motionTarget:设置属性的目标视图 IDmotion:framePosition:目标视图在序列中具有指定属性的帧位置,取值范围是 0 ~ 100 之间的整数(虽然是指定某个帧位置,但是动画会自动对属性的效果进行过度,而不是生硬的切换为该属性的效果)。可选的标准属性有: 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)

    说明:通过 <KeyAttribute> 元素可以设置关键点位置的标准属性,但是在开始位置和结束位置,可以设置视图的属性(包含标准属性和自定义属性),更多详情参考:设置视图属性

    父元素

    <KeyFrameSet>

    3.3 设置视图属性

         前面提到可以通过在 <KeyPosition> 元素中使用 <KeyAttribute> 元素在关键点设置标准属性,改变视图的样式,在 <ConstraintSet> 元素包含的子元素中,也可以设置视图的属性,改变视图样式,包括标准属性和自定义属性。

    3.3.1 <ConstraintSet>插入标准属性

         在 <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" motion:defaultDuration="2000"> <Transition motion:constraintSetStart="@+id/btn7_start" motion:constraintSetEnd="@+id/btn7_end"> <OnSwipe motion:touchAnchorId="@+id/btn7" motion:touchAnchorSide="bottom" motion:dragDirection="dragDown" motion:maxVelocity="2"/> <KeyFrameSet> <KeyPosition motion:motionTarget="@+id/btn7" motion:framePosition="25" motion:keyPositionType="deltaRelative" motion:percentX="0.5" motion:percentY="-0.2"/> <KeyPosition motion:motionTarget="@+id/btn7" motion:framePosition="75" motion:keyPositionType="deltaRelative" motion:percentX="0.4" motion:percentY="0.6"/> </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/btn7_start"> <Constraint android:id="@+id/btn7" android:layout_width="80dp" android:layout_height="80dp" motion:layout_constraintTop_toTopOf="parent" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintLeft_toLeftOf="parent" android:rotation="45" android:alpha="0.2"> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/btn7_end"> <Constraint android:id="@+id/btn7" android:layout_width="80dp" android:layout_height="80dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:rotation="145" android:alpha="1.0"> </Constraint> </ConstraintSet> </MotionScene>

    效果

    标准属性包括:

    android:alpha:视图的透明度android:visibility:视图是否可见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)

    3.3.2 <CustomAttribute> 自定义属性

         在 <Constraint> 元素中,您可以使用 <CustomAttribute> 元素设置属性,自定义属性不仅仅可以设置标准属性,也可以设置非标准的相关属性(例如:backgroundColor 背景色),但是必须要注意一点,设置的自定义属性,必须是在 View 中定义了 getter 和 setter 方法的,而且属性值的类型必须准确。

    一个 <CustomAttribute> 元素必须包含两个属性:

    motion:attributeName:属性名(必须)必须包含以下含类型的属性值的一个: motion:customColorValue: 适用于颜色motion:customIntegerValue:适用于整数motion:customFloatValue:适用于浮点值motion:customStringValue:适用于字符串motion:customDimension:适用于尺寸motion:customBoolean:适用于布尔值

    注意事项:1. 属性名必须正确,且这个属性必须包含对外的 getter 和 setter 方法,否则自定义属性无效=;2. 属性值必须选择正确的类型,否则自定义属性无效(可以查看 setter 方法中的参数类型选择正确的类型)。

    示例: <?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" motion:defaultDuration="2000"> <Transition motion:constraintSetStart="@+id/btn7_start" motion:constraintSetEnd="@+id/btn7_end"> <OnClick motion:targetId="@+id/btn_start" motion:clickAction="toggle" /> <KeyFrameSet> <KeyPosition motion:motionTarget="@+id/btn7" motion:framePosition="25" motion:keyPositionType="deltaRelative" motion:percentX="0.5" motion:percentY="-0.2"/> <KeyPosition motion:motionTarget="@+id/btn7" motion:framePosition="75" motion:keyPositionType="deltaRelative" motion:percentX="0.4" motion:percentY="0.6"/> </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/btn7_start"> <Constraint android:id="@+id/btn7" android:layout_width="80dp" android:layout_height="80dp" motion:layout_constraintTop_toTopOf="parent" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintLeft_toLeftOf="parent" android:alpha="0.2"> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="@color/colorAccent" /> <CustomAttribute motion:attributeName="rotation" motion:customFloatValue="45.0" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/btn7_end"> <Constraint android:id="@+id/btn7" android:layout_width="80dp" android:layout_height="80dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:alpha="1.0"> <CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="@color/colorPrimary" /> <CustomAttribute motion:attributeName="rotation" motion:customFloatValue="145.0" /> </Constraint> </ConstraintSet> </MotionScene> 实现效果

    示例讲解:以上的示例中,使用 <CustomAttribute> 元素添加了两个自定义属性,分别是 backgroundColor 和 rotation,这两个属性均有公开的 getter 和 setter 方法(setBackgroundColor() 和 setRotation()),所以自定义属性有效,其中 backgroundColor 是非标准属性,rotation 是标准属性(可以直接在 <Constraint> 元素中设置)。

    四、编后语

         MotionLayout 在动画处理方面的能力非常强大,完全配置化,如果需要在布局中使用到动画的同学可以试试这个强大的布局。

    Processed: 0.023, SQL: 9