ConstraintLayout的使用教程

小立子發表於2019-01-20

該篇文章的主旨是幫助開發者瞭解ConstraintLayout的基本使用方法以及在日常開發專案中的使用場景的說明

ConstraintLayout官方文件

ConstraintLayout是一個ViewGroup,允許你靈活的指定子View的位置和大小(具體多靈活在下面的場景中進行說明),官方文件中說明ConstraintLayout的特性有以下幾種:

  • Relative positioning - 相對位置
  • Margins - 邊距
  • Centering positioning - 位置居中
  • Visibility behavior - 可見性行為
  • Dimension constraints - 尺寸限制
  • Chains - 鏈
  • Virtual Helpers objects - 虛擬幫助物件(Guideline)
  • Optimizer - 優化

以上幾個特性部分有點抽象,官方文件中也對每一個特性都進行了詳細的說明和舉例,有意者可以單獨去查閱,ConstraintLayout , 在下面的應用場景中也會穿插說明。對於開發者來說,主要了解使用場景和在專案中如何使用,用得多了就對該控制元件有了比較深入的瞭解。再看文件會更容易理解。畢竟文件是英文的。

使用說明

在沒有ConstraintLayout之前我們寫佈局一般使用到的佈局就是相對佈局線性佈局,相對佈局中控制元件的位置都是基於另一個控制元件的位置,這個和ConstraintLayout有一絲相似之處,線性佈局就是直接以瀑布流的形式進行佈局。ConstraintLayout根據字面意思瞭解為約束佈局,所以,所以在寫佈局檔案的時候,需要對每一個控制元件進行約束 ,對每一個顯示在約束佈局中的內容進行約束,約束其大小,位置。下面介紹一下約束佈局的相關屬性和使用。

ConstraintLayout的基本屬性

決定檢視的大小和位置可以由View四個邊來確定,left top right bottom, 所以約束佈局可以通過對四個邊的約束來達到實際佈局效果,相關四個邊的屬性有,如:

app:layout_constraintLeft_toLeftOf
app:layout_constraintLeft_toRightOf
app:layout_constraintRight_toLeftOf
app:layout_constraintRight_toRightOf
app:layout_constraintTop_toTopOf
app:layout_constraintTop_toBottomOf
app:layout_constraintBottom_toTopOf
app:layout_constraintBottom_toBottomOf
app:layout_constraintStart_toEndOf
app:layout_constraintStart_toStartOf
app:layout_constraintEnd_toStartOf
app:layout_constraintEnd_toEndOf
複製程式碼

應該根據這些屬性的名稱就能瞭解它們的作用,下面舉例說明:比如實現一個登陸介面,兩個文字框和一個按鈕。

<?xml version="1.0" encoding="utf-8"?>
<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="match_parent">

    <EditText
        android:id="@+id/edt_username"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_marginStart="25dp"
        android:layout_marginTop="200dp"
        android:layout_marginEnd="25dp"
        android:hint="請輸入使用者名稱"
        android:inputType="text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/edt_password"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:hint="請輸入密碼"
        android:inputType="textPassword"
        app:layout_constraintEnd_toEndOf="@id/edt_username"
        app:layout_constraintStart_toStartOf="@id/edt_username"
        app:layout_constraintTop_toBottomOf="@id/edt_username" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="登 錄"
        app:layout_constraintEnd_toEndOf="@id/edt_password"
        app:layout_constraintStart_toStartOf="@id/edt_password"
        app:layout_constraintTop_toBottomOf="@id/edt_password" />
</androidx.constraintlayout.widget.ConstraintLayout>
複製程式碼

ConstraintLayout的使用教程
很簡單的一個頁面,如果用LinearLayout更快,但是ConstraintLayout本身就是為了解決複雜佈局而生的,在日常開發中的需求可能會讓你各種巢狀佈局,但是ConstraintLayout基本上都是一個佈局就可以ok,所以只有你瞭解後才知道使用有多得勁,現在簡單的分析說明下上面的佈局原理。

1.確定使用者名稱EditText的位置和大小,從四個邊來約束,首先約束top,使用top_toTopOf="parent"將使用者名稱EditText的頂部和父佈局的頂部關聯起來,然後通過marginTop來增加邊距,如果不設定top_toTopOf屬性,marginTop屬性是不起作用的,任何沒有增加約束的設定margin屬性都是不起作用的,上面的程式碼中我們將EditText的width設定為0dp,然後給左右兩邊分別增加了約束,約束到父佈局的start和end,通過以上三個屬性,就確定了該EditText的位置和大小。

2.確定了使用者名稱EditText的位置之後,進行新增密碼EditText,和上一個EditText類似,增加左右上三邊的約束,不同的是top_toTopOf屬性的值改為了edt_username,不在把約束新增到parent,而是新增到使用者名稱的EditText,這樣密碼EditText就顯示到使用者名稱的下面了。登入同理

只需要記住,ConstraintLayout中的所有空間新增上 左上右下 四個邊的約束,就能確定空間的位置(對應了開始說的 Relative positioning 和 Margins 兩個特性) ,記住這個就掌握使用的一大半了

控制元件居中

想讓控制元件居中也很簡單,比如說上面的登入按鈕,不想要那麼大,可以將控制元件的width屬性改成wrap_content,這樣控制元件就直接居中了。

ConstraintLayout的使用教程
在給控制元件新增完約束之後,如果width或者height給的值為0,則控制元件的大小將完全按照約束的大小進行展示,如果設定了wrap_content,則控制元件會居中顯示

基線對齊約束

該約束是針對文字相關控制元件新增的,比如要再新增一個註冊按鈕在登入的右側

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="登 錄"
        app:layout_constraintEnd_toStartOf="@id/btn_sign_up"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="@id/edt_password"
        app:layout_constraintTop_toBottomOf="@id/edt_password" />

    <Button
        android:id="@+id/btn_sign_up"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="註冊"
        app:layout_constraintBaseline_toBaselineOf="@id/btn_login"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toEndOf="@id/btn_login"
        app:layout_constraintEnd_toEndOf="@id/edt_password"
        app:layout_constraintTop_toBottomOf="@id/edt_password" />
複製程式碼

ConstraintLayout的使用教程
在上面的註冊控制元件中,增加了layout_constraintBaseline_toBaselineOf屬性,依賴登入按鈕,這樣他們的繪製基線就在同一y軸上了,從而達到對齊的效果。

Chains

在上面的基線約束中,可能你會發現登入和註冊的位置非常對稱,這個就是chains約束,對於chains約束只說明兩點,你就會輕鬆使用了。

  • 控制元件之間要相互依賴。

例如上面的登入和註冊兩個按鈕,登入的右邊距約束必須新增到註冊的左邊距上,即:登入的 end_ToStartOf="btn_sign_up",註冊的 start_toEndOf="btn_login",如果是多個控制元件一樣,一個控制元件的結束依賴到另一個的開始。這是水平chain , 垂直的桶裡

  • 新增chain屬性 待需要增加chain約束的控制元件都依賴完了之後,就需要給每個控制元件增加chain屬性了,即:layout_constraintHorizontal_chainStyle 或者 layout_constraintVertical_chainStyle , 該屬性可以有多個值,分別對應的效果借鑑官方文件的,如下:
    ConstraintLayout的使用教程

Dimension constraints - 尺寸約束

layout_constraintDimensionRatio

尺寸約束的使用不多,但是這個屬性很重要,在很多的場景中可以使用該約束,先對屬性進行說明,應用場景後面再說。瞭解了作用,自然就能在實際開發中找到場景。比如說我們要實現一個ImageView的寬是高的2倍,可能有人想,我把寬固定了那高除以2不就出來了嘛,當然可以,但是有些場景,比如說寬是螢幕的寬度,match_parent呢,用尺寸約束就可以很輕鬆的達到效果。

  <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp" 
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintDimensionRatio="2:1"
        android:background="@color/colorAccent"
        />
複製程式碼

ConstraintLayout的使用教程
這樣就比較輕鬆的實現了高是寬的2倍,在什麼機型上都是。

百分比約束

layout_constraintHeight_percent

layout_constraintWidth_percent

分別對寬高進行百分比約束。

 <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHeight_percent="0.2"
        app:layout_constraintWidth_percent="0.5"
        android:background="@color/colorAccent"
        />
複製程式碼

ConstraintLayout的使用教程
百分比約束相對很實用,但是比較少用,很類似之前LinearLayout的weight權重。

Visibility behavior

可見性行為的屬性包括:

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
複製程式碼

比如說上面的登入頁面,如果程式中設定了使用者名稱EditText設定了setVisible(false),那麼密碼EditText就會直接到頂部了,甚至造成佈局錯亂,為什麼?應為密碼EditText的左右約束新增到了使用者名稱的EditText上,如果想讓使用者名稱EditText隱藏的時候密碼EditText和top右邊距,就可以給密碼EditText加上goneMarginTop屬性,為了防止因為控制元件隱藏造成佈局錯亂,在已知一些控制元件會隱藏的前提下,其他的控制元件不要左右邊依賴可能會隱藏的檢視,防止佈局錯亂 比如上面的為了防止使用者名稱EditText隱藏造成密碼EditText顯示不了的問題,可以給密碼EditText的左右依賴新增到父佈局即可。

Guideline - Virtual Helpers objects

guideline也是一個控制元件,但是這個控制元件是隻在約束佈局中才能起作用的輔助控制元件 ,是幫助輔助佈局的,比如說,我們新增一個GuideLine,將螢幕平分為兩半,一個檢視在左,一個在右。拿上面的登入註冊兩個按鈕來說,上面的實現方式是增加了chain約束,也可以用GuideLine來實現。程式碼如下:

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="登 錄"
        app:layout_constraintEnd_toStartOf="@id/guideline"
        app:layout_constraintStart_toStartOf="@id/edt_password"
        app:layout_constraintTop_toBottomOf="@id/edt_password" />

    <Button
        android:id="@+id/btn_sign_up"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="註冊"
        app:layout_constraintBaseline_toBaselineOf="@id/btn_login"
        app:layout_constraintEnd_toEndOf="@id/edt_password"
        app:layout_constraintStart_toEndOf="@id/guideline" />
複製程式碼

ConstraintLayout的使用教程
中間的虛線,即為增加的輔助GuideLine控制元件,該控制元件需要設定兩個屬性,第一是設定orientation屬性,垂直或者水平,第二是百分比 layout_constraintGuide_percent,新增好輔助檢視之後,其他控制元件就可以依賴於它進行佈局。

以上幾方面就是在日常開發中的基礎使用相關介紹,掌握了這些基本上都能滿足開發的需求,下面說下ConstraintLayout的使用場景

使用場景

  • 不帶滾動的複雜佈局

以前我們在實現佈局的時候經常各種巢狀,現在不帶滾動的佈局,都可以只用一個父佈局就可以解決,減少了佈局的層級深度

  • 帶滾動的複雜佈局

在NestedScrollView中巢狀一個ConstraintLayout即可。

  • RecyclerView的item佈局

以前item佈局也是各種巢狀佈局,有了ConstraintLayout之後發現真的是省事了很多,程式碼看起來也比較舒服

  • 尺寸約束和百分比的巧用

像有一些banner圖的設計尺寸都是固定的,我們只需要寬度設定全屏,然後設定寬高比,就能適配所有螢幕,等等。。妙用很多,實際開發自己發掘。

總之如果在使用ConstraintLayout看了該內容哪裡不對希望評論補充,或者不對的地方糾正我一下,如果是沒有用過的,希望你趕緊用起來,省時省力

相關文章