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
Row, Column, Box, i innych niestandardowych elementów układu.
W systemie View ConstraintLayout był zalecanym sposobem tworzenia dużych i złożonych układów, ponieważ płaska hierarchia widoków była wydajniejsza niż zagnieżdżone widoki. Nie jest to jednak problem w Compose, który może efektywnie obsługiwać głębokie hierarchie układów, więc ConstraintLayout nie jest tak korzystny.
Rozpoczęcie pracy z ConstraintLayout
Aby używać ConstraintLayout w Compose, musisz dodać tę zależność w pliku
build.gradle (oprócz konfiguracji Compose):
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
ConstraintLayout w Compose działa w ten sposób, że używa
DSL:
- Utwórz odniesienia do każdego elementu kompozycyjnego w
ConstraintLayoutza pomocącreateRefs()lubcreateRefFor(). - Ograniczenia są podawane za pomocą modyfikatora
constrainAs(), który przyjmuje odniesienie jako parametr i umożliwia określenie jego ograniczeń w lambdzie treści. - Ograniczenia są określane za pomocą
linkTo()lub innych przydatnych metod. parentto istniejące odniesienie, którego można użyć do określenia ograniczeń względem samego elementu kompozycyjnegoConstraintLayout.
Oto przykład elementu kompozycyjnego używającego 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ź Button do elementu nadrzędnego z marginesem 16.dp, a Text do dolnej krawędzi Button również z marginesem 16.dp.
Button i Text ograniczone względem siebie w
ConstraintLayout.
Oddzielony interfejs API
W przykładzie ConstraintLayout ograniczenia są określane w tekście za pomocą modyfikatora w elemencie kompozycyjnym, do którego są stosowane. W pewnych sytuacjach lepiej jest jednak oddzielić ograniczenia od układów, do których są stosowane.
Możesz na przykład chcieć zmienić ograniczenia na podstawie konfiguracji ekranu lub animować przejścia między 2 zestawami ograniczeń.
W takich przypadkach możesz użyć ConstraintLayout w inny sposób:
- Przekaż
ConstraintSetjako parametr doConstraintLayout. - Przypisz odniesienia utworzone w
ConstraintSetdo elementów kompozycyjnych za pomocąlayoutIdmodyfikatora.
@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) } } }
Gdy trzeba zmienić ograniczenia, wystarczy przekazać inny ConstraintSet.
Pojęcia związane z ConstraintLayout
ConstraintLayout zawiera takie pojęcia jak linie pomocnicze, bariery i łańcuchy, które mogą pomóc w pozycjonowaniu elementów w elemencie kompozycyjnym.
Linie pomocnicze
Linie pomocnicze to małe wizualne elementy pomocnicze do projektowania układów. Elementy kompozycyjne można ograniczyć do linii pomocniczej. Linie pomocnicze są przydatne do pozycjonowania elementów w a
certain dp or percentage inside the parent composable.
Istnieją 2 rodzaje linii pomocniczych: pionowe i poziome. 2 poziome to top i bottom, a 2 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ć linię pomocniczą, użyj createGuidelineFrom* z wymaganym typem linii pomocniczej. Spowoduje to utworzenie odniesienia, 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 odniesienia, które mają tworzyć barierę.
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val topBarrier = createTopBarrier(button, text) } }
Barierę można następnie użyć w bloku Modifier.constrainAs().
Łańcuchy
Ł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ńcuch można następnie użyć w bloku Modifier.constrainAs().
Łańcuch można skonfigurować za pomocą różnych ChainStyles, które określają, jak
postępować z miejscem otaczającym element kompozycyjny, np.:
ChainStyle.Spread: miejsce jest równomiernie rozłożone na wszystkie elementy kompozycyjne, w tym wolne miejsce przed pierwszym elementem kompozycyjnym i po ostatnim.ChainStyle.SpreadInside: miejsce jest równomiernie rozłożone na wszystkie elementy kompozycyjne, bez wolnego miejsca przed pierwszym elementem kompozycyjnym i po ostatnim.ChainStyle.Packed: miejsce jest rozłożone przed pierwszym i po ostatnim elementem kompozycyjnym, a elementy kompozycyjne są spakowane bez miejsca między nimi.