Android内部分享[9]——约束布局 ConstraintLayout 的使用

ConstraintLayout 允许您创建具有平面视图层次结构(没有嵌套视图组)的大型复杂布局。它类似于 RelativeLayout,因为所有视图都是根据兄弟视图和父视图布局之间的关系来布局的,但是它比 RelativeLayout 更灵活,并且更容易在 Android Studio 的布局编辑器中使用。

约束布局概述

要在 ConstraintLayout 中定义视图的位置,必须为视图添加至少一个水平约束和一个垂直约束。每个约束表示到另一个视图、父布局或不可见的连接或基准线(对齐线)。每个约束定义视图沿垂直或水平轴的位置;因此,每个视图的每个轴必须至少有一个约束,但通常需要更多约束。

当您将视图放入布局编辑器时,即使没有约束,它也会停留在原来的位置。然而,这只是为了使编辑更容易;如果在设备上运行布局时视图没有约束,则在[0,0] (左上角) 处绘制。

例如:视图编辑器在 A 下方显示视图 C,但它没有垂直约束 例如:视图编辑器在 A 下方显示视图 C,但它没有垂直约束

例如:视图 C 现在垂直约束在视图 A 之下 例如:视图 C 现在垂直约束在视图 A 之下

虽然缺少约束不会导致编译错误,但布局编辑器将缺少约束作为工具栏中的错误指示。要查看错误和其他警告,单击 “显示警告和错误”。为了帮助您避免丢失约束,布局编辑器可以使用 Autoconnectinfer constraints 特性自动为您添加约束。

在你的工程引入 ConstraintLayout 约束布局

如果你要在你的工程中使用约束布局,需要做以下几步操作:

第一步:确保在模块级构建中声明了 maven.google.com 库,gradle 配置如下:

1
2
3
repositories {
    google()
}

第二步:将库作为依赖项添加到同一个构建中。如下面的示例所示的 gradle 文件(注意,最新版本可能与示例中的不同,请查询最新版本):

1
2
3
dependencies {
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
}

第三步:在 “工具栏” 或 “同步” 通知中,单击 Sync Project with Gradle Files.

做完上面的三步后你就可以愉快的使用约束布局 ConstraintLayout 了。

布局之间切换

有时候我们需要将我们之前的线性布局 LinearLayout 或者相对布局 RelativeLayout 切换成约束布局 ConstraintLayout,或者反过来切换,Android Studio 中的视图编辑器帮我们提供了一个方便的切换方式,需要如下两个步骤:

第一步:在 Android Studio 中打开布局,单击编辑器窗口底部的 Design 选项卡。

第二步:在 Component Tree 窗口中,右键单击布局并单击 Convert layout to ConstraintLayout. 选项。

将布局转换为约束布局 ConstraintLayout 将布局转换为约束布局 ConstraintLayout

新建约束布局

要创建一个新的约束布局文件,可以按照以下步骤:

第一步:在项目窗口中,单击 module 文件夹,然后选择文件> New > XML > Layout XML。

第二步:输入布局文件的名称并输入 “android.support.constraint”。用于 Root Tag 的 ConstraintLayout。

第三步:点击 Finish 就 ok 了。

添加和删除约束

我们下面来通过几个步骤的演示说明如何添加和删除约束布局 ConstraintLayout.

第一步:将视图组件拖动到视图编辑器中。

当您在 ConstraintLayout 中添加视图时,它将显示一个边界框,每个角上都有调整大小的方形句柄,每边都有圆形约束句柄。

第二步:点击视图来选择这些约束句柄圆点。

第三步:来实现约束关系:

  • 单击约束句柄并将其拖到可用的锚点。这个点可以是另一个视图的边缘,布局的边缘,或者基准线(guideline)。注意,当您拖动约束句柄时,布局编辑器将显示潜在的连接锚和蓝色覆盖区域。
  • 单击 Attributes 窗口布局部分中的 Create a connection 按钮,如图所示。

    Attributes 窗口中创建一个连接关系 Attributes 窗口中创建一个连接关系

    当创建约束时,编辑器会给它一个默认的空白(margin)来分隔两个视图。

当我们创建约束关系的时候要遵循下面的规则:

  • 每个视图必须至少有两个约束:一个水平约束和一个垂直约束。
  • 您只能在共享同一平面的约束句柄和锚点之间创建约束。所以一个视图的垂直面(左右两侧)只能被约束到另一个垂直面;基线只能约束到其他基线。
  • 每个约束句柄只能用于一个约束,但是您可以创建多个约束(从不同的视图)到同一个锚点。

您可以通过执行以下任何操作来删除约束:

  • 单击约束以选择它,然后按Delete。
  • 按住Control (macOS上的命令),然后单击约束锚。注意,约束变为红色,表示您可以单击删除它,如下图所示。

红色约束表示您可以单击以删除它 红色约束表示您可以单击以删除它

如果在视图上添加相反的约束,约束线就会像弹簧一样弯曲,以表示相反的力,如下面视频所示。当视图大小设置为“fixed”或“wrap content”时,效果最为明显,在这种情况下,视图位于约束之间的中心。如果您想要视图拉伸其大小以满足约束条件,请将大小切换为“match constraints”;或者如果您想保持当前大小,但移动视图使其不居中,请调整 “adjust the constraint bias”。

您可以使用约束来实现不同类型的布局行为,如下面的部分所述。本文出自水寒的个人博客,转载请说明出处:https://dp2px.com

约束布局实现不同类型布局

相对父容器

将视图的一侧约束到布局的相应边缘。例如:视图的左侧连接到父布局的左侧。你可以用边距来定义到边缘的距离。

相对父容器的水平约束 相对父容器的水平约束

相邻关系

定义垂直或水平两个视图的外观顺序。如下图:B 总是被约束在A的右边,C 被约束在 A 的下面。但是这些约束并不意味着对齐,所以B仍然可以上下移动。

水平和垂直约束 水平和垂直约束

对齐关系

将视图的边缘对齐到另一个视图的相同边缘。如下图:B 的左侧对齐到 A 的左侧。如果要对齐视图中心,请在两侧创建约束。

水平和垂直约束 水平和垂直约束

你也可以通过从约束中向内拖动视图来偏移对齐。如下图:显示了具有 24dp 偏移对齐的 B。偏移量由受约束视图的边距定义。

偏移水平对齐约束 偏移水平对齐约束

您还可以选择要对齐的所有视图,然后单击工具栏中的 Align 以选择对齐类型。

基准线对齐

将视图的文本基线与另一个视图的文本基线对齐。如下图:B 的第一行与 A 中的文本对齐。

基准线对齐约束 基准线对齐约束

要创建基线约束,右键单击要约束的文本视图,然后单击 Show baseline。然后单击文本基线并将该行拖动到另一个基线。

辅助线(guideline)对齐

您可以添加一个垂直或水平的辅助线,您可以将视图约束到该辅助线上,并且该辅助线对应用程序用户是不可见的。您可以根据 dp 单位或百分比(相对于布局的边缘)在布局中定位。

辅助线对齐约束 辅助线对齐约束

要创建辅助线(guideline),单击工具栏中的 Guidelines,然后单击 Add Vertical GuidelineAdd Horizontal Guideline

我们可以点击辅助线(guideline)上面的圆圈切换测量模式,也可以拖动辅助线。

屏障线(barrier)对齐

与 guideline 类似,barrier 是一条不可见的线,您可以将视图约束到它。除非 barrier 没有定义它自己的位置; 否则 barrier 位置是基于它所包含视图的位置移动的。当您希望将视图约束为一组视图而不是一个特定的视图时,这非常有用。

如下图显示视图 C 被限制在屏障线(barrier)的右侧。屏障线被设置为视图 A 和视图 B 的 “端”(或从左到右布局中的右侧),因此屏障线的移动取决于视图 A 或视图 B 的右侧是否是最右边。

屏障线对齐约束 屏障线对齐约束

在工具栏点击 Guidelines,然后点击 Add Vertical Barrier 或者 Add Horizontal Barrier,将组件树 Component Tree 中的组件添加到屏障布局约束,我们可以打开 Attributes 设置 barrierDirection.

调整约束偏移

当您向视图的两边添加约束时(相同维度的视图大小要么是“fixed”要么是“wrap content”),视图将在两个约束之间居中,默认偏差为 50%。您可以通过拖动属性窗口中的偏置滑块或拖动视图来调整偏置,如下面视频所示。

如果您希望视图扩展其大小以满足约束条件,使用可以改变大小的 “match constraints”。

调整视图的大小

您可以使用角句柄来调整视图的大小,但这是硬编码的大小,因此视图不会为不同的内容或屏幕大小调整大小。要选择不同的调整大小模式,单击视图并打开编辑器右侧的 Attributes 窗口。在 Attributes 窗口的顶部附近是 view inspector,它包含几个布局属性的控件,如下图1所示(这仅对约束布局中的视图可用)。

屏障线对齐约束 屏障线对齐约束

您可以通过单击图中 3 所示的符号来更改计算高度和宽度的方式。这些符号表示大小模式如下(单击符号在这些设置之间切换):

  • Fixed: 您可以在下面的文本框中指定特定的维度,或者在编辑器中调整视图的大小。
  • Wrap Content: 视图只根据其内容的需要进行扩展。
  • Match Constraints: 视图尽可能地扩展以满足每一边的约束(在考虑了视图的边距之后)。但是,您可以使用以下属性和值修改该行为(只有在将视图宽度设置为 match constraints 约束时,这些属性才会生效)

可以影响 match constraints 的属性

layout_constraintWidth_default

  • spread: 尽可能扩展视图以满足每一边的约束。这是默认行为
  • wrap: 只根据需要展开视图以适应其内容,但如果约束需要,仍然允许视图比视图小。因此,这与使用 Wrap Content (上面)的区别在于,设置 Wrap Content 的宽度会迫使宽度始终与内容宽度完全匹配;而使用 Match Constraintslayout constraintWidth 设置为 wrap 允许视图小于内容宽度。

layout_constraintWidth_min 该视图的最小宽度采用 dp 维度。

layout_constraintWidth_max 该视图的最大宽度采用 dp 维度。

然而,如果给定维度只有一个约束,则视图将展开以适应其内容。在高度或宽度上使用此模式还可以设置大小比。

设置比例大小

如果至少有一个视图维度被设置为 match constrants(0dp),则可以将视图大小设置为 16:9。要启用比率,单击 Toggle Aspect ratio Constraint (图中的 1 标记处),然后在出现的输入中输入 width:height 比例。

如果宽度和高度都设置为 match constrants,则可以单击 Toggle Aspect Ratio Constraint,根据另一个约束的比例选择哪个维度。视图检查器通过用实线连接相应的边来指示哪个设置为比值。

如下图,如果您设置双方为 match constrants,单击切换长宽比约束两次设置宽度是高度的比值。 现在整个大小由(其可以以任何方式来限定)高度决定。

视图的宽度根据高度的比例设置为16:9 视图的宽度根据高度的比例设置为16:9

调整视图的 margins

要确保所有视图的间距都是均匀的,请单击工具栏中的 Margin,为添加到布局中的每个视图选择默认的 Margin。对默认页边距所做的任何更改只适用于从此以后添加的视图。您可以通过单击代表每个约束的行上的数字来控制 Attributes 窗口中每个视图的页边距(在上面图中的标记 4 处,显示底部页边距设置为16dp)。

线性组件群约束

链是一组视图,它们通过双向位置约束相互链接。链中的视图可以垂直分布,也可以水平分布。

有两个视图的水平链 有两个视图的水平链

链可以采用以下方式之一进行样式设置(可以参考下图的编号 1~4 和之对应):

  • Spread: 视图是均匀分布的(在考虑了页边距之后)。这是默认值。
  • Spread inside: 第一个和最后一个视图被附加到链的每一端的约束上,其余的则均匀分布。
  • Weighted: 当链被设置为 SpreadSpread inside 时,您可以通过将一个或多个视图设置为 match constraints(0dp)来填充剩余的空间。默认情况下,空间平均分布在每个设置为 match constraints 的视图之间,但是您可以使用 layout_constraintHorizontal_weightlayout_constraintVertical_weight 属性为每个视图分配一个重要的权重。如果您熟悉线性布局中的布局权重,这也是同样的工作方式。所以权重值最高的视图得到最多的空间;具有相同权重的视图获得相同的空间。
  • Packed: 视图挤在一起。

每种链样式的示例 每种链样式的示例

要创建一个链,请选择链中包含的所有视图,右键单击其中一个视图,选择chain,然后选择水平居中或垂直居中,如下面视频所示:

这篇文章之后我还写了一篇关于约束布局 ConstraintLayout 的 API 和属性设置相关的文章,你可以阅读一下 《Android中约束布局Constraintlayout的API和属性解析》