Układ ograniczeń w tworzeniu

ConstraintLayout to układ, który pozwala na umieszczanie funkcji kompozycyjnych względem innych elementów kompozycyjnych na ekranie. Jest alternatywą dla używania wielu zagnieżdżonych elementów Row, Column, Box i innych niestandardowych elementów układu. Parametr ConstraintLayout przydaje się przy wdrażaniu większych układów z bardziej skomplikowanymi wymaganiami dotyczącymi dopasowania.

Rozważ użycie właściwości ConstraintLayout w tych sytuacjach:

  • Aby uniknąć zagnieżdżania wielu elementów Column i Row na potrzeby określania pozycji elementów na ekranie, co poprawia czytelność kodu.
  • Pozycjonowanie tych kompozycyjnych względem innych kompozycji lub ich pozycjonowanie na podstawie wskazówek, barier bądź łańcuchów.

W systemie widoków zalecanym sposobem tworzenia dużych i złożonych układów jest ConstraintLayout, ponieważ płaska hierarchia widoków zapewnia większą wydajność niż widoki zagnieżdżone. Nie dotyczy to jednak funkcji tworzenia, która efektywnie obsługuje precyzyjne hierarchie układów.

Rozpocznij korzystanie z usługi ConstraintLayout

Aby używać ConstraintLayout w usłudze Compose, musisz dodać tę zależność do build.gradle (oprócz konfiguracji tworzenia):

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"

Tag ConstraintLayout w usłudze Utwórz działa w ten sposób z użyciem DSL:

  • Utwórz odwołania dla każdego elementu kompozycyjnego w elemencie ConstraintLayout za pomocą createRefs() lub createRefFor()
  • Ograniczenia są podawane za pomocą modyfikatora constrainAs(), który przyjmuje odwołanie jako parametr i umożliwia określenie jego ograniczeń w obiekcie lambda.
  • Ograniczenia są określane za pomocą atrybutu linkTo() lub innych przydatnych metod.
  • parent to istniejące odwołanie, za pomocą którego można określić ograniczenia dotyczące samego elementu kompozycyjnego ConstraintLayout.

Oto przykład funkcji kompozycyjnej z użyciem klasy 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ą część elementu Button do jednostki nadrzędnej z marginesem 16.dp i Text do dołu elementu Button również z marginesem 16.dp.

Wyświetla przycisk i element tekstowy rozmieszczone w układzie ograniczeń

Odłączony interfejs API

W przykładzie ConstraintLayout ograniczenia są określone w tekście, a modyfikator w komponencie, do którego są stosowane. W niektórych sytuacjach korzystne jest jednak odłączenie ograniczeń od układów, do których mają zastosowanie. Możesz na przykład zmienić ograniczenia na podstawie konfiguracji ekranu lub utworzyć animację między 2 zestawami ograniczeń.

W takich przypadkach możesz używać usługi ConstraintLayout w inny sposób:

  1. Przekaż ConstraintSet jako parametr do ConstraintLayout.
  2. Przy użyciu modyfikatora layoutId przypisz do funkcji kompozycyjnych odwołania utworzone w ConstraintSet.

@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)
        }
    }
}

Następnie, gdy zajdzie potrzeba zmiany ograniczeń, możesz przekazać inny obiekt ConstraintSet.

Pojęcia związane z: ConstraintLayout

ConstraintLayout zawiera takie pojęcia jak wytyczne, bariery i łańcuchy, które mogą pomóc w rozmieszczaniu elementów w funkcji kompozycyjnej.

Wskazówki

Wskazówki to niewielkie pomoce wizualne przy projektowaniu układów. Pliki kompozycyjne można ograniczać do jednej wskazówki. Przydają się wskazówki dotyczące umieszczania elementów w określonym elemencie dp lub percentage w nadrzędnym elemencie kompozycyjnym.

Są 2 rodzaje wytycznych: pionowe i poziome. 2 poziome to top i bottom, a 2 – 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 atrybutu createGuidelineFrom* z odpowiednim typem wskazówki. Spowoduje to utworzenie odwołania, którego można użyć w bloku Modifier.constrainAs().

Barierki

Bariery odwołują się do wielu funkcji kompozycyjnych, aby utworzyć wirtualną wskazówkę opartą na najbardziej ekstremalnym widżecie po określonej stronie.

Aby utworzyć barierę, użyj createTopBarrier() (lub: createBottomBarrier(), createEndBarrier(), createStartBarrier()) i podaj pliki referencyjne, które powinny stanowić barierę.

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val topBarrier = createTopBarrier(button, text)
    }
}

Bariery można użyć w bloku typu Modifier.constrainAs().

Łańcuchy

Łańcuchy pozwalają na zachowanie grupy na jednej osi (poziomo lub pionowo). Drugą oś można blokować niezależnie.

Aby utworzyć sieć, użyj opcji 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że być użyty w bloku Modifier.constrainAs().

Łańcuch można skonfigurować za pomocą różnych elementów ChainStyles, które określają sposób postępowania z pokojem otaczającym funkcję kompozycyjną, takim jak:

  • ChainStyle.Spread: odstęp jest równomiernie rozkładany wśród wszystkich funkcji kompozycyjnych, łącznie z wolnym miejscem przed pierwszym i po ostatnim.
  • ChainStyle.SpreadInside: odstęp jest równomiernie rozkładany w elementach kompozycyjnych, bez wolnego miejsca przed pierwszym i po ostatnim elemencie kompozycyjnym.
  • ChainStyle.Packed: element kompozycyjny jest rozmieszczony przed pierwszym i po ostatnim elemencie kompozycyjnym, bez odstępu między sobą.

Więcej informacji

Więcej informacji o ConstraintLayout w Compose z interfejsów API w działaniu znajdziesz w przykładach tworzenia wiadomości używających ConstraintLayout.