ConstraintLayout

網(wǎng)傳constraintLayout(約束布局)的布局,性能和功能性相當優(yōu)越,雖然RelativeLayout用的飛起來,也得與時俱進。

本文主要分為以下幾個部分:

catalog.png

1. 背景介紹

在面試的時候經(jīng)常會被問到有沒有做過布局優(yōu)化,都通過什么方式優(yōu)化布局界面的?優(yōu)化布局界面其中一種方式就是通過 ConstraintLayout 降低布局層級,從而避免過度測量和繪制。本篇文章重點講解 ConstraintLayout 的用法,關(guān)于 ConstraintLayout 性能方面的優(yōu)勢,可以參考這篇文章:解析 ConstraintLayout 的性能優(yōu)勢。

通過可視化拖拽的方式編寫 ConstraintLayout 布局界面,個人是不太推崇的,雖然它確實很方便,但是即使通過可視化拖拽的方式編寫布局之后,還是需要看懂 xml 文件中關(guān)于 ConstraintLayout 的屬性,才可以更靈活的修改布局界面,所以本文主要講解通過 xml 屬性的方式編寫 ConstraintLayout 布局界面,關(guān)于可視化拖拽的方式編寫 ConstraintLayout 布局界面,可以參考郭霖寫的這篇博客: Android 新特性介紹,ConstraintLayout 完全解析

好了,上面介紹了 ConstraintLayout 的兩個優(yōu)點,下面開始進入本文的正題,通過 xml 布局屬性的方式編寫 ConstraintLayout 布局。使用之前,需要在build.gradle文件中添加對 ConstraintLayout 的依賴:

dependencies {? ? ...? ? implementation'com.android.support.constraint:constraint-layout:1.0.2'...}

2. 詳細使用

本節(jié)主要分為 7 點介紹 ConstraintLayout 的詳細使用,那就開始吧~

2.1 相對位置

ConstraintLayout 和 RelativeLayout 是非常類似的布局控件,它們之間最大的相似之處在于都可以編寫一個控件相對于其他控件或父控件的相對位置,比如下面這個樣式的布局既可以通過

RelativeLayout 實現(xiàn),也可以通過 ConstraintLayout 實現(xiàn)

relativepositioning.png

通過 ConstraintLayout 實現(xiàn)的代碼如下所示:

通過上面的代碼,可以看到幾個陌生的 xml 屬性,它們都是 ConstraintLayout 的 xml 屬性,比如:

通過屬性的名字就可以猜測出它們大概的意思,比如:

app:layout_constraintLeft_toLeftOf是指該控件的左邊緣和某個控件的左邊緣對齊

app:layout_constraintRight_toRightOf是指該控件的右邊緣和某個控件的右邊緣對齊

app:layout_constraintTop_toBottomOf是指該控件的上邊緣和某個控件的下邊緣對齊

依次類推,同樣含義的屬性還有:

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_constraintStart_toEndOf

layout_constraintStart_toStartOf

layout_constraintEnd_toStartOf

layout_constraintEnd_toEndOf

layout_constraintBaseline_toBaselineOf

上述屬性的屬性值可以是某個控件的 id,也可以是parent,比如:

app:layout_constraintLeft_toRightOf="@+id/tv_a"

app:layout_constraintRight_toRightOf="parent"

對于相對位置,官方給出的示意圖如下所示:

relativepositioning1.png

2.2 邊距(Margins)

假如現(xiàn)在有如下這樣一個界面:TextViewA 上邊距離 Toolbar 30dp,在屏幕最左邊,TextViewB 上邊距離 Toolbar 30dp,左邊距離 TextView A 也是 30dp,該如何編寫布局文件呢?

margin.png

該布局 xml 關(guān)鍵代碼如下所示:

在 ConstraintLayout 布局中,下面幾個 Margin 相關(guān)的屬性依然是有效的

android:layout_marginStart

android:layout_marginEnd

android:layout_marginLeft

android:layout_marginTop

android:layout_marginRight

android:layout_marginBottom

注意:在 ConstraintLayout 中,上述屬性值只可以是正數(shù)或者0,不可以是負數(shù)。

假如現(xiàn)在有這樣的一個需求,當 TextViewA 顯示的時候,TextViewB 距離左邊是 20dp;當 TextViewA 可見性為Gone的時候,TextViewB 距離左邊是 30dp,使用 ConstraintLayout 可以很容易的實現(xiàn)這樣的需求。

在 ConstraintLayout 中如下這些邊距屬性就是當依據(jù)的控件變?yōu)?Gone 的時候就會生效

layout_goneMarginStart

layout_goneMarginEnd

layout_goneMarginLeft

layout_goneMarginTop

layout_goneMarginRight

layout_goneMarginBottom

2.3 居中顯示

假如說有如下圖所示的一個界面,TextViewA 在布局的正中間,如果用 RelativeLayout 和 LinearLayout 實現(xiàn)是很方便的,但是用 ConstraintLayout 怎么實現(xiàn)呢?

centerposition.png

其實也很簡單,代碼如下:

在 ConstraintLayout 中并不像 LinearLayout 和 RelativeLayout 是通過android:gravity="center"、android:layout_gravity="center"、android:layout_centerVertical="true"和android:layout_centerHorizontal="true"設(shè)置居中位置的,而是通過app:layout_constraintBottom_toBottomOf、app:layout_constraintLeft_toLeftOf、app:layout_constraintRight_toRightOf和app:layout_constraintTop_toBottomOf設(shè)置該控件上下左右分別依附于指定的控件即可。

在 ConstraintLayout 中有一個非常重要的概念 ---- constraint(約束):當控件有自己的大小時,例如:wrap_content和具體的數(shù)值時,我們?yōu)榭丶砑拥亩际?constraint (約束),這個約束有點像橡皮筋一樣會有一個拉力拉著控件,但是并不會改變控件的大小。

例如上例,在居中顯示中,TextViewA 寬度為 100dp,左邊有app:layout_constraintLeft_toLeftOf="parent"約束,右邊有app:layout_constraintRight_toRightOf="parent"約束,左邊和右邊分別有一個同樣大小的力拉著 TextViewA 控件,所以 TextViewA 會水平居中,豎直方向也是一樣的。

如果想讓上述例子中的 TextViewA 水平方向撐滿整個父控件,即如下圖所示,那該怎么做呢?

centerposition1.png

首先我們想到的是使用android:layout_width="match_parent"實現(xiàn),這樣設(shè)置之后確實也會實現(xiàn)這樣的效果,但是查看 ConstraintLayout 的官方文檔發(fā)現(xiàn),在 ConstraintLayout 中match_parent已經(jīng)被match_constraint所取代,所以使用android:layout_width="0dp"更為合適(在 xml 中并沒有match_constraint這個屬性值,0dp 即代碼match_constraint值)。

Bias屬性

可以在上下和左右分別有約束的時候加上偏移率,屬性如下所示:

app:layout_constraintHorizontal_bias="0.1"

app:layout_constraintVertical_bias="0.8"

layout_constraintHorizontal_bias取值范圍是[0.0 ~ 1.0],從左向右

layout_constraintVertical_bias取值范圍是[0.0 ~ 1.0],從上到下

centerposition2.png

2.4 可見性對布局的影響

在 2.1 節(jié)中提到過幾個特殊的屬性:

layout_goneMarginStart

layout_goneMarginEnd

layout_goneMarginLeft

layout_goneMarginTop

layout_goneMarginRight

layout_goneMarginBottom

這些屬性是配合著layout_marginStart等屬性使用的,當控件的約束所依附的 target 控件的 visibility 不為 GONE 的時候,layout_marginStart等屬性起作用,當 target 控件的 visibility 為 GONE 的時候,layout_goneMarginStart屬性起作用

2.5 尺寸約束

ConstraintLayout 的最小尺寸

當 ConstraintLayout 的寬度或者高度為wrap_content時,可以通過如下屬性為ConstraintLayout設(shè)置最小尺寸或最大尺寸

android:minWidth:最小寬度

android:minHeight:最小高度

android:maxWidth:最大寬度

android:maxHeight:最大高度

控件的尺寸約束

在ConstraintLayout中,設(shè)置控件的大小總共有三種方式,分別是:

一個具體的屬性值,比如:123dp或者一個 Dimension 引用

使用wrap_content,根據(jù)自身大小決定

0dp即match_constraint

控件按寬高比設(shè)置大小

在ConstraintLayout中,其中的控件可以按照寬高比設(shè)置其大小,前提是控件的寬或者高的尺寸至少有一個是0dp,然后通過layout_constraintDimensionRatio設(shè)置控件的寬高比,顯示出來的控件的寬和高即是設(shè)置的比例的大小,如下所示:

在上面 xml 代碼中,Button 的寬度是一個特定值:wrap_content,高度是一個可變值:0dp,寬:高 = 1 :1,則高度也就是和寬度相同的值

通過layout_constraintDimensionRatio設(shè)置的參數(shù)可以是:

一個浮點數(shù),代表寬/高的比例

也可以是上述例子中的形式:寬:高

當控件寬和高的值都是0dp時,也可以通過layout_constraintDimensionRatio設(shè)置寬和高的比例,比如:

在上面 xml 代碼中,Button 的寬是可變值:0dp,高也是可變值:0dp,高:寬 = 16:9,但是 Button 有上下兩個約束:高頂?shù)礁缚丶纳线吘墸醉數(shù)礁缚丶南逻吘?,這樣 Button 的高度就固定了,再通過比例,即可得到寬 = 高 * 9/16.

2.5 鏈(Chains)

在 ConstraintLayout 中有一個非常重要的概念:鏈(Chains)

那什么才是鏈呢?在下圖所示的界面中即存在一個鏈:

chains.png

上圖中 TextViewA、TextViewB 和 TextViewC 形成了一個鏈,上圖對應(yīng)的 xml 代碼是:

從代碼中可以看到形成鏈的三個控件有以下特點:

TextViewA 和 TextViewB 通過app:layout_constraintRight_toLeftOf="@+id/tv_b"和app:layout_constraintLeft_toRightOf="@+id/tv_a"相互依賴

TextViewB 和 TextViewC 通過app:layout_constraintRight_toLeftOf="@+id/tv_c"和app:layout_constraintLeft_toRightOf="@+id/tv_b"相互依賴

這樣便形成了一個鏈,在此鏈中最左邊的控件稱為鏈頭。同樣的也可以通過上下相互依賴形成上下的鏈,最上面的控件稱為鏈頭。

在鏈頭中通過layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle可以設(shè)置鏈的樣式。

鏈的樣式總共有三種:

CHAIN_SPREAD:默認樣式

CHAIN_SPREAD_INSIDE

CHAIN_PACKED

用一張官方的圖解釋上面幾個屬性的含義,如下圖所示:

chainsStyle.png

這里需要強調(diào)下比重鏈(Weighted chain)樣式:在CHAIN_SPREAD樣式的鏈中,如果其中的控件的寬度或高度為 0dp,即可以通過layout_constraintHorizontal_weight或layout_constraintVertical_weight設(shè)置該控件在水平或者豎直方向的比例,類似于 LinearLayout 中的 weight 屬性的作用

2.6 Guideline

在 ConstraintLayout 中有一個特殊的輔助類:android.support.constraint.Guideline,主要用于輔助布局,可以把它看做是一個輔助線,但是不會繪制到界面上,有水平的和垂直的。

Guideline有以下幾個屬性:

android:orientation:vertical或horizontal,表示此 Guideline 是水平的還是垂直的

app:layout_constraintGuide_begin:表示 Guideline 的距離左邊或上邊的距離,根據(jù)方向決定是距離哪邊的

app:layout_constraintGuide_begin:表示 Guideline 的距離右邊或下邊的距離,根據(jù)方向決定是距離哪邊的

app:layout_constraintGuide_percent:表示 Guideline 距離左邊或上邊的百分比,根據(jù)方向決定是距離哪邊的

用一張效果圖展示 Guideline 的作用,一個 TextView 在中線的左邊 32dp 位置處,另一個 TextView 在中線右邊 32dp 處

guideline.png

上圖代碼如下:

好啦,至此關(guān)于 ConstraintLayout 的使用就基本全部介紹完畢,是不是覺得很好用呢?那就趕快在項目中使用起來的!文中涉及的代碼都在這兒:ConstraintLayoutPractic

參考資料:

ConstraintLayout 官方文檔

ConstraintLayout 完全解析 快來優(yōu)化你的布局吧--Hongyang

Android ConstraintLayout 約束布局--打魚還是曬網(wǎng) —— stone

ConstraintLayout約束布局使用教程難點理解--yueding


鏈接:http://www.itdecent.cn/p/6e5fa646ddf5

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容