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

概述

小夥伴們好久不見,我又回來啦。
說實話這篇文章寫的算是比較晚了,距離ConstraintLayout出現至今已經有一年了。
且自AS2.3起創建新的Activity,默認的layout根布局就是ConstraintLayout
所以再不學習就真的晚了。
我也是正式開始學習的道路,先說一下我的學習過程:

  • 先閱讀了ConstraintLayout官方文檔Guideline官方文檔
  • 實踐每個屬性並記下筆記(翻譯)
  • 學習了郭神關於ConstraintLayout可視化操作(拖拖拽拽)的博客,發現博客中對Chain的概念沒有提及
  • 查詢關於Chain以及一些疑點的資料
  • 整理成文
  • 當然中間也遇到了許許多多的問題

本文的順序,大體按照ConstraintLayout官方文檔的順序依次講解(翻譯)屬性和用法,並對疑難點進行額外說明。
關於可視化操作,可參考我寫的動態圖解&實例 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,特么的居然也搜不到。
震驚,於是機智的我去看源碼,發現我使用的1.0.8-alpha版本的源碼里根本沒有Chain相關屬性的支持,所以我就覺得一定是引入的版本有問題,於是我用google搜索”ConstraintLayout last version”,發現誒~官方有說最新版鏈接如下:
http://tools.android.com/recent/constraintlayout102isnowavailable
按照這個鏈接提示,最新版是1.0.2,嗯哼,當我換成1.0.2后,發現無法download….
不知道是網絡問題還是什麼問題,提示我無法下載,具體的錯誤記不清了。反正就是無法獲取到這個版本。
特么的機智的我又直接去AndroidStudio的Library Dependency里去搜索,發現居然搜不到“ConstraintLayout “的庫。再次懵逼。
後來我進行最後的一次嘗試,因為我看google官方上1.0.2版本的上一個版本是1.0.1.於是我修改版本號,sync gradle,居然成功了。
總結踩坑歷程:

  • 1 最新Release版AndroidStudio模板自帶的是1.0.8alpha版ConstraintLayout
  • 2 使用Chain相關屬性報錯
  • 3 發現該版本源碼沒有Chain相關屬性
  • 4 官網說的最新版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”區域搞定,即通過可視化拖拖拽拽生成布局大致的樣子,然後針對具體屬性、約束 精細修改。
甚至可以這麼說,你完全不需要知道ConstraintLayout的具體屬性值分別是什麼,只通過拖拽和鼠標點擊就可以實現一些布局。

那麼本文的意義何在呢?

我覺得首先是要知其然知其所以然,那些拖拽點擊生成的代碼屬性到底是什麼意思?通過本文可以了解。
另外 雖然大部分操作可以在“Design”區域完成,但是保不齊的需要你切換至“Text”區域,寫上一兩行屬性代碼,了解 這些屬性 總是有益無害的。
而且,有一些屬性是無法簡單通過拖拽點擊完成的,例如Margins when connected to a GONE widget

剛才提到RelativeLayout,其實RelativeLayout也是通過約束來布局子View的呀,
以前RelativeLayout的約束有兩種:

  • 1 子控件和子控件之間的約束(如android:layout_below="@id/title"
  • 2 子控件和父控件的約束(如 android:layout_alignParentTop="true"

現在ConstraintLayout也是類似的,只不過除了以上兩種約束,還多了一種

  • 3 子控件和Guideline的約束

其實關於和Guideline的約束,也可以理解成約束1,因為Guideline其實就是一個在屏幕上不显示的View罷了。稍後講到Guideline會帶大家看看它巨簡單的源碼。

下面開始正文,開始屬性的講解

相對定位 (Relative positioning)

這一節的屬性和相對布局的很像,
值得注意的是參數取值是 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代表的是和約束控件哪條邊 發生約束 (取值同樣是 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消失的導致的“位移”。
這就是本節的屬性。
這一節的屬性開始我並沒有理解,後來是通過寫了一些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掉以後:
圖示:


會發現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版本已經修復)
  • 在約束的布局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>

按照我們第一小節講的屬性值,這個定義的意思是,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)

這一節是對前一節goneMargin的補充。
重點是Gone隱藏掉的控件,會被解析成一個點,並忽略margin。

ConstraintLayout能為View.GoneView特殊處理。
通常,GONE的控件不會被显示,並且不是布局本身的一部分(即如果標記為GONE,則其實際尺寸並不會更改)。
但是在布局計算方面,GONE的View仍然是其中的一個重要區別:
對於布局傳遞,它們的維度將被視為零(基本上它們將被解析為一個點
如果他們對其他小部件有約束力,那麼他們仍然會受到尊重,但任何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),也可以使用比例。 在這種情況下,系統會使用滿足所有約束條件和比率的最大尺寸
如果需要根據一個維度的尺寸去約束另一個維度的尺寸。
則可以在比率值的前面添加 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)

鏈條在同一個軸上(水平或者垂直)提供一個類似群組的統一表現。另一個軸可以單獨控制。

創建鏈條(Creating a chain)

如果一組小部件通過雙向連接(見圖,显示最小的鏈,帶有兩個小部件),則將其視為鏈條。


鏈條頭(Chain heads)

鏈條由在鏈的第一個元素(鏈的“頭”)上設置的屬性控制:


頭是水平鏈最左邊的View,或垂直鏈最頂端的View。

鏈的margin(Margins in chains)

如果在連接上指定了邊距,則將被考慮在內。
例如

    <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 時,鏈的行為將根據指定的樣式(默認為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)方法被空實現了,所以用戶也沒辦法改變它的可見度。
  • 推導出它一定是GONE的。在屏幕上不可見
  • this.setMeasuredDimension(0, 0);public void draw(Canvas canvas)的空實現,表明這是一個超輕量的View,不可見,沒有寬高,也不繪製任何東西。僅僅作為我們的錨點使用。

總結

很久不寫博客了,一是工作太忙了,二也是隨意的寫怕誤人子弟。
這篇文章我寫了整整一天,每個例子我都邊寫邊跑了一遍,
也看了幾篇別人的文章,有些人簡單的翻譯了官方文檔,但是對文檔中一些沒有舉例, 不那麼好理解的地方也沒有說明,於是便有了此文。
關於可視化操作,建議直接看我寫的動態圖解&amp;實例 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