ConstraintLayout可能大家也比較熟悉了,在Google I/O 2016 上發(fā)布了 ConstraintLayout,也就是Android Studio 2.2中發(fā)布的新功能。以前我們寫布局的時候基本都是靠編寫XML,遇到復雜的布局避免不了多層嵌套,不可避免的會影響 UI 界面繪制的效率。目前對于復雜的界面,使用 RelativeLayout也無法解決,ConstraintLayout可謂RelativeLayout的升級版,但是要比前者強大太多。
Constraint翻譯為約束,ConstraintLayout就是在子 View 上添加各種約束條件來控制每個子View所在的位置以及顯示的尺寸。而且這一切都是通過可視化操作來實現(xiàn)的。當然,可視化操作的背后仍然還是使用的XML代碼來實現(xiàn)的,只不過這些一切都是AS自動生成的
升級Android Studio到2.3你會發(fā)現(xiàn)新建的XML根布局從以前的RelativeLayout變成了ConstraintLayout,可見Google對這個控件的重視,這也值得我們?nèi)W習。
ConstraintLayout 官方樣例代碼
ConstraintLayout Google官方文檔
布局編輯器功能介紹

此界面是基于Android Studio 2.3的截圖,相對與2.2很多圖標做了改變,其中這幾個主題區(qū)域是沒變的
-
Palette是控件區(qū)域,所有系統(tǒng)View和Layout都在這里,可以分類查找。也可以直接搜索拖入布局中 -
Component Tree當前布局的層級結(jié)構(gòu),當點擊一個View的時候就會選中這個View - 這里是對選中的
View編輯操作的工具欄 -
Design Editor布局編輯器主窗口,可以通過點擊左下Design和Text切換編輯模式 -
Properties可以修改當前選中View的各種屬性。點擊下面的圖標可以查看更多的View屬性
約束
約束幫助你保持控件對齊, 你可以使用錨點來確定各控件之間的對齊規(guī)則,要創(chuàng)建一個約束, 你需要在指定手柄上點擊并按住鼠標, 然后拖到另一個控件的約束手柄. 一旦錨點變綠, 就可以松開鼠標完成約束創(chuàng)建。

這樣就創(chuàng)建了一個簡單的約束,BUTTON2位于BUTTON1下49dp的位置,這樣BUTTON2的水平位置不會變,垂直位置就始終在BUTTON1下49dp處了不管BUTTON1如何移動。

現(xiàn)在我們想BUTTON2 水平和垂直位置都隨著BUTTON1的位置改變而改變呢,我們需要添加新的約束,如下圖

從圖中我們可以看到BUTTON2的位置完全受BUTTON1的約束。
有很多常用的約束在頂部的工具欄中直接使用,用鼠標選中需要約束的控件然后在工具欄選擇約束類型。
在增加一個BUTTON3,要讓BUTTON2和BUTTON3和BUTTON1的右邊對齊。

要讓BUTTON2和BUTTON3和BUTTON1的頂部對齊

可以看到選擇了約束模型后會自動創(chuàng)建好每一個View的約束,還有其他很多模型應該看圖標就能看明白是怎么樣的,我就不一一示范了(懶)。約束對象不僅可以是View也可以說是父布局。

基線約束
還有一種基線約束,其意為控件之間的文本基線約束。換句話說就是文本對齊,當然這種這種約束是有文本控件才有的約束,Layout是沒有基線約束的。創(chuàng)建基線約束只需要選中控件然后點擊左下角的第二個圖標就會出現(xiàn)控件的基線,然后鏈接所需要對齊的其他控件就可以了

使用自動連接創(chuàng)建約束 Autoconnect
在工具欄有一個磁鐵都一樣圖標

這個就是開啟或關(guān)閉自動約束的開關(guān),也叫
Autoconnect 默認是開啟的。Autoconnect會判斷我們的意圖,并自動給控件添加約束。不過Autoconnect是無法保證百分百準確判斷出我們的意圖的,如果自動添加的約束并不是你想要的話,還可以在任何時候進行手動修改??梢园阉敵梢粋€輔助工具,但不能完全靠它去添加控件的約,使用起來也很有局限性。 如下圖所示

使用推理操作創(chuàng)建約束 Inference
Inference也是用于自動添加約束的,但它比Autoconnect的功能要更為強大,使用起來也很方便。因為AutoConnect只能給當前操作的控件自動添加約束,而Inference會給當前界面中的所有元素自動添加約束??梢砸绘I自動生成所有控件的約束,如下圖所示


刪除約束
控件分別有四個方向上的約束點,四個角的正方形圖標拖動可以改變控件的大小。要刪除約束也很簡單,選中控件后點擊坐下角的圖標就刪除了當前控件的所以約束,點擊某一個約束的原點可以刪除單個約束

當然你也可以點擊工具欄的上如下圖的圖標,那么會清除布局中所有的約束

Properties屬性欄
當我們選中某個控件后那么視圖的右邊則是當前控件可以設(shè)置的屬性欄。一些基本的屬性設(shè)置這里就不講解了,主要了解下如圖所示的區(qū)域如何使用,這部分也叫Inspector 這部分就是來控制控件的寬高以及Margins值。

相對約束定位控件
當一個控件上有至少兩個對立的連接時, 比如上和下, 或者左和右, 你可以看到一個可以讓你沿著對立連接的軸調(diào)整控件位置的滑塊. 這也被稱為橫向或縱向偏量. 如下圖

拖動滑塊可以改變控件的橫向或者或者縱向的偏移量. 另外也可以通過移動控件到目標目標位置實現(xiàn)這一點。
控件寬高尺寸
空間的寬高可以通過單擊下圖中的線來控制控件寬高

寬高有以下選項

-
Fixed: 此選項允許你指定控件的高和寬.

-
AnySize: 此選項讓控件占用所有可用空間以適應約束. 換句話說, 這更像是匹配約束. 與match_parent不同, 后者占用父 View 的所有可用空間.

-
Wrap Content: 這個就是以前XML布局的Wrap Content是相同的
注意AnySize和 match_parent 有所不同,如果 左邊的ImageView 約束于右邊的 Button, 設(shè)置為AnySize 只會擴展它適應 右邊的button ,通過下面這張圖應該就很好理解了。

點擊外圍的線可以調(diào)整控件的Margins值。

Guidelines
Guidelines可以幫助你在添加約束布局的時候更方便的確定控件的位置,可以創(chuàng)建垂直或者水平方向的Guidelines,創(chuàng)建后可以點擊選擇Guidelines位置的方式,默認是距離左邊多少dp,點擊后可以切位為距離右邊的距離和屏幕的百分比距離

如果我們要兩個按鈕水平居中就需要用到Guidelines

可以看到我們給左邊的按鈕添加了約束,距離底部
24dp 右邊約束于Guidelines,右邊的按鈕則左邊約束于Guidelines而頂部則于左邊按鈕對齊,這樣兩個按鈕就水平居中對齊了。
鏈條布局 Chains
Chains 是最新才加入的一個新功能。 Chains 為同一個方向(水平或者垂直)上的多個子View 提供一個類似群組的概念。其他的方向則可以單獨控制。Chain 的屬性由該群組的第一個 View 上的屬性所控制(第一個 View 被稱之為 Chain head)
首先我們創(chuàng)建一個水平方向的Chain,通過工具欄我們可以快速的創(chuàng)建一個Chain

可以看到我們快速的創(chuàng)建了一個Chain約束,Chain 的屬性由該群組的第一個View也就是Chain head 上的屬性所控制 。Chain head有很多屬性如下
layout_constraintHorizontal_chainStylelayout_constraintHorizontal_weightlayout_constraintVertical_chainStylelayout_constraintVertical_weight
chainStyle 是設(shè)置到 Chain Head 上的,指定不同的 style 會改變里面所有 View 的布局方式,有如下四種 Style:
-
CHAIN_SPREAD這個是默認的Style, 里面的所有View會分散開布局 -
Weighted chain,在CHAIN_SPREAD模式下,如果有些View的尺寸設(shè)置為MATCH_CONSTRAINT(0dp),則這些View尺寸會占據(jù)所有剩余可用的空間,和LinearLayout weight類似。 -
CHAIN_SPREAD_INSIDE和CHAIN_SPREAD類似,只不過兩端的兩個View和 父容器直接不占用多余空間,多余空間在 子View之間分散 -
CHAIN_PACKED這種模式下,所有的子View都 居中聚集在一起,但是可以設(shè)置bias屬性來控制聚集的位置。

如果多個子View尺寸設(shè)置為 MATCH_CONSTRAINT(0dp),則這些 View 會平均的占用多余的空間。通過layout_constraintHorizontal_weight或layout_constraintVertical_weight屬性,可以控制每個View所占用的多余空間的比例。例如,對于只有兩個 View的一個水平Chain,如果每個View 的寬度都設(shè)置為MATCH_CONSTRAINT, 第一個View的 weight為 2;第二個View 的weight 為 1,則第一個View所占用的空間是 第二個 View 的兩倍。(以上其實就是官方文檔翻譯過來的)
比如我們現(xiàn)在想在界面上水平放置三個按鈕,這三個按鈕均分父容器寬度,且每個按鈕的間距為8dp,首先我們就要設(shè)置Chain head的chainStyle為spread并且layout_constraintHorizontal_weight設(shè)置為1
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="1"
給剩余兩個按鈕添加
app:layout_constraintHorizontal_weight="1"
并且把按鈕的寬度都設(shè)置為0dp然后修改margin值

當我們修改最后一個按鈕的layout_constraintHorizontal_weight為2的時候可以看到如下圖

可以看到最后一個按鈕的寬度是變成了前兩個按鈕的兩倍,說明這個layout_constraintHorizontal_weight和LinearLayout的weight類似
修改第一個按鈕的layout_constraintHorizontal_chainStyle為packed你會發(fā)現(xiàn)layout_constraintHorizontal_weight沒有作用了,按鈕寬度需要重新修改為wrap_content或者固定值。兩邊按鈕的位置可以通過Bias調(diào)節(jié),中間的按鈕可以調(diào)節(jié)margin值

最后需要注意的是每個控件都必須有上下左右的約束,這樣才能確實控件在布局中的準確位置。在右上角的紅色角標標識了當前有多少錯誤,錯誤一般都是控件沒有某一個方向的約束,當然也可以在XML中查看錯誤信息

相信現(xiàn)在用ConstraintLayout去做一個復雜布局應該難不到你了,各種約束也可以滿足各種樣式的布局,Android Studio 2.3發(fā)布后ConstraintLayout已經(jīng)成為了默認的根布局可以看出它的發(fā)展前途, ConstraintLayout簡直是要變革 Android 寫界面方式啊,更簡便更高效!
