ConstraintLayout to układ, który umożliwia umieszczanie elementów kompozycyjnych względem innych elementów kompozycyjnych na ekranie. Jest to alternatywa dla używania wielu zagnieżdżonych elementów Row, Column, Box i innych niestandardowych elementów układu.
W systemie widoków ConstraintLayout był zalecanym sposobem tworzenia dużych i złożonych układów, ponieważ płaska hierarchia widoków była lepsza pod względem wydajności niż widoki zagnieżdżone. Nie jest to jednak problemem w Compose, który może skutecznie obsługiwać głębokie hierarchie układu, więc ConstraintLayout nie jest tak korzystny.
Rozpocznij korzystanie z usługi ConstraintLayout
Aby używać ConstraintLayout w Compose, musisz dodać tę zależność w build.gradle (oprócz konfiguracji Compose):
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
ConstraintLayout w Compose działa w następujący sposób przy użyciu DSL:
- Utwórz odwołania do każdego elementu kompozycyjnego w
ConstraintLayoutza pomocącreateRefs()lubcreateRefFor(). - Ograniczenia są podawane za pomocą modyfikatora
constrainAs(), który przyjmuje odwołanie jako parametr i umożliwia określenie ograniczeń w treści lambda. - Ograniczenia są określane za pomocą
linkTo()lub innych przydatnych metod. parentto istniejący element referencyjny, którego można użyć do określenia ograniczeń dotyczących samego elementu kompozycyjnegoConstraintLayout.
Oto przykład funkcji kompozycyjnej, która używa 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) } ) } }
Ten kod ogranicza górną krawędź elementu Button do elementu nadrzędnego z marginesem 16.dp i elementu Text do dolnej krawędzi elementu Button, również z marginesem 16.dp.
Button i Text ograniczone względem siebie w ConstraintLayout.
Odłączony interfejs API
W przykładzie ConstraintLayout ograniczenia są określone w tekście za pomocą modyfikatora w funkcji kompozycyjnej, do której są stosowane. Są jednak sytuacje, w których lepiej jest oddzielić ograniczenia od układów, do których się odnoszą.
Możesz na przykład zmienić ograniczenia na podstawie konfiguracji ekranu lub animować przejście między 2 zestawami ograniczeń.
W takich przypadkach możesz użyć ConstraintLayout w inny sposób:
- Przekaż
ConstraintSetjako parametr doConstraintLayout. - Przypisz referencje utworzone w
ConstraintSetdo funkcji kompozycyjnych za pomocą modyfikatoralayoutId.
@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) } } }
Jeśli chcesz zmienić ograniczenia, możesz po prostu przekazać inny obiekt ConstraintSet.
ConstraintLayout koncepcje
ConstraintLayout zawiera takie koncepcje jak linie pomocnicze, bariery i łańcuchy, które mogą pomóc w pozycjonowaniu elementów w komponowalnym elemencie interfejsu.
Wskazówki
Prowadnice to niewielkie elementy wizualne, które pomagają w projektowaniu układów. Elementy kompozycyjne można
ograniczyć do linii pomocniczej. Linie pomocnicze są przydatne do pozycjonowania elementów w określonym miejscu dp lub percentage wewnątrz nadrzędnego elementu kompozycyjnego.
Istnieją 2 rodzaje linii pomocniczych: pionowe i poziome. Dwa poziome to top i bottom, a dwa pionowe to start i end.
ConstraintLayout { // Create guideline from the start of the parent at 10% the width of the Composable val startGuideline = createGuidelineFromStart(0.1f) // Create guideline from the end of the parent at 10% the width of the Composable val endGuideline = createGuidelineFromEnd(0.1f) // Create guideline from 16 dp from the top of the parent val topGuideline = createGuidelineFromTop(16.dp) // Create guideline from 16 dp from the bottom of the parent val bottomGuideline = createGuidelineFromBottom(16.dp) }
Aby utworzyć wytyczne, użyj createGuidelineFrom* z wymaganym typem wytycznych. Spowoduje to utworzenie odwołania, którego można użyć w bloku Modifier.constrainAs().
Bariery
Bariery odwołują się do wielu elementów kompozycyjnych, aby utworzyć wirtualną linię pomocniczą na podstawie najbardziej skrajnego widżetu po określonej stronie.
Aby utworzyć barierę, użyj createTopBarrier() (lub: createBottomBarrier(), createEndBarrier(), createStartBarrier()) i podaj odwołania, które powinny tworzyć barierę.
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val topBarrier = createTopBarrier(button, text) } }
Barierę można następnie wykorzystać w bloku Modifier.constrainAs().
Sieci
Łańcuchy zapewniają zachowanie podobne do grupy w jednej osi (poziomej lub pionowej). Drugą oś można ograniczyć niezależnie.
Aby utworzyć łańcuch, użyj createVerticalChain lub createHorizontalChain:
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread) val horizontalChain = createHorizontalChain(button, text) } }
Łańcucha można następnie użyć w bloku Modifier.constrainAs().
Łańcuch można skonfigurować z różnymi ChainStyles, które określają, jak postępować z przestrzenią wokół elementu kompozycyjnego, np.:
ChainStyle.Spread: przestrzeń jest równomiernie rozłożona między wszystkimi elementami kompozycyjnymi, w tym wolna przestrzeń przed pierwszym elementem kompozycyjnym i po ostatnim elemencie kompozycyjnym.ChainStyle.SpreadInside: przestrzeń jest równomiernie rozłożona między wszystkimi elementami kompozycyjnymi, bez wolnego miejsca przed pierwszym elementem kompozycyjnym ani po ostatnim.ChainStyle.Packed: odstęp jest rozłożony przed pierwszym i po ostatnim elemencie kompozycyjnym, elementy kompozycyjne są spakowane razem bez odstępów między nimi.