MotionLayout的大致使用

MotionLayout

简介

(补间)动画布局。

  • MotionLayout是ConstraintLayout的子类,拥有丰富强大的布局功能。

  • Motionlayout的设计是为了连接布局过渡与复杂的手势处理。它相当于一个动画框架、过渡动画管理(Transitionmanager)和Coordinatorlayout三种能力于一身的框架。

  • 它还支持触摸处理和关键帧(keyFrames),允许开发者非常容易地定制元素之间的过渡动画。

  • MotionLayout是完全声明式,我们可以用xml描述处任何复杂的效果。

  • MotionLayout不支持嵌套子布局或者activity transition。(如果有需求还是使用TransitionManager)

使用场景:当用户需要与有动效的UI元素交互时使用MotionLayout

MotionScene

MotionLayout会引用一个xml文件作为动画的规则。一般存放在res/xml路径下。这个xml文件的根元素为MotionScene

MotionScene主要有三个成员:

  • StateSet 状态集,主要用于存储当前布局内个活动View的一些状态。

  • ConstraintSet 约束集,直接在xml中引入,用以对View进行约束属性控制。一般至少存在一个起始态(start)和一个终止态(end)表示起始状态的布局和终止状态的布局。

  • Transition 运动过渡。时启用动画时必须定义的元素。内部的各种属性可以控制多种运动状态。

img

(图片源自Android新控件MotionLayout介绍(一)-CSDN博客

MotionLayout实现的根本就在于这个MotionScene文件中。

使用

导依赖包

implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

引用已经存在的布局

这中情况是在layout布局目录中已经创建好了起始和终止的布局。在MotionScene文件中就不需要ConstraintSet,直接引用这两个布局就行。

这是MotionLayout主布局。目标想要将这个“滑动”的TextView移动到屏幕右侧。

motion_view是这个TextView的id。

<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:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/activity_main_scene"
    tools:context=".MainActivity">
​
    <TextView
        android:background="#ff4450"
        android:id="@+id/motion_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginStart="30dp"
        android:text="滑动"
        android:textSize="20sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        />
​
</androidx.constraintlayout.motion.widget.MotionLayout>

起始布局:

布局的文件 motion_01_start.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
​
    <TextView
        android:background="#ff4450"
        android:id="@+id/motion_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="滑动"
        android:layout_marginStart="30dp"
        android:textSize="20sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

终止布局:

布局文件 motion_01_end.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
​
    <TextView
        android:background="#ff4450"
        android:id="@+id/motion_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="30dp"
        android:text="滑动"
        android:textSize="20sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />
​
</androidx.constraintlayout.widget.ConstraintLayout>

MotionScene中引用这两个布局

<MotionScene
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">
​
    <Transition
        motion:constraintSetEnd="@layout/motion_01_end"
        motion:constraintSetStart="@layout/motion_01_start"
        motion:duration="1000">
        <OnSwipe
            motion:touchAnchorId="@id/motion_view"
            motion:touchAnchorSide="middle"
            motion:dragDirection="dragRight"
            />
    </Transition>
​
<!--    <ConstraintSet android:id="@+id/start">-->
<!--    </ConstraintSet>-->
​
<!--    <ConstraintSet android:id="@+id/end">-->
<!--    </ConstraintSet>-->
<!--    我们引用外部的布局就不用再定义ConstraintSet-->
</MotionScene>

首先在Transitionmotion:constraintSetEnd=""和 motion:constraintSetStart=""属性中指定起始和终止布局。

OnSwipe

在Transition中又添加了一个< OnSwipe>标签。OnSwipe是一个与用户交互的功能,可以让控件或者视图跟随用户的手指(拖动)而移动。

更多属性

img

  • motion:dragScale:控制目标视图的滑动距离和用户手指滑动距离的相对比例,默认值是1。取值小于1时目标视图的移动速度小于手指滑动速度,取值大于1时目标视图的移动速度大于手指的滑动速度。

  • motion:maxVelocity:目标视图的最大速度。

  • motion:maxAcceleration:目标视图的最大加速度。

  • motion:onTouchUp:触摸收起时的动作,可选值有:stop(停止动画)、autoComplete(自动完成动画)、autoCompleteToEnd(自动完成到结束状态)、autoCompleteToStart(自动完成到开始状态)、decelerate(减速停止动画)、decelerateAndComplete(减速并完成动画)、

MotionLayout是ConstraintLayout的子类,他们主要的区别在于MotionLayout指定了MotionScene文件,而MotionScene文件就是动画的实现过程。

OnClick

另一个视图交互标签。

该元素用于指定当用户点击特定试图时要执行的操作,用于< Transition>元素内部,指定当用户点击视图时会触发动画序列。

属性

onClick只有两个属性

motion:targetId="@id/motion_view"//用于指定监听的控件或视图的id
motion:clickAction="toggle"//用于指定点击时触发的操作

关于motion:clickAction有多个可选值:

  • transitionToStart:从当前状态转变为< Transition>元素中motion:constrantSetStart属性指定的状态。

  • jumpToStart:从当前状态转变为< Transition>元素中motion:constrantSetStart属性指定的状态。

    transition……的转变过程有动画效果,而jump……的转变过程没有动画效果。

  • transitionToEnd:从当前状态转变到< Transition>元素中motion:xonstraintSetEnd属性指定的状态。

  • jumpToEnd:从当前状态转变为< Transition>元素中motion:constrantSetEnd属性指定的状态。

    同样transition……的转变过程有动画效果,而jump……的转变过程没有动画效果。

  • toggle:在< Transition>元素中 motion:constraintSetStartmotion:constraintSetEnd两个属性指定的两个状态中相互转换,转换过程中动画效果。

    只要在非这两个状态下,触发都会向目标状态的相反状态转变。例如:当动画执行到中间时,将会向当前动画的目标状态的相反状态转变。

设置了OnClick,OnSwipe可能会无效。

将刚才的代码换成

    <Transition
        motion:constraintSetEnd="@layout/motion_01_end"
        motion:constraintSetStart="@layout/motion_01_start"
        motion:duration="1000">
​
        <OnClick
            motion:targetId="@id/motion_view"
            motion:clickAction="toggle"
            />
​
    </Transition>

此时只需要点击一下就可以运动到右边。

引用定义的ConstraintSet

同样是上面的代码。

如果不适用外部已经创建好的布局文件,而是使用ConstraintSet定义起始和终止的布局。

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/apk/res-auto">
​
    <Transition
        motion:constraintSetEnd="@id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="1000">
        <OnSwipe
            motion:touchAnchorId="@id/motion_view"
            motion:touchAnchorSide="middle"
            motion:dragDirection="dragRight"
            />
    </Transition>
​
    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:background="#ff4450"
            android:id="@+id/motion_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="滑动"
            android:layout_marginStart="30dp"
            android:textSize="20sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>
​
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:background="#ff4450"
            android:id="@+id/motion_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="30dp"
            android:text="滑动"
            android:textSize="20sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />
    </ConstraintSet>
</MotionScene>

ConstraintSet中必须包含< Constraint>元素。起始布局和结束布局基本是由< Constraint>实现的。

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

效果和之前是一样的。

使用KeyFrameSet

关键帧集合

img

关键帧集合常用的几个属性:

  • KeyPosition:关键帧位置点,用以控制控件出现的位置,是动画在运行到该帧时达到定义的点位。

  • KeyAttributes:关键帧属性点,用以设置该点的View属性和自定义属性。

  • KeyCycle:关键帧周期点,用以定义周期运动的波幅及波形。

KeyPosition

设置关键位置,改变控件行进的路径。

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/apk/res-auto">
​
    <Transition
        motion:constraintSetEnd="@id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="1000">
        <OnClick
            motion:targetId="@id/motion_view"
            motion:clickAction="toggle"
            />
       <KeyFrameSet>
           <KeyPosition
               motion:motionTarget="@id/motion_view"
               motion:framePosition="30"
               motion:percentX="0.4"
               motion:percentY="0.1"
               motion:keyPositionType="parentRelative"/>
           <KeyPosition
               motion:motionTarget="@id/motion_view"
               motion:framePosition="60"
               motion:percentX="0.8"
               motion:percentY="0.9"
               motion:keyPositionType="parentRelative"/>
       </KeyFrameSet>
    </Transition>
...
</MotionScene>

解释KeyPosition的属性:

  • motionTarget:表示要操作的控件的id

  • framePosition:表示帧进度

  • keyPositionType:表示坐标系

(图片源自MotionLayout初探-CSDN博客

parentRelative 是以父容器维度来定义坐标系,对应着Android View坐标系。

deltaRelative 是以状态起始点作为坐标原点,x、y轴仍对应着Android View坐标系。

pathRelative 是以起始点与结束点两点间的连线作为坐标横轴,并平分y轴来划分坐标系。

  • percentX/percentY:表示相对X/Y轴偏移的百分比。

KeyAttributes

属性关键帧,可以在转换过程中来指定属性。

  
  <Transition
        motion:constraintSetEnd="@id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="1000">
        <OnClick
            motion:targetId="@id/motion_view"
            motion:clickAction="toggle"
            />
       <KeyFrameSet>
           <KeyPosition
               motion:motionTarget="@id/motion_view"
               motion:framePosition="30"
               motion:percentX="0.4"
               motion:percentY="0.1"
               motion:keyPositionType="parentRelative"/>
           <KeyPosition
               motion:motionTarget="@id/motion_view"
               motion:framePosition="60"
               motion:percentX="0.8"
               motion:percentY="0.9"
               motion:keyPositionType="parentRelative"/>
           
           <KeyAttribute
               motion:motionTarget="@id/motion_view"
               android:scaleX="4"  //视图 X 轴方向放大4倍
               android:scaleY="4"  //视图 Y 轴方向放大4倍
               android:rotation="180"  //视图的旋转角度180°
               motion:framePosition="50"
               />
​
       </KeyFrameSet>
​
    </Transition>

这里指定了KeyAttribute的属性:

  • motion:motionTarget:表示需要设置属性的视图或控件的id。

  • motion: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>元素可以设置关键的某一帧的标准属性,但是在起始位置和结束位置,可以字节设置视图的属性(标准属性和自定义属性)

KeyCycle

根据给定的函数对设定好的属性进行周期性变化。

img

  • wavePeriod 即波动周期 这里0.5为一个循环周期

  • wavePeriod 属性偏移量

  • waveShape 波形类型,可供选择的库sin、cos、bounce等。

  • 动画会根据上面的wavePeriod,waveShape对如下支持的属性进行周期变化

    • android:alpha 视图的透明度

    • android:elevation 视图的 Z 轴深度

    • android:rotation 视图的旋转角度(默认方向)

    • android:rotationX 视图 X 轴方向旋转角度

    • android:rotationY视图 Y 轴方向旋转角度

    • android:scaleX 视图 X 轴方向缩放

    • android:scaleY 视图 Y 轴方向缩放

    • android:translationX 视图 X 轴方向的平移量

    • android:translationY 视图 Y 轴方向的平移量

    • android:translationZ 视图 Z 轴方向的平移量

    所以还需指定以上一些属性。

    <Transition
        motion:constraintSetEnd="@id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="1000">
        <OnClick
            motion:targetId="@id/motion_view"
            motion:clickAction="toggle"
            />
​
       <KeyFrameSet>
           <KeyCycle
               motion:motionTarget="@id/motion_view"
               motion:wavePeriod="1"
               motion:waveShape="sin"
               android:translationY="50dp"
               />
​
       </KeyFrameSet>
​
    </Transition>

设置视图属性

刚才说了< KeyAttribute>可以设置某一帧的标准属性,在< ConstraintSet>的< Constraint>元素中也可以设置视图的标准属性

标准属性包括:

  • 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)

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@id/motion_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="滑动"
            android:layout_marginStart="30dp"
            android:textSize="20sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:alpha="0">
        </Constraint>
    </ConstraintSet>
​
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@id/motion_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="30dp"
            android:text="滑动"
            android:textSize="20sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:alpha="1">
        </Constraint>
    </ConstraintSet>

在刚刚的代码中,给起始布局添加了个android:alpha="1"(完全不透明),给终止布局添加了个android:alpha="0"(完全透明)。

这个的效果和给起始布局设置android:visibility="visible",给终止布局设置android:visibility="invisible"的效果一样。

但如果给起始布局设置android:visibility="visible",给终止布局设置android:visibility="invisible",就会在屏幕上以特殊的方式消失。这应该是代码默认设置的消失动画吧。

CustomAttribute

介绍一下CustomAttribute,自定义属性。

img

自定义属性的结构包括属性名和属性值

例如:

<CustomAttribute
    motion:attributeName="backgroundColor"
    motion:customColorValue="@color/white"/>

自定义属性可以通过属性名指定,但必须要存在get/set方法,否则自定义属性无效。一般使用常用的非标准属性就可以了,例如backgroundColor

自定义属性的值:

  • customColorValue 针对颜色数据类型

  • customIntegerValue 针对整形数据类型

  • customFloatValue 针对浮点型数据

  • customStringValue 针对字符串数据

  • customDimension 针对尺寸

  • customBoolean 针对布尔类型

CustomAttribute可以在KeyAttribute(关键帧属性)和Constraint(约束)中使用。

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/apk/res-auto">
​
    <Transition
        motion:constraintSetEnd="@id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="1000">
        <OnClick
            motion:targetId="@id/motion_view"
            motion:clickAction="toggle"
            />
        <OnSwipe
            motion:touchAnchorId="@id/motion_view"
            motion:touchAnchorSide="middle"
            motion:dragDirection="dragRight"
            />
       <KeyFrameSet>
           <KeyPosition
               motion:motionTarget="@id/motion_view"
               motion:framePosition="30"
               motion:percentX="0.4"
               motion:percentY="0.1"
               motion:keyPositionType="parentRelative"/>
           <KeyPosition
               motion:motionTarget="@id/motion_view"
               motion:framePosition="60"
               motion:percentX="0.8"
               motion:percentY="0.9"
               motion:keyPositionType="parentRelative"/>
           <KeyAttribute
               motion:motionTarget="@id/motion_view"
               android:scaleX="2"
               android:scaleY="2"
               android:rotation="45"
               motion:framePosition="50"
               >
               <CustomAttribute
                   motion:attributeName="backgroundColor"
                   motion:customColorValue="@color/black"
                   />
<!--               在KeyAttributes使用自定义属性,设置背景颜色为黑色-->
           </KeyAttribute>
​
       </KeyFrameSet>
​
    </Transition>
​
    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@id/motion_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="滑动"
            android:layout_marginStart="30dp"
            android:textSize="20sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent" >
            <CustomAttribute
                motion:attributeName="backgroundColor"
                motion:customColorValue="#ff4450"/>
            <!--               在Constraint中使用自定义属性,设置背景颜色-->
        </Constraint>
    </ConstraintSet>
​
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@id/motion_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="30dp"
            android:text="滑动"
            android:textSize="20sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" >
            <CustomAttribute
                motion:attributeName="backgroundColor"
                motion:customColorValue="@color/white"/>
            <!--               在Constraint中使用自定义属性,设置背景颜色为白色-->
        </Constraint>
    </ConstraintSet>
</MotionScene>

分别在起始、终止和50(百分比吧)帧处设置了不同的颜色,观察变化。

学习参考博客:Android新控件MotionLayout介绍(一)-CSDN博客

MotionLayout初探-CSDN博客

Android新控件MotionLayout介绍(二)_motionbutton-CSDN博客

Android MotionLayout详解-CSDN博客

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值