1. 概述
在Android中有許多的佈局,比如 RelativeLayout,LinearLayout,FrameLayout 等,但是這些佈局使用起來,需要一層層的嵌套。ConstraintLayout的誕生,是爲了解決在開發中的複雜多層級佈局的問題,在一定程度上進行佈局的優化。這是Google的介紹:ConstraintLayout 官方文檔
2. 導入 ConstraintLayout
在Android Studio 中(這裏使用的是3.4),創建工程後,默認的佈局都已經是 ConstraintLayout 了,系統已經默認導入 ConstraintLayout 所需要的庫了:
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
3. ConstraintLayout 的使用
在Android的官方介紹中,存在以下幾種約束的類型:
- Relative positioning
- Margins
- Centering positioning
- Circular positioning
- Visibility behavior
- Dimension constraints
- Chains
3.1 Relative position 相對定位
ConstraintLayout具有RelativeLayout的能力,可以將一個控件置於相對於另一個控件的位置。
示例:將B按鈕放在A按鈕的右邊
代碼如下:
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toRightOf="@+id/buttonA" />
相對定位中控件的邊界如圖所示:
相對定位還有其他的屬性:
layout_constraintLeft_toLeftOf
layout_constraintLeft_toRightOf
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf
layout_constraintBaseline_toBaselineOf
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
從上面的屬性中,可以看出相對定位屬性的格式形如:
layout_constraint’DIRECTION’_to’TARGET DIRECTION’Of=”TARGET“
a. constraint’DIRECTION’ 裏的 ‘DIRECTION’代表是這個子控件自身的哪條邊
b. to’TARGET DIRECTION’Of 裏的 ‘TARGET DIRECTION’ 代表的是和約束控件的哪條邊發生約束
c. TARGET 爲目標約束控件對應的 id(如果是外層的佈局則 id 理解爲 parent)
3.2 Margin 邊距
margin指的是控件相對其他控件的距離,如圖所示:
margin 常用的屬性有:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
注意:margin屬性只對其相約束的View起作用,如果沒有約束條件,則margin就會失效。
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginLeft="120dp"
android:layout_marginTop="200dp"
android:text="Button A" />
從下圖可以看出margin屬性失效了:
當加上相應的約束屬性後:
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginLeft="120dp"
android:layout_marginTop="200dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:text="Button A" />
margin 屬性就生效了:
看一個栗子,Button B的位置依賴於 Button A,約束關係如下:
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginLeft="120dp"
android:layout_marginTop="200dp"
android:text="Button A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginLeft="128dp"
android:layout_marginTop="112dp"
android:text="Button B"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonA" />
效果如圖所示:
如果這時候 Button A 可見狀態爲gone的話,Button B會是神馬樣子呢?
從圖上我們可以看出 Button B 的 margin-top 屬性約束條件變成了與父佈局的關係了。而有時候當被約束條件狀態爲 gone 以後,佈局需要作出調整,這時候還有其他屬性可以用。
<Button
android:id="@+id/buttonB"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginLeft="128dp"
android:layout_marginTop="112dp"
android:text="Button B"
app:layout_goneMarginTop="40dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonA" />
效果:
可以看出 Button B 的上邊距由原來的112dp 變成了40dp。
goneMargin相關的屬性有如下幾種:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
3.3 Centering positioning 居中定位
在ConstraintLayout中沒有直接的屬性讓一個控件者豎直居中或者豎直居中,可以使用如下方法:
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="200dp"
android:text="Button A"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
效果:
可以設置bias屬性,表示子控件相對父控件的位置傾向:
layout_constraintHorizontal_bias
layout_constraintVertical_bias
居中情況下,bias的默認值爲0.5,取值範圍是0~1。
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="200dp"
android:text="Button A"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
效果:
3.4 Circular positioning 圓形定位
可以使用角度和距離來約束一個控件相對於另一個控件的位置。
相關的屬性:
layout_constraintCircle:參照控件的id
layout_constraintCircleRadius:兩個控件中心連線的距離
layout_constraintCircleAngle:當前View的中心與目標View的中心的連線與Y軸方向的夾角(取值:0~360)
注意:此處的Y軸是數學座標系中的Y軸。如下圖所指示:
例子:
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="200dp"
android:text="Button A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="8dp"
android:text="Button B"
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleAngle="60"
app:layout_constraintCircleRadius="120dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
結果:
3.5 Visibility behavior 能見度行爲
當控件設置了visibility屬性爲GONE屬性後,控件就不會出現在佈局中了,B控件對A控件的margin屬性也就沒有作用了。但是 ConstraintLayout 能對已經設置 GONE屬性的控件進行特殊處理。當A控件設置 GONE之後,A控件相當於變成了一個點,B控件相對於對A的約束仍然是起作用的。
3.6 Dimensions constraints 尺寸約束
3.6.1 設置最小或最大尺寸
可以設置最小或者最大尺寸,有以下屬性:
android:minWidth
android:minHeight
android:maxWidth
android:maxHeight
當控件的尺寸設置爲 WRAP_CONTENT 的時候,這是屬性才生效。
3.6.2 控件的尺寸約束
ConstraintLayout中有3中方式來設置子View的寬高尺寸:
a. Xdp,X爲具體數值。
b. WARP_CONTENT。
c. 0dp,0dp代表MATCH_CONSTRAINT,ConstraintLayout不推薦使用MATCH_PARENT。
3.7 Chains 鏈
鏈能夠對一組在水平或豎直方向互相關聯的控件的屬性進行統一管理。
在一個水平或者豎直方向上,一排view兩兩互相約束,即爲鏈。
鏈的頭部:
頭部是水平鏈最左邊的控件或者垂直鏈的最頂部的控件。
鏈的樣式:
鏈有以下幾種樣式:
-
spread
默認模式,分佈樣式如上圖 -
spread_inside
如圖,和spread的區別是沒算兩端的約束 -
packed
所有元素擠在中間,也可以配合使用bias來改變位置偏移
例子:
<Button
android:id="@+id/buttonA"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="100dp"
android:text="Button A"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/buttonB"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonB"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="100dp"
android:text="Button B"
app:layout_constraintLeft_toRightOf="@+id/buttonA"
app:layout_constraintRight_toLeftOf="@+id/buttonC"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonC"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginTop="100dp"
android:text="Button C"
app:layout_constraintLeft_toRightOf="@+id/buttonB"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
結果:
例子中鏈的style設置爲 packed,鏈的所有元素被打包在一起。
參考:
https://www.jianshu.com/p/106e4282a383
https://www.cnblogs.com/angrycode/p/9739513.html