概述
小伙伴們好久不見您没,我又回來啦眉尸。
說實話這篇文章寫的算是比較晚了,距離ConstraintLayout
出現(xiàn)至今已經(jīng)有一年了。
且自AS2.3起創(chuàng)建新的Activity
,默認的layout根布局就是ConstraintLayout
喳魏。
所以再不學習就真的晚了卖毁。
我也是正式開始學習的道路羡藐,先說一下我的學習過程:
- 先閱讀了ConstraintLayout官方文檔和Guideline官方文檔
- 實踐每個屬性并記下筆記(翻譯)
- 學習了郭神關于
ConstraintLayout
可視化操作(拖拖拽拽)的博客贩毕,發(fā)現(xiàn)博客中對Chain
的概念沒有提及 - 查詢關于
Chain
以及一些疑點的資料 - 整理成文
- 當然中間也遇到了許許多多的問題
本文的順序,大體按照ConstraintLayout官方文檔的順序依次講解(翻譯)屬性和用法仆嗦,并對疑難點進行額外說明辉阶。
關于可視化操作,可參考我寫的動態(tài)圖解&實例 ConstraintLayout Chain和郭神博文可視化操作
使用前的準備
引入也有坑瘩扼,無力吐槽睛藻。
先放上 截止至20170524,最新版本1.0.1:
compile 'com.android.support.constraint:constraint-layout:1.0.1'
坑是啥邢隧?因為我使用的是最新的release版AndroidStudio2.3.2店印,新建Activity后,自動幫我引入的是1.0.8-alpha
版本倒慧,
開始我就這么愉快的學習了按摘,可是當我學習到Chain
相關姿勢時,特碼的纫谅,他居然報錯炫贤。說找不到屬性:
Error:(10) No resource identifier found for attribute 'layout_constraintHorizontal_chainStyle' in package 'com.mcxtzhang.constraintlayoutdemo'
ok,那我百度,顯然搜不到的付秕,ok兰珍,那我再google,特么的居然也搜不到询吴。
震驚掠河,于是機智的我去看源碼,發(fā)現(xiàn)我使用的1.0.8-alpha
版本的源碼里根本沒有Chain
相關屬性的支持猛计,所以我就覺得一定是引入的版本有問題唠摹,于是我用google搜索"ConstraintLayout last version",發(fā)現(xiàn)誒~官方有說最新版鏈接如下:
http://tools.android.com/recent/constraintlayout102isnowavailable
按照這個鏈接提示,最新版是1.0.2
奉瘤,嗯哼勾拉,當我換成1.0.2
后,發(fā)現(xiàn)無法download....
不知道是網(wǎng)絡問題還是什么問題盗温,提示我無法下載藕赞,具體的錯誤記不清了。反正就是無法獲取到這個版本卖局。
特么的機智的我又直接去AndroidStudio的Library Dependency里去搜索斧蜕,發(fā)現(xiàn)居然搜不到"ConstraintLayout "的庫。再次懵逼吼驶。
后來我進行最后的一次嘗試店煞,因為我看google官方上1.0.2版本的上一個版本是1.0.1.于是我修改版本號鸣个,sync gradle,居然成功了。
總結踩坑歷程:
- 1 最新Release版AndroidStudio模板自帶的是1.0.8alpha版ConstraintLayout
- 2 使用
Chain
相關屬性報錯 - 3 發(fā)現(xiàn)該版本源碼沒有
Chain
相關屬性 - 4 官網(wǎng)說的最新版1.0.2 我無法下載
- 5 AndroidStudio自帶的Library Dependency搜不到
ConstraintLayout
- 6 修改版本號為1.0.1 下載
對此温赔,我只能說“驚不驚喜瓜晤! 意不意外雄驹!”
ConstraintLayout是什么
先概況一下,它是一個為了解決布局嵌套和模仿前端flexible布局的一個新布局颓遏。
從字面上理解演训,ConstraintLayout
是約束布局蔼水。
在我理解雅宾,這是一個RelativeLayout
的升級版昏苏。
而當初推出RelativeLayout
的目的是為了在減少多層嵌套布局孵构,
推出ConstraintLayout
也是同樣的目的,盡可能的使布局 寬而短豪直,而不是 窄而長劣摇。
而ConstraintLayout
更加強大,很多需要多層嵌套的布局弓乙,使用ConstraintLayout
只需要一層即可解決末融。
它的Chain
幾種style方式,和前端的flexbox布局風格一致唆貌,官方文檔中也說了它是flexible方式布局控件的東西滑潘。
A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way.
而且搭配可視化的操作,使得布局也變得更輕松锨咙。
Google官方推薦所有操作都在"Design"區(qū)域搞定,即通過可視化拖拖拽拽生成布局大致的樣子追逮,然后針對具體屬性酪刀、約束 精細修改粹舵。
甚至可以這么說,你完全不需要知道ConstraintLayout
的具體屬性值分別是什么骂倘,只通過拖拽和鼠標點擊就可以實現(xiàn)一些布局眼滤。
那么本文的意義何在呢?
我覺得首先是要知其然知其所以然历涝,那些拖拽點擊生成的代碼屬性到底是什么意思诅需?通過本文可以了解。
另外 雖然大部分操作可以在“Design”區(qū)域完成荧库,但是保不齊的需要你切換至“Text”區(qū)域堰塌,寫上一兩行屬性代碼场刑,了解 這些屬性 總是有益無害的。
而且瞎疼,有一些屬性是無法簡單通過拖拽點擊完成的丑慎,例如Margins when connected to a GONE widget
。
剛才提到RelativeLayout
腻异,其實RelativeLayout
也是通過約束來布局子View的呀,
以前RelativeLayout
的約束有兩種:
- 1 子控件和子控件之間的約束(如
android:layout_below="@id/title"
) - 2 子控件和父控件的約束(如
android:layout_alignParentTop="true"
)
現(xiàn)在ConstraintLayout
也是類似的机打,只不過除了以上兩種約束残邀,還多了一種
- 3 子控件和
Guideline
的約束
其實關于和Guideline
的約束,也可以理解成約束1空另,因為Guideline
其實就是一個在屏幕上不顯示的View罷了。稍后講到Guideline
會帶大家看看它巨簡單的源碼循榆。
下面開始正文冯痢,開始屬性的講解
相對定位 (Relative positioning)
這一節(jié)的屬性和相對布局的很像,
值得注意的是參數(shù)取值是 ID(@id/button1
)代表約束1、3振劳, 或者 字符串"parent"
代表約束2:
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_constraintXXX_toYYYOf
,這里我的理解,
constraintXXX
里的XXX
代表是這個子控件自身的哪條邊(Left、Right吮旅、Top庇勃、Bottom、Baseline
)罕拂,而
toYYYOf
里的YYY
代表的是和約束控件的哪條邊 發(fā)生約束 (取值同樣是 Left蒿秦、Right、Top碗旅、Bottom、Baseline
)旧困。當
XXX
和YYY
相反時,表示控件自身的XXX
在約束控件的YYY
的一側拗盒,例如
app:layout_constraintLeft_toRightOf="@id/button1"
,表示的是控件自身的左側在button1的右側哮肚。
當XXX
和YYY
相同時恼策,表示控件自身的XXX
和約束控件的YYY
的一側 對齊戏蔑,
例如:app:layout_constraintBottom_toBottomOf="parent"
,表示控件自身底端和父控件底端對齊情龄。
代碼為:
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Demo"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button2"
app:layout_constraintLeft_toRightOf="@id/button1"/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="button3 跳轉match頁"
app:layout_constraintBottom_toBottomOf="parent"/>
圖示:
Margins
margin和以往的使用一致,注意margin不能為負值即可睹逃。
在上圖中也順便展示了margin的使用。
當約束的widget為GONE時的Margins
Margins when connected to a GONE widget
舉例翼闹,當A控件 約束 在B控件的左邊猎荠,B控件GONE了,此時A會額外擁有一個margin的能力拒垃,來“補充”B消失的導致的“位移”。
這就是本節(jié)的屬性横堡。
這一節(jié)的屬性開始我并沒有理解,后來是通過寫了一些Demo實驗才明白胸蛛。奈何官方文檔惜字如金,只有一句話民珍,并沒有Demo展示:
When a position constraint target's visibility is View.GONE, you can also indicates a different margin value to be used using the following attributes:
先看屬性:
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
在看Demo:
<Button
android:id="@+id/button4"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="button4"
app:layout_constraintRight_toRightOf="parent"
/>
<!-- android:layout_marginRight="10dp"
配合 app:layout_goneMarginRight="110dp"一起使用陋桂,
在約束的布局gone時,起用goneMargin身坐,
但是一定要預先設置對應方向上的margin -->
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="button5"
app:layout_constraintRight_toLeftOf="@id/button4"
app:layout_goneMarginRight="110dp"/>
此時圖示:
當給button4 隱藏GONE掉以后:
圖示:
會發(fā)現(xiàn)Button5紋絲不動咐蝇,并沒有收到Button4消失的影響抹腿。
這里我們再仔細看看button4的android:layout_width="100dp"
警绩,
而button5的android:layout_marginRight="10dp"
,app:layout_goneMarginRight="110dp"
110 = 100 +10 , 這是一道小學計算題。
什么意思混狠?
幾個注意事項:
-
app:layout_goneMarginRight
要配合android:layout_marginRight
一起使用。 - 如果只設置了
app:layout_goneMarginRight
沒有設置android:layout_marginRight
,則無效湖饱。(alpha版本的bug坠七,1.0.1版本已經(jīng)修復) - 在約束的布局gone時彪置,控件自身的
marginXXX
會被goneMarginXXX
替換掉惶桐,以本文Demo為例,原本button4寬度是100救恨,button5的marginRight
是10, 加起來是110,如果想讓button4隱藏之后寂纪,button5仍然紋絲不動捞蛋,則需要設置goneMarginRight
為10+100 = 110.
居中定位和傾向(Centering positioning and bias)
居中定位
約束布局一個有用的地方是它如何處理“不可能”的約束。
比如你定義如下:
<android.support.constraint.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
按照我們第一小節(jié)講的屬性值捣域,這個定義的意思是,Button的左邊和父控件的左邊對齊贞言,Button的右邊和父控件的右邊對齊阀蒂。
可是控件是wrap_content
的该窗,它如果不鋪滿父控件要如何能滿足這兩個約束呢弟蚀?
實際效果如下:
控件會居中顯示,因為這兩個約束作用 類似于 水平方向上酗失,有相反的力 去拉控件义钉,最終控件會居中顯示。
傾向(Bias)
搭配bias,能使約束偏向某一邊兑牡,默認是0.5,有以下屬性:
- layout_constraintHorizontal_bias (0最左邊 1最右邊)
- layout_constraintVertical_bias (0最上邊 1 最底邊)
比如上個Demo氓涣,我加入app:layout_constraintHorizontal_bias="0.9"
,則會在水平方向上向右偏移至90%。
<android.support.constraint.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
...
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
對可見性的處理(Visibility behavior)
這一節(jié)是對前一節(jié)goneMargin
的補充。
重點是Gone隱藏掉的控件嘱丢,會被解析成一個點,并忽略margin履澳。
ConstraintLayout
能為View.Gone
的View
特殊處理。
通常,GONE的控件不會被顯示馏颂,并且不是布局本身的一部分(即如果標記為GONE拂铡,則其實際尺寸并不會更改)。
但是在布局計算方面聪轿,GONE的View仍然是其中的一個重要區(qū)別:
對于布局傳遞外莲,它們的維度將被視為零(基本上它們將被解析為一個點)
如果他們對其他小部件有約束力摆舟,那么他們?nèi)匀粫艿阶鹬兀?strong>但任何margin都將等于零
注意A的margin也被忽略了兢仰。
拿上個Demo改一下宗收,為A 加上一個android:layout_marginRight="10dp"
,
為了使A 隱藏后,B仍能紋絲不動间聊,則B的app:layout_goneMarginRight="120dp"
。
B goneMarginRight120 = A寬度100 + A marginRight10 +B marginRight10
<Button
android:id="@+id/button4"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="button4"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="button5"
app:layout_constraintRight_toLeftOf="@id/button4"
app:layout_goneMarginRight="120dp"/>
尺寸約束(Dimensions constraints)
ConstraintLayout的最小尺寸 (Minimum dimensions on ConstraintLayout)
可以為ConstraintLayout
自身定義最小的尺寸苫拍,他會在 ConstraintLayout
為WRAP_CONTENT
時起作用凰兑。
● android:minWidth
● android:minHeight
控件尺寸約束(Widgets dimension constraints)
控件的寬高有三種方式為其設置:
- 確定尺寸
WRAP_CONTENT
-
0dp
锦秒,就等于MATCH_CONSTRAINT
有些人可能有疑問蚜厉,為什么不用MATCH_PARENT
了看彼。
官方文檔如是說:
MATCH_PARENT is not supported for widgets contained in a ConstraintLayout, though similar behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom constraints being set to "parent".
意思是MATCH_PARENT
不再被支持了,通過MATCH_CONSTRAINT
替代囚聚。
我們寫個Demo看一下三種方式設置的效果吧:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="200dp"
android:layout_height="100dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/button10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/button"
app:layout_constraintRight_toRightOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/button"/>
<Button
android:id="@+id/button11"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/button10"
app:layout_constraintRight_toRightOf="@+id/button10"
app:layout_constraintTop_toBottomOf="@+id/button10"/>
</android.support.constraint.ConstraintLayout>
效果如圖:
有些人是不是要說靖榕,你特么逗我,不是說好的0dp等于
MATCH_CONSTRAINT
顽铸,應該是撐滿屏幕的呀茁计,OK ,把刀放下谓松。讓我們仔細看這個
MATCH_CONSTRAINT
屬性星压。它match的是約束。而這里第三個按鈕的約束是第二個按鈕鬼譬,所以它的寬度設置為
MATCH_CONSTRAINT
時娜膘,是和它的約束按鈕,即第二個按鈕一樣寬优质。注意竣贪,此時军洼,豎直方向上沒有約束,所以不能使用
MATCH_CONSTRAINT
屬性.
我們僅僅將第三個按鈕的屬性修改為
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
則它寬度會撐滿屏幕:
我們再修改Demo演怎,分別為后兩個按鈕加上margin:
<android.support.constraint.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="200dp"
android:layout_height="100dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/button10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/button"
app:layout_constraintRight_toRightOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/button"/>
<Button
android:id="@+id/button12"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
app:layout_constraintLeft_toLeftOf="@id/button10"
app:layout_constraintRight_toRightOf="@id/button10"
app:layout_constraintTop_toBottomOf="@id/button10"/>
<Button
android:id="@+id/button11"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button12"/>
</android.support.constraint.ConstraintLayout>
效果如圖:
最后匕争,記住一句話約束要和 0dp 的 方向一致。否則無效爷耀。
比例(Ratio)
只有一個方向約束:
可以以比例去定義View的寬高甘桑。
為了做到這一點,需要將至少一個約束維度設置為0dp
(即MATCH_CONSTRAINT
)
并將屬性layout_constraintDimentionRatio
設置為給定的比例畏纲。
例如:
<Button
android:layout_width="200dp"
android:layout_height="0dp"
android:text="Ratio"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintTop_toTopOf="parent"/>
如圖:
比例值有兩種取值:
- 浮點值扇住,表示寬度和高度之間的比率 (2,0.5)
- “width:height”形式的比例 (5:1,1:5)
當約束多于一個(寬高都被約束了)
如果兩個維度均設置為MATCH_CONSTRAINT(0dp),也可以使用比例盗胀。 在這種情況下艘蹋,系統(tǒng)會使用滿足所有約束條件和比率的最大尺寸。
如果需要根據(jù)一個維度的尺寸去約束另一個維度的尺寸票灰。
則可以在比率值的前面添加 W 或者 H 來分別約束寬度或者高度女阀。
例如,如果一個尺寸被兩個目標約束(比如寬度為0屑迂,在父容器中居中)浸策,可以使用 W 或H 來指定哪個維度被約束。
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,2:1"
app:layout_constraintTop_toTopOf="parent"/>
這里用“H”表示以高度為約束惹盼,高度的最大尺寸就是父控件的高度庸汗,“2:1”表示高:寬 = 2 : 1.
則寬度為高度的一半:
鏈條(Chains)
鏈條在同一個軸上(水平或者垂直)提供一個類似群組的統(tǒng)一表現(xiàn)。另一個軸可以單獨控制手报。
創(chuàng)建鏈條(Creating a chain)
如果一組小部件通過雙向連接(見圖蚯舱,顯示最小的鏈,帶有兩個小部件)掩蛤,則將其視為鏈條枉昏。
鏈條頭(Chain heads)
鏈條由在鏈的第一個元素(鏈的“頭”)上設置的屬性控制:
頭是水平鏈最左邊的View,或垂直鏈最頂端的View揍鸟。
鏈的margin(Margins in chains)
如果在連接上指定了邊距兄裂,則將被考慮在內(nèi)。
例如
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/buttonB"/>
<Button
android:id="@+id/buttonB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintLeft_toRightOf="@+id/buttonA"
app:layout_constraintRight_toRightOf="parent"/>
通過app:layout_constraintRight_toLeftOf="@+id/buttonB"
和app:layout_constraintLeft_toRightOf="@+id/buttonA"
就建立了鏈條阳藻,(我中有你晰奖,你中有我)。
然后它們兩個成了一個整體腥泥,所以鏈條左邊設置app:layout_constraintLeft_toLeftOf="parent"
使得和父控件左對齊畅涂,
右邊設置app:layout_constraintRight_toRightOf="parent"
使得和父控件右對齊,
這樣整個鏈條就居中了道川,最后對左控件設置了margin,相當于整個鏈條左邊有了margin
效果:
鏈條樣式(Chain Style)
當在鏈的第一個元素上設置屬性 layout_constraintHorizontal_chainStyle
或layout_constraintVertical_chainStyle
時,鏈的行為將根據(jù)指定的樣式(默認為CHAIN_SPREAD
)而更改冒萄。
看圖這里就很像JS里的flexible有木有臊岸。因為ConstraintLayout
就是模仿flexible做的。
取值如下:
-
spread
- 元素將被展開(默認樣式) - 加權鏈 - 在spread模式下尊流,如果某些小部件設置
為MATCH_CONSTRAINT
帅戒,則它們將拆分可用空間 -
spread_inside
- 類似,但鏈的端點將不會擴展 -
packed
- 鏈的元素將被打包在一起崖技。 孩子的水平或垂直偏差屬性將影響包裝元素的定位
拿加權鏈舉個例子:
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:text="Button"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/buttonB"/>
<Button
android:id="@+id/buttonB"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintLeft_toRightOf="@+id/buttonA"
app:layout_constraintRight_toRightOf="parent"/>
加權鏈(Weighted chains)
和LinearLayou
t的weight
類似逻住。
鏈的默認行為是在可用空間中平均分配元素。 如果一個或多個元素使用MATCH_CONSTRAINT
迎献,它們將使用剩余的空白空間(在它們之間相等)瞎访。 屬性layout_constraintHorizontal_weight
和layout_constraintVertical_weight
將決定這些都設置了MATCH_CONSTRAINT
的View如何分配空間。 例如吁恍,在包含使用MATCH_CONSTRAINT
的兩個元素的鏈上扒秸,第一個元素使用權重為2,第二個元素的權重為1冀瓦,第一個元素占用的空間將是第二個元素的兩倍
最后關于鏈條伴奥,再給大家看一個關于margin
的demo:
<Button
android:id="@+id/buttonA"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:text="Button"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/buttonB"/>
<Button
android:id="@+id/buttonB"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintLeft_toRightOf="@+id/buttonA"
app:layout_constraintRight_toRightOf="parent"/>
一圖勝千言,可以看到雖然他們的weight相等翼闽,但是margin是被計算在約束里的拾徙,所以左邊的按鈕寬度比右邊的小。
Guideline
Guideline
只能用于ConstraintLayout
中感局,是一個工具類尼啡,不會被顯示,僅僅用于輔助布局蓝厌。
它可以是horizontal
或者 vertical
的玄叠。(例如:android:orientation="vertical"
)
-
vertical
的Guideline
寬度為零,高度為ConstraintLayout
的高度 -
horizontal
的Guideline
高度為零拓提,寬度為ConstraintLayout
的高度
定位Guideline
有三種方式:
- 指定距離左側或頂部的固定距離(
layout_constraintGuide_begin
) - 指定距離右側或底部的固定距離(
layout_constraintGuide_end
) - 指定在父控件中的寬度或高度的百分比(
layout_constraintGuide_percent
)
一個栗子一看便知:
<android.support.constraint.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">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="100dp"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Button"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
預覽:
Guideline源碼:
public class Guideline extends View {
public Guideline(Context context) {
super(context);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs) {
super(context, attrs);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr);
super.setVisibility(8);
}
public void setVisibility(int visibility) {
}
public void draw(Canvas canvas) {
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.setMeasuredDimension(0, 0);
}
}
public static final int GONE = 0x00000008;
源碼就這么點读恃,這貨的源碼和ViewStub
有點像啊,可以看出
- 它默認是GONE的代态。8 就是View.GONE的值寺惫。
- 它的
public void setVisibility(int visibility)
方法被空實現(xiàn)了,所以用戶也沒辦法改變它的可見度蹦疑。 - 推導出它一定是GONE的西雀。在屏幕上不可見
-
this.setMeasuredDimension(0, 0);
和public void draw(Canvas canvas)
的空實現(xiàn),表明這是一個超輕量的View歉摧,不可見艇肴,沒有寬高腔呜,也不繪制任何東西。僅僅作為我們的錨點使用再悼。
總結
很久不寫博客了核畴,一是工作太忙了,二也是隨意的寫怕誤人子弟冲九。
這篇文章我寫了整整一天谤草,每個例子我都邊寫邊跑了一遍,
也看了幾篇別人的文章莺奸,有些人簡單的翻譯了官方文檔丑孩,但是對文檔中一些沒有舉例, 不那么好理解的地方也沒有說明灭贷,于是便有了此文温学。
關于可視化操作,建議直接看我寫的動態(tài)圖解&實例 ConstraintLayout Chain和郭神博文可視化操作氧腰,
我覺得ConstraintLayout 枫浙,有這幾篇就夠了。
文中代碼地址在我的Demo合集中:
https://github.com/mcxtzhang/Demos/tree/master/constraintlayoutdemo/src/main
想看我更多文章:【張旭童的博客】http://blog.csdn.net/zxt0601
想來gayhub和我gaygayup:【mcxtzhang的Github主頁】https://github.com/mcxtzhang