當前描述是基於constraint-layout:1.1.2。android
在之前,android是使用佈局如LinearLayout 、RelativeLayout等來構建頁面,但這些佈局使用起來很麻煩,而且常常須要一層一層嵌套,寫一個簡單的頁面就須要費很大的勁。因此在16年I/O大會上,google發佈了全新的佈局-ConstraintLayout,其餘佈局和ConstraintLayout比起來,根本就沒有存在的必要了...
ConstraintLayout具備如下優點:api
較高的性能優點。
佈局嵌套層次越高,性能開銷越大。而使用ConstraintLayout,常常就一層嵌套就搞定了,因此其性能要好不少。app
完美的屏幕適配
ConstraintLayout的大小、距離均可以使用比例來設置,因此其適配性更好。編輯器
書寫簡單ide
可視化編輯。
ConstraintLayout也有十分方便完善的可視化編輯器,不用寫xml也基本上能實現大部分功能。但我的仍是比較喜歡寫xml,因此本篇文章主要介紹如何使用代碼控制。若是想看如何使用可視化編輯器,能夠參考郭霖大神的這篇文章佈局
1 引入:api 'com.android.support.constraint:constraint-layout:1.1.2'
肯定位置的屬性提供了下面13個屬性,其實本質上都是同樣的,看名字應該基本上都知道怎麼用了(就是哪一條邊和哪一條邊對齊)性能
來看個例子:動畫
1 <android.support.constraint.ConstraintLayout 2 ...> 3 4 <Button 5 android:id="@+id/a" 6 .... 7 app:layout_constraintLeft_toLeftOf="parent" 8 app:layout_constraintTop_toTopOf="parent" 9 android:text="A" /> 10 11 <Button 12 android:id="@+id/b" 13 .... 14 app:layout_constraintLeft_toRightOf="@id/a" 15 app:layout_constraintTop_toTopOf="@id/a" 16 android:text="B" /> 17 18 <Button 19 android:id="@+id/c" 20 .... 21 app:layout_constraintLeft_toLeftOf="@id/a" 22 app:layout_constraintTop_toBottomOf="@id/a" 23 android:text="C" /> 24 25 <Button 26 android:id="@+id/d" 27 .... 28 app:layout_constraintLeft_toRightOf="@id/a" 29 app:layout_constraintTop_toTopOf="@id/c" 30 android:text="D" /> 31 </android.support.constraint.ConstraintLayout>
從中能夠看到,ui
app:layout_constraintLeft_toRightOf="@id/a"
,C位於A的下邊,則使用app:layout_constraintTop_toBottomOf="@id/a"
對於一個View的邊界界定,官方給了下面這張圖:google
設置margin仍是繼續用之前的屬性layout_margin*
。
不過須要注意,要使margin生效,必須具備對應方向的layout_constraint*
,不然margin不生效.
假如如今有以下佈局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 5 <Button 6 android:id="@+id/a" 7 ... 8 android:layout_marginLeft="100dp" 9 android:layout_marginTop="20dp" 10 app:layout_constraintLeft_toLeftOf="parent" 11 app:layout_constraintTop_toTopOf="parent" /> 12 13 <Button 14 android:id="@+id/b" 15 ... 16 android:layout_marginLeft="20dp" 17 android:layout_marginTop="20dp" 18 app:layout_constraintLeft_toRightOf="@id/a" 19 app:layout_constraintTop_toTopOf="@id/a" 20 /> 21 22 <Button 23 android:id="@+id/c" 24 .... 25 android:layout_marginLeft="20dp" 26 android:layout_marginTop="20dp" 27 app:layout_constraintLeft_toRightOf="@id/b" 28 app:layout_constraintTop_toTopOf="@id/b" /> 29 </android.support.constraint.ConstraintLayout>
考慮一個問題,若是B動態設爲gone了,C會怎麼顯示呢?
真實狀況以下:
爲何會這樣顯示呢?看他的藍圖應該會好理解些:
layout_goneMargin*="xdp"
,意思是好比當constrainleft的錨點gone時,layout_goneMarginLeft將生效。但由於這個只能設置固定的距離,我的感受靈活性不是很高。一個view如何設置爲居中呢?若是查找屬性,會發現並無如RelativeLayout相似的layout_centerVertical屬性,那如何設置居中呢?constraint的思想很巧妙。
根據第一節的知識,你們知道若是設置app:layout_constraintLeft_toLeftOf="parent"
,則view會貼着父view的左邊,設置app:layout_constraintRight_toRightOf="parent"
則會貼着右邊,那若是兩個都設置,效果會怎樣呢?
bias即偏移量,他們的取值範圍從0~1,0即挨着左邊,1是挨着右邊,因此要使處於1/3處,能夠設置以下屬性app:layout_constraintHorizontal_bias="0.33"
,效果圖以下:
設置view的大小除了傳統的wrap_content、指定尺寸、match_parent(雖然官方不推薦使用match_parent)外,還能夠設置爲0dp(官方取名叫MATCH_CONSTRAINT),0dp在constraint可不是指大小是0dp,而是有特殊含義的。他的做用會隨着不一樣的設置有不一樣的含義:
spread
,默認值,意思是佔用全部的符合約束的空間1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 5 <Button 6 android:id="@+id/a" 7 android:layout_width="0dp" 8 ... 9 android:layout_marginLeft="20dp" 10 android:layout_marginRight="20dp" 11 app:layout_constraintRight_toRightOf="parent" 12 app:layout_constraintLeft_toLeftOf="parent"/> 13 14 </android.support.constraint.ConstraintLayout>
能夠看到layout_width爲0dp,實際的效果則是寬度和約束同樣,左右兩邊的留白是margin的效果。
percent
,意思是按照父佈局的百分比設置,須要layout_constraintWidth_percent
設置百分比例
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout > 3 4 <android.support.constraint.ConstraintLayout 5 android:layout_width="300dp" 6 android:layout_height="400dp" 7 app:layout_constraintHorizontal_bias="0.3" 8 > 9 10 <Button 11 android:id="@+id/a" 12 android:layout_width="0dp" 13 ... 14 app:layout_constraintRight_toRightOf="parent" 15 app:layout_constraintWidth_default="percent" 16 app:layout_constraintWidth_percent="0.4" /> 17 </android.support.constraint.ConstraintLayout> 18 19 </android.support.constraint.ConstraintLayout>
A的寬度設爲0.4,則其寬度爲父佈局的0.4倍。另外,設置了layout_constraintWidth_percent屬性,能夠不用指定layout_constraintWidth_default,他會自動設置爲percent
wrap
,意思匹配內容大小但不超過約束限制,注意和直接指定寬度爲wrap_content的區別就是不超過約束限制,以下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 5 6 <Button 7 android:id="@+id/a" 8 ... 9 app:layout_constraintLeft_toLeftOf="parent" /> 10 <Button 11 android:id="@+id/c" 12 ... 13 app:layout_constraintRight_toRightOf="parent" /> 14 15 <Button 16 android:id="@+id/b" 17 android:layout_width="0dp" 18 ... 19 app:layout_constraintWidth_default="wrap" 20 app:layout_constraintLeft_toRightOf="@id/a" 21 app:layout_constraintRight_toLeftOf="@id/c"/> 22 23 <Button 24 android:id="@+id/d" 25 android:layout_width="wrap_content" 26 ... 27 app:layout_constraintTop_toBottomOf="@id/b" 28 app:layout_constraintLeft_toRightOf="@id/a" 29 app:layout_constraintRight_toLeftOf="@id/c"/> 30 31 </android.support.constraint.ConstraintLayout>
能夠看到雖然文字很長,但第一行的綠色button寬度達到約束時,就不在增長,而第二行的button顯示了完整的內容,超過約束的限制。
在1.1上 對於wrap_content會超過約束限制,谷歌又新增了以下屬性
設置爲true也能夠限制內容不超過約束(這樣感受layout_constraintWidth_default這個屬性已經沒什麼用了)
layout_constraintDimensionRatio
,即寬和高成必定的比例,其值能夠是"width:height"的形式,也能夠是width/height的值。該屬性生效的前提:寬和高其中有一項爲0dp,有constraint。下面按照有幾個0dp來分別介紹下:如圖,在一個水平或者豎直方向上,一排view兩兩互相約束,即爲鏈
鏈的第一個元素稱爲鏈頭,能夠經過設置layout_constraintHorizontal_chainStyle
來控制鏈的分佈形式
spread
默認模式,分佈樣式如上圖
spread_inside
如圖,和spread的區別是沒算兩端的約束
鏈的第一個元素稱爲鏈頭,能夠經過設置layout_constraintHorizontal_chainStyle
來控制鏈的分佈形式
spread
默認模式,分佈樣式如上圖
spread_inside
如圖,和spread的區別是沒算兩端的約束
能夠看出,鏈與LinearLayout效果大體同樣。和LinearLayout同樣,鏈也可使用layout_constraintHorizontal_weight
,來分割剩餘空間。但又和 android:layout_weight不太同樣,不同的地方以下:
以下面的示例:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 ...> 4 5 <LinearLayout 6 ... 7 android:orientation="horizontal"> 8 <Button 9 android:layout_width="10dp" 10 android:layout_height="50dp" 11 android:layout_weight="1" 12 ... /> 13 <Button 14 android:layout_width="wrap_content" 15 android:layout_height="50dp" 16 android:layout_weight="1" 17 ... /> 18 <Button 19 android:layout_width="0dp" 20 android:layout_height="50dp" 21 android:layout_weight="1" 22 ... /> 23 </LinearLayout> 24 25 <android.support.constraint.ConstraintLayout 26 ....> 27 28 <Button 29 android:id="@+id/a" 30 android:layout_width="10dp" 31 android:layout_height="50dp" 32 .... 33 app:layout_constraintHorizontal_weight="1" 34 app:layout_constraintLeft_toLeftOf="parent" 35 app:layout_constraintRight_toLeftOf="@id/b" /> 36 <Button 37 android:id="@+id/b" 38 android:layout_width="wrap_content" 39 android:layout_height="50dp" 40 .... 41 app:layout_constraintHorizontal_weight="1" 42 app:layout_constraintLeft_toRightOf="@id/a" 43 app:layout_constraintRight_toLeftOf="@id/c" /> 44 45 <Button 46 android:id="@+id/c" 47 android:layout_width="0dp" 48 android:layout_height="50dp" 49 ... 50 app:layout_constraintHorizontal_weight="1" 51 app:layout_constraintLeft_toRightOf="@id/b" 52 app:layout_constraintRight_toRightOf="parent" /> 53 54 /> 55 </android.support.constraint.ConstraintLayout> 56 57 </LinearLayout>
能夠看出,LinearLayout和ConstraintLayout雖然三個子view的layout_width值是同樣的,weight也都設置了1,但效果徹底不同
ConstraintLayout還提供了一種比較炫酷的圓形佈局,這是以往的佈局所作不到的。涉及到的屬性也很簡單,就下面三個:
示例以下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 ...> 4 5 <Button 6 android:id="@+id/a" 7 ... 8 /> 9 10 <Button 11 android:id="@+id/b" 12 ... 13 app:layout_constraintCircle="@id/a" 14 app:layout_constraintCircleAngle="300" 15 app:layout_constraintCircleRadius="100dp" /> 16 17 <Button 18 android:id="@+id/c" 19 ... 20 app:layout_constraintCircle="@id/a" 21 app:layout_constraintCircleAngle="45" 22 app:layout_constraintCircleRadius="200dp" /> 23 /> 24 </android.support.constraint.ConstraintLayout>
除了
ConstraintLayout
自身屬性以外,谷歌還提供了不少輔助佈局(只是在佈局中起輔助做用,並不會在界面真正顯示),來使ConstraintLayout
的功能更增強大。下面,咱們就一一來了解下這些佈局
即參考線的意思,有水平參考線和豎直參考線兩種。他的做用就像是一個虛擬的參考線,只是用來方便其餘View以他爲錨點來佈局。
如上一篇所瞭解到的,ConstraintLayout 的定位原則就是一個View參考其餘View的相對佈局,若是有的時候當前佈局沒有合適的參考View,而建一個專門用於定位的View又會過重,這種狀況正是GuideLine的用武之地。
例如:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 5 <android.support.constraint.Guideline 6 android:id="@+id/guideline" 7 ... 8 android:orientation="vertical" 9 app:layout_constraintGuide_percent="0.33" /> 10 11 <android.support.constraint.Guideline 12 android:id="@+id/guideline2" 13 ... 14 android:orientation="horizontal" 15 app:layout_constraintGuide_begin="130dp" /> 16 17 <Button 18 ... 19 app:layout_constraintLeft_toLeftOf="@id/guideline" 20 app:layout_constraintTop_toTopOf="@id/guideline2" /> 21 22 23 </android.support.constraint.ConstraintLayout>
能夠看到我分別添加了一個水平參考線和豎直參考線,以後的Button的佈局就參考與這兩個參考線,而在佈局中並不會顯示。
Guideline
的大部分的屬性如layout_width都是不會生效的,而他的位置的肯定是由下面三個屬性之一來肯定的:
Group是一個能夠同時控制多個view 可見性的虛擬View。
例如:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 5 <android.support.constraint.Group 6 ... 7 android:visibility="invisible" 8 app:constraint_referenced_ids="a,c" /> 9 10 <android.support.constraint.Group 11 ... 12 android:visibility="visible" 13 app:constraint_referenced_ids="b,d" /> 14 15 <Button 16 android:id="@+id/a" 17 ... /> 18 19 <Button 20 android:id="@+id/b" 21 ... /> 22 23 <Button 24 android:id="@+id/c" 25 ... /> 26 27 <Button 28 android:id="@+id/d" 29 .../> 30 </android.support.constraint.ConstraintLayout>
能夠看到,第一個Group經過app:constraint_referenced_ids
指定了a、c兩個控件,這樣當該Group可見性爲invisible時,a、c的可見性都會變爲invisible,爲gone則都爲gone。因此Group很適合處理有網無網之類的場景,再也不須要像以前那樣一個一個view控制可見性,經過Group就能夠統一處理了。
Group有一些注意事項:
app:constraint_referenced_ids
裏直接寫的是id的字符串,初始化後會經過getIdentifier
來反射查找叫該名字的id。因此若是你的項目用了相似AndResGuard的混淆id名字的功能,切記不要混淆app:constraint_referenced_ids
裏的id,不然在release版本就會因找不到該id而失效。或者也能夠經過代碼setReferencedIds
來設置id。佔位佈局。他本身自己不會繪製任何內容,但他能夠經過設置app:content="id"
,將id View的內容繪製到本身的位置上,而原id的 View就像gone了同樣。
以下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 <Button 5 android:id="@+id/a" 6 android:layout_width="50dp" 7 android:layout_height="50dp" 8 android:layout_marginLeft="30dp" 9 ... 10 app:layout_constraintLeft_toLeftOf="parent" 11 app:layout_constraintTop_toTopOf="parent" /> 12 13 <Button 14 android:id="@+id/b" 15 android:layout_width="50dp" 16 android:layout_height="50dp" 17 android:layout_marginLeft="20dp" 18 ... 19 app:layout_constraintLeft_toRightOf="@+id/a" 20 app:layout_constraintTop_toTopOf="@+id/a" /> 21 22 <android.support.constraint.Placeholder 23 android:id="@+id/place" 24 android:layout_width="200dp" 25 android:layout_height="200dp" 26 app:content="@+id/a" 27 app:layout_constraintBottom_toBottomOf="parent" 28 app:layout_constraintLeft_toLeftOf="parent"/> 29 30 <Button 31 ... 32 app:layout_constraintBottom_toBottomOf="@+id/place" 33 app:layout_constraintLeft_toRightOf="@+id/place" /> 34 </android.support.constraint.ConstraintLayout>
效果如圖:
能夠看到,本來B是位於A的右邊而且頂部對齊的,但由於A被Placeholder引用,使A 至關於Gone了。而Placeholder的位置則顯示了A的內容,而且大小也和A相符,Placeholder的大小設置並無生效。
大概總結能夠認爲,Placeholder引用A後的效果是,本來位置的A gone,本來位置的Placeholder變爲Placeholder的約束屬性+A的內容屬性。另外,Placeholder也支持使用代碼setContentId
動態的修改設置內容。
關於Placeholder的應用場景,網上其餘人也都列出了一些例子:好比能夠做爲位置模板,引入後只須要寫內容view;使用代碼動態改變內容,結合TransitionManager能夠作一些有趣的過分動畫等。
屏障,一個虛擬View。他主要解決下面遇到的問題:
1 <android.support.constraint.Barrier 2 android:id="@+id/barrier" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 app:barrierDirection="end"//end,left,right,top,bottom 6 app:constraint_referenced_ids="text1,text2" />
則Barrier始終位於text1,text2兩個View最大寬度的右邊,示意圖以下:
這裏基本的用法就講完了。
下面再考慮一個狀況,假若有以下的佈局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout 3 ...> 4 5 <Button 6 android:id="@+id/a" 7 ... 8 android:layout_marginTop="20dp" 9 /> 10 11 <Button 12 android:id="@+id/b" 13 ... 14 android:layout_marginTop="40dp" 15 /> 16 17 <android.support.constraint.Barrier 18 android:id="@+id/barrier" 19 ... 20 app:barrierDirection="top" 21 app:constraint_referenced_ids="a,b" /> 22 23 <Button 24 android:id="@+id/c" 25 ... 26 app:layout_constraintTop_toTopOf="@+id/barrier" /> 27 </android.support.constraint.ConstraintLayout>
目前Button C和Button a、b的最上值對齊,沒有問題。但若是a Gone了呢?效果以下:
barrierAllowsGoneWidgets
,設爲false後,就不在關注Gone的View了,效果以下:
本篇已基本上介紹完ConstraintLayout全部的屬性了(除了代碼寫佈局的ConstraintSet類)。相信ConstraintLayout以後會愈來愈強大。