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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章