使用 ConstraintLayout 打造回應式 UI   Android Jetpack 的一部分。

試試 Compose 的方式
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中處理版面配置。

ConstraintLayout 可讓您使用平面檢視區塊階層建立複雜的大型版面配置,而不必使用巢狀檢視區塊群組。與 RelativeLayout 相似,所有檢視畫面都會根據同層級檢視畫面與父版面配置之間的關係進行版面配置,但它比 RelativeLayout 更具彈性,且更容易與 Android Studio 的版面配置編輯器搭配使用。

版面配置 API 和版面配置編輯器是專為彼此而建構,因此您可以直接透過版面配置編輯器的視覺工具,運用 ConstraintLayout 的所有功能。您可以使用 ConstraintLayout 拖曳,而非編輯 XML,即可完全建構版面配置。

本頁面說明如何在 Android Studio 3.0 以上版本中使用 ConstraintLayout 建構版面配置。如要進一步瞭解版面配置編輯器,請參閱「使用版面配置編輯器打造 UI」一文。

如要查看可透過 ConstraintLayout 建立的各種版面配置,請參閱 GitHub 上的 Constraint Layout 範例專案

限制總覽

如要定義檢視畫面在 ConstraintLayout 中的位置,請為檢視畫面新增至少一個水平和一個垂直限制條件。每個限制條件代表與其他檢視畫面、父項版面配置或隱形指南的連接或對齊方式。每個限制都會定義檢視畫面沿著垂直或水平軸的位置。每個檢視畫面必須為每個軸指定至少一個限制條件,但通常需要更多限制條件。

將檢視畫面放到版面配置編輯器後,即使沒有限制,檢視畫面也會停留在您放置的位置。這只是為了方便編輯。如果在裝置上執行版面配置時,檢視畫面沒有任何約束條件,則會在 [0,0] 位置 (左上角) 繪製。

在圖 1 中,版面配置在編輯器中看起來不錯,但 View C 沒有垂直限制。當這個版面配置在裝置上繪製時,檢視區塊 C 會與檢視區塊 A 的左右邊緣水平對齊,但由於沒有垂直約束,因此會顯示在螢幕頂端。

圖 1. 編輯器會在 A 下方顯示檢視區塊 C,但沒有垂直限制。

圖 2. 檢視畫面 C 現已在檢視畫面 A 下方垂直受限。

雖然缺少的限制條件不會導致編譯錯誤,但版面配置編輯器會在工具列中將缺少的限制條件視為錯誤。如要查看錯誤和其他警告,請按一下「顯示警告和錯誤」圖示 。為避免遺漏限制條件,版面配置編輯器會使用「Autoconnect and infer constraints」功能,自動為您新增限制條件。

將 ConstraintLayout 新增至專案

如要在專案中使用 ConstraintLayout,請按照下列步驟操作:

  1. 請確認您已在 settings.gradle 檔案中宣告 maven.google.com 存放區:

    Groovy

        dependencyResolutionManagement {
          ...
          repositories {
              google()
          }
        )
        

    Kotlin

        dependencyResolutionManagement {
          ...
          repositories {
              google()
          }
        }
        
  2. 在模組層級 build.gradle 檔案中,將程式庫新增為依附元件,如以下範例所示。最新版本可能與範例中顯示的版本不同。

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-beta01"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-beta01")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01")
    }
    
  3. 在工具列或同步通知中,按一下「Sync Project with Gradle Files」

您現在可以使用 ConstraintLayout 建構版面配置了。

轉換版面配置

圖 3. 將版面配置轉換為 ConstraintLayout 的選單。

如要將現有的版面配置轉換為約束版面配置,請按照下列步驟操作:

  1. 在 Android Studio 中開啟版面配置,然後按一下編輯器視窗底部的「Design」分頁。
  2. 在「Component Tree」視窗中,在版面配置上按一下滑鼠右鍵,然後按一下「將 LinearLayout 轉換為 ConstraintLayout」

建立新的版面配置

如要開始建立新的約束條件版面配置檔案,請按照下列步驟操作:

  1. 在「Project」視窗中,按一下模組資料夾,然後依序選取「File」>「New」>「XML」>「Layout XML」
  2. 輸入版面配置檔案的名稱,並輸入「androidx.constraintlayout.widget.ConstraintLayout」做為根標記
  3. 按一下「Finish」

新增或移除限制

如要新增限制條件,請按照下列步驟操作:

影片 1. 檢視畫面的左側會受限於父項的左側。

  1. 將檢視畫面從「Palette」視窗拖曳至編輯器。

    ConstraintLayout 中新增檢視畫面時,會在定界框中顯示,每個角落都有正方形的大小調整控點,每側都有圓形的限制控點。

  2. 按一下要選取的檢視畫面。
  3. 執行下列任一操作:
    • 按一下約束控點,然後將其拖曳至可用的錨點。 這個點可以是其他檢視畫面的邊緣、版面配置的邊緣或指南。請注意,當您拖曳限制控點時,版面配置編輯器會顯示潛在的連結錨點和藍色疊加層。
    • 按一下「Attributes」視窗「Layout」部分中的「Create a connection」 按鈕,如圖 4 所示。

      圖 4. 您可以透過「屬性」視窗的「版面配置」部分建立連線。

建立限制時,編輯器會為其提供預設邊界,用於分隔兩個檢視畫面。

建立限制條件時,請注意下列規則:

  • 每個檢視畫面都必須至少有兩個限制條件:一個水平和一個垂直。
  • 您只能在共用相同平面的限制手柄和錨點之間建立限制。檢視畫面的垂直平面 (左右兩側) 只能限制另一個垂直平面,而基準線只能限制其他基準線。
  • 每個限制控點只能用於單一限制,但您可以從不同檢視畫面建立多個限制,並指向相同的錨點。

您可以執行下列任一操作來刪除限制條件:

  • 按一下限制條件選取它,然後點選「刪除」
  • 按住 Control 鍵 (在 macOS 上為 Command 鍵) 並點選限制錨點。約束條件會變成紅色,表示您可以點選刪除,如圖 5 所示。

    圖 5. 紅色限制表示您可以點選刪除。

  • 在「Attributes」視窗的「Layout」部分中,按一下約束錨點,如圖 6 所示。

    圖 6. 按一下約束錨點即可刪除。

影片 2. 新增與現有限制條件相反的限制條件。

如果您在檢視畫面上新增相反的約束條件,約束線會像彈簧般捲曲,以表示相反的力量,如影片 2 所示。當檢視區塊大小設為「固定」或「包裝內容」時,效果最明顯,因為在這種情況下,檢視區塊會置於限制之間的中央。如果您希望檢視畫面會拉伸至符合限制條件的大小,請將大小切換為「符合限制條件」。如果您想保留目前的大小,但移動檢視畫面,使其不在中央,請調整約束偏差

您可以使用約束條件實現不同類型的版面配置行為,如以下各節所述。

父項位置

將檢視畫面的側邊限制為版面配置的對應邊緣。

在圖 7 中,檢視畫面的左側會連結至父版面配置的左側邊緣。您可以使用邊距定義與邊緣的距離。

圖 7. 父項的水平限制。

訂單位置

定義兩個檢視畫面的顯示順序,可為垂直或水平。

在圖 8 中,B 一律會位於 A 右側,而 C 則位於 A 下方。不過,這些限制並未暗示對齊,因此 B 仍可上下移動。

圖 8. 水平和垂直限制條件。

切合需求

將一個檢視畫面的邊緣對齊至另一個檢視畫面的相同邊緣。

在圖 9 中,B 的左側會與 A 的左側對齊。如要對齊檢視畫面中心,請在兩側建立限制。

您可以將檢視區塊從約束條件向內拖曳,藉此偏移對齊方式。舉例來說,圖 10 顯示 B 的 24dp 偏移對齊方式。偏移量是由受限檢視畫面的邊界定義。

您也可以選取要對齊的所有檢視畫面,然後按一下工具列中的「對齊」圖示 ,選取對齊類型。

圖 9.水平對齊限制條件。

圖 10. 水平偏移對齊限制條件。

基準對齊

將檢視畫面的文字基準線對齊至另一個檢視畫面的文字基準線。

在圖 11 中,B 的第一行與 A 中的文字對齊。

如要建立基準限制,請在要限制的文字檢視畫面上按一下滑鼠右鍵,然後點選「Show Baseline」。接著按一下文字基準線,然後將該線拖曳至其他基準線。

圖 11. 基準對齊限制。

限制至指南

您可以新增垂直或水平的規範,用於限制檢視畫面,並讓應用程式使用者無法看到這些規範。您可以根據 dp 單位或相對於版面配置邊緣的百分比,在版面配置中放置規則。

如要建立規則,請按一下工具列中的「Guidelines」圖示 ,然後點選「Add Vertical Guideline」或「Add Horizontal Guideline」

拖曳虛線重新調整位置,然後按一下規則邊緣的圓圈,切換測量模式。

圖 12. 受引導線限制的檢視畫面。

限制為障礙物

與指南類似,邊界也是可用來限制檢視區塊的無形線條,但邊界不會定義自身位置。相反地,邊界位置會根據其中包含的檢視區位置移動。如果您想將檢視區塊限制為一組檢視區塊,而非特定檢視區塊,這項功能就很實用。

舉例來說,在圖 13 中,檢視畫面 C 會受到限制,只能顯示在邊界右側。將邊界設為檢視畫面 A 和 B 的「結尾」(或從左到右的版面配置中的右側)。視檢視畫面 A 或 B 的右側是否最右側而定,邊界會移動。

如要建立隔離區,請按照下列步驟操作:

  1. 按一下工具列中的「Guidelines」圖示 ,然後點選「Add Vertical Barrier」或「Add Horizontal Barrier」
  2. 在「Component Tree」視窗中,選取所需的邊界內檢視區塊,然後將這些檢視區塊拖曳至邊界元件。
  3. 從「Component Tree」中選取障礙物,開啟「Attributes」 視窗,然後設定 barrierDirection

您現在可以從其他檢視畫面建立限制,以便與阻隔區連結。

您也可以限制內含邊界區塊的檢視畫面。這樣一來,即使您不知道哪個檢視區塊最長或最高,也能將所有檢視區塊對齊。

您也可以在邊界內加入指南,確保邊界有「最小」的寬度。

圖 13. 檢視畫面 C 受到限制,只能在檢視畫面 A 和 B 的位置和大小範圍內移動。

調整限制偏差

當您在檢視畫面兩側新增限制條件,且相同維度的檢視畫面大小為「固定」或「包裝內容」時,系統會將檢視畫面置於兩個限制條件之間,並預設偏移 50%。您可以拖曳「Attributes」視窗中的偏差滑桿,或是拖曳檢視畫面來調整偏差,如影片 3 所示。

如果您希望檢視畫面會拉伸至符合限制條件的大小,請將大小切換為「符合限制條件」。

影片 3. 調整限制偏差。

調整檢視畫面大小

圖 14. 選取檢視畫面時,「Attributes」視窗會提供控制項,用於設定1 大小比例、2 刪除限制條件、3 高度或寬度模式、4 邊界,以及5 限制偏差。您也可以在版面配置編輯器中點選限制清單中的限制,醒目顯示個別限制。6

您可以使用角落控點調整檢視畫面大小,但這會將大小硬式編碼,也就是說,檢視畫面不會根據不同的內容或螢幕大小調整大小。如要選取其他大小調整模式,請按一下檢視畫面,然後在編輯器右側開啟「Attributes」視窗。

「Attributes」視窗頂端附近是檢視器,其中包含多個版面配置屬性的控制項,如圖 14 所示。這項功能僅適用於限制版面配置中的檢視區塊。

如要變更計算高度和寬度的方式,請按一下圖 14 中以註解 3 標示的符號。這些符號代表下列大小模式。按一下符號,即可在下列設定之間切換:

  • 固定:在下列文字方塊中指定特定尺寸,或在編輯器中調整檢視區塊的大小。
  • 自動換行內容:檢視畫面只會盡可能依照內容來延伸。
    • layout_constrainedWidth
    • 將此值設為 true,讓水平維度變更以遵守限制條件。根據預設,設定為 WRAP_CONTENT 的小工具不會受到限制。

  • 符合限制條件:在考量檢視畫面的邊界後,檢視畫面會盡可能擴大,以符合各邊的限制條件。不過,您可以使用下列屬性和值修改該行為。只有在將檢視區寬設為「符合限制」時,這些屬性才會生效:
    • layout_constraintWidth_min

      這會為檢視畫面的最小寬度採用 dp 維度。

    • layout_constraintWidth_max

      這會為檢視畫面的最大寬度採用 dp 維度。

    不過,如果指定的維度只有一個限制,則檢視畫面會延伸以配合內容。在高度或寬度上使用這個模式,您也可以設定大小比例

以比例設定大小

圖 15. 檢視畫面會設為 16:9 顯示比例,寬度則根據高度的比例計算。

如果至少有一組檢視區域的尺寸設為「符合限制條件」(0dp),您可以將檢視區域大小設為比例,例如 16:9。如要啟用比例,請按一下「切換顯示比例限制」 (圖 14 中的註解 1),然後在顯示的輸入框中輸入 width:height 比例。

如果寬度和高度都設為「配合限制」,您可以點選「切換顯示比例限制」,選取以哪個尺寸的比例為依據。檢視畫面檢查器會透過以實線連接對應的邊緣,指出哪個維度已設為比例。

舉例來說,如果您將兩側都設為「符合限制條件」,請按兩下「切換顯示比例限制」,將寬度設為高度的比例。整個大小取決於檢視區塊的高度,而高度可以以任何方式定義,如圖 15 所示。

調整檢視畫面邊界

如要讓檢視區塊間隔均等,請按一下工具列中的「Margin」圖示 ,為您新增至版面配置的每個檢視區塊選取預設邊界。您對預設邊界所做的任何變更,只會套用至從此新增的檢視畫面。

您可以在「屬性」視窗中控制每個檢視畫面的邊界,方法是點選代表各限制的列上方的數字。在圖 14 中,註解 4 顯示底部邊界已設為 16dp。

圖 16. 工具列的「Margin」按鈕。

工具提供的所有邊界都是 8dp 的因數,可協助您的檢視畫面對齊 Material Design 的 8dp 方格建議。

使用鏈結控制線性群組

圖 17. 包含兩個檢視畫面的水平鏈結。

鏈結是藉由雙向位置限制條件互相連結的一組檢視畫面。鏈結中的檢視畫面可以垂直或水平分布。

圖 18. 各個鏈結樣式的示例。

您可以使用下列任一方式設定鏈條的樣式:

  1. 散布:系統會在考量邊界後,平均分配檢視畫面。此為預設值。
  2. 內部散布:第一個和最後一個檢視畫面會固定在鏈結兩端的限制條件上,其餘的則平均分配。
  3. Weighted:如果鏈結設為「spread」或「spread inside」,您可以將一個或多個檢視畫面設為「match constraints」(0dp),填滿剩餘空間。根據預設,系統會將空間平均分配給設為「match constraints」的每個檢視畫面,但您可以使用 layout_constraintHorizontal_weightlayout_constraintVertical_weight 屬性,為每個檢視畫面指派重要性權重。這與線性版面配置中的 layout_weight 運作方式相同:權重值最高的檢視區塊會獲得最多空間,而權重相同的檢視區塊會獲得相同的空間。
  4. Packed:系統會在計算邊距後將檢視區塊排列在一起。您可以變更鏈條的「頭部」檢視偏差,調整整個鏈條的偏差,例如向左或向右、向上或向下。

鏈結的「頭部」檢視畫面 (水平鏈結中最左邊的檢視畫面,在由左至右的版面配置中) 和垂直鏈結中最上方的檢視畫面,會在 XML 中定義鏈結的樣式。不過,您可以選取鏈結中的任何檢視畫面,然後按一下檢視畫面下方顯示的鏈結按鈕 ,即可在「散布」、「散布內部」和「擠壓」之間切換。

如要建立鏈結,請按照影片 4 中的說明操作:

  1. 選取要納入鏈結的所有檢視畫面。
  2. 在其中一個檢視畫面上按一下滑鼠右鍵。
  3. 選取「連鎖店」
  4. 選取「水平置中」或「垂直置中」

影片 4. 建立水平鏈結。

使用鏈結時,請考量以下幾點:

  • 檢視畫面可同時是水平和垂直鏈結的一部分,因此您可以建立彈性的格狀版面配置。
  • 只有在鏈條的兩端都受到同一軸上其他物件的約束時,鏈條才能正常運作,如圖 14 所示。
  • 雖然鏈結的方向是垂直或水平,但使用鏈結不會將檢視畫面對齊該方向。如要讓鏈結中每個檢視畫面都顯示在適當位置,請加入其他限制,例如對齊限制

自動建立限制

您可以將每個檢視區塊移至版面配置編輯器中所需的位置,然後按一下「推斷限制」 自動建立限制,而非在將檢視區塊放入版面配置時為每個檢視區塊新增限制。

「推斷限制條件」會掃描版面配置,為所有檢視畫面找出最有效的限制條件組合。它會將檢視畫面限制在目前位置,同時提供彈性。您可能需要進行調整,讓版面配置能夠根據不同螢幕大小和方向做出回應。

您可以啟用「自動連結上層版面」這項獨立功能。啟用這項功能後,如果您將子項檢視區塊新增至父項,這項功能會在您將檢視區塊新增至版面配置時,為每個檢視區塊自動建立兩個或更多約束條件,但只有在適合將檢視區塊約束至父項版面配置時才會如此。Autoconnect 不會在版面配置中為其他檢視區塊建立限制條件。

自動連線功能預設為停用。如要啟用此功能,請按一下「Layout Editor」(版面配置編輯器) 工具列中的「Enable Autoconnection to Parent」(啟用自動連結上層版面功能) 圖示

主要畫面格動畫

ConstraintLayout 中,您可以使用 ConstraintSetTransitionManager 為元素的大小和位置變更製作動畫。

ConstraintSet 是輕量物件,可代表 ConstraintLayout 中所有子項元素的限制條件、邊界和邊框間距。將 ConstraintSet 套用至顯示的 ConstraintLayout 時,版面配置會更新所有子項的限制。

如要使用 ConstraintSet 建立動畫,請指定兩個版面配置檔案,做為動畫的起始和結束主要畫面格。接著,您可以從第二個關鍵影格檔案載入 ConstraintSet,並將其套用至顯示的 ConstraintLayout

以下程式碼範例說明如何將單一按鈕動畫效果移至螢幕底部。

// MainActivity.kt

fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.keyframe_one)
    constraintLayout = findViewById(R.id.constraint_layout) // member variable
}

fun animateToKeyframeTwo() {
    val constraintSet = ConstraintSet()
    constraintSet.load(this, R.layout.keyframe_two)
    TransitionManager.beginDelayedTransition()
    constraintSet.applyTo(constraintLayout)
}
// layout/keyframe1.xml
// Keyframe 1 contains the starting position for all elements in the animation
// as well as final colors and text sizes.

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
// layout/keyframe2.xml
// Keyframe 2 contains another ConstraintLayout with the final positions.

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

其他資源

ConstraintLayout 用於 Sunflower 試用版應用程式。