ConstraintLayout 屬性詳解 和Chain的使用

mcxtzhang發表於2017-05-24

想看我更多文章:【張旭童的部落格】blog.csdn.net/zxt0601
想來gayhub和我gaygayup:【mcxtzhang的Github主頁】github.com/mcxtzhang

概述

小夥伴們好久不見,我又回來啦。
說實話這篇文章寫的算是比較晚了,距離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",發現誒~官方有說最新版連結如下:
tools.android.com/recent/cons…
按照這個連結提示,最新版是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 屬性詳解 和Chain的使用

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

ConstraintLayout 屬性詳解 和Chain的使用

屬性都形如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"/>複製程式碼

圖示:

ConstraintLayout 屬性詳解 和Chain的使用

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"/>複製程式碼

此時圖示:

ConstraintLayout 屬性詳解 和Chain的使用

當給button4 隱藏GONE掉以後:
圖示:

ConstraintLayout 屬性詳解 和Chain的使用

會發現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的,它如果不鋪滿父控制元件要如何能滿足這兩個約束呢?
實際效果如下:

ConstraintLayout 屬性詳解 和Chain的使用

ConstraintLayout 屬性詳解 和Chain的使用

控制元件會居中顯示,因為這兩個約束作用 類似於 水平方向上,有相反的力 去拉控制元件,最終控制元件會居中顯示。

傾向(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>複製程式碼

ConstraintLayout 屬性詳解 和Chain的使用

對可見性的處理(Visibility behavior)

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

ConstraintLayout能為View.GoneView特殊處理。
通常,GONE的控制元件不會被顯示,並且不是佈局本身的一部分(即如果標記為GONE,則其實際尺寸並不會更改)。
但是在佈局計算方面,GONE的View仍然是其中的一個重要區別:
對於佈局傳遞,它們的維度將被視為零(基本上它們將被解析為一個點
如果他們對其他小部件有約束力,那麼他們仍然會受到尊重,但任何margin都將等於零

ConstraintLayout 屬性詳解 和Chain的使用

注意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>複製程式碼

效果如圖:

ConstraintLayout 屬性詳解 和Chain的使用

有些人是不是要說,你特麼逗我,不是說好的0dp等於MATCH_CONSTRAINT,應該是撐滿螢幕的呀,
OK ,把刀放下。讓我們仔細看這個MATCH_CONSTRAINT屬性。它match的是約束。
而這裡第三個按鈕的約束是第二個按鈕,所以它的寬度設定為MATCH_CONSTRAINT 時,是和它的約束按鈕,即第二個按鈕一樣寬。
注意,此時,豎直方向上沒有約束,所以不能使用MATCH_CONSTRAINT屬性.

我們僅僅將第三個按鈕的屬性修改為

        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"複製程式碼

則它寬度會撐滿螢幕:

ConstraintLayout 屬性詳解 和Chain的使用

我們再修改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>複製程式碼

效果如圖:

ConstraintLayout 屬性詳解 和Chain的使用

最後,記住一句話約束要和 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"/>複製程式碼

如圖:

ConstraintLayout 屬性詳解 和Chain的使用

比例值有兩種取值:

  • 浮點值,表示寬度和高度之間的比率 (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.
則寬度為高度的一半:

ConstraintLayout 屬性詳解 和Chain的使用

鏈條(Chains)

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

建立鏈條(Creating a chain)

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

ConstraintLayout 屬性詳解 和Chain的使用

鏈條頭(Chain heads)

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

ConstraintLayout 屬性詳解 和Chain的使用

頭是水平鏈最左邊的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
效果:

ConstraintLayout 屬性詳解 和Chain的使用

鏈條樣式(Chain Style)

當在鏈的第一個元素上設定屬性 layout_constraintHorizontal_chainStylelayout_constraintVertical_chainStyle 時,鏈的行為將根據指定的樣式(預設為CHAIN_SPREAD)而更改。
看圖這裡就很像JS裡的flexible有木有。因為ConstraintLayout就是模仿flexible做的。

ConstraintLayout 屬性詳解 和Chain的使用

取值如下:

  • 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"/>複製程式碼

ConstraintLayout 屬性詳解 和Chain的使用

加權鏈(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"/>複製程式碼

ConstraintLayout 屬性詳解 和Chain的使用

一圖勝千言,可以看到雖然他們的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>複製程式碼

預覽:

ConstraintLayout 屬性詳解 和Chain的使用

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,不可見,沒有寬高,也不繪製任何東西。僅僅作為我們的錨點使用。

總結

很久不寫部落格了,一是工作太忙了,二也是隨意的寫怕誤人子弟。
這篇文章我寫了整整一天,每個例子我都邊寫邊跑了一遍,
也看了幾篇別人的文章,有些人簡單的翻譯了官方文件,但是對文件中一些沒有舉例, 不那麼好理解的地方也沒有說明,於是便有了此文。
關於視覺化操作,建議直接看我寫的動態圖解&例項 ConstraintLayout Chain和郭神博文視覺化操作
我覺得ConstraintLayout ,有這幾篇就夠了。

文中程式碼地址在我的Demo合集中:
github.com/mcxtzhang/D…

想看我更多文章:【張旭童的部落格】blog.csdn.net/zxt0601
想來gayhub和我gaygayup:【mcxtzhang的Github主頁】github.com/mcxtzhang

相關文章