ConstraintLayout
在 2016 年 Google IO 中面世,它的出現是爲了解決開發中過於複雜的頁面層級嵌套過多的問題——層級過深會增長繪製界面須要的時間,影響用戶體驗。android
在使用過程當中,ConstraintLayout
能夠看作是一個更強大的 RelativeLayout
,它提供了更多的 API 來約束控件的相對關係,更容易知足複雜的頁面佈局。app
約束佈局擁有更強大的約束能力,其擁有的佈局屬性數量也很是多,筆者在這裏進行分類講解。ide
相對定位是約束佈局中建立佈局的基本屬性之一。這些屬性和 RelativeLayout
佈局屬性是相似的,用來控制控件相對於另一個控件或者父容器的位置。佈局
分別能夠在水平軸和垂直軸上約束控件:動畫
簡單來講就是將給定一側須要約束的控件約束到另外一個控件的另外一側。 舉個例子,把按鈕 B 放到按鈕 A 的右邊:ui
咱們能夠這樣寫:spa
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ... app:layout_constraintLeft_toRightOf="@+id/buttonA" />
複製代碼
除了指定另一個控件 id 進行約束,咱們還能夠與父佈局進行約束:設計
<Button android:id="@+id/buttonB" ... app:layout_constraintLeft_toLeftOf="parent" />
複製代碼
設置控件的間距屬性與其餘佈局相同,但約束佈局中對應間距值生效須要有對應的約束條件,好比須要給控件設置左間距,那該控件它的 constraint<Left/Start>_toXXXOf
必定須要,不然間距沒法生效。3d
與其餘控件不一樣的是新增了一系列 goneMargin
屬性,用來控制當約束目標可見性爲 GONE
的時候,設置不一樣的間距值。code
實踐過程當中筆者可以想到的一個場景需求是:
在動畫中,A 不可見的時候,須要保證 B 的佈局位置不變,這個時候設置 goneMarginStart
的值爲 A 的寬度加上 B 的 marginStart
,就能夠知足該需求。
跟其餘佈局同樣,約束佈局一樣擁有子控件居中的能力,居中定位是以橫向/豎向兩端同時約束來定位佈局位置。好比讓 A 在父容器中左右居中:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ... app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent/> </> 複製代碼
豎直居中同理。
上述佈局約束會把控件居中對齊,使用 bias 能夠進行偏移。
若是沒有設置 bias 值,則左右兩邊取值各佔有 50% 也就是居中的效果,若是把 bias 修改成 0.3 (30%),則左邊空白的邊距會減小,右邊會相應增多。
給上述代碼增長一行 app:layout_constraintHorizontal_bias="0.3"
,就能夠獲得圖片的效果。
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ... app:layout_constraintHorizontal_bias="0.3" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent/> </> 複製代碼
constraintCircle
屬性在 1.1 版本中添加,提供開發者相對控件的中心一個角度和距離上約束另一個控件的能力。
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ... app:layout_constraintCircle="@+id/buttonA" app:layout_constraintCircleRadius="100dp" app:layout_constraintCircleAngle="45" />
複製代碼
在 ConstraintLayout
中設置控件的高度和寬度是經過 android:layout_width
和 android:layout_height
來指定,但有三種不一樣類型:
36dp
WRAP_CONTENT
該效果與其餘控件相同0dp
來表示 MATCH_CONSTRAINT
, 意思是根據約束規則指定高寬(a) 設置爲 WRAP_CONTENT
;(b) 設置爲 0dp;(c) 是設置了 margin
狀況下的 (b)
WRAP_CONTENT
下的強制約束 (ver 1.1)在 1.1 版本以前,約束佈局對於控件的 WRAP_CONTENT
是不會限制它的結果大小。因此這在你但願使用 WRAP_CONTENT
但仍然須要強制約束條件來限制它的結果,就可能須要添加如下屬性:
在最後業務實戰的第一個例子中會具體說明該屬性的使用場景
layout_constraintDimensionRatio
限制控件的寬高比,若是要使用寬高比來約束尺寸,則至少要設置寬高其中一個尺寸爲0dp
,而後再設置上 layout_constraintDimentionRatio
屬性。
<Button android:layout_width="wrap_content" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:1" />
複製代碼
上述代碼會獲得一個高度跟寬度相同的 Button。
關於比例的取值有兩種方式:
若是寬高都是 MATCH_CONSTRAINT (0dp)
也能夠是用寬高比,這種狀況系統會使用知足全部約束條件和寬高比率的最大尺寸。若是要根據其中一個尺寸來約束另一個尺寸,能夠在比率數值前添加 "W/H" 來分別約束寬度或者高度。 舉例:app:layout_constraintDimensionRatio="H,16:9"
這行代碼表示約束該 View 的高度,其數值須要符合 16:9 的比率。
Chains 爲同一個方向(水平或者垂直)上的多個控件提供一個相似羣組的概念。其餘的方向則能夠單獨控制。
多個控件相互在同一個方向上雙向引用就能夠建立一個 Chain.
如下屬性是用來控制 Chain Style 的:
– layout_constraintHorizontal_chainStyle – layout_constraintHorizontal_weight – layout_constraintVertical_chainStyle – layout_constraintVertical_weight
其中 Style 有 4 種:
CHAIN_SPREAD
這個是默認的 Style, 裏面的全部控件會分散開佈局CHAIN_SPREAD
模式下,若是有些控件的尺寸設置爲 MATCH_CONSTRAINT(0dp)
,則這些控件尺寸會佔據全部剩餘可用的空間,和 LinearLayout weight 相似。CHAIN_SPREAD_INSIDE
和 CHAIN_SPREAD
相似,只不過兩端的兩個控件和父容器直接不佔用多餘空間,多餘空間在控件之間分散CHAIN_PACKED
這種模式下,全部的控件都居中彙集在一塊兒,可是能夠設置 bias 屬性來控制彙集的位置。Guideline 是約束佈局中一個特殊的輔助佈局類,能夠建立水平或者垂直的參考線,其餘的控件能夠根據這個參考線來進行佈局,它本質是不可見的控件。
參考線的位置屬性:
Barrier 在約束佈局中經過 constraint_referenced_ids
引用多個控件,看做一個總體來添加一個與另一個控件限制最大寬/高的約束。
經過 app:barrierDirection
屬性來決定 Barrier 的方向。
<android.support.constraint.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="start" app:constraint_referenced_ids="button1,button2" />
複製代碼
Group 是約束佈局用來控制一組控件的可見性。
<android.support.constraint.Group android:id="@+id/group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="visible" app:constraint_referenced_ids="button4,button9" />
複製代碼
被引用 id 的控件的可見性(visibility)和深度(elevation)屬性與 Group 相同。
換句話說:被 Group 引用的控件會致使它們的自身的可見性和深度失效。
設計需求:頭像位置固定,中間文字長度可變,最右側按鈕跟在文字右側,但不能超出屏幕。
<androidx.constraintlayout.widget.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="60dp" tools:background="@color/background_gray">
<ImageView android:id="@+id/iv_avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginStart="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars[2]" />
<TextView android:id="@+id/tv_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" android:singleLine="true" app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="@+id/iv_avatar" app:layout_constraintEnd_toStartOf="@id/tv_action" app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintStart_toEndOf="@id/iv_avatar" app:layout_constraintTop_toTopOf="@+id/iv_avatar" tools:text="ConstraintLayout is available as a support library" />
<TextView android:id="@+id/tv_action" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="15dp" app:layout_constraintBottom_toBottomOf="@+id/iv_avatar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/tv_text" app:layout_constraintTop_toTopOf="@+id/iv_avatar" tools:text="查看" />
</androidx.constraintlayout.widget.ConstraintLayout>
複製代碼
該場景重點須要熟悉屬性:layout_constrainedWidth/Height
應用。
設計需求:右側圖片和文字,須要總體跟左邊頭像居中。
<androidx.constraintlayout.widget.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="300dp" tools:background="@color/background_gray">
<ImageView android:id="@+id/iv_avatar" android:layout_width="150dp" android:layout_height="150dp" android:layout_marginStart="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.3" tools:srcCompat="@tools:sample/avatars[2]" />
<ImageView android:id="@+id/iv_pic" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginStart="50dp" android:scaleType="centerCrop" app:layout_constraintBottom_toTopOf="@+id/tv_content" app:layout_constraintStart_toEndOf="@id/iv_avatar" app:layout_constraintTop_toTopOf="@id/iv_avatar" app:layout_constraintVertical_chainStyle="packed" tools:srcCompat="@tools:sample/backgrounds/scenic[6]" />
<TextView android:id="@+id/tv_content" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="5dp" app:layout_constraintBottom_toBottomOf="@id/iv_avatar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/iv_pic" app:layout_constraintTop_toBottomOf="@+id/iv_pic" tools:text="Chains provide group-like behavior in a single axis (horizontally or vertically). " />
</androidx.constraintlayout.widget.ConstraintLayout>
複製代碼
該場景重點須要熟悉約束佈局:Chain
的應用。 iv_pic
與 tv_content
雙向依賴,使用 packed
Style 讓它們緊靠一塊兒,同時,iv_pic
頭部與 iv_avatar
的頭部對齊, tv_content
的底部與 iv_avatar
的底部對齊,達到它們居中顯示的效果。