개요
저번 글에는 Compose의 Layout에 대해서 다뤄봤습니다.
사실 SubComposeLayout을 다루기 위해서 먼저 Layout을 다뤄본 것입니다.
즉 SubComposeLayout을 이해하기 위해선 Compose의 Layout 과정을 숙지하고 있어야 합니다.
[Android] - Jetpack Compose Layout
취업 이후 첫 글인 것 같네요.개발 실력이 모자라 배우느라 바쁘기도 했지만, 개발 외적으로 회사의 프로세스를 적응하고 이해하는데 많은 시간을 쏟고 있는 요즘입니다. 최근엔 서서히 적응을
jja2han.tistory.com
단순한 레이아웃은 기본 제공 컴포저블(Row, Box, Column)이나 Layout 함수만으로 충분히 구현할 수 있습니다.
하지만 하위 레이아웃의 크기나 상태에 따라 상위 레이아웃이 다시 하위 레이아웃을 구성해야 하는 복잡한 상황에선 한계가 있습니다.
이를 해결하기 위해서 등장한 개념이 바로 SubComposeLayout입니다.
Layout과 SubComposeLayout의 차이를 살펴보기 전에 Layout에 대해 간단히 짚고 넘어가 보시죠.
Layout
Layout은 Compose UI 렌더링 과정(Composition -> Layout -> Draw)의 한 단계로,

각 UI 요소의 크기를 측정하고 위치를 배포하는 역할을 수행합니다.
조금 더 디테일하게 파고 들어가자면 Layout 함수는 이 과정에서 하위 레이아웃의 크기를 먼저 측정한 뒤, 상위 레이아웃이 배치 결정을 내립니다.
하지만 하위 레이아웃의 크기나 상위 레이아웃의 제약조건에 따라 하위 레이아웃을 다시 그려야 하는 경우는 기존 Layout만으로는 한계가 있습니다.
SubComposeLayout
SubComposeLayout은 Layout과 유사하지만, Measure 단계에서 별도의 Composition을 실행할 수 있는 Layout입니다.

Composition -> Layout -> Draw의 과정에서 별도의 Composition 단계가 끼어들 수 있습니다.
일반적인 Layout에서는 Single Composition이지만, SubComposeLayout에서는 Layout의 Measure 단계에서 필요한 만큼 하위 레이아웃을 동적으로 구성할 수 있고, 상위 레이아웃의 제약조건이나 측정 결과에 따라 하위 레이아웃을 유연하게 바꿀 수 있습니다.
핵심은 같은 컨텐츠를 여러 번 subcompose하여 각각 다른 조건으로 측정할 수 있다는 점입니다.
이를 통해 일반 Layout에선 불가능한 측정 -> 분석 -> 재측정 패턴을 구현할 수 있습니다.
이제 SubcomposeLayout을 사용하는 특별한 경우를 살펴보죠.
예제
BoxWithConstraints


content 블럭은 BoxWithConstraintScope를 이용하는데, 해당 스코프에선 제약사항과 최소, 최대 너비와 높이를 사용할 수 있습니다.
즉, BoxWithConstraints는 부모의 (최대/최소 크기) 정보를 자식 Composable에 제공하고, 자식의 UI를 동적으로 바꿀 수 있게 해 줍니다.
내부적으로는 SubcomposeLayout을 사용해 measure 단계에서 자식의 composition을 실행합니다.
부모의 제약조건이 결정된 뒤 자식의 composition이 구성되기에 자식은 부모 크기 정보를 바탕으로 UI를 그릴 수 있게 됩니다.

흐름은 다음과 같습니다.
- BoxWithConstraints가 배치될 공간의 constraints를 파악합니다.
- 부모의 (최대/최소 정보)를 subcomposition에서 자식 composable에 전달
- 자식 composable은 maxHeight 값을 읽어, 조건에 따른 composition을 실행
해당 요구사항은 Layout 함수로는 불가능합니다.
이유는 자식 트리가 이미 composition 된 이후 measure가 가능하기 때문에, 부모 크기에 따라 자식을 변경할 수 없기 때문입니다.
단계를 간단하게 요약하면 아래와 같은 그림이 되겠네요.

LazyRow - 아이템 높이 통일하기
다음과 같은 요구사항이 있습니다.

고정 높이로 합의가 되면 가장 이상적이지만,
만약 합의가 되지 않는다면 우리는 "실제로 그리기 전까지 각 아이템의 정확한 높이 중 가장 큰 높이"를 알아내야 하고,
이 값을 기반으로 모든 아이템의 높이를 맞춰주는 커스텀 레이아웃을 구현해야 합니다.
LazyColumn/LazyRow 등 Compose의 기본 Lazy 리스트는 아이템의 실제 높이를 미리 알 수 없습니다.
일반 Layout 함수로 이를 구현하려고 하면
- 모든 아이템을 한 번 측정해서 최대 높이를 구함
- 그 최대 높이로 모든 아이템을 다시 측정
하지만 Compose에서는 같은 Measurable을 두 번 측정할 수 없으므로 불가능합니다.
이럴 경우 SubComposeLayout은 효과적인 해결책이 될 수 있습니다.
측정 단계에서 자식 composable을 여러 번 composition 하고 측정할 수 있기 때문입니다.
- 모든 아이템을 한 번씩 측정해 개별 높이를 구함.
- 그중 최대 높이를 찾음
- 모든 아이템의 높이를 최대 높이로 재측정

각 아이템들의 높이를 가장 큰 높이로 맞추기 위해선 각 아이템의 높이 중 최대 높이를 구해야 합니다.
이후, LazyRow의 아이템의 높이를 maxHeight로 맞춰주고 layout 단계에서 배치를 해주면 끝입니다.
⛔️한계
불필요하게 많은 subcompositon을 남발하면 오버헤드가 발생할 수 있습니다.
아무래도 Layout 단계에서 추가로, composition 단계가 생기다 보니 당연한 결과입니다.
따라서 공식문서에서도, SubcomposeLayout을 언제 사용해야 하고, 필요하지 않은 상황이 무엇인지 분명하게 이해하는 것이 매우 중요하다고 합니다.
👌사용해야 하는 경우
자식의 composition이 다른 자식의 measure 결과에 의존하는 경우
- BoxWithConstraints
- 부모의 제약 조건과 그 값에 따라 자식 컴포저블의 구조를 다르게 함.
- LazyColumn / LazyRow
- 실제로 필요한 아이템만 동적으로 compose 해야 합니다.
- 이를 위해 SubComposeLayout을 사용해서 measure 단계에서 필요한 자식 composable을 Subcomposition
- 특정 자식 컴포저블의 measure 결과에 따라 다른 자식 composable의 표시 여부를 결정하는 경우
- 첫 번째 자식의 높이가 일정 값 이상일 때만 두 번째 자식을 보여주거나, 다른 UI를 구성할 경우
사실 공식문서는 여기까지 얘기를 하고 있지만, 저는 하나의 경우가 더 있다고 생각합니다.
자식의 measure가 다른 자식의 measure 결과에 따라 달라지는 경우
이 경우가 2-measure 문제를 해결하는 핵심 사용 사례입니다.
- 모든 아이템을 가장 큰/작은 아이템 크기로 통일
- 한 아이템의 크기를 기준으로 다른 아이템들 크기 조정
- 특정 기준에 따른 동적 크기 조정
일반 Layout에서는 single pass measure가 원칙이기 때문에, 2-measure 패턴은 SubComposeLayout이 해결책입니다.
❌사용하면 안 되는 경우
한 자식 컴포저블의 측정 결과가 다른 컴포저블의 크기를 정하는 데 필요한 경우
예를 들어 두 개의 Text중 더 긴 텍스트에 맞춰 둘 다 같은 높이로 만들고 싶은 요구사항이 있습니다.

이런 단순한 요구사항의 경우 SubComposeLayout이 아닌 일반적인 Layout을 사용해서 구현할 수 있습니다.
이 외에 측정 결과가 composition(UI 구성)이 아닌 measure에 영향을 끼친다면 굳이 SubComposeLayout을 사용하지 않아도 됩니다.
실무에서는 SubComposeLayout을 도입할 땐 여러 가지를 고려해야 한다고 생각합니다.
일반적인 Layout으로 정말 불가능한가?
자식의 composition 자체가 다른 자식의 measure 결과에 의존을 하는지 혹은 single pass measure로 가능한지 고려해야 합니다.
성능 트레이드오프를 감수할 만한 가치가 있는가?
가장 고려해야 할 사항이라고 생각합니다.
성능 저하가 우려되지만, 사용자 경험상 꼭 필요한 기능인지, 다른 대안적 해결책은 정말 없는지 고려해야 합니다.
복잡도 대비 효과가 충분한가?
SubComposeLayout을 사용함으로써 구현이 복잡해지고, 유지 보수 측면에서 좋지 않은지 고려해야 합니다.
SubComposeLayout은 일반 Layout의 Single Pass Measure 제약을 우회하여, 복잡한 레이아웃 요구사항을 해결할 수 있게 해주는 강력한 도구이지만, 사용해야 하는 경우와 아닌 경우에 대해서 인지하고 있어야 합니다.
특히, 단순히 더 유연해 보인다거나 더 고급 기술 같다는 이유로 남용해서는 안됩니다.
참고 자료
https://foso.github.io/Jetpack-Compose-Playground/ui/layout/subcomposelayout/
'Skils > Android' 카테고리의 다른 글
| Navigation 코드를 줄여보세요 (feat: Compose Destinations) (2) | 2025.06.11 |
|---|---|
| Compose Layout (2) | 2025.05.18 |
| [Android] - Interceptor를 이용한 Retrofit 에러 핸들링 (1) | 2024.10.19 |
| [Android] - Authenticator를 활용해 JwtToken 갱신하기 (2) | 2024.10.12 |
| [Android] - Test 코드를 작성해보자(Compose UI Test) (3) | 2024.09.17 |