ConstraintLayout 屬性詳解 和Chain的使用

想看我更多文章:【張旭童的博客】http://www.reibang.com/p/9b6e12d8eea0

概述

小伙伴們好久不見您没,我又回來啦眉尸。
說實話這篇文章寫的算是比較晚了,距離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)旧困。
XXXYYY相反時,表示控件自身的XXX在約束控件的YYY的一側拗盒,
例如app:layout_constraintLeft_toRightOf="@id/button1" ,表示的是控件自身的左側在button1的右側哮肚。

XXXYYY相同時恼策,表示控件自身的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.GoneView特殊處理。
通常,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 自身定義最小的尺寸苫拍,他會在 ConstraintLayoutWRAP_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_chainStylelayout_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)

LinearLayout的weight類似逻住。

鏈的默認行為是在可用空間中平均分配元素。 如果一個或多個元素使用MATCH_CONSTRAINT迎献,它們將使用剩余的空白空間(在它們之間相等)瞎访。 屬性layout_constraintHorizontal_weightlayout_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"

  • verticalGuideline寬度為零,高度為ConstraintLayout的高度
  • horizontalGuideline高度為零拓提,寬度為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

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末古拴,一起剝皮案震驚了整個濱河市箩帚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌黄痪,老刑警劉巖紧帕,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異桅打,居然都是意外死亡是嗜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門挺尾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹅搪,“玉大人,你說我怎么就攤上這事遭铺±鍪粒” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵魂挂,是天一觀的道長甫题。 經(jīng)常有香客問我,道長涂召,這世上最難降的妖魔是什么坠非? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮果正,結果婚禮上炎码,老公的妹妹穿的比我還像新娘盟迟。我一直安慰自己,他們只是感情好辅肾,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布队萤。 她就那樣靜靜地躺著,像睡著了一般矫钓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舍杜,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天新娜,我揣著相機與錄音,去河邊找鬼既绩。 笑死概龄,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的饲握。 我是一名探鬼主播私杜,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼救欧!你這毒婦竟也來了衰粹?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤笆怠,失蹤者是張志新(化名)和其女友劉穎铝耻,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹬刷,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡瓢捉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了办成。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泡态。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖迂卢,靈堂內(nèi)的尸體忽然破棺而出某弦,到底是詐尸還是另有隱情,我是刑警寧澤冷守,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布刀崖,位于F島的核電站板鬓,受9級特大地震影響蛮位,放射性物質(zhì)發(fā)生泄漏薪伏。R本人自食惡果不足惜麻蹋,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一刻炒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碎罚,春花似錦欣硼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚁滋,卻和暖如春宿接,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辕录。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工睦霎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人走诞。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓副女,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚣旱。 傳聞我的和親對象是個殘疾皇子碑幅,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容