美文网首页
Android ConstraintLayout相关

Android ConstraintLayout相关

作者: 高丕基 | 来源:发表于2018-09-03 21:37 被阅读167次

1、概述

ConstraintLayout是一个强大的布局类,它是用来替代之前RelativeLayout或LinearLayout等的布局类。目前官方也将其作为创建布局时的默认类。相比于传统的布局类,ConstraintLayout更加易于操作,并且功能强大,绘制视图的性能也更具优势,同时配有强大的动画支持,所以毫不夸张的说,今后的布局只要采用ConstraintLayout就够了。

2、基础操作

2.1 布局编辑器(The Layout Editor)

ConstraintLayout的一大优势就是具有极其良好的可视化布局编辑器。它允许将UI元素拖动到可视设计区和蓝图视图区,将元素放置在布局中,并添加约束和设置属性。布局编辑器如下所示:

布局编辑器

① 工具栏 :有一些关于ConstraintLayout的处理工具和用来设置编辑视图的一些工具。例如

② 调色板:内有各种需要的视图,例如button、textView等。

③ 设计视图:目前设计的布局展现在对应型号的手机中的样子。

④ 蓝图视图:包含布局内各个视图之间的关系可视化描述。

⑤ 组件树:目前布局内的各个视图之间的关系树。

2.2 视图检查器

单击设计视图中的每一个视图会出现视图检查器版面:

视图检查器

① 点击该按钮能关闭视图检查器

② 用来展示该视图的对应方向的边距,可更改。

③ 用来展示该视图的layout_width和layout_height类型。

定值类型

定值类型:指定视图的宽度和高度。

匹配约束类型

匹配约束类型:允许视图占有约束剩余空间,类似于将layout_width或者layout_height设置成match_parent的效果。但是在ConstraintLayout中不存在match_parent这个值,在xml里需要将layout_width或者layout_height设置成0dp来达到该效果。

内容适应类型

内容适应类型:该类型就是将layout_width或者layout_height设置成wrap_content。

宽高类型切换

④ 用来调整约束偏差。

默认情况下当左右或者上下两边都设置了约束时(如果只设置一边,会挨着设置的一边,也就不存在约束偏差一说),其默认约束偏差为50,也就是说处于两者约束的中间。当其偏差不为50时,就会存在更加靠近其中一边。效果如下:

调整约束偏差

tips:

查看视图所有属性

2.3 约束(Constraints)

ConstraintLayout最核心也是最基础的概念就是约束。约束定义布局中两个视图之间的关系,并控制这些视图在布局中的定位方式。RelativeLayout和中一些约束关系很像。如下图:

约束

上面的两个箭头表明Button在右侧和底部存在对于父ConstraintLayout的边缘的约束。还可以看到有8dp的边距。一个视图存在上下左右四个约束锚点。一旦添加上约束,那么它的位置就要受这个约束所束缚。

在蓝图视图或设计视图中,可以看到每个视图上下左右有四个小点,这四个小点称作约束句柄,用来创建四个方向的约束:

约束句柄

同时在四个角有四个小方块,这四个小方块用来调整视图的大小:

调整大小句柄

同时可以将一个元素约束到另一个元素:

约束到另一视图

还可以使用基线约束来对齐具有文本的视图,这种约束可以使两者的文本基线对齐:

基线约束

可以将视图的约束句柄连接到任何的其他视图或布局的约束句柄,但是只能是水平句柄连水平句柄,垂直句柄连垂直句柄。同时基线句柄只能和基线句柄相连。

用户可以点击工具栏中的如下按钮来开启自动创建约束按钮:

自动创建约束

其开启后当视图移动到一些推荐指南位置放下,将会自动创建相关约束:

自动创建约束

Tips:要删除句柄只要将数遍移动到句柄上,点击一下即可。

2.4 比例尺寸(Dimensions)

有时需要创建具有固定宽高比的视图。例如,书籍封面或电影海报视图(通常为4:6); 或者是电影视图(通常是1.85:1或2.39:1)或电视(通常是4:3或16:9)的剧照。其中的w:h代表宽高比。

如果图像保证都具有完全相同的宽高比和物理尺寸,那么用在两个维度中使用wrap_content就好了。然而,在现实世界中经常存在微小的变化。如果使一个孤立的图像,这通常不是问题,但如果显示多个图像,那么尺寸的小差异即使比较微小也会使布局看起来不平衡。对此之前的一个解决方案是实现一个继承自ImageView的自定义View和覆盖onMeasure()方法以固定宽高比。现在不用这么麻烦了ConstraintLayout提供了一种用于固定子视图宽高比的机制。操作方法如下:

约束了一个维度为match_constraint,“切换纵横比约束”选项就会出现在正方形左上角的检查器视图中。单击“切换纵横比约束”选项。比例输入框出现在视图检查器的右下角进行比例设置:

设置比例

此时宽度是按照之前的宽度不变,高度会根据比例进行调整。对应的xml中的内容是app:layout_constraintDimensionRatio="h,16:9"。如果想改成高度不变,宽度按比例调整,将比例前的h改成w即可。

2.5 障碍(Barriers)

创建An​​droid布局时,有时会遇到布局可能会根据本地化或者其他情况而发生变化的情况,这时候就有可能发生两个视图之间的重叠:

视图重叠

设置障碍的作用就可以避免上述事情的发生,给左边视图设置一个尾部障碍,这样右边的视图遇到障碍时就会自动调整而不会越过障碍。右键单击ConstraintLayout蓝图或组件树。会看到 Add Vertical barrier 和 Add Horizontal barrier,来添加垂直障碍或水平障碍:

添加障碍

将需要障碍的视图拖到障碍下面,并且给障碍设置合适的barrierDirection,这个属性用来表示障碍应该阻挡的位置,上面的例子中应该设置为end,代表给左边视图的结尾处(右边界)设置障碍:

对视图设置障碍

右边视图添加约束到障碍:

添加障碍约束

对障碍的约束就像对视图之间的约束。但是,用户看不到障碍,并且障碍不会为添加应用程序的视图层次,这意味着不会影响性能。

2.6 链接(Chains)

链其实是两个视图彼此之间互相约束,链中的视图可以垂直或水平分布。它允许链中的视图之间共享空间并控制可用空间在它们之间的划分方式。类似于传统Android布局中LinearLayout的权重布局,但链接的作用远不止于此。

链接

链接有多种模式:

链接模式

① Spread:视图均匀分布(在计算margins之后)。这是默认模式。

② Spread inside:第一个和最后一个视图附加在链的每一端的约束上,其余视图均匀分布。

③ Weighted:当链被设置为Spread或Spread inside时,可以通过将一个或多个视图设置为“匹配约束类型”(0dp)来填充剩余空间。默认情况下,空间均匀分布在每个设置为“匹配约束类型”的视图之间,但可以使用layout_constraintHorizontal_weight和layout_constraintVertical_weight 属性为每个视图指定权重 。类似于LinearLayout的权重布局。

④ Packed:视图打包在一起(在计算margins之后)。可以通过更改链的第一个视图的约束偏差来调整整个链的约束偏差(左/右或上/下)。

使用链接

2.7 指示线(Guidelines)

指示线是一个视觉指南,在运行时不会看到与其他视图对齐的指示线。这是一个抽象的概念,说白了就是布局时候有一条用于方便对齐的线。单击顶部(或左侧)的指示器可在指南定位模式之间切换:左/右(或上/下)的固定距离,以及父视图宽度/高度的百分比:

使用指示线

3、其他技巧

3.1 处理View.GONE

在处理ConstraintLayout中View的View.GONE时,与RelativeLayout相比,可以拥有更多控制权。任何设置为GONE的View在两个维度中都缩小为零,但仍然参与计算约束。在此视图上设置的任何边距也都变为零。同时可以使用layout_goneMargin Start(Top、End、Bottom等)来为另一个视图设置当其关联的约束视图为View.GONE时的边距:

处理View.GONE

3.2 各种居中处理

除了一开始提到的设置两边约束并调整比例尺寸为50的方式来设置居中,这边还有一些其他方式。

在其他视图之间水平居中 相对父布局居中 相对另一视图居中 相对另一视图边居中

3.3 空格(Space)作为负边距

ConstraintLayout中的视图不能具有负边距(不支持)。但是,通过简单的技巧,可以通过插入Space(实际上是一个空视图)并将其大小设置为想要的边距来实现类似的功能:

使用Space

3.4 循环定位(Circular Positioning)

循环定位是指通过角度和半径来约束视图:

循环定位

其xml中的布局代码如下:


<Button android:id="@+id/buttonA" ...  />

<Button android:id="@+id/buttonB" ...

      app:layout_constraintCircle="@+id/buttonA"

      app:layout_constraintCircleRadius="100dp"

      app:layout_constraintCircleAngle="45"

/>

3.5 组(Groups)

有时当需要一次显示或隐藏多个元素。可以将多个视图归为同一个组。组不会增加视图的层次结构,它只是标记视图的一种方式。


<android.support.constraint.Group

    android:id =“@ + id / profile”

    app:constraint_referenced_ids =“profile_name,profile_image”/>

一旦定义了组profile,就可以对组应用可见性,它将同时应用于profile_name和profile_image:


profile.visibility = GONE

profile.visibility = VISIBLE

3.6 Constraint Layout优化

Constraint Layout 1.1添加了几个新的优化,可以加快布局。优化作为独立的操作进行,并会尝试减少布局视图所需的约束数。

有一个名为layout_optimizationLevel的标签用于配置优化级别。它可以设置为以下内容:

① barriers :确定障碍的位置,并以更简单的约束取而代之。

② direct:优化直接连接到的固定元素,例如屏幕的一侧或指示线,并继续优化直接连接到它们的视图。

③ standard:是默认的优化选项。

④ dimensions: 它通过计算尺寸来优化布局。

⑤ chain:计算出如何布置具有固定尺寸的元素链。

使用方法如下:


<android.support.constraint.ConstraintLayout

    app:layout_optimizationLevel="barriers|direct|standard|dimensions|chains" 

    ...>

4、传统布局的替换

前面我提到,有了ConstraintLayout之前的传统布局都可以被淘汰掉。这边来讨论下其对传统布局的替换。

4.1 LinearLayout

LinearLayout是根据方向使其子项在水平或垂直方向上布局。在编辑器中实现这一点非常简单。要创建与垂直相同的行为,LinearLayout只需添加其他视图,然后将每个视图的顶部约束紧邻其上方的视图底部:

垂直线性布局

也可以通过加链的形式来完成LinearLayout的布局:

通过链来进行线性布局

同时可以通过前面讲的关于链的模式来实现按权重分配空间。

4.2 RelativeLayout

RelativeLayout用于基于每种相对于另一种视图的关系来布局视图。所以可以理解为RelativeLayout是简化版的ConstraintLayout。所以后者的许多概念可以直接映射到RelativeLayout。前面基本上都讨论了直接在布局编辑器中编辑操作,其实ConstraintLayout也是可以在xml中布局的。但无疑对于ConstraintLayout来说在布局编辑器中操作更加方便。下面是两张关于RelativeLayout和ConstraintLayout属性的映射关系表:

① 相对于父布局的约束

RelativeLayout 属性 ConstraintLayout 属性
android:layout_alignParentLeft="true" app:layout_constraintLeft_toLeftOf="parent"
android:layout_alignParentStart="true" app:layout_constraintStart_toStartOf="parent"
android:layout_alignParentTop="true" app:layout_constraintTop_toTopOf="parent"
android:layout_alignParentRight="true" app:layout_constraintRight_toRightOf="parent"
android:layout_alignParentEnd="true" app:layout_constraintEnd_toEndOf="parent"
android:layout_alignParentBottom="true" app:layout_constraintBottom_toBottomOf="parent"
android:layout_centerHorizontal="true" app:layout_constraintStart_toStartOf="parent" 和 app:layout_constraintEnd_toEndOf="parent"
android:layout_centerVertical="true" aapp:layout_constraintTop_toTopOf="parent" 和 app:layout_constraintBottom_toBottomOf="parent"
android:layout_centerInParent="true" app:layout_constraintStart_toStartOf="parent",app:layout_constraintTop_toTopOf="parent",app:layout_constraintEnd_toEndOf="parent",和app:layout_constraintBottom_toBottomOf="parent"

① 相对于其他视图的约束

RelativeLayout 属性 ConstraintLayout 属性
android:layout_toLeftOf app:layout_constraintRight_toLeftOf
android:layout_toStartOf app:layout_constraintEnd_toStartOf
android:layout_above app:layout_constraintBottom_toTopOf
android:layout_toRightOf app:layout_constraintLeft_toRightOf
android:layout_toEndOf app:layout_constraintStart_toEndOf
android:layout_below app:layout_constraintTop_toBottomOf
android:layout_alignLeft app:layout_constraintLeft_toLeftOf
android:layout_alignStart app:layout_constraintStart_toStartOf
android:layout_alignTop app:layout_constraintTop_toTopOf
android:layout_alignRight app:layout_constraintRight_toRightOf
android:layout_alignEnd app:layout_constraintEnd_toEndOf
android:layout_alignBottom app:layout_constraintBottom_toBottomOf
android:layout_alignBaseline app:layout_constraintBaseline_toBaselineOf

5、ConstraintLayout的性能优势

从上面的讨论可以看出,ConstraintLayout操作起来非常方便。但正真官方将其作为默认布局的原因还是因为其性能上的优势。首先有了ConstraintLayout,可以大大降低布局的层次,不用一堆LinearLayout进行嵌套了。布局绘制过程中的每个阶段都需要自上而下遍历视图树。因此,在视图层次结构中彼此嵌入(或嵌套)的视图越多,设备绘制视图所需的时间和计算能力就越大。通过在Android应用布局中保持平面层次结构,可以为应用创建快速响应的用户界面。

同时ConstraintLayout底层实现的算法和RelativeLayout等传统布局完全不同,其之所以被称为ConstraintLayout,一个原因是其布局核心是各种视图之间的约束,另一个更深层次的原因是其实现的算法是基于线性约束来进行的。关于其底层算法的实现,可以参考这篇论文——Solving Linear Arithmetic Constraints for User Interface Applications。下图是有人做的关于ConstraintLayout和RelativeLayout在相同布局下的测量和布局测试结果,可以看出ConstraintLayout提高了大约20%的性能:

ConstraintLayout和RelativeLayout 测量和布局性能比较

Tips:其实ConstraintLayout也支持非常强大的动画,关于其动画部分会在之后另一篇文章讨论其子类MotionLayout时候一起讨论。

相关文章

网友评论

      本文标题:Android ConstraintLayout相关

      本文链接:https://www.haomeiwen.com/subject/qzaiwftx.html