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

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

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

版面配置編輯器的視覺工具可直接存取 ConstraintLayout 的所有功能,因為版面配置 API 和版面配置編輯器是專為彼此建構而成。您可以使用 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. 輸入版面配置檔案的名稱,並在「Root Tag」中輸入「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 偏移對齊方式。偏移量是由受限檢視畫面的邊界定義。

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

圖 9.水平對齊限制。

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

基準對齊

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

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

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

圖 11. 基準對齊限制。

限制符合準則

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

如要建立引導線,請按一下工具列中的「Guidelines」 然後點選「Add Vertical Guideline」或「Add Horizontal Guideline」

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

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

限制到障礙

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

舉例來說,在圖 13 中,檢視區塊 C 會受到限制,只能顯示在區隔區的右側。將邊界設為檢視畫面 A 和 B 的「end」(或從左到右版面配置的右側)。視檢視畫面 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. 選取檢視畫面時,「屬性」視窗會提供下列控制項: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 比例。

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

舉例來說,如果您將兩側設為「比對限制」,請按一下「Toggle 長寬比限制」兩次,即可將寬度設為高度的比例。整個大小取決於檢視區塊的高度,而高度可以以任何方式定義,如圖 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 試用版應用程式。