ConstraintLayout 介紹與實戰

介紹

ConstraintLayout 在 2016 年 Google IO 中面世,它的出現是爲了解決開發中過於複雜的頁面層級嵌套過多的問題——層級過深會增長繪製界面須要的時間,影響用戶體驗。android

在使用過程當中,ConstraintLayout 能夠看作是一個更強大的 RelativeLayout,它提供了更多的 API 來約束控件的相對關係,更容易知足複雜的頁面佈局。app

佈局屬性

約束佈局擁有更強大的約束能力,其擁有的佈局屬性數量也很是多,筆者在這裏進行分類講解。ide

相對定位屬性

相對定位是約束佈局中建立佈局的基本屬性之一。這些屬性和 RelativeLayout 佈局屬性是相似的,用來控制控件相對於另一個控件或者父容器的位置。佈局

分別能夠在水平軸和垂直軸上約束控件:動畫

  • Horizontal: left, right, start, end
  • Vertical: top, bottom, text baseline

簡單來講就是將給定一側須要約束的控件約束到另外一個控件的另外一側。 舉個例子,把按鈕 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" />
複製代碼

Margins

設置控件的間距屬性與其餘佈局相同,但約束佈局中對應間距值生效須要有對應的約束條件,好比須要給控件設置左間距,那該控件它的 constraint<Left/Start>_toXXXOf 必定須要,不然間距沒法生效。3d

與其餘控件不一樣的是新增了一系列 goneMargin 屬性,用來控制當約束目標可見性爲 GONE 的時候,設置不一樣的間距值。code

實踐過程當中筆者可以想到的一個場景需求是:

在動畫中,A 不可見的時候,須要保證 B 的佈局位置不變,這個時候設置 goneMarginStart 的值爲 A 的寬度加上 B 的 marginStart ,就能夠知足該需求。

居中和 Bias

居中

跟其餘佈局同樣,約束佈局一樣擁有子控件居中的能力,居中定位是以橫向/豎向兩端同時約束來定位佈局位置。好比讓 A 在父容器中左右居中:

<android.support.constraint.ConstraintLayout ...>
  <Button android:id="@+id/button" ... app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent/> </> 複製代碼

豎直居中同理。

Bias

上述佈局約束會把控件居中對齊,使用 bias 能夠進行偏移。

  • layout_constraintHorizontal_bias
  • layout_constraintVertical_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/> </> 複製代碼

相對圓周定位 (ver 1.1)

constraintCircle 屬性在 1.1 版本中添加,提供開發者相對控件的中心一個角度和距離上約束另一個控件的能力。

  • layout_constraintCircle
  • layout_constraintCircleRadius
  • layout_constraintCircleAngle

<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_widthandroid:layout_height 來指定,但有三種不一樣類型:

  1. 使用肯定的尺寸,給定數值,好比 36dp
  2. 使用 WRAP_CONTENT 該效果與其餘控件相同
  3. 使用 0dp 來表示 MATCH_CONSTRAINT, 意思是根據約束規則指定高寬

(a) 設置爲 WRAP_CONTENT;(b) 設置爲 0dp;(c) 是設置了 margin 狀況下的 (b)

WRAP_CONTENT 下的強制約束 (ver 1.1)

在 1.1 版本以前,約束佈局對於控件的 WRAP_CONTENT 是不會限制它的結果大小。因此這在你但願使用 WRAP_CONTENT 但仍然須要強制約束條件來限制它的結果,就可能須要添加如下屬性:

  • app:layout_constrainedWidth="true|false"
  • app:layout_constrainedHeight="true|false"

在最後業務實戰的第一個例子中會具體說明該屬性的使用場景

寬高比例

layout_constraintDimensionRatio 限制控件的寬高比,若是要使用寬高比來約束尺寸,則至少要設置寬高其中一個尺寸爲0dp,而後再設置上 layout_constraintDimentionRatio 屬性。

<Button android:layout_width="wrap_content" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:1" />
複製代碼

上述代碼會獲得一個高度跟寬度相同的 Button。

關於比例的取值有兩種方式:

  • float 值,表明寬度/高度的比率
  • 寬度:高度這種比率值,好比 9:16

若是寬高都是 MATCH_CONSTRAINT (0dp) 也能夠是用寬高比,這種狀況系統會使用知足全部約束條件和寬高比率的最大尺寸。若是要根據其中一個尺寸來約束另一個尺寸,能夠在比率數值前添加 "W/H" 來分別約束寬度或者高度。 舉例:app:layout_constraintDimensionRatio="H,16:9"

這行代碼表示約束該 View 的高度,其數值須要符合 16:9 的比率。

鏈條

Chains 爲同一個方向(水平或者垂直)上的多個控件提供一個相似羣組的概念。其餘的方向則能夠單獨控制。

建立鏈條

多個控件相互在同一個方向上雙向引用就能夠建立一個 Chain.

Chain Style

如下屬性是用來控制 Chain Style 的:

– layout_constraintHorizontal_chainStyle – layout_constraintHorizontal_weight – layout_constraintVertical_chainStyle – layout_constraintVertical_weight

其中 Style 有 4 種:

  1. CHAIN_SPREAD 這個是默認的 Style, 裏面的全部控件會分散開佈局
  2. Weighted chain,在 CHAIN_SPREAD 模式下,若是有些控件的尺寸設置爲 MATCH_CONSTRAINT(0dp),則這些控件尺寸會佔據全部剩餘可用的空間,和 LinearLayout weight 相似。
  3. CHAIN_SPREAD_INSIDECHAIN_SPREAD 相似,只不過兩端的兩個控件和父容器直接不佔用多餘空間,多餘空間在控件之間分散
  4. CHAIN_PACKED 這種模式下,全部的控件都居中彙集在一塊兒,可是能夠設置 bias 屬性來控制彙集的位置。

輔助佈局

Guideline

Guideline 是約束佈局中一個特殊的輔助佈局類,能夠建立水平或者垂直的參考線,其餘的控件能夠根據這個參考線來進行佈局,它本質是不可見的控件。

參考線的位置屬性:

  • orientation:vertical/horizontal
  • layout_constraintGuide_begin 指定距離左/上邊開始的固定位置
  • layout_constraintGuide_end 指定距離右/下邊開始的固定位置
  • layout_constraintGuide_percent 指定位於佈局中所在的百分比

Barrier

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

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 引用的控件會致使它們的自身的可見性和深度失效。

業務經典場景

1. 固定一邊,中間寬度可變,另外一邊跟隨中間尾部

設計需求:頭像位置固定,中間文字長度可變,最右側按鈕跟在文字右側,但不能超出屏幕。

<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 應用。

2. 根據某個 View 的高度/寬度,來居中一組 View

設計需求:右側圖片和文字,須要總體跟左邊頭像居中。

<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_pictv_content 雙向依賴,使用 packed Style 讓它們緊靠一塊兒,同時,iv_pic 頭部與 iv_avatar 的頭部對齊, tv_content 的底部與 iv_avatar 的底部對齊,達到它們居中顯示的效果。

相關文章
相關標籤/搜索