Animation with MotionLayout
Posted xiaoqiang_0719
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Animation with MotionLayout相关的知识,希望对你有一定的参考价值。
文章目录
简介
MotionLayout是ConstraintLayout的子类,它能够为布局内的控件添加动画效果
它的实现方式简单来讲就是通过处理两个ConstraintSet之间的切换(start,end),并根据ConstraintSet定义的参数来自动生成切换动画
使用入门
添加 ConstraintLayout 依赖
在 build.gradle 文件添加 ConstraintLayout 2.0 的依赖,注意 MotionLayout 是 ConstraintLayout 2.0 以后才有的功能,所以ConstraintLayout版本必须是大于等于2.0
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
将ConstraintLayout转为MotionLayout
如下图,打开布局文件进入split或者Design模式,右键选择Convert to MotionLayout这样就会进入MotionLayout的布局模式 ,ConstraintLayout会被转换成MotionLayout,并且在res下创建xml文件夹新增一个MotionScene文件,动画的相关配置都是储存在这个文件中
<?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:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/test_scene">
</androidx.constraintlayout.motion.widget.MotionLayout>
自动生成的MotionScene文件代码:
<?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">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
</ConstraintSet>
</MotionScene>
开始创建动画
动画的设置可以在xml文件中进行编辑,也可以在MotionLayout Editor中进行编辑,推荐大家使用第二种方式(操作简单,提示智能)
在编辑区域可以看到两个可以点击的区域,一个名字是start,一个是end。 他们代表的是动画效果的开始状态和结束状态
定义开始和结束动画
Motion编辑器中点击start、end,选择下方需要执行动画的控件修改其开始、结束的参数,可以修改位置,大小,透明度,以及自定义属性(get、set方法)等等。。
定义过渡动画
定义动画应花费的时间以及如何处理用户触摸以滑动动画。
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<OnClick
motion:targetId="@id/button"
motion:clickAction="toggle" />
//<OnSwipe /> 只有两种操作,点击(OnClick)和滑动(OnSwipe)
</Transition>
在Motion编辑器中预览动画
图片变换
使用ImageFilterView设置srcCompat和altSrc, 分别代表显示的第一张图片和第二张图片
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/image_filter_view"
android:layout_width="100dp"
android:layout_height="100dp"
app:altSrc="@mipmap/back_local_hdd_cover"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"
app:srcCompat="@mipmap/back_local_usb_cover" />
KeyFrameSet 定义关键帧
位置关键帧 KeyPosition
motion:framePosition=“20” 数值区间是[0-100]
motion:keyPositionType=“parentRelative” 相对布局坐标系
motion:motionTarget="@+id/image_filter_view" 目标控件
keyPositionType有三种坐标系, deltaRelative、parentRelative、pathRelative
parentRelative
deltaRelative
pathRelative
<KeyPosition
motion:framePosition="20"
motion:keyPositionType="parentRelative"
motion:motionTarget="@+id/image_filter_view"
motion:percentX="0.2"
motion:percentY="0.4" />
属性关键帧 KeyAttribute
<KeyAttribute
android:alpha="0.5"
motion:framePosition="50"
motion:motionTarget="@+id/image_filter_view" />
标准属性的列表:
- android:visibility
- android:alpha
- android:elevation
- android:rotation
- android:rotationX
- android:rotationY
- android:scaleX
- android:scaleY
- android:translationX
- android:translationY
- android:translationZ
触发器关键帧 KeyTrigger
当到达某个关键帧之后触发该motionTarget的某个方法
<KeyTrigger
motion:framePosition="10"
motion:motionTarget="@+id/image_button"
motion:onNegativeCross="revertImage"
motion:onPositiveCross="changeImage" />
循环关键帧 KeyCycle
用来给动画添加振动,他表示在动画过程中的循环动画
<KeyCycle
motion:framePosition="30"
motion:motionTarget="@id/button_first"
motion:wavePeriod="1"
motion:waveShape="sin"
android:rotation="50" />
循环动画关键帧 KeyTimeCycle
表示循环动画,他会一直显示在View上,不会随着动画的变化而消失
<KeyTimeCycle
android:rotation="50"
motion:motionTarget="@id/button_first"
motion:wavePeriod="1"
motion:waveShape="sin" />
触发动画的几种方式
OnClick
<OnClick
motion:clickAction="toggle"
motion:targetId="@id/button_first" />
targetId表示点击对应的View触发。
clickAction标识view在start状态和end状态切换的方式,它有5个值:
toggle:来回切换
jumpToStart:瞬间跳转到start状态,没有动画
jumpToEnd:瞬间跳转到end状态,没有动画
transitionToStart:动画过渡到start状态
transitionToEnd:动画过渡到end状态
OnSwipe
<OnSwipe
motion:dragDirection="dragRight"
motion:touchAnchorId="@id/button_first"
motion:touchAnchorSide="bottom" />
代码调用
motion_layout.setTransitionDuration(3000)
motion_layout.transitionToState(R.id.end)
motion_layout.transitionToEnd()
motion_layout.addTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
Log.i(TAG, "onTransitionStarted: $p1..$p2")
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
Log.i(TAG, "onTransitionChange: $p1..$p2..$p3")
}
override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {
Log.i(TAG, "onTransitionCompleted: $p1 ")
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
Log.i(TAG, "onTransitionTrigger: $p1..$p2..$p3")
}
})
注意事项
-
MotionScene 中的定义的布局优先于 MotionLayout 中的任何类似定义
-
当MotionLayout侦听拖动事件时,侦听器将在MotionLayout视图上注册,而不是在touchAnchorId指定的视图上touchAnchorId
-
使用OnSwipe一定要设置dragDirection,不然会有回弹
-
直接通过xml代码的情况下,无法设置动画的衔接,设定动画的先后顺序,但是可以通过别的途径来修改
比如:触发器关键帧 KeyTrigger到100 之后执行某个动作,或者在代码中使用addTransitionListener监听来处理两个动画衔接(虽然可以通过上述方式实现,但是MotionLayout的使用场景不是用来衔接动画的,而是作为一个过渡动画,应该适用于一些控件切换,界面变化之类的动画)
Demo示例
以上是关于Animation with MotionLayout的主要内容,如果未能解决你的问题,请参考以下文章
《Character Animation with Direct3D》阅读笔记
《Character Animation with Direct3D》阅读笔记