Android

Android) Compose의 ConstraintLayout

가짜 개발자 2022. 6. 1. 19:35


 

기존의 안드로이드에서 레이아웃의 중첩된 계층 구조의 성능을 개선하기 위해 ConstaintLayout을 사용했습니다.

Compose에서는 measure를 한 번만 하기 때문에 ConstraintLayout의 성능상 이점이 필요 없습니다. 

다만, 개인적으로 뷰를 짜게 될 때 여전히 ConstraintLayout이 편하다는 생각이 들었습니다.

 

build.gradle

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

 

 

Compose-ConstrainLayout

  • Compose-ConstratinLayout은 Kotlin DSL(Domain Specific Language)와 함께 작동합니다.
  • ID를 생성하여 이를 참조하여 뷰의 배치를 구성할 수 있습니다.
  • ModifierconstraintAs()를 사용하여 생성한 ID를 Compose로 사용할 수 있습니다.
  • ID를 하나를 생성하려면 createRef()로 생성합니다. 여러 ID를 생성하려면 createRefs()로 생성합니다.
  • 기존의 ContsraintLayoutapp:layout_constraintTop_toTopOf 처럼 뷰들의 ID를 참조하여 연결하는 방식을 Compose-ConstraintLayout에서 linkTo를 통해 사용합니다.

 

@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        // 참조할 ID 생성.
        val (button, text) = createRefs()

        Button(
            onClick = { /* Do something */ },
            modifier = Modifier.constrainAs(button) {
            	// linkTo를 통해 button의 top을 parent의 top에 오게한다. 
            	// parent의 top을 기준으로 16.dp 마진
                top.linkTo(parent.top, margin = 16.dp) 
            }
        ) {
            Text("Button")
        }

        Text("Text", Modifier.constrainAs(text) {
        	// text의 top을 button의 bottom에 오게 한다.
            // button의 bottom을 기준으로 16.dp 마진
            top.linkTo(button.bottom, margin = 16.dp) 
        })
    }
}

 

 

  • Text를 중앙에 배치하려면, centerHorizontallyTo를 사용합니다.
  • 다만, Text를 centerHorizontallyTo parent로 줬는데, Button 기준으로 중앙에 배치된 것처럼 보입니다.
  • 이는 자식 Composables를 표현할 수 있는 최소한의 크기만을 사용하기 때문입니다.
  • 전체 화면으로 확장해서 사용하려면 Modifier fillMaxSize, size 등을 사용하면 됩니다.

 

@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        ... 

        Text("Text", Modifier.constrainAs(text) {
            top.linkTo(button.bottom, margin = 16.dp)
            centerHorizontallyTo(parent)
        })
    }
}

 

 

분리된 API

  • 화면 구성에 따라 다르게 ConstraintLayout을 구성할 때 이를 분리시켜 사용할 수 있습니다.
  • ConstraintSetConstraintLayout 생성 시 파라미터로 전달합니다.
  • ConstraintLayout에서는 ConstraintSet에서 정의해놓은 구성에서 ID만 입력해 사용할 수 있습니다. 
@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)
        }
    }
}
반응형