Barrier 和 Chains
如果選擇使用,一定要看明白,不要漏掉屬性,否則你到時候會發(fā)狂的。
1. Barrier
是一個準則,可以說是對其的規(guī)則,這樣說還不夠名義,我們可以列表一些比較常見的場景;
官網(wǎng) Barrier。
- 具體看圖
簡單的布局
“第二行的label”和“第二行value”是一個整體,他們距離上面是100dp,但是有可能“第二行value”的值為空或者是空,也需要“第二行l(wèi)abel”距離上面的距離是100dp,由于我們知道“第二行value”的高度高于第一個,所以采用的是“第二行l(wèi)abel”跟“第二行value”對其,“第二行value”距離上邊100dp的距離,但是由于“第二行value”有可能為空,所以當“第二行value”為空的時候就會出現(xiàn)下面的效果:
“第二行value”消失的效果
我們發(fā)現(xiàn)達不到預期,現(xiàn)在能想到的辦法有,首先在代碼控制的時候隨便把“第二行l(wèi)abel”的marginTop也添加進去;還有就是換布局,將“第二行l(wèi)abel”和“第二行value”放到一個布局中,比如LinearLayout,這樣上邊的marginTop由LinearLayout控制;這樣的話即便“第二行value”消失了也會保持上邊的效果。
除了上邊的方法還能使用其他的嘛,比如我們不使用代碼控制,我們不使用其他的布局,因為我們知道布局嵌套太多性能也會相應的下降,所以在編寫的時候能減少嵌套的情況下盡可能的減少,當然也不能為了減少嵌套讓代碼變得格外的復雜。
為了滿足上面的需求, Barrier 出現(xiàn)了,它能做到隱藏的也能依靠它,并且與它的距離保持不變對于隱藏的“第二行value”來說,雖然消失了,但保留了 marginTop 的數(shù)值。下面看看布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="頭部"
android:textSize="36sp"
app:layout_constraintBottom_toTopOf="@id/barrier3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
android:layout_marginTop="100dp"
app:constraint_referenced_ids="textView2,textView3" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="第二行l(wèi)abel"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="@+id/textView3"
app:layout_constraintStart_toStartOf="@+id/textView4"
app:layout_constraintTop_toTopOf="@+id/textView3"
app:layout_constraintVertical_bias="0.538" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_marginStart="12dp"
android:layout_marginTop="100dp"
android:text="第二行value"
android:textSize="36sp"
app:layout_constraintStart_toEndOf="@+id/textView2"
app:layout_constraintTop_toBottomOf="@+id/barrier3" />
</androidx.constraintlayout.widget.ConstraintLayout>
這樣即便將“第二行value”消失,那么總體的布局仍然達到預期,并且也沒有添加很多布局內(nèi)容。在代碼中:
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
android:layout_marginTop="100dp"
app:constraint_referenced_ids="textView2,textView3" />
這里主要有兩個屬性 app:barrierDirection 和 app:constraint_referenced_ids :
- app:barrierDirection 是代表位置,也就是在包含內(nèi)容的哪一個位置,我這里寫的是
top,是在頂部,還有其他的屬性top,bottom,left,right,start和end這幾個屬性,看意思就很明白了。 - app:constraint_referenced_ids 上面說的內(nèi)容就是包含在這里面的,這里面填寫的是
id的名稱,如果有多個,那么使用逗號隔開;這里面的到Barrier的距離不會改變,即便隱藏了也不會變。
這里可能會有疑惑,為啥我寫的 id 為 textView4 的也依賴于 Barrier ,這是因為本身 Barrier 只是規(guī)則不是實體,它的存在只能依附于實體,不能單獨存在于具體的位置,如果我們只有“第二行value”依賴于它,但是本身“第二行value”沒有上依賴,也相當于沒有依賴,這樣只會導致“第二行l(wèi)abel”和“第二行value”都消失,如果 textView4 依賴于 Barrier ,由于 textView4 的位置是確定的,所以 Barrier 的位置也就確定了。
-
類似表格的效果??床季中Ч?/p>
表格的樣式
我要做成上面的樣子。也就是右邊永遠與左邊最長的保持距離。下面是我的代碼:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="頭部"
android:textSize="36sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="第二行"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="@+id/textView3"
app:layout_constraintStart_toStartOf="@+id/textView4"
app:layout_constraintTop_toTopOf="@+id/textView3" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="第二行value"
android:textSize="36sp"
app:layout_constraintStart_toEndOf="@+id/barrier4"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="第三次測試"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="@+id/textView6"
app:layout_constraintStart_toStartOf="@+id/textView4"
app:layout_constraintTop_toTopOf="@+id/textView6" />
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="第三行value"
android:textSize="36sp"
app:layout_constraintStart_toEndOf="@+id/barrier4"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="textView2,textView5"
tools:layout_editor_absoluteX="411dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
添加好了,記得讓右邊的約束指向 Barrier 。這里的 Barrier ,我們看到包含 textView2 和 textView5 ,這個時候就能做到誰長聽誰的,如果此時 textView2 變長了,那么就會將就 textView2 。
2. Chains
我們特別喜歡使用線性布局,因為我們發(fā)現(xiàn) UI 圖上的效果使用線性布局都可以使用,當然也有可能跟大部分人的思維方式有關系。比如我們非常喜歡的,水平居中,每部分的空間分布等等都非常的順手。既然線性布局這么好用,那為啥還有約束布局呢,因為線性布局很容易寫出嵌套很深的布局,但約束布局不會,甚至大部分情況都可以不需要嵌套就能實現(xiàn),那是不是代表線性布局有的約束布局也有,答案是肯定的。
使用普通的約束關系就很容易實現(xiàn)水平居中等常用效果,其他的如水平方向平均分布空間,使用一般的約束是實現(xiàn)不了的,于是就要使用 Chains ,這個就很容易實現(xiàn)下面的效果:

其實上一篇中我已經(jīng)把官網(wǎng)的教程貼上去了,這里主要寫雙向約束怎么做,一旦雙向約束形成,那么就自然進入到
Chains 模式。
1)在視圖模式中操作

如果直接操作,那么只能單向約束,如果要形成這樣的約束,需要選擇相關的的節(jié)點,比如我這里就是同時選擇 A 和 B ,然后點擊鼠標右鍵,就可以看到 Chains → Create Horizontal Chain 。
選擇圖中的選項即可完成從 A 指向 B ,修改的示意圖為:

我們發(fā)現(xiàn)已經(jīng)實現(xiàn)了水平方向的排列效果了。至于怎么實現(xiàn)上面的效果,主要是改變 layout_constraintVertical_chainStyle 和 layout_constraintHorizontal_chainStyle 屬性。至于權重則是屬性 layout_constraintHorizontal_weight 。
layout_constraintHorizontal_chainStyle 屬性說明:
- spread 默認選項,效果就是上面的那種,也就是平均分配剩余空間;
- spread_inside 兩邊的緊挨著非
Chains的視圖,中間的平均分配;
spread_inside的效果圖 - packed 所有的都在中間
packed效果圖
注意了,layout_constraintHorizontal_weight這個屬性只有在A身上設置才可以,也就是首節(jié)點上設置才可行,同時layout_constraintHorizontal_weight是代表水平方向,只能在水平方向才發(fā)生作用,如果水平的設置了垂直則不生效。
layout_constraintHorizontal_weight 這個屬性只有在當前視圖的寬或者高是 0dp 。至于這個的取值跟線性布局相同。

2)代碼的方式
跟上面的差別就是在做雙向綁定,用代碼就很容易實現(xiàn)雙向綁定,可平時添加約束相同。




