MotionLayout&MotionScene入坑指南

2,251 阅读5分钟

Android想要实现复杂和酷炫的交互逻辑一直需要自己去实现自定义View,或者用coordinatorlayout自定义behavior来实现,直到接触到了MotionLayout,简直不要太爽,和之前开发cocos可以界面化编辑动画效果有异曲同工之秒

MotionLayout

app:layoutDescription="@xml/scene"

指定这个motionlayout的MotionScene,简单理解就是指向一个场景,那个场景定义了哪个view怎么运动,运动多久,运动轨迹,如何触发运动等

app:motionDebug="SHOW_PATH" 

是否展示debug信息

SHOW_PATH 显示运动路线

SHOW_PROGRESS 显示帧率,运动进度,例:56 fps start->end (progress:100.0) state=end

SHOW_All 显示所有

NO_DEBUG 不显示

app:showPaths="true"

同上,显示运动路径

MotionScene

MotionScene元素下有Transition,ConstraintSet和StateSet3个元素

StateSet:描述系统支持的状态(可选)

ConstraintSet:一个ConstraintLayout约束+与视图相关的其他属性,指定所有视图在某个进度的属性与位置,可以有多个

Transition:描述两个状态或约束集之间的转换,一个transition元素可以指定两个ConstraintSet

一个简单的motionscene

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">
    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@+id/start"
        motion:duration="500">
        <OnSwipe
            motion:dragDirection="dragRight"
            motion:touchAnchorId="@id/button"
            motion:touchAnchorSide="middle" />
    </Transition>
    <ConstraintSet android:id="@+id/start">
        <Constraint android:id="@id/button">
            <Layout
                android:layout_width="64dp"
                android:layout_height="64dp"
                motion:layout_constraintStart_toStartOf="parent"/>
        </Constraint>
    </ConstraintSet>
    <ConstraintSet
        android:id="@+id/end"
        motion:deriveConstraintsFrom="@id/start">
        <Constraint android:id="@id/button">
            <Layout
                android:layout_width="64dp"
                android:layout_height="64dp"
                motion:layout_constraintEnd_toEndOf="parent" />
        </Constraint>
    </ConstraintSet>
</MotionScene>

我们看看上面的示例,MotionScene元素下有一个Transition,两个ConstraintSet,

Transition的motion:constraintSetStart="@+id/start"和motion:constraintSetEnd="@+id/end"属性刚好指向了两个ConstraintSet的id,OnSwipe元素表示transition由滑动触发

两个ConstraintSet元素下又各包含一个Constraint元素,这个很好理解,每个ConstraintSet就是某一进度的所有视图状态的集合,而每个Constraint就是具体到某个view在某个进度下的属性和位置,然后在看每个Constraint元素下有一个Layout元素,描述了其view的位置信息。

Transition

constraintSetStart

指定动画开始时(progress=0)的ConstraintSet

constraintSetEnd

指定动画结束时(progress=100)的ConstraintSet

duration

动画时长,单位毫秒

motionInterpolator

动画插值器,熟悉android动画的应该知道,目前有线性,回弹,慢进,慢出,慢进出

staggered

(float)一种快速错开物体移动的方法 (不是很懂什么意思,需要看下源码研究一下)

autoTransition

第一次自动执行动画,有几个值选,使用动画,不使用动画

transition下有3个元素

<OnSwipe>

滑动触发动画

<OnClick>

点击触发动画

<KeyFrameSet>

描述一组修改ConstraintSet动画的关键帧。

OnClick

motionTarget

触发点击的view的id

clickAction

点击后的动作,可以多个组合:toggle(来回), transitionToEnd, transitionToStart(带动画), jumpToEnd, jumpToStart(不带动画)

OnSwipe

touchAnchorId

要滑动的view的id

touchRegionId

将触摸可以开始的区域限制在该view的边界内(即使该视图是不可见的)

touchAnchorSide

移动对象的边{上|左|右|下}

maxVelocity

限制最大速度(进度/秒)的动画将touch up。默认的4

dragDirection

从哪边滑动{上拉|下拉|下拉|右拉}

maxAcceleration

在touch up时动画加速和减速的速度。默认的1.2

dragScale

调整划动的比例系数。(例如,0.5将需要你移动2倍的距离)

moveWhenScrollAtTop

是否滑动是滚动和视图(如RecyclerView或NestedScrollView)做滚动和转换发生在同一时间

autoComplete

滑动自动动画开始或结束,默认true。tips:关闭此功能并使用时间周期可能导致连续动画。

KeyFrameSet 关键帧

<KeyPosition>

控制动画期间的布局位置  

<KeyAttribute>

控制动画期间view的属性

<KeyCycle>

控制动画过程中相对于后布局属性位置的振荡

<KeyTimeCycle>

控制动画期间相对于后布局属性的时间的振荡

<KeyTrigger>

在动画的固定点触发回调到代码中  

几个元素共有的属性motion:framePosition="50"取值0-100),表示当前帧在动画的哪个时刻

motion:motionTarget表示应用在哪个view上

keyPosition中有一个属性motion:keyPositionType="deltaRelative"比较重要,表示的是位置的参考坐标系,有3种:

parentRelative:以父布局为坐标系(Android坐标系)

pathRelative:以start到end这条直线为X轴,Y轴为X轴顺时针90度方向

deltaRelative:起点为(0,0),终点为(1,1)展开的坐标轴

keyCycle和KeyTimeCycle不是很好理解,这里用图来说明

KeyCycle

waveShape

周期类型,生成波浪的形状{sin|square|triangle|sawtooth|reverseSawtooth|cos|bounce}

wavePeriod

循环的周期数

waveOffset

属性偏移量

transitionPathRotate

应用于相对于视图移动路径的旋转的循环

progress

调用这个视图上的setProgress(float)方法(用于与嵌套的ConstraintLayouts等通信)。

<KeyCycle
    motion:framePosition="80"
    motion:motionTarget="@+id/button"
    motion:wavePeriod="0.5"
    motion:waveShape="sin"
    android:translationY="30dp"/>

只设置这些值是看不出什么效果,还要设置view的一些基础属性来实现效果,比如图中就是用android:translationY来表示波浪的振幅,如果用rotation就可以实现翻转效果

需要注意的是这里的motion:framePosition的含义是作用范围(0 -> value),而不是某个时刻

KeyTimeCycle

一个是在运动过程中做周期运动,一个是在帧上做周期运动

属性和KeyCycle一样,motion:wavePeriod越大,变化速度越快

使用两个KeyTimeCycle就能实现view在原地环绕

<KeyTimeCycle
    motion:motionTarget="@+id/button"
    motion:wavePeriod="1"
    android:translationX="6dp"
    motion:waveShape="sin"
    />
<KeyTimeCycle
    motion:motionTarget="@+id/button"
    motion:wavePeriod="1"
    android:translationY="6dp"
    motion:waveShape="cos"
    />

原地转圈圈:

<KeyTimeCycle
    motion:motionTarget="@+id/button"
    motion:wavePeriod="1"
    android:rotation="-180"
    motion:waveShape="sawtooth"
    />

ConstraintSet

只有一个id标签,可以有多个Constraint元素

Constraint

android:id

指定view的id

[ConstraintLayout attributes]

任何ConstraintLayout的属性

[Standard View attributes]

系统支持的视图属性集合

transitionEasing

定义一个缓动曲线用于从这一点动画(例如曲线(1.0,0,0,1.0)) 或关键字 {standard | accelerate | decelerate | linear }

pathMotionArc

路径将以圆弧(四分之一圆)或关键词 {startVertical | startHorizontal | none }移动

transitionPathRotate

(float) 旋转物体相对于所采取的路径

drawPath

绘制的路径布局将动画显示

progress

调用这个视图上的setProgress(float)方法(用于与嵌套的ConstraintLayouts等通信)。  

<CustomAttribute>

自定义属性

<Layout>

ConstraintLayout的属性,例如layout_constraintTop_toTopOf

<PropertySet>

目前只有visible,alpha, motionProgress,layout_constraintTag。

<Transform>

所有的视图转换API ,例如android:rotation.

<Motion>

运动布局控制命令,如transitionEasing和pathMotionArc

CusTomAttribute 自定义属性

attributeName

属性的名称。区分大小写。MyAttr将寻找方法setMyAttr(…)

customColorValue

颜色值,见setMyAttr(int )

customIntegerValue

整形值 

customFloatValue

浮点型值

customStringValue

字符串值

customDimension

定义的dimension

customBoolean

布尔值