ConstraintLayout 2.0新特性解析(三)-- MockView UI原型布局,Space边距补偿,MotionLayout动画

前言

MockView是一种UI原型样式的View,使用场景不是很多,了解下就行了。Space的边距补偿用处很大,使用ConstraintLayout的时候,往往有些场景设置margin不生效,但又不能设置约束条件,这个时候Space就派上用场了。MotionLayout动画非常强大,可以制作出各种出乎意料的动画,值得大家花些时间去学习。

系列文章:
ConstraintLayout 2.0新特性解析(一)--Flow流式布局
ConstraintLayout 2.0新特性解析(二)-- Layer层布局,圆角视图
ConstraintLayout 2.0新特性解析(三)-- MockView UI原型布局,Space边距补偿,MotionLayout动画

MockView

产品给出的原型稿,用MockView也可以轻松实现。例如:


图1

有几个属性可以配置:

  • app:mock_label:可以配置中间字体文案
  • app:mock_labelColor:中间字体文案色值
  • app:mock_diagonalsColor:对角线颜色
  • app:mock_labelBackgroundColor:中间字体的背景色
  • app:mock_showDiagonals:是否显示对角线,默认是true

Space

边距补偿的使用场景还是挺多的,有时候我们的约束条件并没写全,导致设置margin会有不生效的情况,这个时候如果想要达到margin效果,可以用Space的边距补偿效果。


图2

如图2,如果我们想让两个Image有相交汇的部分,该怎么实现呢?首先就想到设置下面图的marginTop和marginStart为负值就行了。
但很遗憾的告诉你,这种写法在ConstraintLayout是不会有效果的。

使用Space后:


图3

上代码:

    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Space
        android:id="@+id/space"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginEnd="30dp"
        android:layout_marginBottom="30dp"
        app:layout_constraintBottom_toBottomOf="@id/image1"
        app:layout_constraintRight_toRightOf="@id/image1" />

    <ImageView
        android:id="@+id/image2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintLeft_toLeftOf="@id/space"
        app:layout_constraintTop_toTopOf="@id/space" />

Space本质就是一个View,严格的说,Space并不是ConstraintLayout的新特性,只是一个单纯的占位view。结合ConstraintLayout使用,可以更灵活。

MotionLayout

接下来是压轴戏MotionLayout,MotionLayout可以让我们之间在xml里实现动画效果,无需再写一堆的代码,而且有专门的动画编辑器,可以实时预览动画效果,大大增加了开发效率。

1.使用

首先创建一个xml文件:


图1

MotionLayout是继承于ConstraintLayout,所以直接用MotionLayout当根标签即可。

刚刚创建好的MotionLayout会报错,是因为MotionLayout有一个必要属性:app:layoutDescription,可以直接使用快捷提示方式,创建对应的scene文件,

图2

会在xml文件夹下生成一个对应的scene文件。此时MotionLayout扔会报错:
图3

layoutDescription加上命名空间即可:

图4

到这里,一个完整的MotionLayout就创建完成了。

2.MotionScene

MotionLayout核心操作都在刚刚我们自动生成对应的scene的xml文件,这个xml的根标签是MotionScene

图5

MotionScene有两个子标签:ConstraintSetTransition

2.1 ConstraintSet

ConstraintSet有以下特点:
1.需成对出现,用来标识一个或多个动画的start和end。2.有一个子标签Constraint,用来标识需要操作的控件id及约束条件。可以使用ConstraintLayout对应的约束方式来约束需要操作的控件id。控件id需要跟MotionLayout中放置的view的id一致。

比如我们在MotionLayout添加一个图片:

图6

那么在ConstraintSet中就需要这么写:

图7

控制动画的开始和结束,只需要在Constraint设置约束条件即可,比如我们设置开始位置是水平居中,结束位置是水平居中,底部靠齐,就可以设置:
图8

基本可以理解为Constraint当成一个代理,通过对应的id可以代理MotionLayout中任何我们预先设置的控件。

2.2 Transition

Transition是用来操作动画,通过必要属性app:constraintSetStartapp:constraintSetEnd来操作对应id的控件的开始和结束。

Transition还有几个其他比较重要的属性:

  • app:duration:动画持续时间
  • app:autoTransition:自动开始动画效果,取值:none,animateToEnd(过渡到动画结束),animateToStart(过渡到动画开始),jumpToStart(直接跳转到动画开始状态),jumpToEnd(直接跳转到动画结束状态),默认取值none。
  • app:layoutDuringTransition:动画执行期间,MotionLayout子View调用reqeustLayout,是否做出响应回调。取值:ignoreRequest(不回调),honorRequest(回调)
  • app:motionInterpolator:动画插值器,取值:linear(线性),bounce(弹簧),easeIn(淡入),easeOut(淡出),easeInOut(淡入淡出,默认值)
  • app:pathMotionArc:运动弧线,取值:startHorizontal(水平默认,俗称抛物线模式),startVertical(锤子模式),flip(反转模式,需配合KeyPosition才有效果)
  • app:transitionDisable:动画是否启用,取值:true(启动),false(不启用)

Transition有几个关键的子标签

2.2.1 OnClick

OnClick子标签,可设置对应id的点击效果,有以下属性:

  • app:targetId:需要操作的控件Id
  • app:clickAction:点击效果,取值:toggle(可循环点击),jumpToStart(跳转到动画开始处),jumpToEnd(跳转到动画结束处),transitionToStart(过渡到动画开始),transitionToEnd(过渡到动画结束)
2.2.2 OnSwipe

OnSwipe子标签,可设置对应id的拖拽效果。有以下属性:



此次借用其他朋友的图来展示,一目了然。

2.2.3 KeyFrameSet

KeyFrameSet是中间帧的集合,其内有多个控制中间帧的子标签:KeyPosition,KeyAttribute,KeyCycle,KeyTimeCycle,KeyTrigger。Transition的属性仅能控制动画的起始,并不能对其轨迹做多种变化,如果想要更炫酷的动画,就需要这几个子标签的配合了。

2.2.3.1 KeyPosition

KeyPosition可以称为位置关键帧,主要用来定义动画移动的某个位置的动画。简单的说,就是可以将直线动画改成曲线,并且可以配置多个KeyPosition标签,让动画看起来更炫酷一些。

关键属性:

  • app:motionTarget:需要操作的视图Id
  • app:framePosition:发生曲线的位置。取值:0-100,将动画整体划分100份,设置多少,就代表在哪个位置发生曲线改变。
  • app:keyPositionType:参考坐标系。取值:pathRelative,parentRelative,deltaRelative。非常重要的属性,决定了坐标X和Y的结果。

pathRelative:以动画运动轨迹为参考。X轴和Y轴的0点坐标是start位置,start->end方向为X轴,此时Y轴方向为X轴方向的左侧,如图:

            <KeyPosition
                app:framePosition="50"
                app:motionTarget="@id/action_image"
                app:keyPositionType="pathRelative"
                app:percentX="0.5"
                app:percentY="0.2" />

此时Y轴有正有负,各种效果多测试下即可。

parentRelative:以父控件为参考。此时坐标0点为父控件的左上角。如图:

            <KeyPosition
                app:framePosition="50"
                app:motionTarget="@id/action_image"
                app:keyPositionType="parentRelative"
                app:percentX="0.2"
                app:percentY="0.5" />

deltaRelative:以整个动画过渡为参考,与pathRelative不同的是,坐标原点是start位置,坐标终点是end位置,可以理解为:start位置是(0.0)坐标,end位置是(1.1)坐标。

其余属性比较简单,大家自行测试,不再赘述。

2.1.3.1 KeyAttribute

KeyAttribute是属性动画关键帧,可以简单的配置旋转,缩放,位移等。
关键属性:
app:motionTarget:指定需要操作的视图id
app:framePosition:发生曲线的位置。取值:0-100,将动画整体划分100份,设置多少,就代表在哪个位置发生曲线改变。
其余属性很简单,大家自行测试,不再赘述。

2.2.3.2 KeyCycle

KeyCycle是循环关键帧。作用有很多,可以做出各种波形的轨迹,也可以自身旋转,缩放等具有循环功能的中间动画。
比如:

                        <KeyCycle app:motionTarget="@id/action_image"
                            app:waveShape="sin"
                            android:rotationY="180"
                            android:rotationX="180"
                            app:wavePeriod="1"/>

关键属性:

  • app:waveShape:循环帧模式,取值:sin,cos,square,bounce,triangle,sawtooth,reverseSawtooth
  • app:wavePeriod:波周期
2.2.3.2 KeyTimeCycle

KeyTimeCycle整体属性跟KeyCycle基本一致,唯一的区别就在于KeyCycle动画在OnClick或者OnSwip之后触发,而KeyTimeCycle的动画是始终存在,无论是否点击或者拖拽。

2.2.3.2 KeyTrigger

KeyTrigger意为关键帧方法触发。简单的来说,就是在设定的关键字位置上触发我们自定义的某个方法,来达到某些特殊的需求。
关键属性:

  • motionTarget:目标id
  • framePosition :关键帧位置。取值:0-100,将动画整体划分100份,设置多少,就代表在哪个位置发生曲线改变。
  • onCross :当动画越过此位置,调用配置的方法,value为自定义的方法名称。
  • onPositiveCross:关键帧前调用的方法
  • onNegativeCross:关键帧后调用的方法
  • motion_postLayoutCollision:定义动画前或者后的布局
  • motion_triggerOnCollision:定义与另一个motionTarget发生碰撞的motionTarget的id。
  • triggerId:发生碰撞后,使用此触发器调用TransitionListener
  • triggerSlack:如果framePosition没有将该分数移离触发点,则不要再次调用触发器

结语

MotionLayou功能比较强大,使用熟练后可以进行各种复杂的组合,从而创造出各种酷炫的动画。各种属性还需多做测试,看懂了,写熟练了,才能变成自己的东西。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容