ABOUT ME

-

  • Android) Compose의 ConstraintLayout
    Android 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)
            }
        }
    }
    반응형

    댓글

Designed by Me.