简单描述/说明
谈MotionLayout之前得先了解一下过渡动画,工作中我其实很少去使用过渡动画,工作中目前用的最多的应该就是属性动画了,但是都知道属性动画的变化受其ViewGroup的影响,简言之:View的变化不会使ViewGroup及其子元素跟着变化,没有一种联动的效果。
过渡动画的使用很简单,就是在view的属性改动前,加上一句:
TransitionManager.beginDelayedTransition(viewGroup); //改变view的layoutParams ...
注意这里是传入ViewGroup,TransitionManager会先记录当前VG的状态,这样在View属性改变时才会有一种过渡的感觉,即:View的变化会使ViewGroup及其子元素跟着变化,这样在你改变一个子view的时候,ViewGroup和其中的子view都会重新进行测量。
当然过渡动画也可以对一个viewGroup进行整体的过渡替换,使用的方法是:
ViewGroup viewGroup=findViewById(R.id.root); Scene sceneStart = Scene.getSceneForLayout(viewGroup, R.layout.rootStart, this); Scene sceneEnd = Scene.getSceneForLayout(viewGroup, R.layout.rootEnd, this); //---- 切换到初始布局 TransitionManager.go(sceneStart); OR //---- 切换到结束布局 TransitionManager.go(sceneEnd); ...
但是有个点需要注意:数据、点击事件等都需要重新绑定。原因可以在go方法源码中找到,在go方法的方法体内有个changeScene函数,在该函数调用的scene.enter()中可以看到以下代码:
然后看注释也就明白了。总结下过渡动画的大致流程:
- 两个场景,一个【开始场景】一个【结束场景】,记录场景上的空控件的各种参数
- 有了参数,创建出动画对象
- 播放动画
上面说到两种过渡动画的使用,都有缺点,第一种是只能给单个view进行设置,属性的更改需要在代码中进行。第二种是对ViewGroup设置后,因为控件被重新初始化从而需要重新绑定数据。那么有没有一个可以将这两个优点结合,缺点解决的办法呢?答案是有的,就是ConstraintSet()。
PS:关于过渡动画细节,网上很多地方都有写到,比如:https://juejin.im/post/5ae057e46fb9a07aa83e682
ConstraintSet,一听就知道是约束布局的辅助,所以这里还不需要用到MotionLayout,仅仅只需要ConstraintLayout即可,用法如下:
ConstraintLayout root = findViewById(R.id.root); TransitionManager.beginDelayedTransition(root); ConstraintSet constraintSet=new ConstraintSet(); //---- clone初始布局属性 constraintSet.clone(this,R.layout.constraint_rootStart); OR //---- clone结束布局属性 constraintSet.clone(this,R.layout.constraint_rootEnd); //应用 constraintSet.applyTo(root);
这里是clone方法,意思是,将对应布局对应id的控件属性值进行重新赋值,你可以先在xml中写好界面,执行上面的代码就可以随意切换了,这里需要注意的是:与TransitionManager.go一样,xml布局中每个元素都需要有id,且两个布局中控件id 类型需要对应。区别是,TransitionManager.go会移除控件再添加,这个只是做布局参数属性赋值。
那,这样就完美了吗?答案肯定不是的,缺点如下:
- 不能控制进度,过程中无法暂停。
- 不支持触摸反馈,没办法设置高级的触摸反馈,只有点击什么的,因为改了布局属性,其他的对view的设置都会失效无法保存。
- 布局中存在重复部分,它们id一样,属性也有相同的地方。
- 增加了新的layout文件,增加了文件查找的复杂度,而这些文件实际只是布局片段。
MotionLayout
MotionLayout,一句话,很简单:MotionLayout 类继承自 ConstraintLayout 类,允许你为各种状态之间的布局设置过渡动画,意味着,你可以在xml中进行过渡动画的设置。
因为比较懒,就不弄图文+动效了,直接上配置文件,把关键点记录下。
用法:
- ConstraintLayout 改为 MotionLayout。
- 创建 MotionScene 文件并使⽤ app:layoutDescription进行关联,MotionScene文件放xml文件夹即可。
MotionLayout使用MotionScene文件进行相关动画配置,配置文件主要分三大部分,如下
<?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"> <!--用于过渡动画的详细配置--> <Transition app:constraintSetEnd="@id/end" app:constraintSetStart="@id/start" app:duration="1000"> //... </Transition> <!--用于过渡动画的起始点状态参数配置--> <ConstraintSet android:id="@+id/start"> //... </ConstraintSet> <!--用于过渡动画的结束点状态参数配置--> <ConstraintSet android:id="@+id/end"> //... </ConstraintSet> </MotionScene>
没看错,就这么点东西,本来用代码写的,可以全配置在这个MotionScene文件中,然后介绍下相关节点
Constraint节点
ConstraintSet中可以包含多个Constraint,每个Constraint对应一个view,可控制view的UI显示,约束,宽高等属性状态,自定义view也可支持,结构如下:
<Constraint android:id="@id/viewId"> <!-- 运动模型: 弧线路路径,时间模型等 --> <Motion/> <!-- 布局相关 注意: width 、 height 和 margin 的命名空间是 android: (beta1 开始) 而约束相关的命名空间是 app (或 motion ) --> <Layout/> <!-- 动画变换:做旋转,位移,缩放,海海拔等属性 --> <Transform/> <!-- 自定义属性 attributeName 会加上 set/get 反射找到真正的函数名, ⽐如 backgroundColor 就会调用 setBackgroundColor() 函数 custom(xxx)Value 对应属性的数据类型 --> <CustomAttribute/> <!-- 特定的属性 visibility 、alpha 等属性 --> <PropertySet/> </Constraint>
关于时间模型(加速、减速插值器…)
每个控件可以单独设置时间模型
在 <Motion> 节点中使⽤ app:transitionEasing
整个 Transition 也可以设置插值器
在<Transition>中使⽤app:motionInterpolator
Transition 节点
过渡动画的详细配置,可进行动画时长,触摸反馈,关键帧,动画的相关配置。大概结构如下:
<Transition app:constraintSetStart="@+id/start" app:constraintSetEnd="@+id/end" app:duration="1000"> <OnSwipe app:touchAnchorId="@id/viewId" app:dragDirection="dragDown"/> <OnClick app:clickAction="toggle" app:targetId="@id/viewId"/> <KeyFrameSet > <KeyAttribute> <CustomAttribute/> </KeyAttribute> <KeyPostion/> <KeyCycle/> <KeyTimeCycle/> </KeyFrameSet> </Transition>
onSwipe
滑动触摸事件
- touchRegionId 指的是哪一个控件响应触摸事件。
- touchAnchorId ⼀般不用
- autoComplete 默认的是 true ,会根据动画完成的百分⽐⾃动到最近的一个状态
- dragDirection 拖拽的方向
OnClick
点击触摸事件
- targetId 指定控件
- clickAction 注意这里是指点击后动画状态的改变 而不是执行某个自定义函数
- toggle 反转状态
- transitionToEnd/Start 通过动画到结束/起始状态
- jumpToEnd/Start 没有动画直接到结束/起始状态
KeyFrameSet
可以设置位移,旋转,缩放等属性,同时还可以通过 CustomAttribute 添加自定义属性
- app:motionTarget 目标对象 ID
- app:framePosition 百分⽐(0 – 100) 需要改变的帧位置
其子节点有:
KeyPosition 位置关键帧
KeyPosition 可以帮助视图改变运动的路径形状
- percentX/Y 在关键帧时,对应路路径的对应百分⽐
- percentWidth/Height 在关键帧时,控件⼤⼩改变的百分⽐
- curveFit 运动路径的样式(直线,曲线等)
- keyPositionType 坐标系
- parentRelative
- (0,0)为父容器左上⻆
- (1,1)为⽗容器右下角
- deltaRelative
- (0,0)为起始控件中心
- (1,1)为结束控件中⼼
- pathRelative
- (0,0)为起始控件中⼼
- (1,0)为结束控件中⼼
- parentRelative
KeyCycle 和 KeyTimeCycle
通过 3 个 KeyCycle 定义一个准确的循环关键帧,主要用于处理类似波形的动画
<KeyFrameSet>
<KeyTimeCycle
android:rotation="0"
app:framePosition="0"
app:motionTarget="@id/viewId"
app:wavePeriod="0"
app:waveShape="sin" />
<KeyTimeCycle
android:rotation="45"
app:framePosition="50"
app:motionTarget="@id/viewId"
app:wavePeriod="10"
app:waveShape="sin" />
<KeyTimeCycle
android:rotation="0"
app:framePosition="100"
app:motionTarget="@id/viewId"
app:wavePeriod="0"
app:waveShape="sin" />
</KeyFrameSet>
相关属性:
- wavePeriod 表示循环次数 (在KeyTimeCycle中表示每秒循环次数)
- waveShape 数学模型
分享一篇文章,用于加深部分属性的理解:https://juejin.im/post/5d2afcfef265da1b8a4f4d0e
实例有同僚写了:https://juejin.im/post/5c358e05f265da615b71a536
以上,仅作笔记记录,部分总结来自讲义。
本站由以下主机服务商提供服务支持:
小王
您好,我是一名刚毕业的学生,现在正在求职中,主要求职方向为Android开发。在求职的过程中逐渐认识到了自身的不足,想提高下自身水平,无意间看到了朱老师的【HenCoder Plus】系列课程,但由于囊中羞涩承担不起正版课…想问下能否麻烦楼主分享下本课的相关资源呢?不胜感激!
Mosaic-C
不好意思的说,不太方便。
第一是因为 腾讯课堂并不支持离线后分享,如果使用技术手段实现,章节之多耗费精力也不小,并可能给我带来法律隐患。
第二是因为 Hencoder Plus 本身不适合新手去听,两年前我买的,现在在重新刷,因为很多之前未能理解。(扔老师的原话也是需要刷3~5遍)。
第三是因为 这个课是重基础与原理,完成耗时巨大,不适合用于短时间内进行面试突破,同时本身需要结合很多背景知识才能理解通透。
其实我那时候刚毕业也是用了花呗分期才买下来的,所以你现在最适合的是在面试过程中,总结经验,缺什么去补什么,虔诚一点,会找到公司的,然后在周末,多做练习。
刚出来不要怕失败,多吃点苦懂得也多点,加油!