Glacier's Daily Log

[Android] Compose의 SubcomposeLayout이란? 본문

카테고리 없음

[Android] Compose의 SubcomposeLayout이란?

h__glacier_ 2025. 11. 13. 20:24
반응형

SubcomposeLayout이란?

SubcomposeLayout은 Jetpack Compose의 레이아웃 API.

컴포저블을 순차적으로 측정하고, 측정 결과를 바탕으로 다른 컴포저블의 크기를 결정할 수 있다.

일반적인 Compose의 문제점(?)

일반적으로 Compose는 모든 컴포저블을 동시에 측정함. 예를 들어:

  • 배경 Box와 텍스트가 동시에 측정됨
  • 텍스트 높이를 모르는 상태에서 배경 높이를 결정해야 함
  • onSizeChanged는 측정 후에 호출되어 리컴포지션이 필요함

SubcomposeLayout을 통한 해결법

SubcomposeLayout은 측정 순서를 제어할 수 있음:

  1. 먼저 텍스트를 측정해 높이를 얻음
  2. 그 높이로 배경 높이를 계산
  3. 계산된 높이로 배경을 측정
  4. 최종적으로 배치

현업에서 SubcomposeLayout으로 문제를 해결한 경험

문제 상황

  • 박스 위에 겹쳐있는 텍스트 위젯의 높이에따라, 박스 배경 높이가 달라져야 하는 상황.
  • 하지만 Column으로 묶여있거나 하는 상황이 아니기 때문에 두개 높이를 동기화하기 쉽지 않음

실패한 시도1

기존 코드는 onSizeChanged로 텍스트 높이를 측정해봄

Text(...)
    .onSizeChanged { size ->
        subtitleTextHeightDp = size.height.toDp()
    }

  • onSizeChanged는 측정 후 비동기로 호출됨
  • 프리뷰에서는 첫 렌더링 시 높이가 0으로 시작
  • 배경이 먼저 그려지고 텍스트 높이는 나중에 업데이트됨
    • 따라서 원하는 결과 (텍스트 높이에 맞춰 뒷 배경 높이가 동적으로 바뀌어야함) 가 나오지 않음

 

해결 방법: SubcomposeLayout 적용

1단계: 텍스트 먼저 측정

val textPlaceable = subcompose("text") {
    Text(
        text = panelCard.subTitle,
        style = XXXDesignSystemTypo.title01,
    )
}[0].measure(constraints)

subtitleTextHeightDp = textPlaceable.height.toDp()
  • subcompose("text"): 텍스트 컴포저블 생성
  • .measure(constraints): 실제 크기 측정
  • 측정된 높이를 변수에 저장

2단계: 배경 높이 계산 

val backgroundHeight = if (panelCard.subTitle.isNotEmpty()) {
    XXXDesignSystemSpacing.spacing24 + 
    subtitleTextHeightDp + 
    XXXDesignSystemSpacing.spacing20 + 
} else { 0.dp } + 104.dp - 15.dp
  • 측정된 텍스트 높이로 배경 높이 계산

3단계: 배경 레이아웃 측정

val backgroundPlaceable = subcompose("background") {
    Box(
        modifier = Modifier.height(backgroundHeight)  // 계산된 높이 사용
            .background(backgroundColor)
    )
}[0].measure(constraints.copy(maxHeight = backgroundHeightPx))

  • 계산된 높이로 배경 측정

4단계: 최종 배치 

layout(constraints.maxWidth, contentPlaceable.height) {
    backgroundPlaceable.placeRelative(0, 0)  // 배경을 먼저 배치
    textPlaceable.placeRelative(0, 0)    // 컨텐츠를 위에 배치
}
  • 배경과 컨텐츠를 같은 위치에 겹쳐 배치

요약

  1. 측정 순서 제어: 텍스트 → 배경 → 컨텐츠 순서로 측정
  2. 동기적 측정: onSizeChanged 대신 measure()로 즉시 높이 획득
  3. 프리뷰 호환성: 프리뷰에서도 첫 렌더링부터 정확한 높이 계산
반응형
Comments