網(wǎng)傳constraintLayout(約束布局)的布局,性能和功能性相當(dāng)優(yōu)越撩匕,雖然RelativeLayout用的飛起來蜂嗽,也得與時(shí)俱進(jìn)。
本文主要分為以下幾個(gè)部分:
catalog.png
1. 背景介紹
在面試的時(shí)候經(jīng)常會(huì)被問到有沒有做過布局優(yōu)化博其,都通過什么方式優(yōu)化布局界面的套才?優(yōu)化布局界面其中一種方式就是通過 ConstraintLayout 降低布局層級(jí),從而避免過度測(cè)量和繪制慕淡。本篇文章重點(diǎn)講解 ConstraintLayout 的用法背伴,關(guān)于 ConstraintLayout 性能方面的優(yōu)勢(shì),可以參考這篇文章:解析 ConstraintLayout 的性能優(yōu)勢(shì)峰髓。
通過可視化拖拽的方式編寫 ConstraintLayout 布局界面傻寂,個(gè)人是不太推崇的,雖然它確實(shí)很方便携兵,但是即使通過可視化拖拽的方式編寫布局之后疾掰,還是需要看懂 xml 文件中關(guān)于 ConstraintLayout 的屬性,才可以更靈活的修改布局界面徐紧,所以本文主要講解通過 xml 屬性的方式編寫 ConstraintLayout 布局界面静檬,關(guān)于可視化拖拽的方式編寫 ConstraintLayout 布局界面,可以參考郭霖寫的這篇博客: Android 新特性介紹浪汪,ConstraintLayout 完全解析
好了巴柿,上面介紹了 ConstraintLayout 的兩個(gè)優(yōu)點(diǎn),下面開始進(jìn)入本文的正題死遭,通過 xml 布局屬性的方式編寫 ConstraintLayout 布局。使用之前凯旋,需要在build.gradle文件中添加對(duì) ConstraintLayout 的依賴:
dependencies {? ? ...? ? implementation'com.android.support.constraint:constraint-layout:1.0.2'...}
2. 詳細(xì)使用
本節(jié)主要分為 7 點(diǎn)介紹 ConstraintLayout 的詳細(xì)使用呀潭,那就開始吧~
2.1 相對(duì)位置
ConstraintLayout 和 RelativeLayout 是非常類似的布局控件,它們之間最大的相似之處在于都可以編寫一個(gè)控件相對(duì)于其他控件或父控件的相對(duì)位置至非,比如下面這個(gè)樣式的布局既可以通過
RelativeLayout 實(shí)現(xiàn)钠署,也可以通過 ConstraintLayout 實(shí)現(xiàn)
relativepositioning.png
通過 ConstraintLayout 實(shí)現(xiàn)的代碼如下所示:
通過上面的代碼,可以看到幾個(gè)陌生的 xml 屬性荒椭,它們都是 ConstraintLayout 的 xml 屬性谐鼎,比如:
通過屬性的名字就可以猜測(cè)出它們大概的意思,比如:
app:layout_constraintLeft_toLeftOf是指該控件的左邊緣和某個(gè)控件的左邊緣對(duì)齊
app:layout_constraintRight_toRightOf是指該控件的右邊緣和某個(gè)控件的右邊緣對(duì)齊
app:layout_constraintTop_toBottomOf是指該控件的上邊緣和某個(gè)控件的下邊緣對(duì)齊
依次類推趣惠,同樣含義的屬性還有:
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
上述屬性的屬性值可以是某個(gè)控件的 id狸棍,也可以是parent身害,比如:
app:layout_constraintLeft_toRightOf="@+id/tv_a"
app:layout_constraintRight_toRightOf="parent"
對(duì)于相對(duì)位置,官方給出的示意圖如下所示:
relativepositioning1.png
2.2 邊距(Margins)
假如現(xiàn)在有如下這樣一個(gè)界面:TextViewA 上邊距離 Toolbar 30dp草戈,在屏幕最左邊塌鸯,TextViewB 上邊距離 Toolbar 30dp,左邊距離 TextView A 也是 30dp唐片,該如何編寫布局文件呢丙猬?
margin.png
該布局 xml 關(guān)鍵代碼如下所示:
在 ConstraintLayout 布局中,下面幾個(gè) Margin 相關(guān)的屬性依然是有效的
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
注意:在 ConstraintLayout 中费韭,上述屬性值只可以是正數(shù)或者0茧球,不可以是負(fù)數(shù)。
假如現(xiàn)在有這樣的一個(gè)需求星持,當(dāng) TextViewA 顯示的時(shí)候抢埋,TextViewB 距離左邊是 20dp;當(dāng) TextViewA 可見性為Gone的時(shí)候钉汗,TextViewB 距離左邊是 30dp羹令,使用 ConstraintLayout 可以很容易的實(shí)現(xiàn)這樣的需求。
在 ConstraintLayout 中如下這些邊距屬性就是當(dāng)依據(jù)的控件變?yōu)?Gone 的時(shí)候就會(huì)生效
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
2.3 居中顯示
假如說有如下圖所示的一個(gè)界面损痰,TextViewA 在布局的正中間福侈,如果用 RelativeLayout 和 LinearLayout 實(shí)現(xiàn)是很方便的,但是用 ConstraintLayout 怎么實(shí)現(xiàn)呢卢未?
centerposition.png
其實(shí)也很簡單肪凛,代碼如下:
在 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 中有一個(gè)非常重要的概念 ---- constraint(約束):當(dāng)控件有自己的大小時(shí),例如:wrap_content和具體的數(shù)值時(shí)汉匙,我們?yōu)榭丶砑拥亩际?constraint (約束)拱烁,這個(gè)約束有點(diǎn)像橡皮筋一樣會(huì)有一個(gè)拉力拉著控件,但是并不會(huì)改變控件的大小噩翠。
例如上例戏自,在居中顯示中,TextViewA 寬度為 100dp伤锚,左邊有app:layout_constraintLeft_toLeftOf="parent"約束擅笔,右邊有app:layout_constraintRight_toRightOf="parent"約束,左邊和右邊分別有一個(gè)同樣大小的力拉著 TextViewA 控件,所以 TextViewA 會(huì)水平居中猛们,豎直方向也是一樣的念脯。
如果想讓上述例子中的 TextViewA 水平方向撐滿整個(gè)父控件,即如下圖所示阅懦,那該怎么做呢和二?
centerposition1.png
首先我們想到的是使用android:layout_width="match_parent"實(shí)現(xiàn),這樣設(shè)置之后確實(shí)也會(huì)實(shí)現(xiàn)這樣的效果耳胎,但是查看 ConstraintLayout 的官方文檔發(fā)現(xiàn)惯吕,在 ConstraintLayout 中match_parent已經(jīng)被match_constraint所取代,所以使用android:layout_width="0dp"更為合適(在 xml 中并沒有match_constraint這個(gè)屬性值怕午,0dp 即代碼match_constraint值)废登。
Bias屬性
可以在上下和左右分別有約束的時(shí)候加上偏移率,屬性如下所示:
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 可見性對(duì)布局的影響
在 2.1 節(jié)中提到過幾個(gè)特殊的屬性:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
這些屬性是配合著layout_marginStart等屬性使用的,當(dāng)控件的約束所依附的 target 控件的 visibility 不為 GONE 的時(shí)候兆蕉,layout_marginStart等屬性起作用羽戒,當(dāng) target 控件的 visibility 為 GONE 的時(shí)候,layout_goneMarginStart屬性起作用
2.5 尺寸約束
ConstraintLayout 的最小尺寸
當(dāng) ConstraintLayout 的寬度或者高度為wrap_content時(shí)虎韵,可以通過如下屬性為ConstraintLayout設(shè)置最小尺寸或最大尺寸
android:minWidth:最小寬度
android:minHeight:最小高度
android:maxWidth:最大寬度
android:maxHeight:最大高度
控件的尺寸約束
在ConstraintLayout中易稠,設(shè)置控件的大小總共有三種方式,分別是:
一個(gè)具體的屬性值包蓝,比如:123dp或者一個(gè) Dimension 引用
使用wrap_content驶社,根據(jù)自身大小決定
0dp即match_constraint
控件按寬高比設(shè)置大小
在ConstraintLayout中,其中的控件可以按照寬高比設(shè)置其大小测萎,前提是控件的寬或者高的尺寸至少有一個(gè)是0dp亡电,然后通過layout_constraintDimensionRatio設(shè)置控件的寬高比,顯示出來的控件的寬和高即是設(shè)置的比例的大小硅瞧,如下所示:
在上面 xml 代碼中份乒,Button 的寬度是一個(gè)特定值:wrap_content,高度是一個(gè)可變值:0dp腕唧,寬:高 = 1 :1冒嫡,則高度也就是和寬度相同的值
通過layout_constraintDimensionRatio設(shè)置的參數(shù)可以是:
一個(gè)浮點(diǎn)數(shù),代表寬/高的比例
也可以是上述例子中的形式:寬:高
當(dāng)控件寬和高的值都是0dp時(shí)四苇,也可以通過layout_constraintDimensionRatio設(shè)置寬和高的比例,比如:
在上面 xml 代碼中方咆,Button 的寬是可變值:0dp月腋,高也是可變值:0dp,高:寬 = 16:9,但是 Button 有上下兩個(gè)約束:高頂?shù)礁缚丶纳线吘売苌В醉數(shù)礁缚丶南逻吘壠模@樣 Button 的高度就固定了,再通過比例妓肢,即可得到寬 = 高 * 9/16.
2.5 鏈(Chains)
在 ConstraintLayout 中有一個(gè)非常重要的概念:鏈(Chains)
那什么才是鏈呢捌省?在下圖所示的界面中即存在一個(gè)鏈:
chains.png
上圖中 TextViewA、TextViewB 和 TextViewC 形成了一個(gè)鏈碉钠,上圖對(duì)應(yīng)的 xml 代碼是:
從代碼中可以看到形成鏈的三個(gè)控件有以下特點(diǎn):
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"相互依賴
這樣便形成了一個(gè)鏈纲缓,在此鏈中最左邊的控件稱為鏈頭。同樣的也可以通過上下相互依賴形成上下的鏈喊废,最上面的控件稱為鏈頭祝高。
在鏈頭中通過layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle可以設(shè)置鏈的樣式。
鏈的樣式總共有三種:
CHAIN_SPREAD:默認(rèn)樣式
CHAIN_SPREAD_INSIDE
CHAIN_PACKED
用一張官方的圖解釋上面幾個(gè)屬性的含義污筷,如下圖所示:
chainsStyle.png
這里需要強(qiáng)調(diào)下比重鏈(Weighted chain)樣式:在CHAIN_SPREAD樣式的鏈中工闺,如果其中的控件的寬度或高度為 0dp,即可以通過layout_constraintHorizontal_weight或layout_constraintVertical_weight設(shè)置該控件在水平或者豎直方向的比例瓣蛀,類似于 LinearLayout 中的 weight 屬性的作用
2.6 Guideline
在 ConstraintLayout 中有一個(gè)特殊的輔助類:android.support.constraint.Guideline陆蟆,主要用于輔助布局,可以把它看做是一個(gè)輔助線惋增,但是不會(huì)繪制到界面上叠殷,有水平的和垂直的。
Guideline有以下幾個(gè)屬性:
android:orientation:vertical或horizontal器腋,表示此 Guideline 是水平的還是垂直的
app:layout_constraintGuide_begin:表示 Guideline 的距離左邊或上邊的距離溪猿,根據(jù)方向決定是距離哪邊的
app:layout_constraintGuide_begin:表示 Guideline 的距離右邊或下邊的距離,根據(jù)方向決定是距離哪邊的
app:layout_constraintGuide_percent:表示 Guideline 距離左邊或上邊的百分比纫塌,根據(jù)方向決定是距離哪邊的
用一張效果圖展示 Guideline 的作用诊县,一個(gè) TextView 在中線的左邊 32dp 位置處,另一個(gè) TextView 在中線右邊 32dp 處
guideline.png
上圖代碼如下:
好啦措左,至此關(guān)于 ConstraintLayout 的使用就基本全部介紹完畢依痊,是不是覺得很好用呢?那就趕快在項(xiàng)目中使用起來的怎披!文中涉及的代碼都在這兒:ConstraintLayoutPractic胸嘁。
參考資料:
ConstraintLayout 完全解析 快來優(yōu)化你的布局吧--Hongyang
Android ConstraintLayout 約束布局--打魚還是曬網(wǎng) —— stone
ConstraintLayout約束布局使用教程難點(diǎn)理解--yueding
鏈接:http://www.reibang.com/p/6e5fa646ddf5