1、前语

最近在开发中,搭档竟然对MontionLayout一知半解,那怎么行!百里偷闲写出此文章,一起学习、一起前进。假如写的不好,或许有过错之处,恳请在谈论、私信、邮箱指出,万分感谢

期望你在阅览这篇文章的时分,现已对下面的内容熟练掌握了

  • Animated Vector Drawable
  • Property Animation framework
  • LayoutTransition animations
  • Layout transitions with TransitionManager

对了还有ConstraintLayout有必要熟练掌握

对了,假如可以,请跟随敲代码,毕竟你脑补的代码,没有编译器。

当然你也可以阅览我的上一篇文章

  • 5分钟带你学会MotionLayou 第一篇
  • 5分钟带你学会MotionLayou 第二篇

2、OnSwipe、OnClick

同学们或许发现了,在上篇文章中,咱们运用了两个交互动作OnSwipeOnClick

  <Transition
    motion:constraintSetEnd="@+id/end"
    motion:constraintSetStart="@+id/start"
    motion:duration="1000"><OnSwipe
      motion:dragDirection="dragEnd"
      motion:touchAnchorId="@+id/button1"
      motion:touchAnchorSide="end" />
    <!--OnClick 用于处理用户点击事情 -->
    <!--targetId 设置触发点击事情的组件 -->
    <!--clickAction 设置点击操作的呼应行为,这里是使动画过渡到完毕状况 -->
    <OnClick
      motion:clickAction="transitionToEnd"
      motion:targetId="@+id/button1" /></Transition>

这两位直面意思便是点击事情和滑动事情,OnClick的特点是十分简练的,由于仅仅个点击事情而已

  • targetId:点击事情要运用的视图 ID。

  • clickAction:界说点击事情的行为,可以有以下几种取值:

    • toggle:切换视图的状况。
    • transitionToEnd:将视图从当时方位过渡到完毕方位。
    • transitionToStart:将视图从当时方位过渡到开端方位。
    • jumpToEnd:立行将视图移动到完毕方位。
    • jumpToStart:立行将视图移动到开端方位。

OnSwipe的话,特点就比较多,可是都很直白,各位直接看看,需求用的时分找一找,多用用多看看就记住啦。

  • dragScale:界说拖拽操作的缩放比例。这个特点通常用于完成一些扩大缩小的作用,可以让用户经过手势对视图进行缩放。

  • dragThreshold:界说拖拽的最小阈值,当拖拽间隔小于该值时,视图不会呼应拖拽事情。这个特点可以用于操控视图呼应拖拽事情的灵敏度。

  • autoCompleteMode:界说主动完结的形式,可以有以下两种取值:

    • continuousVelocity:运用连续的速度主动完结。
    • spring:运用绷簧作用主动完结。
  • maxVelocity:界说最大速度,当拖拽速度超越该值时,视图将不再呼应拖拽事情。

  • maxAcceleration:界说最大加速度,当拖拽加速度超越该值时,视图将不再呼应拖拽事情。

  • springMass:界说绷簧质量。

  • springStiffness:界说绷簧刚度。

  • springDamping:界说绷簧阻尼。

  • springStopThreshold:界说绷簧中止的阈值,当速度小于该值时,绷簧将中止弹动。

  • springBoundary:界说绷簧鸿沟,可以有以下几种取值:

    • overshoot:超出鸿沟时绷簧会继续弹动。
    • bounceStart:当拖拽到开端方位时绷簧会弹动。
    • bounceEnd:当拖拽到完毕方位时绷簧会弹动。
    • bounceBoth:当拖拽到开端或完毕方位时绷簧会弹动。
  • dragDirection:界说拖拽方向,可以有以下几种取值:

    • horizontal:只能水平拖拽。
    • vertical:只能笔直拖拽。
    • both:可以水平和笔直拖拽。
  • touchAnchorId:界说接触点的锚定视图 ID。

  • touchAnchorSide:界说接触点在锚定视图中的方位,可以有以下几种取值:

    • top:接触点坐落锚定视图的顶部。
    • bottom:接触点坐落锚定视图的底部。
    • left:接触点坐落锚定视图的左侧。
    • right:接触点坐落锚定视图的右侧。
    • center:接触点坐落锚定视图的中心。
  • rotationCenterId:界说旋转中心的视图 ID。

  • touchRegionId:界说接触区域的视图 ID。

  • limitBoundsTo:界说限制鸿沟的视图 ID。

  • nestedScrollFlags:界说嵌套翻滚的标志位,可以有以下几种取值:

    • none:不支撑嵌套翻滚。
    • disablePostScroll:制止翻滚完毕后的翻滚。
    • disableScroll:制止翻滚。
    • supportScrollUp:支撑向上翻滚。
  • moveWhenScrollAtTop:界说是否在翻滚到顶部时答应拖拽。

  • onTouchUp:界说当手指离开屏幕时的行为,可以有以下几种取值:

    • autoComplete:主动完结拖拽。
    • autoCompleteToStart:主动完结拖拽并回到开端方位。
    • autoCompleteToEnd:主动完结拖拽并回到完毕方位。
    • stop:中止拖拽。
    • decelerate:减速拖拽。
    • decelerateAndComplete:减速拖拽并完结拖拽。
    • neverCompleteToStart:永久不要主动完结到开端方位。
    • neverCompleteToEnd:永久不要主动完结到完毕方位。

关于绷簧作用,单纯是为了愈加天然。

以上便是两个的全部(部分?)特点啦,假如你需求更详细的了解,你可以在MotionLayout的资源目录中找到。

3、KeyFrameSet

在输入<符号时,弹出的三个提示,前面两个咱们现已了解了。那么第三个KeyFrameSet是什么意思呢。

5分钟带你学会MotionLayout 第二篇

在一些情况下,您或许期望在转化视图状况时,具有中间状况,即一个需求经过但不需求逗留的状况。您可以指定多于两个 ConstraintSet,但更轻量的办法是运用 Keyframes。

在束缚布局中运用 Keyframes,需求界说一个 KeyPosition 方针和一个 KeyAttribute 方针。KeyPosition 方针界说了中间状况的方位,KeyAttribute 方针界说了中间状况的特点值。您可以将多个 KeyPositionKeyAttribute 方针组合成一个 Keyframes 方针,并将其运用于束缚布局中的任何特点。

fragment_motion_04_basic.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"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/ml_container"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layoutDescription="@xml/motion_layout_04_scene"
  tools:showPaths="true">
​
  <View
    android:id="@+id/button1"
    android:layout_width="64dp"
    android:layout_height="64dp"
    android:layout_marginStart="8dp"
    android:background="@color/orange"
    android:text="Button"/>
​
  <View
    android:id="@+id/button2"
    android:layout_width="64dp"
    android:layout_height="64dp"
    android:layout_marginStart="8dp"
    android:background="@color/orange"
    android:text="Button" />
</androidx.constraintlayout.motion.widget.MotionLayout>

motion_layout_04_scene.xml

<?xml version="1.0" encoding="utf-8"?>
<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="1000"
    motion:motionInterpolator="linear">
    <OnSwipe
      motion:dragDirection="dragRight"
      motion:touchAnchorId="@+id/button1"
      motion:touchAnchorSide="right" />
​
    <KeyFrameSet>
      <KeyPosition
        motion:framePosition="25"
        motion:keyPositionType="pathRelative"
        motion:motionTarget="@+id/button1"
        motion:percentY="0.1" />
​
      <KeyPosition
        motion:framePosition="75"
        motion:keyPositionType="pathRelative"
        motion:motionTarget="@+id/button1"
        motion:percentY="-0.1" />
    </KeyFrameSet>
​
    <KeyFrameSet>
      <KeyPosition
        motion:framePosition="25"
        motion:keyPositionType="pathRelative"
        motion:motionTarget="@+id/button2"
        motion:percentY="0.3" />
​
      <KeyPosition
        motion:framePosition="75"
        motion:keyPositionType="pathRelative"
        motion:motionTarget="@+id/button2"
        motion:percentY="-0.3" />
      <KeyAttribute
        android:scaleX="2"
        android:scaleY="2"
        android:rotation="-45"
        motion:framePosition="50"
        motion:motionTarget="@id/button2" />
    </KeyFrameSet>
  </Transition>
​
  <ConstraintSet android:id="@+id/start">
    <Constraint
      android:id="@+id/button1"
      android:layout_width="64dp"
      android:layout_height="64dp"
​
      android:layout_marginStart="6dp"
      motion:layout_constraintBottom_toTopOf="@id/button2"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toTopOf="parent" />
​
    <Constraint
      android:id="@+id/button2"
      android:layout_width="64dp"
      android:layout_height="64dp"
​
      android:layout_marginStart="8dp"
      motion:layout_constraintBottom_toBottomOf="parent"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toBottomOf="@id/button1" />
  </ConstraintSet>
​
  <ConstraintSet android:id="@+id/end">
    <Constraint
      android:id="@+id/button1"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      android:layout_marginEnd="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button2"
      motion:layout_constraintEnd_toEndOf="parent"
      motion:layout_constraintHorizontal_bias="1"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toTopOf="parent" />
​
​
    <Constraint
      android:id="@+id/button2"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      android:layout_marginEnd="8dp"
      motion:layout_constraintBottom_toBottomOf="parent"
      motion:layout_constraintEnd_toEndOf="parent"
      motion:layout_constraintHorizontal_bias="1"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toBottomOf="@id/button1" />
  </ConstraintSet>
​
</MotionScene>

作用如下啦。

5分钟带你学会MotionLayout 第二篇

KeyPosition还有许多特点,大都都是一看就懂的特点

  • keyPositionType:界说如何核算要害帧的误差。可以设置为 deltaRelativepathRelativeparentRelative 三种取值之一。运用 deltaRelative 时,要害帧的误差相关于线性途径核算;运用 pathRelative 时,要害帧的误差相关于途径核算;运用 parentRelative 时,要害帧的误差相关于父视图核算。
  • percentXpercentY:界说要害帧在 X 和 Y 轴上的方位。可以设置为 0 到 1 之间的浮点数,表明从开端状况到完毕状况之间的相对方位。
  • percentWidthpercentHeight:界说宽度和高度的改变量。可以设置为 0 到 1 之间的浮点数,表明从开端状况到完毕状况之间的相对改变量。注意,假如宽度或高度没有改变,则这些特点将没有任何作用。
  • framePosition:界说要害帧在动画中的方位。可以设置为 0 到 100 之间的整数,表明从动画开端到完毕之间的相对方位。
  • motionTarget:界说运用此要害帧的运动方针。可以是一个视图或许一个运动场景。
  • transitionEasing:界说要害帧的过渡缓动作用。可以运用 Android 体系中供给的各种缓动函数,比如 easeIn, easeOut 等。
  • pathMotionArc:界说要害帧在途径上的运动方式。可以设置为 nonestartVerticalendVerticalfliprotate 等五种取值之一。
  • curveFit:界说要害帧的插值方式。可以设置为 linearsplinediscrete 等三种取值之一。
  • drawPath:界说是否在编辑器中制作要害帧途径。
  • sizePercent:界说宽度和高度的百分比。可以设置为 0 到 1 之间的浮点数,表明相关于视图父级的百分比。

由于keyPositionType可以说许多,我会在后面的文章,继续展开。这里咱们只运用pathRelative

KeyAttribute还有许多特点,大都都是一看就懂的特点

  • framePosition:界说要害帧在动画中的方位。可以设置为 0 到 100 之间的整数,表明从动画开端到完毕之间的相对方位。
  • motionTarget:界说运用此要害帧的运动方针。可以是一个视图或许一个运动场景。
  • transitionEasing:界说要害帧的过渡缓动作用。可以运用 Android 体系中供给的各种缓动函数,比如 easeIn, easeOut 等。
  • curveFit:界说要害帧的插值方式。可以设置为 linearsplinediscrete 等三种取值之一。
  • motionProgress:界说要害帧的运动进展,即从开端状况到完毕状况之间的进展百分比。
  • alpha:界说视图的不透明度。可以设置为 0 到 1 之间的浮点数,表明视图的透明度。
  • elevation:界说视图的高度。可以设置为一个浮点数,表明视图的高度。
  • rotationrotationXrotationY:界说视图的旋转视点,可以别离设置 X、Y、Z 轴上的旋转视点。
  • transformPivotXtransformPivotY:界说视图的改换中心点坐标。
  • transformPivotTarget:界说改换中心点的方针视图。
  • transitionPathRotate:界说视图在途径上的旋转视点。
  • scaleXscaleY:界说视图的缩放比例。
  • translationXtranslationYtranslationZ:界说视图的方位偏移量。

4、CustomAttribute

假如仅仅只能动画化咱们之前提过的特点,那么MotionLayout只会显得过于单调,而假如经过代码去动态修改某些状况,那就体现不出MotionLayout的优势了。

所以CustomAttribute一个自界说特点调集,用于将自界说特点运用于视图或运动场景。运用 CustomAttribute,您可以将任何自界说特点与束缚布局中的其他特点结合运用,从而完成愈加杂乱和灵活的布局作用。

CustomAttribute 自界说特点调集中的一些要害特点:

  • attributeName:界说自界说特点的称号。。
  • customColorValue:界说自界说颜色值。可以设置为一个整数,表明颜色值。
  • customDimension:界说自界说尺度值。可以设置为一个浮点数,表明尺度值。
  • customFloatValue:界说自界说浮点数值。可以设置为任何浮点数。
  • customIntegerValue:界说自界说整数值。可以设置为任何整数。
  • customStringValue:界说自界说字符串值。可以设置为任何字符串。

咱们来试一下

fragment_motion_05_basic.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"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/ml_container"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layoutDescription="@xml/motion_layout_05_scene"
  tools:showPaths="true">
​
  <View
    android:id="@+id/button1"
    android:layout_width="64dp"
    android:layout_height="64dp"
    android:layout_marginStart="8dp"
    android:background="@color/orange"
    android:text="Button"
    app:layout_constraintBottom_toTopOf="@id/button2"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
​
  <androidx.constraintlayout.utils.widget.ImageFilterView
    android:id="@+id/button2"
    android:layout_width="64dp"
    android:layout_height="64dp"
    android:layout_marginStart="8dp"
    android:src="@mipmap/icon_menu_emoticon1"
    app:altSrc="@mipmap/icon_menu_emoticon3"
    android:text="Button"
    app:layout_constraintBottom_toTopOf="@id/button3"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/button1" />
​
  <androidx.constraintlayout.utils.widget.ImageFilterView
    android:id="@+id/button3"
    android:layout_width="64dp"
    android:layout_height="64dp"
    android:layout_marginStart="8dp"
    android:src="@mipmap/icon_menu_emoticon2"
    android:text="Button"
    app:layout_constraintBottom_toTopOf="@id/button4"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/button2" />
​
</androidx.constraintlayout.motion.widget.MotionLayout>

motion_layout_05_scene.xml

<?xml version="1.0" encoding="utf-8"?>
<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="1000">
    <!--OnClick 用于处理用户点击事情 -->
    <!--targetId 设置触发点击事情的组件 -->
    <!--clickAction 设置点击操作的呼应行为,这里是使动画过渡到完毕状况 -->
    <OnSwipe
      motion:dragDirection="dragEnd"
      motion:touchAnchorId="@+id/button1"
      motion:touchAnchorSide="end" />
​
  </Transition>
​
  <ConstraintSet android:id="@+id/start">
​
    <Constraint
      android:id="@+id/button1"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button2"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toTopOf="parent">
      <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60" />
    </Constraint>
​
    <Constraint
      android:id="@+id/button2"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button3"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toBottomOf="@id/button1">
      <CustomAttribute
        motion:attributeName="crossfade"
        motion:customFloatValue="0" />
    </Constraint>
    <Constraint
      android:id="@+id/button3"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button4"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toBottomOf="@id/button2" >
      <CustomAttribute
        motion:attributeName="saturation"
        motion:customFloatValue="1" />
    </Constraint>
​
  </ConstraintSet>
​
  <ConstraintSet android:id="@+id/end">
    <Constraint
      android:id="@+id/button1"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginEnd="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button2"
      motion:layout_constraintEnd_toEndOf="parent"
      motion:layout_constraintHorizontal_bias="1"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toTopOf="parent">
      <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#9999FF" />
    </Constraint>
​
    <Constraint
      android:id="@+id/button2"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button3"
      motion:layout_constraintEnd_toEndOf="parent"
      motion:layout_constraintHorizontal_bias="1"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toBottomOf="@id/button1">
      <CustomAttribute
        motion:attributeName="crossfade"
        motion:customFloatValue="1" />
    </Constraint>
​
    <Constraint
      android:id="@+id/button3"
      android:layout_width="64dp"
      android:layout_height="64dp"
      android:layout_marginStart="8dp"
      motion:layout_constraintBottom_toTopOf="@id/button4"
      motion:layout_constraintEnd_toEndOf="parent"
      motion:layout_constraintHorizontal_bias="1"
      motion:layout_constraintStart_toStartOf="parent"
      motion:layout_constraintTop_toBottomOf="@id/button2" >
      <CustomAttribute
        motion:attributeName="saturation"
        motion:customFloatValue="0" />
​
    </Constraint>
  </ConstraintSet>
​
</MotionScene>

5分钟带你学会MotionLayout 第二篇

值得注意的是

自界说特点的称号有必要与View具有相应的setter办法称号相匹配,才能在MotionLayout中运用。例如,假如您想要界说一个名为”customText”的CustomAttribute来操控TextView的文本内容,那么TextView中需求有一个名为为”setCustomText”的办法,以便MotionLayout可以找到相应的setter办法。

因此,只要View具有相应的setter办法的自界说特点才能被运用。假如您想要运用一个View没有的特点,您需求创建一个新的自界说View并完成相应的setter和getter办法。

5、下个华章

由于篇幅原因,咱们先到这,下一篇咱们将会深化了解各种运用事例~。

假如您有任何疑问、对文章写的不满意、发现过错或许有更好的办法,欢迎在谈论、私信或邮件中提出,十分感谢您的支撑。

6、感谢

  1. 校稿:ChatGpt
  2. 文笔优化:ChatGpt