MotionLayout Structure

以下是梳理的整个MotionLayout框架中设计到所有布局配置,点击参见详细的属性解释

MotionLayout II - 图1

Custom attribute

MotionLayout II - 图2
由于原始ConstraintSet的只封装了layout 规则,为了更丰富的动画,我们需要过渡一些其他的东西(比如在此的 background color). 在ConstraintLayout 2.0中,ConstraintSet可以保存自定义的属性状态(attribute states),如下所示的变化:
MotionLayout II - 图3

只需要在ConstraintSet中预设如下自定义属性:

  1. <Constraint
  2. android:id="@+id/button" ...>
  3. <CustomAttribute
  4. motion:attributeName="backgroundColor"
  5. motion:customColorValue="#D81B60"/>
  6. </Constraint

CustomAttribute(自定义属性)通过attributeName被指定,此属性需要满足定义在对象中的 getter/setter 方法,比如:

  • getter: getName (e.g. getBackgroundColor)

  • setter: setName (e.g. setBackgroundColor)

属性的值(value)需要被指定为如下的值之一:

  • customColorValue

  • customIntegerValue

  • customFloatValue

  • customStringValue

  • customDimension

  • customBoolean

当指定了自定义属性时,需要同时在 start 和 end ConstraintSet 配置中同时配置,形成一一对应的关系

Keyframe

对于MotionLayout通常的想法就是作为ConstraintSets实现的一个叫 “resting states” 的状态。通过此方式,我们知道结果布局(result layouts)将会被适配到不同的屏幕尺寸上: 实际上,MotionLayout和ContraintLayout表现一致。

在某些情况下,我们可能想要一个中间态(an intermediate state) - (a state to go through, but not a state to stay in)用于穿过,而不是保存??. 可以通过指定操作2个ConstraintSets,但是一个更轻量级的实现方式就是使用 KeyFrames.

KeyFrames 可以被应用于 postion 或者 attributes值中,它们基本上能让你在transition的过程中在某个点指定一个改变

Keyframe - Position

MotionLayout II - 图4

target View的Id
framePosition 当前frame位置点[0,100] 插值器的概念(如果是匀速,此点就是当前位置比例)
type 此关键帧线性直线的偏差计算方式 {deltaRelative | pathRelative | parentRelative}
deltaRelative 是相对两点的直线delta距离
pathRelative 是基于其他配置参数,如percentY.
transitionEasing 在当前指定点的ease curve动画曲线(例如:curve(1.0,0,0,1.0))
percentX (float)[start,end]在x坐标上的百分比距离(deltaRelative),pathRelative 则是沿着曲线距离
percentY (float)[start,end]在y坐标(属性中的Y坐标值)上的百分比距离(deltaRelative)
pathRelative则表示垂直于线的距离
drawPath Debug中显示的辅助线样式,定义线的值有 {deltaRelative | pathRelative | asConfiged | path | retangles | none}
sizePercent 如果View的大小改变,这个用于控制View size变化逻辑(就是表示在该点时,view的size达到了此处定义的size大小)
curveFit 线的定义样式:{linear | spline} 直线或者曲线
<KeyFrameSet>
    <KeyPosition
        motion:type="pathRelative"
        motion:percentY="-0.25"
        motion:percentX="0.7"
        motion:framePosition="50"
        motion:curveFit="spline"
        motion:sizePercent="1"
        motion:drawPath="deltaRelative"
        motion:target="@id/button"/>
</KeyFrameSet>

上述代码代表帧点的效果如下图所示,此帧在图中粉色点位置,由于interporator是设置的linear,并且设置了 framePosition=”50”, 明显点左边部分的线稀疏,右边紧凑,就是为了保证此粉色点是能代表 “50”点;
percentY=”-0.25” 帧点相对原始位置Y坐标上移动 0.25 Y,因此点在整个基准线上方位置
percentX=”0.7” 针对相对原始位置X坐标移动 0.7
(endX - startX)
curveFit=”spline” 表示运动是曲线,而不是直线(linear)
MotionLayout II - 图5

并且可以通过Android studio design 工具去实时预览效果:
tools:progress 用于调节当前帧的进度
tools:showPaths 用于显示辅助线
MotionLayout II - 图6

Keyframe - Attribute

target View的 Id
framePosition 当前frame位置点[0,100] 插值器的概念(如果是匀速,此点就是当前位置比例)
curveFit 线的定义样式:{linear | spline} 直线或者曲线
transitionEasing 在当前指定点的ease curve动画曲线(例如:curve(1.0,0,0,1.0))
transitionPathRotate (float) rotate object relative to path taken
相对提供的线旋转对象
drawPath draw the path the layout will animate animate
progress call method setProgress(float) on this view (used to talk to nested ConstraintLayouts etc.)
[standard view attributes] 标准的android:开头的辅助属性
<CustomAttribute> 通过set方法设置的自定义属性(反射调用)
<KeyFrameSet>
    <KeyAttribute
        android:scaleX="2"
        android:scaleY="2"
        android:rotation="-45"
        motion:framePosition="50"
        motion:target="@id/button" />
    <KeyPosition
        motion:type="pathRelative"
        motion:percentY="-0.3"
        motion:framePosition="50"
        motion:target="@id/button"/>
</KeyFrameSet>

在framePosition=”50”时, 旋转-45度(rotation), 并且缩放两倍(scaleX,scaleY)
MotionLayout II - 图7

attributeName attribute的名字,大小写敏感, “MyAttr” 对应的方法类似setMyAttr(…)
customColorValue The value is a color looking setMyAttr(int )
customIntegerValue The value is an integer looking setMyAttr(int )
customFloatValue The value is a float looking setMyAttr(float )
customStringValue The value is a String looking setMyAttr(String )
customDimension The value is a dimension looking setMyAttr(float )
customBoolean The value is true or false looking setMyAttr(boolean )

Keyframe - Cycle

target View的 Id
framePosition 当前frame位置点[0,100] 插值器的概念(如果是匀速,此点就是当前位置比例)
[Standard View attributes] A collection of view attributes supported by the system (see below)
waveShape 生成波动的形状{sin|square|triangle|sawtooth|reverseSawtooth|cos|bounce}
wavePeriod 在此区域内的循环周期数
waveOffset offset value added to the attribute
对应属性的偏移量
transitionPathRotate Cycles applied to rotation relative to the path the view is travelling 暂时不清楚此用法
progress call method setProgress(float) on this view (used to talk to nested ConstraintLayouts etc.) (目前测试没效果)
<CustomAttribute> call a set”name” method via reflection (limited to floats)
<KeyFrameSet>
    <KeyCycle --第一个
        android:translationY="50dp"
        motion:framePosition="100"
        motion:target="@id/button"
        motion:waveOffset="0"
        motion:wavePeriod="1"
        motion:waveShape="square" />

    <KeyCycle --第二个
        android:translationY="50dp"
        motion:framePosition="0"
        motion:target="@id/button"
        motion:waveOffset="0"
        motion:wavePeriod="2"
        motion:waveShape="sin" />
</KeyFrameSet>

注意:当KeyFrameSet定义了多个KeyCycle时,只有最后一个定义(按照顺序而和framePostion无关系)的KeyCycle中的 waveShape会应用到整个 KeyFrameSet中(代码亲测):如上代码中,只有 waveShape=”sin” 会应用,而忽略 square的定义

MotionLayout II - 图8