Android - ConstraintLayout Chain 链布局能干啥

本文是 ConstraintLayout 小课堂系列第 2 讲,课程目录:

  1. 一个 item 布局带你领略 ConstraintLayout 的魅力
  2. ConstraintLayout Chain 链布局能干啥

平均间隔

先看一个需求:存在多个 TextView,他们的宽度是可变的,但它们之间的间隔是相等的,并且要平均分配整个屏幕的宽度。

使用原生的 LinearLayout 也能做到这点,简单看一下如何实现:

添加若干不可见的 View 来填充 TextView 之间的间隙,通过设置相同的 layout_weight 使得这些 View 的尺寸相同,这样 TextView 的间隔就是相同的了。

按照套路应该说这样做的缺点了:

  • 可能产生 ViewGroup 嵌套(没错,用 ConstraintLayout 就是为了不嵌套)
  • 多余的 View 在绘制过程中浪费 CPU(没错,不嵌套的终极目的就是提高绘制速度)
  • 想动态操作这些 TextView 以及间隔,需要给这些间隔 View 添加引用,手动设置 visibility,使用起来很不方便。

那么用 ConstraintLayout 怎么实现这个功能呢?

使用 ConstraintLayout 中的 Chain(链)可以更简单地实现这个需求,不用添加任何辅助对象,只需要在这些 TextView 之间形成链,默认就是平均分配间隔的样子。

Chain(链)

什么是 Chain?

两个 View 在一个方向上互相约束对方就形成了链,多个 View 两两成链,就形成了更长的链,见下图(图来自官网):

这里吐个槽,本文写作时最新 Android Studio 3.3.2 版本无法通过拖拽创建链,需要手写代码。

代码这么写,举个栗子:

<Button
    android:id="@+id/buttonOK"
    app:layout_constraintEnd_toStartOf="@+id/buttonCancel" 👉 左边的右手牵左手
    app:layout_constraintStart_toStartOf="parent" />
<Button
    android:id="@+id/buttonCancel"
    app:layout_constraintStart_toEndOf="@+id/buttonOK" 👉 右边的左手牵右手
    app:layout_constraintEnd_toEndOf="parent" />

形成链的一系列 View 会表现出一些整体特征,可以设置一些特殊的布局效果,见下图(图来自官网):

  • Spread Chain:伸展链,默认设置,形成链的 View 分散排列,间隔相等。
  • Spread Inside Chain:内部伸展链,也是平均分配间隔,但 View 和 parent 直接没有间隔。
  • Weighted Chain:权重链,与 LinearLayout 的 weight 相似,按比例分配空间大小。
  • Packed Chain:打包链,将所有 View 打包在一起,当做整体,居中。
  • Packed Chain with Bias:带偏斜的打包链。

如何设置不同的布局效果

数据结构里的链表都有个头节点,它的引用就是整个链表的引用。在 ConstraintLayout 中,左侧第一个或者上方第一个成链的 View 就是头节点。给这个头节点设置链属性,就相当于给整个链设置了链属性。实现以上各种效果需要设置哪些链属性呢,我们一个一个看。

Spread Chain

这个就是开篇提到的平均间隔布局了,只要结成链,默认就是这个效果。

设置方法:

  1. 链头节点设置 chainStyle
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintVertical_chainStyle="spread"
  1. 所有 View 设置 wrap_content
android:layout_width="wrap_content"
android:layout_height="wrap_content"

与 LinearLayout 的实现相比:

  • 没有多余的 View,不用维护多个间隔 View 的引用
  • 如果要隐藏某个 TextView,直接设置为 gone 就行了,剩余的 TextView 仍然是平均分隔的。

通过设置 margin 可以微调一下间隔,margin 相当于扩大了 TextView 的占用空间,剩余的空间再平分给间隔,有 margin 的 View 看起来间隔会大一些。注意 ConstraintLayout 中使用的 margin 只能是非负数,设置成负数无效。

Spread Inside Chain

设置方法:

  1. 链头节点设置 chainStyle
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintVertical_chainStyle="spread_inside"
  1. 所有 View 设置 wrap_content
android:layout_width="wrap_content"
android:layout_height="wrap_content"

这个设置成两边贴着 parent,如果要求左侧贴着 parent,右侧不贴呢?

如果是 LinearLayout,去掉左侧贴边的辅助 View 即可,比较方便。用 ConstraintLayout 的 Chain 怎么做呢?

直接去掉左侧第一个 TextView 对 第二个 TextView 的约束,也就是第一个的右手放开第二个的左手。这样整个链就少了一个 View,第一个 View 没有了右侧约束,直接靠在了左侧 parent 上,剩下的 View 仍然是一个链,分配剩余的空间。

放手之前
放手之后

Weighted Chain

设置方法:

  1. chainStyle:设置成任何值都没区别,不用设置
  2. 至少有一个 View 设置成 match_constraint
android:layout_width="0dp"
android:layout_height="0dp"
  1. 可选的 weight
app:layout_constraintHorizontal_weight="1"
app:layout_constraintVertical_weight="1"

只要在链上有一个 View 设置为了 match_constraint,这些 View 之间的剩余空间都会被占用,因此 chainStyle 属性设置为任何一个都没有区别。

如果不设置 weight 属性,就有点复杂了:

  • 所有 match_constraint 的 View 都不设置。大家平分,与都设置了 weight="1" 的效果相同。
  • 一些 View 设置了 weight 属性,一些 View 没设置。没设置的 View 完全消失了,所占空间被分配给剩余的 View 了。
  • 设置了 weight="0" 的 View 完全消失,剩余空间被其他 View 瓜分。
  • 有趣的是,如果只有不设置的和设置为 weight="0" 的,则相当于都不设置,大家平分。

Packed Chain & Packed Chain with Bias

设置方法:

  1. 链头节点设置 chainStyle
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintVertical_chainStyle="packed"
  1. 所有 View 设置为 wrap_content
android:layout_width="wrap_content"
android:layout_height="wrap_content"
  1. 链头节点设置 bias
app:layout_constraintHorizontal_bias="0.1"

打包链将整个链中的所有 View 打包成一个整体,可以与其他 View 关联约束。可能的应用场景是多个可变长的 TextView 紧挨在一起,并且它们的整体要在某个范围内居中。如果不用 ConstraintLayout,就只能将它们嵌套在一个单独的 View 中来做到了,你看,这就是 ConstraintLayout 能减少嵌套的原因👏👍。

Bias 属性是用来设置一个 View 被居中时,偏向某一侧的程度。通常取值范围是 [0, 1],表示左侧或上侧的空白区域占所有空白区域的范围。有趣的是,这个值也可以取 [0, 1] 之外的值,这个 View 就超出了约束的范围,小于 0 向左移,大于 0 向右移。

回到 Packed Chain with Bias,由于打包效果,整个链上的 View 对于其他 View 来说相当于一个 View,设置的 bias 属性也与一个 View 的 bias 相同。

总结

经过上面的讲解可以看到 ConstraintLayout 的链布局非常强大,可以实现的布局效果非常丰富,如果有什么难度较高的布局普通方法实现不了,可以考虑用链式布局来思考。

(ole)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容