ConstraintLayout在AS2.2時候就有了,2.3時代作為了AS EmptyActivity模板的默認xml,現(xiàn)做如下如下記錄
轉(zhuǎn)自:http://blog.coderclock.com/2017/04/09/android/android-constraintlayout/
1- 基本使用:
- ConstraintLayout最大的好處在于讓我們通過拖控件的形式進行布局,并且不用擔(dān)心適配問題卦睹。
我們先關(guān)注 下部分那個TextView
xml 里反應(yīng)出的代碼如下
<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,
也可以設(shè)置指定某個控件的id吕嘀,其他類似的屬性就不再贅述违寞,以上四個約束聯(lián)合起來便實現(xiàn)了Button的居中,ConstraintLayout總共有下面這些同類的屬性:
你會發(fā)現(xiàn)ConstraintLayout非常靈活的把RelativeLayout的活給干了偶房,關(guān)于left趁曼、right、top棕洋、bottom挡闰、start、end掰盘、baseline的基準(zhǔn)可以參照下圖:
現(xiàn):欲增加一個Btn 與原有Btn底部對齊,且 在原有Btn 右側(cè),只需按如下寫:
xml里表現(xiàn)如下:
<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"
組件 的尺寸有如下三種設(shè)置方法: - 固定大小
- WRAP_CONTENT,讓系統(tǒng)讓組件自己決定大小
- 0dp 相當(dāng)于 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自己設(shè)置最小尺寸,組件的最小尺寸,將在組件被設(shè)置為WRAP_CONTENT 時 生效
2- 一些Margin屬性:
除了Android常見的各種android:layout_marginXXX外摄悯,ConstraintLayout自行添加了如下屬性:
這些設(shè)置生效于當(dāng)依賴的約束對象被設(shè)置visibility為gone時,非常簡單愧捕,讀者自行設(shè)置實踐對比即可奢驯,這里就不展示效果了。
0418 UPDATE
https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout.html
2.1 Visibility behavior 關(guān)于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計算的一部分,這里有一個重要區(qū)別:
- For the layout pass, their dimension will be considered as if zero (basically, they will be resolved to a point)
- 為了layout 能通過,Gone的組件的 尺寸將被認為是 0 ,(基本上,他們會被當(dāng)做一個點來處理,筆者記: 這都在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的組件仍然是被系統(tǒng)重視的,但是,他的任何margins 會被認為 是 0
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布局,(見上圖),這一點,在實現(xiàn)一下簡單的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 建立聯(lián)系時,給B設(shè)置的margin.
在某些情況下,這可能不是你想咬的margin值(舉個栗子: A 有一個100dp 的margin到他的parent容器,B 左margin A 16dp,現(xiàn)在,讓A Gone,這時候,B 將margin parent容器 16dp,這特么就尷尬了),為了解決這個問題,你可以特別的聲明一個margin 值 即layout_goneMarngLeft = 100dp(筆者記:個人認為,沒測試)專門又來解決 當(dāng)自己聯(lián)系的組件被Gone時,margin 不準(zhǔn)的情況,具體的見上文藍色文字鏈接.
3- Basic 屬性:
Bias屬性次绘,ConstraintLayout新增了如下兩個屬性用于控制控件在水平和垂直方向在屏幕上的偏移比例,
在本文開頭的TextView 中可以看到這樣一條屬性: app:layout_constraintVertical_bias="0.802"
只有:當(dāng)為目標(biāo)控件設(shè)置好橫縱向的約束時:
- app:layout_constraintLeft_toLeftOf=”parent”
- app:layout_constraintRight_toRightOf=”parent”
- app:layout_constraintTop_toTopOf=”parent”
- app:layout_constraintBottom_toBottomOf=”parent”
這個兩個屬性才會生效瘪阁。
注意,這里需要上下左右都有約束,否則basic 屬性沒用的.
實際操作過程中,你會發(fā)現(xiàn)對著設(shè)置好橫縱向約束的Button進行拖動邮偎,布局中的layout_constraintHorizontal_bias和layout_constraintVertical_bias會一直發(fā)生相應(yīng)的變化管跺,如果你需要Button居中,那么直接將這兩個屬性的參數(shù)值設(shè)置為0.5即可禾进。
4- 進階使用:
0526 UPDATE
http://www.reibang.com/p/32a0a6e0a98a
視圖尺寸
ConstraintLayout也支持自動填充寬高, 把寬高設(shè)置為0dp會根據(jù)位置自動填充. 如, Large按鈕, 左側(cè)與Small按鈕的左側(cè)對齊, 右側(cè)與constraintLayout(父控件)的右側(cè)對齊, 寬度設(shè)置為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>
View的尺寸
我們已經(jīng)討論了許多關(guān)于View如何放置的問題』砼埽現(xiàn)在我們來討論下關(guān)于View尺寸的問題。關(guān)于為View指定尺寸泻云,ConstraintLayout的方式可能與你以往使用的不大一樣贩绕。ConstraintLayout提供了三種方式用于指定子View的尺寸:
Exact: 為子View指定一個確切的尺寸火的。
將layout_width或layou_height設(shè)為一個非零尺寸值(xx dp)即可
Wrap Content: 使子View的尺寸正好“包裹”子View的內(nèi)容
將layout_width或layout_heigth設(shè)為wrap_content即可
Any Size: 讓子View填滿父容器的剩余空間
將layout_width或layout_heigth設(shè)為0dp即可
什么鬼!match_parent跑哪去了淑倾?實際上ConstrainLayout不支持match_parent馏鹤,至于為什么,后文會進行解釋娇哆。簡單的說就是Any Size就已經(jīng)實現(xiàn)了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被設(shè)為了0dp治力,這意味著它會在水平方向填滿父布局的剩余可用空間。顯示效果如下:
ConstraintLayout也支持自動填充寬高, 把寬高設(shè)置為0dp會根據(jù)位置自動填充. 如, Large按鈕, 左側(cè)與Small按鈕的左側(cè)對齊, 右側(cè)與constraintLayout(父控件)的右側(cè)對齊, 寬度設(shè)置為0dp, 則會填充全部空位.
4.1 寬高比:
補充一個關(guān)于ConstraintLayout的知識點勃黍,與其他Layout不同之處在于宵统,它的layout_width和layout_height不支持設(shè)置match_parent,其屬性取值只有以下三種情況:
- wrap_content覆获;
- 指定具體dp值马澈;
- 0dp(match_constraint),代表填充約束之意弄息,注意不要以為和match_parent是一樣的痊班;
想想如果沒有ConstraintLayout,我們要讓一個控件的寬高按某個比例進行布局應(yīng)該怎么做摹量?有了ConstraintLayout后涤伐,我們可以使用layout_constraintDimentionRatio屬性設(shè)置寬高比例,前提是目標(biāo)控件的layout_width和layout_height至少有一個設(shè)置為0dp缨称,如下讓一個ImageView寬高按照2:1的比例顯示:
layout_constraintDimentionRatio默認參數(shù)比例是指寬:高凝果,變成高:寬可以設(shè)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:
我們也可以把長寬,都設(shè)為0dp,再給組件設(shè)置app:layout_constraintDimensionRatio,在這種情況下,系統(tǒng)將給組件設(shè)置一個能滿足所有約束且維護給定長寬比 的最大尺寸
我們也可通過附加:W 或∧谰 H豆村,來在寬高方向上分別限制,例如:
假設(shè)骂删,一個尺寸被兩個目標(biāo)約束:(例如:寬度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
4.1 鏈 式的使用 :
ConstraintLayout的鏈條(Chains)特性非常強大,在沒有ConstraintLayout之前四啰,線性布局我們主要都依靠LinearLayout來完成宁玫,有了ConstraintLayout之后,它把LinearLayout的活也干了柑晒,例如要把按鈕水平排成一行欧瘪,可以這樣操作:
這樣ButtonA、B匙赞、C就在水平方向形成了一條Chain佛掖,并且底部對齊妖碉。回去看xml文件芥被,會見到ButtonA新增app:layout_constraintHorizontal_chainStyle的屬性設(shè)置欧宜,這個屬性在一條Chain中只會出現(xiàn)在第一個控件中,這個控件是整條Chain的Head拴魄。
NOTE: AS 2.3 中并未出現(xiàn):app:layout_constraintHorizontal_chainStyle,最后自己手動加上了這個屬性,其有三個可取的值:
- packed
- spread
- spread_inside
效果分別如下:
默認效果是這樣的:
可以看出:默認效果 和 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設(shè)置成為0dp匹中,還可以配合layout_constraintHorizontal_weight夏漱、layout_constraintVertical_weight兩個屬性實現(xiàn)和LinearLayout中設(shè)置layout_weight相同的效果,具體的操作這里就不再展示了顶捷,下面一張圖告訴你Chain的強大之處挂绰。
5- Guideline
如果我們需要對著屏幕的中軸線進行布局,就可以使用到Guideline進行操作服赎,例如下面兩個Button分別分布在中軸線的左右兩側(cè)
Guideline也分為垂直和水平兩種葵蒂,并且支持設(shè)置在屏幕中所處的位置,可以使用如下三種模式:
- layout_constraintGuide_begin
- layout_constraintGuide_end設(shè)置具體dp值专肪,
也可以使用 - layout_constraintGuide_percent來設(shè)置比例刹勃。
實際上它也只是一個輔助我們布局的View而已,其源碼內(nèi)部實現(xiàn)也非常簡單嚎尤,并且默認設(shè)置了visibility為gone荔仁,關(guān)于ConstraintLayout的進階使用便介紹到這里。
總結(jié):
使用優(yōu)勢:
- 高效布局芽死,Android這么多年以來真正意義上的實現(xiàn)了所見即所得的拖曳方式布局乏梁,極大的提高開發(fā)效率;
- 輕松靈活的實現(xiàn)復(fù)雜的布局关贵;
- 解決多重布局嵌套問題遇骑,通過前面介紹你會發(fā)現(xiàn)ConstraintLayout真的是非常靈活,可以很大程度的避免Layout之間的嵌套揖曾;
- 滿足屏幕適配的需求落萎,想想沒有ConstraintLayout之前的拖曳式布局,你就知道有多惡心炭剪;
最佳實踐:
ConstraintLayout最開始出來就有很多開發(fā)者盼著完全依賴于拖曳方式實現(xiàn)布局练链,而在實際操作過程中,完全通過拖曳其實效率反倒是會打折扣奴拦,在此建議是拖曳方式和xml編碼相結(jié)合才是最佳實踐的方式媒鼓。