Compose의 ConstraintLayout

ConstraintLayout은 화면에 다른 요소를 기준으로 컴포저블을 배치하는 데 도움이 될 수 있으며 중첩된 여러 Row, Column, Box 및 맞춤 레이아웃 요소 대신 사용할 수 있습니다. ConstraintLayout은 더 복잡한 정렬 요구사항이 있는 더 큰 레이아웃을 구현할 때 유용합니다.

Compose에서 ConstraintLayout을 사용하려면 build.gradle에 이 종속 항목을 추가해야 합니다.

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02"

다음과 같이 Compose의 ConstraintLayoutDSL과 함께 작동합니다.

  • 참조는 createRefs() 또는 createRefFor()를 사용하여 생성되며 ConstraintLayout의 각 컴포저블에는 연결된 참조가 있어야 합니다.
  • 제약 조건은 constrainAs() 수정자를 사용하여 제공됩니다. 이 수정자는 참조를 매개변수로 사용하고 본문 람다에 제약 조건을 지정할 수 있게 합니다.
  • 제약 조건은 linkTo() 또는 다른 유용한 메서드를 사용하여 지정됩니다.
  • parentConstraintLayout 컴포저블 자체에 대한 제약 조건을 지정하는 데 사용할 수 있는 기존 참조입니다.

다음은 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를 여백이 16.dpButton의 하단으로 제한합니다.

ConstraintLayout에 정렬된 버튼 및 텍스트 요소 예

ConstraintLayout을 사용하는 방법에 관한 더 많은 예를 보려면 레이아웃 Codelab을 사용해 보세요.

분리된 API

ConstraintLayout 예에서 제약 조건은 적용되는 컴포저블의 수정자와 함께 인라인으로 지정됩니다. 그러나 제약 조건이 적용되는 레이아웃에서 제약 조건을 분리하는 것이 더 좋은 상황이 있습니다. 예를 들어 화면 구성을 기반으로 제약 조건을 변경하거나 두 제약 조건 세트 사이에 애니메이션을 적용할 수 있습니다.

이 같은 경우에는 ConstraintLayout을 서로 다른 방식으로 사용할 수 있습니다.

  1. ConstraintSet을 매개변수로 ConstraintLayout에 전달합니다.
  2. layoutId 수정자를 사용하여 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)
        }
    }
}

그러면 제약 조건을 변경해야 할 때 다른 ConstraintSet을 전달하기만 하면 됩니다.

자세히 알아보기

Jetpack Compose 레이아웃 Codelab의 제약 조건 레이아웃 섹션에서 Compose의 ConstraintLayout에 관해 자세히 알아보고 ConstraintLayout을 사용하는 Compose 샘플에서 작동 중인 API를 확인하세요.