본문 바로가기
카테고리 없음

SubcomposeLayout

by h4r3 2025. 1. 19.
반응형

SubcomposeLayout란?

SubcomposeLayout은 Jetpack Compose에서 제공하는 고급 레이아웃 API로, 레이아웃의 일부 요소를 먼저 측정하고, 이 정보를 바탕으로 다른 요소를 측정하거나 배치할 수 있도록 설계된 커스텀 레이아웃입니다.

보통 Compose의 레이아웃은 모든 자식 요소를 동시에 측정하고 배치합니다. 하지만 **SubcomposeLayout**은 이런 일반적인 흐름을 벗어나 순차적인 측정 및 배치가 필요한 복잡한 레이아웃에 적합합니다.


왜 SubcomposeLayout이 필요한가?

  1. 순차적인 측정
    일부 요소의 크기나 배치 정보가 다른 요소를 측정하거나 배치하는 데 필요할 때.
  2. 동적 레이아웃
    예를 들어, 특정 UI 요소의 크기를 기반으로 다른 요소를 배치해야 하는 경우.
  3. 레이아웃 최적화
    특정 요소를 조건부로 렌더링하거나, 필요한 요소만 측정/배치하여 성능을 최적화할 수 있음.

사용법

SubcomposeLayout은 기본적으로 다음 단계를 따릅니다:

  1. subcompose: 특정 키로 자식 컴포저블을 정의.
  2. measure: 자식의 크기를 측정.
  3. layout: 부모 레이아웃의 크기를 정의하고 자식을 배치.

기본 코드 예제

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.dp

@Composable
fun ExampleSubcomposeLayout() {
    SubcomposeLayout { constraints ->
        // Step 1: 첫 번째 컴포저블을 측정
        val headerPlaceable = subcompose("header") {
            Box(
                modifier = Modifier
                    .background(Color.Blue)
                    .height(50.dp)
            )
        }.first().measure(constraints)

        // Step 2: 두 번째 컴포저블을 측정
        val contentPlaceable = subcompose("content") {
            Box(
                modifier = Modifier
                    .background(Color.Red)
                    .height(100.dp)
            )
        }.first().measure(constraints)

        // Step 3: 전체 레이아웃 크기 결정 및 자식 배치
        layout(constraints.maxWidth, headerPlaceable.height + contentPlaceable.height) {
            headerPlaceable.place(0, 0)
            contentPlaceable.place(0, headerPlaceable.height)
        }
    }
}

코드 설명

  1. subcompose("header")
    • "header"라는 키를 사용해 헤더 컴포저블을 정의.
    • 이 키는 중복을 방지하고 특정 요소를 재구성할 때 활용.
  2. measure(constraints)
    • 헤더와 콘텐츠를 부모의 제약 조건에 맞춰 측정.
    • 크기를 결정하고 Placeable 객체로 반환.
  3. layout(width, height)
    • 부모 레이아웃의 전체 크기를 결정.
    • 각 자식 요소를 특정 위치에 배치.

실제 사용 예시

상황 1: 자식 크기에 따라 레이아웃 동기화

@Composable
fun SyncSizeExample() {
    SubcomposeLayout { constraints ->
        // Box2 측정
        val box2Placeable = subcompose("Box2") {
            Box(
                modifier = Modifier
                    .background(Color.Green)
                    .height(60.dp)
            )
        }.first().measure(constraints)

        // Box1 측정, 크기를 Box2에 맞춤
        val box1Placeable = subcompose("Box1") {
            Box(
                modifier = Modifier
                    .background(Color.Yellow)
                    .height(box2Placeable.height.toDp()) // Box2의 높이에 맞춤
            )
        }.first().measure(constraints)

        // 전체 레이아웃 크기 결정 및 배치
        layout(constraints.maxWidth, box1Placeable.height + box2Placeable.height) {
            box1Placeable.place(0, 0)
            box2Placeable.place(0, box1Placeable.height)
        }
    }
}

장단점

장점

  • 순차적인 측정 및 배치 가능.
  • 요소 간의 의존 관계가 있는 복잡한 레이아웃에 유용.
  • 특정 요소를 조건부로 렌더링해 성능 최적화 가능.

단점

  • 코드가 복잡해질 수 있음.
  • 간단한 레이아웃에서는 불필요한 오버헤드.

SubcomposeLayout vs 일반 레이아웃

특징 일반 레이아웃 SubcomposeLayout

측정 순서 모든 자식 동시에 측정 순차적으로 측정 가능
유연성 제한적 매우 유연
성능 간단한 레이아웃에서 더 빠름 복잡한 레이아웃에 최적화
코드 복잡도 간단 복잡해질 가능성

언제 사용해야 할까?

  • UI 요소 간 크기 또는 위치 의존성이 있는 복잡한 레이아웃.
  • 성능을 최적화하거나, 순차적인 측정/배치가 필수인 경우.

예:

  • Box2의 크기에 따라 Box1을 동기화해야 하는 경우.
  • 동적으로 크기가 변하는 UI 컴포넌트.

 

반응형