ContraintLayout 屬性
本文基於ContraintLayout 1.1版本, 參考ContraintLayout官方文件並結合實際的例子說明
ContraintLayout 有以下作用:
- Relative positioning 相對位置
- Margin 邊距
- Centering position 中間位置
- Visibility behavior 可見性行為
- Dimension constraints 尺寸約束
- Chains 鏈
- Virtual Helpers objects 虛擬幫助工具類
- Optimizer 優化
相對位置
類似於RelativeLayout佈局,例如:相對父類的最左邊,相對某個View的左邊 等等
這種屬性有很多,就舉例兩個屬性:
layout_constraintLeft_toLeftOf
自身的左邊相對於誰的左邊, 如果相對於父View,就用parentlayout_constraintLeft_toRightOf
自身的左邊相對於誰的右邊, 如果相對於父View,就用parent
邊距
邊距屬性繼承ViewGroup.LayoutParam, 如下所示:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
但是需要注意的是:
-
設定的邊距必須>= 0 。
-
設定的邊距要和正確的相對位置約束一起使用才有效過,例如:
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="10dp" //layout_marginTop要和layout_constraintTop_x 一起使用才有效,單獨layout_marginTop是無效的 複製程式碼
View的可見或不可見時呈現不同邊距
用於設定某個View隱藏時的邊距。需求有時A-View的可見或不可見時,B-View的邊距會呈現不同的邊距 。這是可以用到如下屬性:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
但是需要注意的是:
-
設定的邊距要和正確的相對位置約束一起使用, 並且這個約束是作用在目標View時才有效過,例如:
<TextView android:id="@+id/tv_a" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" android:visibility="gone" /> <TextView android:id="@+id/tv_b" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintRight_toLeftOf="@+id/tv_a" app:layout_goneMarginRight="20dp" /> // layout_goneMarginRight 這是屬性是設定右邊距, // 要與layout_constraintRight_toLeftOf結合使用採用效果。 // layout_constraintRight_toLeftOf屬性是自身view的右邊相對 // 於tv_a的左邊,也就是自身的view在tv_a的左邊,只有在tv_a的左邊時, // tv_a隱藏了layout_goneMarginRight才有效果。 複製程式碼
中間位置與偏移量
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
複製程式碼
看上面的程式碼,一個Button在父類左邊, 同時又在父類右邊,如果這個Button的寬度不是和父View相同就不可能同時滿足兩個條件。但是父類是ConstraintLayout佈局,這個Button的寬度小於父View的寬度時,同時設定app:layout_constraintLeft_toLeftOf="parent", app:layout_constraintRight_toRightOf="parent"時會使該Button位於父類的中心。layout_constraintLeft_toLeftOf, layout_constraintRight_toRightOf 這兩個屬性也可以作用於其他View,達到位於該View中心位置。
Bias 偏移量
當A同時設定了layout_constraintLeft_toLeftOf和layout_constraintRight_toRightOf在一個B-View時, 你還可以通過layout_constraintHorizontal_bias屬性移動A在B-View某個位置上。layout_constraintHorizontal_bias的值是0-1之間,0.5 就是在B-View的中間。
同理layout_constraintVertical_bias 是作用在垂直方向上的,結合layout_constraintBottom_toBottomOf和layout_constraintTop_toTopOf使用。
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3333"
android:gravity="center"
android:textSize="18sp"
android:text="HHHHHHH"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
稍微解析一下bias這個屬性,以layout_constraintHorizontal_bias為例,看上面的程式碼和效果圖,水平bias屬性設定了0.3333, 大約是1/3。 上圖中C為手機的左邊緣,D為手機右邊緣,A和B分別是TextView的左右邊緣。
0.3333 = CA / BD。很多人會誤以為CA / CD, 這個要注意。總結起來就是bias屬性的值等於該View左邊到父view左邊距離 除以該View右邊到父view右邊距離
Circular positioning 圓形位置
你可以約束一個View的中心相對於另一個View的中心。
layout_constraintCircle
: references another widget id 另一個View的idlayout_constraintCircleRadius
: the distance to the other widget center。半徑layout_constraintCircleAngle
: which angle the widget should be at (in degrees, from 0 to 360) 角度
可能有些人覺得沒鳥用,下面舉個栗子:
先來效果張圖,有張小圓圖的圓心需要放在一張大圖的下面中心位置,(用相對佈局之類不好搞了吧.....)
<ImageView
android:id="@+id/iv_shop_big_photo"
android:layout_height="200dp"
tools:srcCompat="@drawable/ic_big_shop"
android:layout_width="match_parent"
android:scaleType="fitXY"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<ImageView
android:id="@+id/iv_shop_logo"
android:layout_width="56dp"
android:layout_height="56dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:srcCompat="@drawable/ic_home_category"
app:layout_constraintCircle="@+id/iv_shop_big_photo"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="180"
/>
複製程式碼
上面程式碼就能達到效果啦,半徑為大圖高的一半,角度是180度。
Visibility behavior 可見性行為
就佈局計算而言,GONE的View仍然是其中的一部分,具有重要的區別:
-
對於佈局的傳遞,它們的尺寸將被視為零(基本上,它們將被解析為一個點)
-
如果他們對其他小部件有約束,約束仍然有效,但任何邊距都會等於零
Dimensions constraints 尺寸約束
最低限度尺寸
-
android:minWidth
set the minimum width for the layout -
android:minHeight
set the minimum height for the layout -
android:maxWidth
set the maximum width for the layout -
android:maxHeight
set the maximum height for the layoutConstraintLayout的子View設定wrap_content時才有效
尺寸約束
android:layout_width
andandroid:layout_height
有三種值:
-
準確的值,例如10dp
-
wrap_content
-
用
0dp
相當於match_contraint, 可以結合約束來限制寬高尺寸。官方推薦:少用match_parent, 多用0dp
當使用0dp,沒加任何約束屬性,就等於match_parent
強制約束
當設定了wrap_content, 約束不會限制view的尺寸。當時你可以用app:layout_constrainedWidth="true|false"或者app:layout_constrainedHeight=”true|false”來約束尺寸, 設定true就是約束。
下面舉個栗子:
<ConstraintLayout>
<View
android:id="@+id/view"
android:layout_width="320dp"
android:layout_height="24dp"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:id="@+id/tv_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
app:layout_constrainedWidth=”true|false” // 預設是false
app:layout_constraintLeft_toRightOf="@+id/view"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCDEFGHI"
/>
</ConstraintLayout>
複製程式碼
圖一
圖二
圖一沒有app:layout_constrainedWidth屬性,該屬性預設是false; 圖二app:layout_constrainedWidth的屬性為true。TextView 雖然設定了layout_constraintLeft_toRightOf在紅色View的右邊約束,但並沒有限制寬度,需要用layout_constrainedWidth屬性來限制寬度。
0dp使用
針對約束來限制大小,還有一些屬性:
layout_constraintWidth_min
andlayout_constraintHeight_min
: will set the minimum size for this dimension 設定最小尺寸layout_constraintWidth_max
andlayout_constraintHeight_max
: will set the maximum size for this dimension 設定最大尺寸layout_constraintWidth_percent
andlayout_constraintHeight_percent
: will set the size of this dimension as a percentage of the parent 設定百分比
上面這些屬性需要設定了0dp才能生效。下面舉些個栗子:
- 栗子1,設定了layout_width="0dp", app:layout_constraintWidth_min="50dp", 限制了最小寬度為50dp
<android.support.constraint.ConstraintLayout>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="B"
android:id="@+id/tv_b"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/tv_b"
app:layout_constraintWidth_min="50dp"
android:gravity="center"
android:textSize="18sp"
android:lines="1"
android:text="A"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
- 栗子2, app:layout_constraintWidth_percent="0.5" 設定了寬度為父View寬的一半
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
![](https://user-gold-cdn.xitu.io/2019/1/4/168176735e1d9c4f?w=624&h=200&f=png&s=36404)
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="B"
android:id="@+id/tv_b"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/tv_b"
app:layout_constraintWidth_percent="0.5"
android:gravity="center"
android:textSize="18sp"
android:lines="1"
android:text="A"
/>
複製程式碼
比例
你可以定義寬和高之間比例。設定寬高比例至少一邊尺寸設定為0dp, 要有個基準(基於寬還是高), 屬性如下:
- layout_constraintDimensionRatio 它的值可以是float,也可以是width:height, 當沒有基準時,可以(W/H,width:height)
<android.support.constraint.ConstraintLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="1:2"
android:gravity="center"
android:textSize="18sp"
android:text="ABCD"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
上面效果layout_constraintDimensionRatio設定了1:2, 就是寬 : 高 = 1 :2 , 寬為wrap_content,高為0dp,所有寬根據text是一個準確的寬,然後高 = 寬 x 2 , 所有就呈現了上面的效果。
下面再看個效果,
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="1:2"
android:gravity="center"
android:textSize="18sp"
android:text="ABCD"
/>
複製程式碼
看效果圖可能會覺得有點怪,設上面例子的區別是 寬為0dp,高為wrap_content, 寬高比還是1 :2。為什麼會出現這個情況,是因為基準不同,高為wrap_content,所以這次高是基準, 至於為什麼是這個效果,自己去看原始碼,不深入啦。
Chains 鏈
Creating a chain 建立鏈
不是什麼情況都是鏈,如果一組View通過雙向連線連結在一起,則它們被視為鏈。下圖就是一個鏈:
Chain heads 鏈頭
鏈的屬性是由在鏈的第一個元素上設定控制, 第一個元素被稱為鏈頭。
如上圖所示,A就是鏈頭。
鏈頭: 水平方向是最左邊的一個,垂直方向是最上面一個
Chain Style 鏈樣式
定義鏈樣式使用layout_constraintHorizontal_chainStyle 或者 layout_constraintVertical_chainStyle,分別對應水平和垂直方向, 這個屬性只作用在第一個元素(鏈頭)才有效, 它的值有如下幾個:
CHAIN_SPREAD
-- 元素將會被擴充套件 (預設的屬性)- Weighted chain -- 在
CHAIN_SPREAD
模式下, 如果一些View被設定MATCH_CONSTRAINT了,可以利用權重等分空間 CHAIN_SPREAD_INSIDE
-- 和CHAIN_SPREAD相似, 但鏈條的終點不會分散開來CHAIN_PACKED
-- 這些元素會被包在一起,預設是放在中間, 可以結合水平或者垂直bias屬性分配位置。
官方介紹圖:
下面一一程式碼舉例:- Spread Chain 的效果
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_chainStyle="spread" //Spread Chain 作用與鏈頭
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
- Spread Inside Chain 的效果
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_chainStyle="spread_inside" //Spread Inside Chain 作用與鏈頭
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
- Pick Chain 與 Pick Chain with Bias 的效果
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_chainStyle="packed" // Packed Chain
app:layout_constraintHorizontal_bias="0.2" // Bias 屬性
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
A距離左邊佔0.2比例,layout_constraintHorizontal_bias = 0.2; 當不加layout_constraintHorizontal_bias屬性時,預設是0.5, 效果如下圖:
Weighted chains 權重鏈
使用權重屬性, 需要View被設定MATCH_CONSTRAINT(也就是0dp)
- layout_constraintHorizontal_weight
- layout_constraintVertical_weight
下面是程式碼示例, 使用weight把3個View分成1:2:2 的比例:
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_weight="1.0"
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
app:layout_constraintHorizontal_weight="2.0"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="2.0"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
Virtual Helper objects 虛擬助手類
Guideline
本身繼承View,0 寬度, 0高度。
-
app:layout_constraintGuide_begin 與父類左邊的距離
-
app:layout_constraintGuide_end 與父類右邊的距離
-
app:layout_constraintGuide_percent 佔父類總寬度的百分比
-
android:orientation 指引線的方向
-
<android.support.constraint.ConstraintLayout> <android.support.constraint.Guideline android:id="@+id/guide_line_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintGuide_percent="0.1" android:orientation="vertical" /> <android.support.constraint.Guideline android:id="@+id/guide_line_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintGuide_begin="100dp" android:orientation="horizontal" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toRightOf="@+id/guide_line_vertical" app:layout_constraintTop_toTopOf="@+id/guide_line_horizontal" android:text="Guide Line" /> </android.support.constraint.ConstraintLayout> 複製程式碼
Barrier
Barrier本身繼承View,0 寬度, 0高度。作用:引用多了View建立一個屏障。
- barrierDirection 方向
- constraint_referenced_ids View ids 用逗號隔開
下面用一個場景來說明:
如上圖所示,3個TextView, C在 A和B右邊,但是A,B長度不定。通常我們可以用一個ViewGroup包含A和B,C在那個ViewGroup的右邊就可以啦。但是這樣就多了一層佈局,ConstraintLayout目的是減少層級,這時Barrier就可以發揮作用力,Barrier可以在A和B最右邊建立一個豎立屏障,C約束在這個屏障即可。
程式碼如下:
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_b_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/s_01"
app:layout_constraintTop_toBottomOf="@+id/tv_b_02"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:id="@+id/tv_b_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
android:text="@string/s_02" />
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="tv_b_01,tv_b_02"
/>
<TextView
android:id="@+id/tv_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:text="@string/s_content"
app:layout_constraintLeft_toRightOf="@+id/barrier" />
</android.support.constraint.ConstraintLayout>
複製程式碼
Group
Group本身繼承View,0 寬度, 0高度。
用來控制一群View的可見性,程式碼例項:
<TextView
android:id="@+id/tv_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ABCDEFG"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<TextView
android:id="@+id/tv_111"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HIJKLMN"
app:layout_constraintTop_toBottomOf="@+id/tv_center"
app:layout_constraintLeft_toLeftOf="@+id/tv_center"
/>
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_center, tv_111"
/>
複製程式碼
如上面程式碼所示,Group使用constraint_referenced_ids屬性把兩個view的id弄成了一個群體,把這兩個view隱藏啦。Group也可以程式碼去控制。
Optimizer 優化
使用屬性app:layout_optimizationLevel="direct|barrier|chain"制定優化
- none : 沒有任何優化
- standard : 預設 (direct and barrier)
- direct : 優化直接約束
- barrier : 優化barrier屏障約束
- chain : 優化鏈約束 (實驗功能)
- dimensions : 優化View的測量 (實驗功能), 減少測量次數