MotionLayout 基础教程 2

阅读说明:php

  • 本文假设读者已掌握如何使用 ConstraintLayout
  • 本文假设读者已对 MotionLayout 有了基本了解,知道如何建立 MotionScene 文件,以及如何使用 MotionLayout 在两个 layout 布局文件间建立过渡动画。如您彻底不了解这些,建议您阅读 《MotionLayout 基础教程》
  • 建议读者在阅读过程当中动手实践,有助于更好的理解,如您如今不方便,建议稍后阅读。
  • 因为官方文档不全,部份内容来自笔者的我的理解,若有错误,欢迎指正。

本文是 《MotionLayout 基础教程》 的第 2 篇,主要向读者介绍如何在 MotionScene 文件中定义场景约束以及如何使用自定义属性。android

在 MotionScene 文件中定义约束

能够在 <MotionScene> 元素中使用 <ConstraintSet> 子元素定义一个场景约束集,并在 <ConstraintSet> 元素中使用 <Constraint> 元素定义单个 View 的属性约束。app

:在 MotionScene 文件中定义 End 场景的约束集框架

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- 定义 End 场景的约束集 -->
    <ConstraintSet android:id="@+id/activity_main_end">

        <!-- 定义布局中 id 为 image 的 View 的属性约束 -->
        <Constraint android:id="@+id/button" android:layout_width="56dp" android:layout_height="56dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" />

    </ConstraintSet>

    <!-- Start 场景是布局文件,End 场景是定义在 MotionScene 文件中的约束集 -->
    <Transition app:constraintSetStart="@layout/activity_main" app:constraintSetEnd="@id/activity_main_end" app:duration="1000">

        <OnClick app:clickAction="toggle" app:targetId="@id/button" />

    </Transition>

</MotionScene>
复制代码

实际上,你便可以把 Start 场景的约束集定义在 MotionScene 文件中,也能够把 End 场景的约束集定义在 MotionScene 文件中。或者仅在 MotionScene 文件中定义这二者之一,另外一个场景使用 layout 布局文件定义。布局

建议:建议把 Start 场景和 End 场景的约束集都定义在 MotionScene 文件中。由于 MotionLayout 框架某些特性(例如自定义属性(下节会介绍))依赖于 MotionScene 文件中 Start 场景,若是 Start 场景没有定义在 MotionScene 文件中,这些特性可能会没法使用。post

:在 MotionScene 文件中定义 Start 场景约束与 End 场景约束(本示例分为如下两步)学习

1. 建立布局文件:测试

文件名:activity_main.xml动画

<?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:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/activity_main_motion_scene">

    <Button android:id="@+id/button" android:layout_width="56dp" android:layout_height="56dp" android:background="@color/colorPrimary" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" />

</androidx.constraintlayout.motion.widget.MotionLayout>
复制代码

提示:布局文件仍是要有的,并非说将 Start 场景约束和 End 场景约束都定义在了 MotionScene 文件中就能够不须要布局文件了。spa

布局文件预览:

2. 建立 MotionScene 文件:

文件名:activity_main_motion_scene.xml

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- 定义 Start 场景的属性约束集 -->
    <ConstraintSet android:id="@+id/activity_main_start">

        <!-- 定义布局中 id 为 button 的 View 的属性约束 -->
        <Constraint android:id="@id/button" android:layout_width="56dp" android:layout_height="56dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" />

    </ConstraintSet>


    <!-- 定义 End 场景的属性约束集 -->
    <ConstraintSet android:id="@+id/activity_main_end">

        <!-- 定义布局中 id 为 button 的 View 的属性约束 -->
        <Constraint android:id="@+id/button" android:layout_width="56dp" android:layout_height="56dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" />

    </ConstraintSet>

    <!-- Start 场景与 End 场景都是定义在 MotionScene 文件中的约束集 -->
    <Transition app:constraintSetStart="@id/activity_main_start" app:constraintSetEnd="@id/activity_main_end" app:duration="1000">

        <OnClick app:clickAction="toggle" app:targetId="@id/button" />

    </Transition>

</MotionScene>
复制代码

<ConstraintSet> 元素属性说明:

  • android:id:设置当前约束集的 id。这个 id 值可被 <Transition> 元素的 app:constraintSetStart 或者 app:constraintSetEnd 引用。

<Constraint> 元素属性说明:

  • android:id:当前约束关联到的那个 Viewid
  • app:transitionEasing:定义动画到此点时使用的缓动曲线,该值能够是一个字符串(例如 "curve(1.0,0,0,1.0)")还能够是如下几个枚举值之一:
    • standard:标准
    • accelerate:加速
    • decelerate:减速
    • linear:线性

提示 1<Constraint> 元素的 app:transitionEasing 属性与 <Transition> 元素的 app:motionInterpolator 属性相似,都是用来定义过渡动画的插值器的。不一样的是,<Constraint> 元素的 app:transitionEasing 属性定义的是单独某个 View 的过渡动画的插值器,而 <Transition> 元素的 app:motionInterpolator 定义的是整个过渡动画的插值器。

提示 2:若是为 <Constraint> 元素指定了 app:transitionEasing 插值器,这个插值器将与 app:motionInterpolator 属性指定的全局插值器同时做用于 View 的过渡动画,而不是替换掉 app:motionInterpolator 属性指定的全局插值器。

提示 3<Constraint> 元素的 app:transitionEasing 属性值应该在 Start 场景中指定,(经测试)仅在 End 场景中指定 app:transitionEasing 没法生效。

提示 4:(经测试,彷佛无效)可使用形如 "curve(1.0,0,0,1.0)" 的字符串来为 <Constraint> 元素的 app:transitionEasing 属性设置一个缓动曲线,MotionLayout 框架将根据这个缓动曲线来生成一个插值器。

  • app:transitionPathRotate:【浮点值】相对于所采用的路径旋转对象(弧形路径/关键帧 相关)。
  • app:drawPath:绘制过渡动画路径(调试用,关键帧相关)。能够是如下几个枚举值之一:
    • none
    • path
    • pathRelative
    • deltaRelative
    • asConfigured
    • rectangles
  • app:progress:【浮点值】在关联的 View 上调用 setProgress(float) 方法(用于与嵌套的 ConstraintLayout 交互)

前面说过,<Constraint> 元素用来定义单个 View 的属性约束,它支持对 View 的全部 ConstraintLayout 属性定义约束,以及对 View 的下面这些标准属性定义约束:

  • android:visibility
  • android:alpha
  • android:elevation
  • android:rotation
  • android:rotationX
  • android:rotationY
  • android:scaleX
  • android:scaleY
  • android:translationX
  • android:translationY
  • android:translationZ

View 的标准属性或者 ConstraintLayout 属性发生改变时,MotionLayout 会自动应用过渡动画。

自定义属性

MotionLayout 控件只会检测标准属性和 ConstraintLayout 属性这类布局相关的属性变更,对于其余的属性变更,如 View 的背景颜色变更是没法检测出来的,所以就须要使用自定义属性。

<Constraint> 元素中使用 <CustomAttribute> 子元素来指定自定义属性。

例:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- 定义 Start 场景的属性约束集 -->
    <ConstraintSet android:id="@+id/activity_main_start">

        <!-- 定义布局中 id 为 image 的 View 的属性约束 -->
        <Constraint android:id="@id/button" android:layout_width="56dp" android:layout_height="56dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0">

            <!-- 使用自定义属性 -->
            <CustomAttribute app:attributeName="backgroundColor" app:customColorValue="@color/colorPrimary" />

        </Constraint>

    </ConstraintSet>


    <!-- 定义 End 场景的属性约束集 -->
    <ConstraintSet android:id="@+id/activity_main_end">

        <!-- 定义布局中 id 为 image 的 View 的属性约束 -->
        <Constraint android:id="@+id/button" android:layout_width="56dp" android:layout_height="56dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0">

            <!-- 使用自定义属性 -->
            <CustomAttribute app:attributeName="backgroundColor" app:customColorValue="@color/colorAccent" />

        </Constraint>

    </ConstraintSet>

    <Transition app:constraintSetEnd="@id/activity_main_end" app:constraintSetStart="@id/activity_main_start" app:duration="1000">

        <OnClick app:clickAction="toggle" app:targetId="@id/button" />

    </Transition>

</MotionScene>
复制代码

效果预览:

<CustomAttribute> 元素属性说明:

  • app:attributeName 属性用来指定自定义属性的名字(例如 "backgroundColor")。关联的 View 必需要有一对与这个名字相关的 getter/setter 方法(例如 getBackgroundColor()/setBackgroundColor(int color))。
  • 剩下的其余属性都是用来设置自定义属性的值的。须要根据自定义属性的值类型使用如下 XML 属性之一来设置自定义属性的值:
    • app:customColorValue:设置属性的值(颜色类型)。
    • app:customColorDrawableValue:设置属性的值(颜色类型)。
    • app:customIntegerValue:设置属性的值(整数类型)。
    • app:customFloatValue:设置属性的值(浮点类型)。
    • app:customStringValue:设置属性的值(字符串类型)。
    • app:customDimension:设置属性的值(尺寸类型)。
    • app:customPixelDimension:设置属性的值(尺寸类型)。
    • app:customBoolean:设置属性的值(布尔类型)。

结语

本篇文章是 《MotionLayout 基础教程》 的第 2 篇,阅读完这两篇文章后您基本就能掌握 MotionLayout 的基础内容了。

写这两篇文章的主要目的是为了向读者介绍 MotionLayout 的基础内容,让读者可以入门,并在此基础上进一步学习。如您想要了解更多 MotionLayout 内容,推荐您阅读如下 3 篇文章:

相关文章
相关标签/搜索