Compose 中的 ConstraintLayout

ConstraintLayout 可 協助 將 可組合的 相對 其他人 置於 螢幕上, 也可以 同時 使用 多個 巢狀 RowColumnBox 和 自訂 配置 元素。 當 實作 較 大的 配置 有 較 複雜 的 對準 要求 時, ConstraintLayout 很有用。

欲 在 Compose 中 使用 ConstraintLayout, 您 必須 在 build.gradle 中 加入 這個 依附元件:

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02"
增進 可讀性 和 維護性。

Compose 中的 ConstraintLayout 適用於 DSL

  • 參考 是 為了 使用 createRefs()createRefFor() 而建立的, 而且 ConstraintLayout 中的 每個 可組合 都需要 相關的 參考資料。
  • 限制 是透過 constrainAs() 調節器 提供, 將 參考資料 視為 參數, 並且 讓 您 在 lambda 中 指定 它的 限制。
  • 限制 是透過 linkTo() 或其他 有幫助的 方式 指定。
  • parent 是 現有 參考資料, 可 用來 指定 ConstraintLayout 可組合 本身 所適用的 限制。

以下 是 使用 ConstraintLayout 的 可組合 範例:

@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        // Create references for the composables to constrain
        val (button, text) = createRefs()

        Button(
            onClick = { /* Do something */ },
            // Assign reference "button" to the Button composable
            // and constrain it to the top of the ConstraintLayout
            modifier = Modifier.constrainAs(button) {
                top.linkTo(parent.top, margin = 16.dp)
            }
        ) {
            Text("Button")
        }

        // Assign reference "text" to the Text composable
        // and constrain it to the bottom of the Button composable
        Text("Text", Modifier.constrainAs(text) {
            top.linkTo(button.bottom, margin = 16.dp)
        })
    }
}

這個 程式碼 會限制 Button 的上層 與 16.dp 形成 邊界, 然後 Text 連結 Button 的 底部 也與 16.dp 形成 邊界。

顯示 安排在 ConstraintLayout 中的 按鈕 和 文字 元素

如需 更多 有關 使用 ConstraintLayout 的範例, 請嘗試 配置CodeLab

解耦 API

ConstraintLayout 例子中, 限制 是與 他們 應用的 可組成中的 調節器 內嵌式 指定的。 但是, 在某些情況下, 最好 將限制 與 所套用的 配置 分離。 例如, 您 可能 想要 根據 畫面 設定 或是 兩個 限制 集合 之間的 動畫 來變更 限制。

對於 這樣 的案例, 您 可以 透過 不同 方式 使用 ConstraintLayout

  1. ConstraintSet 做為 參數 傳遞 給 ConstraintLayout
  2. 指派 在 ConstraintSet 創建的 參考, 以 組合 使用 layoutId 調節器。
@Composable
fun DecoupledConstraintLayout() {
    BoxWithConstraints {
        val constraints = if (minWidth < 600.dp) {
            decoupledConstraints(margin = 16.dp) // Portrait constraints
        } else {
            decoupledConstraints(margin = 32.dp) // Landscape constraints
        }

        ConstraintLayout(constraints) {
            Button(
                onClick = { /* Do something */ },
                modifier = Modifier.layoutId("button")
            ) {
                Text("Button")
            }

            Text("Text", Modifier.layoutId("text"))
        }
    }
}

private fun decoupledConstraints(margin: Dp): ConstraintSet {
    return ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        constrain(button) {
            top.linkTo(parent.top, margin = margin)
        }
        constrain(text) {
            top.linkTo(button.bottom, margin)
        }
    }
}

然後, 如果 您 需要 變更 限制, 只要 傳遞 不同的 ConstraintSet 即可。

瞭解詳情

在 Jetpack Compose codelab的 ConstraintLayout的部分,進一步瞭解 Compose 中的 ConstraintLayout, 以及 在用了 ConstraintLayoutCompose 範例中 查看 API的行動。