ConstraintLayout使用

ConstraintLayout在AS2.2時候就有了,2.3時代作為了AS EmptyActivity模板的默認xml,現做如下如下記錄


轉自:http://blog.coderclock.com/2017/04/09/android/android-constraintlayout/


1- 基本使用:

  • ConstraintLayout最大的好處在于讓我們通過拖控件的形式進行布局,并且不用擔心適配問題。
constraint_1.png

我們先關注 下部分那個TextView
xml 里反應出的代碼如下

constraint_2.png
<TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="20sp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginRight="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintVertical_bias="0.802" />

app:layout_constraintBottom_toBottomOf=”parent”
意思是TextView底部的布局約束是位于parent的底部,
parent是指包裹著它的ConstraintLayout,
也可以設置指定某個控件的id,其他類似的屬性就不再贅述,以上四個約束聯合起來便實現了Button的居中,ConstraintLayout總共有下面這些同類的屬性:

constraint_3.png

你會發現ConstraintLayout非常靈活的把RelativeLayout的活給干了,關于left、right、top、bottom、start、end、baseline的基準可以參照下圖:

constraint_4.png

現:欲增加一個Btn 與原有Btn底部對齊,且 在原有Btn 右側,只需按如下寫:

Constraint_5.gif

xml里表現如下:

<Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toTopOf="@+id/textView"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2"
        android:layout_marginLeft="32dp"
        app:layout_constraintLeft_toRightOf="@id/button"
        app:layout_constraintBottom_toBottomOf="@id/button"
        />

至此,button2 依賴了button后,隨著button移動,button2也移動,

1.1 Widgets dimension constraints

The dimension of the widgets can be specified by setting the android:layout_width and android:layout_height attributes in 3 different ways:

  • Using a specific dimension (either a literal value such as 123dp or a Dimension reference)
  • Using WRAP_CONTENT, which will ask the widget to compute its own size
  • Using 0dp, which is the equivalent of "MATCH_CONSTRAINT"
    組件 的尺寸有如下三種設置方法:
  • 固定大小
  • WRAP_CONTENT,讓系統讓組件自己決定大小
  • 0dp 相當于 MATCH_CONSTRAINT
1.2 Dimensions constraints

Minimum dimensions on ConstraintLayout
You can define minimum sizes for the ConstraintLayout itself:

android:minWidth set the minimum width for the layout
android:minHeight set the minimum height for the layout
Those minimum dimensions will be used by ConstraintLayout when its dimensions are set to WRAP_CONTENT.

1.2 約束尺寸

你可以給ConstraintLayout自己設置最小尺寸,組件的最小尺寸,將在組件被設置為WRAP_CONTENT 時 生效

2- 一些Margin屬性:

除了Android常見的各種android:layout_marginXXX外,ConstraintLayout自行添加了如下屬性:

constraint_6.png

這些設置生效于當依賴的約束對象被設置visibility為gone時,非常簡單,讀者自行設置實踐對比即可,這里就不展示效果了。

0418 UPDATE

https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout.html

2.1 Visibility behavior 關于View的Gone:

ConstraintLayout has a specific handling of widgets being marked as View.GONE.
對于Gone的組件ConstraintLayout 有一套特殊的處理方式
GONE widgets, as usual, are not going to be displayed and are not part of the layout itself (i.e. their actual dimensions will not be changed if marked as GONE).
通常情況下Gone的組件,是不被展示而且 不作為layout本身的一部分的(也就是說:這些Gone的組件,一旦給了Gone屬性,其本身的尺寸將不會改變)
But in terms of the layout computations, GONE widgets are still part of it, with an important distinction:
但是,在layout計算方面,Gone的組件,仍然是layout計算的一部分,這里有一個重要區別:

  • For the layout pass, their dimension will be considered as if zero (basically, they will be resolved to a point)
    • 為了layout 能通過,Gone的組件的 尺寸將被認為是 0 ,(基本上,他們會被當做一個點來處理,筆者記: 這都在layout的preview里可以直觀看到)
  • If they have constraints to other widgets they will still be respected, but any margins will be as if equals to zero
    • 如果,某個Gone的組件 和其他組件之間有約束,那么這個Gone的組件仍然是被系統重視的,但是,他的任何margins 會被認為 是 0
constraint_gone_margin.png

This specific behavior allows to build layouts where you can temporarily mark widgets as being GONE, without breaking the layout (Fig. 6), which can be particularly useful when doing simple layout animations.

ConstraintLayout的這種特殊的行為,造成了 它允許你在布局的時候,能臨時的把某個組件Gone,而不需要打破整個layout布局,(見上圖),這一點,在實現一下簡單的layout動畫時,尤為常用
**Note: **The margin used will be the margin that B had defined when connecting to A (see Fig. 6 for an example). In some cases, this might not be the margin you want (e.g. A had a 100dp margin to the side of its container, B only a 16dp to A, marking A as gone, B will have a margin of 16dp to the container). For this reason, you can specify an alternate margin value to be used when the connection is to a widget being marked as gone (see the section above about the gone margin attributes).
注意:<font color=#00ffff size=72>color=#00ffff</font>
真正被使用的margin 實際上是: B 在與 A 建立聯系時,給B設置的margin.
在某些情況下,這可能不是你想咬的margin值(舉個栗子: A 有一個100dp 的margin到他的parent容器,B 左margin A 16dp,現在,讓A Gone,這時候,B 將margin parent容器 16dp,這特么就尷尬了),為了解決這個問題,你可以特別的聲明一個margin 值 即layout_goneMarngLeft = 100dp(筆者記:個人認為,沒測試)專門又來解決 當自己聯系的組件被Gone時,margin 不準的情況,具體的見上文藍色文字鏈接.

3- Basic 屬性:

Bias屬性,ConstraintLayout新增了如下兩個屬性用于控制控件在水平和垂直方向在屏幕上的偏移比例,
在本文開頭的TextView 中可以看到這樣一條屬性: app:layout_constraintVertical_bias="0.802"

只有:當為目標控件設置好橫縱向的約束時:

  • app:layout_constraintLeft_toLeftOf=”parent”
  • app:layout_constraintRight_toRightOf=”parent”
  • app:layout_constraintTop_toTopOf=”parent”
  • app:layout_constraintBottom_toBottomOf=”parent”

這個兩個屬性才會生效
注意,這里需要上下左右都有約束,否則basic 屬性沒用的.
實際操作過程中,你會發現對著設置好橫縱向約束的Button進行拖動,布局中的layout_constraintHorizontal_bias和layout_constraintVertical_bias會一直發生相應的變化,如果你需要Button居中,那么直接將這兩個屬性的參數值設置為0.5即可。

4- 進階使用:

0526 UPDATE


http://www.lxweimin.com/p/32a0a6e0a98a


視圖尺寸

ConstraintLayout也支持自動填充寬高, 把寬高設置為0dp會根據位置自動填充. 如, Large按鈕, 左側與Small按鈕的左側對齊, 右側與constraintLayout(父控件)的右側對齊, 寬度設置為0dp, 則會填充全部空位.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    android:id="@+id/constraintLayout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/small"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Small"
        app:layout_constraintStart_toStartOf="@id/constraintLayout"
        app:layout_constraintTop_toTopOf="@id/constraintLayout"/>

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Large"
        app:layout_constraintBottom_toBottomOf="@id/constraintLayout"
        app:layout_constraintEnd_toEndOf="@id/constraintLayout"
        app:layout_constraintStart_toEndOf="@id/small"
        app:layout_constraintTop_toTopOf="@id/constraintLayout"/>

</android.support.constraint.ConstraintLayout>
width_0.png

View的尺寸

我們已經討論了許多關于View如何放置的問題。現在我們來討論下關于View尺寸的問題。關于為View指定尺寸,ConstraintLayout的方式可能與你以往使用的不大一樣。ConstraintLayout提供了三種方式用于指定子View的尺寸:

Exact: 為子View指定一個確切的尺寸。
將layout_width或layou_height設為一個非零尺寸值(xx dp)即可

Wrap Content: 使子View的尺寸正好“包裹”子View的內容
將layout_width或layout_heigth設為wrap_content即可

Any Size: 讓子View填滿父容器的剩余空間
將layout_width或layout_heigth設為0dp即可

什么鬼!match_parent跑哪去了?實際上ConstrainLayout不支持match_parent,至于為什么,后文會進行解釋。簡單的說就是Any Size就已經實現了match_parent的功能。

我們來看一個例子:

<ConstraintLayout
  xmlns:android="..."
  xmlns:app="..."
  android:id="@+id/constraintLayout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <Button
    android:id="@+id/button_cancel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintStart_toStartOf="@+id/constraintLayout"
    app:layout_constraintTop_toTopOf="@+id/constraintLayout"/>

  <Button
    android:id="@+id/button_next"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintStart_toEndOf="@+id/button_cancel"
    app:layout_constraintEnd_toEndOf="@+id/constraintLayout"
    app:layout_constraintTop_toTopOf="@+id/constraintLayout"
    app:layout_constraintBottom_toBottomOf="@+id/constraintLayout" />

</ConstraintLayout>

我們可以看到,button_next在指定尺寸時,使用了Any Size方式:它的layout_width被設為了0dp,這意味著它會在水平方向填滿父布局的剩余可用空間。顯示效果如下:

width_00.png

ConstraintLayout也支持自動填充寬高, 把寬高設置為0dp會根據位置自動填充. 如, Large按鈕, 左側與Small按鈕的左側對齊, 右側與constraintLayout(父控件)的右側對齊, 寬度設置為0dp, 則會填充全部空位.

4.1 寬高比:

補充一個關于ConstraintLayout的知識點,與其他Layout不同之處在于,它的layout_width和layout_height不支持設置match_parent,其屬性取值只有以下三種情況:

  • wrap_content;
  • 指定具體dp值;
  • 0dp(match_constraint),代表填充約束之意,注意不要以為和match_parent是一樣的;

想想如果沒有ConstraintLayout,我們要讓一個控件的寬高按某個比例進行布局應該怎么做?有了ConstraintLayout后,我們可以使用layout_constraintDimentionRatio屬性設置寬高比例,前提是目標控件的layout_width和layout_height至少有一個設置為0dp,如下讓一個ImageView寬高按照2:1的比例顯示:


constraint_7.png

layout_constraintDimentionRatio默認參數比例是指寬:高,變成高:寬可以設app:layout_constraintDimensionRatio=”H,2:1”。其效果與:
app:layout_constraintDimensionRatio=”1:2”是一樣的

You can also use ratio if both dimensions are set to MATCH_CONSTRAINT (0dp). In this case the system sets the largest dimensions the satisfies all constraints and maintains the aspect ratio specified. To constrain one specific side based on the dimensions of another.
You can pre append W," or H, to constrain the width or height respectively. For example, If one dimension is constrained by two targets (e.g. width is 0dp and centered on parent) you can indicate which side should be constrained, by adding the letter W (for constraining the width) or H (for constraining the height) in front of the ratio, separated by a comma:
我們也可以把長寬,都設為0dp,再給組件設置app:layout_constraintDimensionRatio,在這種情況下,系統將給組件設置一個能滿足所有約束且維護給定長寬比 的最大尺寸

我們也可通過附加:W 或 H,來在寬高方向上分別限制,例如:
假設,一個尺寸被兩個目標約束:(例如:寬度0dp,居parent 容器中央),你可以通過W 或 H 來指明,到底在那個方向來約束寬高比,如下:

 <Button android:layout_width="0dp"
                   android:layout_height="0dp"
                   app:layout_constraintDimensionRatio="H,16:9"
                   app:layout_constraintBottom_toBottomOf="parent"
                   app:layout_constraintTop_toTopOf="parent"/>

這個Btn 高度將遵循16:9,同時btn寬度將充滿Constrants

Constraint_ratio_H.png
Constraint_ratio_H_2.png

4.1 鏈 式的使用 :

ConstraintLayout的鏈條(Chains)特性非常強大,在沒有ConstraintLayout之前,線性布局我們主要都依靠LinearLayout來完成,有了ConstraintLayout之后,它把LinearLayout的活也干了,例如要把按鈕水平排成一行,可以這樣操作:

Constraint_8.gif

這樣ButtonA、B、C就在水平方向形成了一條Chain,并且底部對齊。回去看xml文件,會見到ButtonA新增app:layout_constraintHorizontal_chainStyle的屬性設置,這個屬性在一條Chain中只會出現在第一個控件中,這個控件是整條Chain的Head。

Constraint_chain_instruction.png

NOTE: AS 2.3 中并未出現:app:layout_constraintHorizontal_chainStyle,最后自己手動加上了這個屬性,其有三個可取的值:

  • packed
  • spread
  • spread_inside
    效果分別如下:
Constraint_chain_packed_8.png
Constraint_chain_sparead_8.png
Constraint_chain_spread_inside.png

默認效果是這樣的:

Constraint_chain_default_8.png

可以看出:默認效果 和 sparead 是一樣的
筆者認為,這里的這種布局方式 可以 參考 html 里的flex 布局
附上 三個 Button 的xml 代碼:

<?xml version="1.0" encoding="utf-8"?>
<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">


    <Button
        android:id="@+id/buttona"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button a"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/buttonb"
        app:layout_constraintVertical_bias="0.203"

        />

    <Button
        android:id="@+id/buttonb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button b"
        app:layout_constraintBottom_toBottomOf="@+id/buttona"
        app:layout_constraintRight_toLeftOf="@+id/buttonc"
        app:layout_constraintLeft_toRightOf="@+id/buttona"

        />

    <Button
        android:id="@+id/buttonc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button c"
        app:layout_constraintBottom_toBottomOf="@+id/buttonb"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/buttonb"

        />
</android.support.constraint.ConstraintLayout>

除了水平方向的layout_constraintHorizontal_chainStyle外還有垂直方向的layout_constraintVertical_chainStyle,兩者均有spread,spread_inside,packed這三種取值,如果將控件的layout_width和layout_height設置成為0dp,還可以配合layout_constraintHorizontal_weight、layout_constraintVertical_weight兩個屬性實現和LinearLayout中設置layout_weight相同的效果,具體的操作這里就不再展示了,下面一張圖告訴你Chain的強大之處。

Constraint_chain_instruction2.png

5- Guideline

如果我們需要對著屏幕的中軸線進行布局,就可以使用到Guideline進行操作,例如下面兩個Button分別分布在中軸線的左右兩側

Constraint_guildline.gif

Guideline也分為垂直和水平兩種,并且支持設置在屏幕中所處的位置,可以使用如下三種模式:

  • layout_constraintGuide_begin
  • layout_constraintGuide_end設置具體dp值,
    也可以使用
  • layout_constraintGuide_percent來設置比例。
    實際上它也只是一個輔助我們布局的View而已,其源碼內部實現也非常簡單,并且默認設置了visibility為gone,關于ConstraintLayout的進階使用便介紹到這里。

總結:

使用優勢:

  • 高效布局,Android這么多年以來真正意義上的實現了所見即所得的拖曳方式布局,極大的提高開發效率;
  • 輕松靈活的實現復雜的布局;
  • 解決多重布局嵌套問題,通過前面介紹你會發現ConstraintLayout真的是非常靈活,可以很大程度的避免Layout之間的嵌套;
  • 滿足屏幕適配的需求,想想沒有ConstraintLayout之前的拖曳式布局,你就知道有多惡心;

最佳實踐:

ConstraintLayout最開始出來就有很多開發者盼著完全依賴于拖曳方式實現布局,而在實際操作過程中,完全通過拖曳其實效率反倒是會打折扣,在此建議是拖曳方式和xml編碼相結合才是最佳實踐的方式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,224評論 6 529
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,916評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,014評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,466評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,245評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,795評論 1 320
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,869評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,010評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,524評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,487評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,634評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,173評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,884評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,282評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,541評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,236評論 3 388
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,623評論 2 370

推薦閱讀更多精彩內容