MotionLayout 的简单使用

under Android  tag     Published on October 16th , 2021 at 04:28 pm

MotionLayout

支持在各种状态之间进行动画处理,需要通过 layoutDescription 属性添加 MotionScene 文件,该文件包含一个顶级标签 “MotionScene”。布局内正常放控件,但内部控件都需要 id,动画处理都要在该文件中进行。

MotionScene 文件内说明

MotionScene 文件是 res/xml/... 下的文件。在使用 MotionLayout 报错时,Alt+Enter 补全缺失方法后会自动生成对应文件和 layoutDescription 属性。可以自己创建文件。

标签描述
<ConstrainSet>约束集
<Transition>ConstrainSet 之间的转换
<StateSet>系统支持的状态(可选)
<ViewTransition>视图在状态或约束集中的转换

至少写两个 ConstraintSet 用于 Start 和 End,在 Transition 使用。MotionLayout 继承的是 ConstraintLayout,可以直接在 ConstraintSet 描述控件,布局文件会对应内容改变。

简单缩放

布局内控件只有一个,实现起来很容易,很好上手。

24251565727019128022551975304.gif

布局文件

@dimen/box -> 140dp,@dimen/icon -> 70dp

MotionLayout 的 layoutDescription 属性和控件 id 必须要写!

<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="@dimen/box"
    android:layout_height="@dimen/box"
    app:layoutDescription="@xml/activity_motion_scene">

    <ImageView
        android:id="@+id/pingpang"
        android:layout_width="@dimen/icon"
        android:layout_height="@dimen/icon"
        android:src="@mipmap/pingpang" />

</androidx.constraintlayout.motion.widget.MotionLayout>

activity_motion_scene.xml

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">
    
    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@id/pingpang"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/pingpangEnd">
        <Constraint
            android:id="@id/pingpang"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            android:scaleX="2"
            android:scaleY="2"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <Transition
        motion:constraintSetEnd="@id/pingpangEnd"
        motion:constraintSetStart="@id/start">
        <OnClick motion:targetId="@id/pingpang" />
    </Transition>
</MotionScene>
  • OnClick 点击开始动画
  • OnSwipe 滑动运行动画
  • targetId 属性,指定动画目标。如果不写点击或滑动 MotionLayout 内的任意位置都能开始动画

多个控件

MotionLayout_mult.gif

布局文件

<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="@dimen/box"
    android:layout_height="@dimen/box"
    app:layoutDescription="@xml/activity_motion_scene">
    <ImageView
        android:id="@+id/pingpang"
        android:layout_width="@dimen/icon"
        android:layout_height="@dimen/icon"
        android:src="@mipmap/pingpang" />

    <ImageView
        android:id="@+id/run"
        android:layout_width="@dimen/icon"
        android:layout_height="@dimen/icon"
        android:src="@mipmap/run" />

    <ImageView
        android:id="@+id/boxing"
        android:layout_width="@dimen/icon"
        android:layout_height="@dimen/icon"
        android:src="@mipmap/boxing" />

    <ImageView
        android:id="@+id/gymnastics"
        android:layout_width="@dimen/icon"
        android:layout_height="@dimen/icon"
        android:src="@mipmap/gymnastics" />
</androidx.constraintlayout.motion.widget.MotionLayout>

activity_motion_scene.xml

四个控件都是一样的动画效果,我省略了两个控件的动画代码。

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

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@id/pingpang"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
        <Constraint
            android:id="@id/run"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_editor_absoluteY="@dimen/icon" />
        <Constraint
            android:id="@id/boxing"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
        <Constraint
            android:id="@id/gymnastics"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_editor_absoluteY="@dimen/icon" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/pingpangEnd">
        <Constraint
            android:id="@id/pingpang"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            android:scaleX="2"
            android:scaleY="2"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <Transition
        motion:constraintSetEnd="@id/pingpangEnd"
        motion:constraintSetStart="@id/start">
        <OnClick motion:targetId="@id/pingpang" />
        <KeyFrameSet>
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="80"
                motion:motionTarget="@id/run" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="80"
                motion:motionTarget="@id/boxing" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="80"
                motion:motionTarget="@id/gymnastics" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@id/run" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@id/boxing" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@id/gymnastics" />
        </KeyFrameSet>
    </Transition>

    <ConstraintSet android:id="@+id/runEnd">
        <Constraint
            android:id="@id/run"
            android:layout_width="@dimen/icon"
            android:layout_height="@dimen/icon"
            android:scaleX="2"
            android:scaleY="2"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <Transition
        motion:constraintSetEnd="@id/runEnd"
        motion:constraintSetStart="@id/start">
        <OnClick motion:targetId="@id/run" />
        <KeyFrameSet>
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="80"
                motion:motionTarget="@id/pingpang" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@id/pingpang" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="80"
                motion:motionTarget="@id/boxing" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@id/boxing" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="80"
                motion:motionTarget="@id/gymnastics" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@id/gymnastics" />
        </KeyFrameSet>
    </Transition>
    ... ...
</MotionScene>

KeyFrameSet 关键帧

  • KeyPosition
  • KeyTrigger
  • KeyAttribute
  • KeyCycle
  • KeyTimeCycle

MotionLayout 的一些属性

属性描述
layoutDescription指定 MotionScene 文件(@xml/...)
showPaths是否显示动画运动路线(布尔值)
motionDebug是否显示动画信息(布尔值)
motionProgress设置动画进度的某个关键点(数值)

motion.jpg

参考文章:

Android MotionLayout

《译文》MotionLayout系列-4

JetPack知识点实战系列十一:MotionLayout让动画如此简单


本文由 surface 创作,采用 知识共享署名4.0 国际许可协议进行许可,转载前请务必署名
  文章最后更新时间为:October 15th , 2021 at 04:03 pm
分享到:Twitter  Weibo  Facebook