Android 개발/Jetpack Compose

Compose 1.11 FlexBox API로 칩·태그 자동 줄바꿈, Row 47줄을 3줄로 줄인 후기

stackD 2026. 7. 17. 18:00
반응형

 

지난주에 태그 묶음 화면 새로 짜는데, 가로 스크롤로 뒤쪽 칩이 잘려나가더라고요. 결국 Compose 1.11 FlexBox API 로 줄바꿈 지점을 통째로 갈아엎었습니다.

 

Row + horizontalScroll 로 칩 12개 깔았더니 생긴 문제

QA 검수가 들어왔는데, 가로 스크롤 끝에 숨어 있는 필터 칩 4개를 사용자가 인지 못 한다는 리포트가 올라왔습니다. 화면 폭이 좁은 기기에서는 12개 칩 중 절반이 오른쪽 너머로 사라져 있는 상태였어요.

 

요구 조건은 단순했습니다. 화면 폭에 따라 자동 줄바꿈, 칩 간격 8dp, 줄 간격 12dp 유지. 말로 풀면 한 줄인데 코드로 옮기는 부분이 매번 발목을 잡았습니다.

 

 

FlowRow·SubcomposeLayout 으로 우회하던 한계

처음에는 FlowRow 를 썼어요. 줄바꿈은 잘 되는데 maxItemsInEachRowhorizontalArrangement 를 같이 걸어두면 마지막 줄 정렬이 미묘하게 틀어집니다. 너비 비례 분배 옵션도 없어서 "마지막 칩만 남는 공간을 채우게" 같은 디테일이 막혔습니다.

 

그다음엔 SubcomposeLayout 으로 줄바꿈을 직접 계산했어요. 한 줄에 들어갈지 다음 줄로 내릴지 매 자식마다 측정해서 누적 폭을 잡는 코드인데요, RTL 대응까지 깔면 70줄을 가뿐히 넘기게 됩니다. 47줄짜리 측정 로직을 한 번 짜두긴 했는데, 간격 값 하나 바꾸려고 들어갈 때마다 멘붕이 오더라고요.

 

 

Compose FlexBox API 로 자동 줄바꿈 3줄에 정리하기

androidx.compose.foundation:foundation-layout:1.11.0 에 합류한 FlexBox 는 CSS 의 display: flex 를 거의 그대로 옮겨온 컨테이너로 알려져 있어요. 2026년 4월 안정 버전부터 @ExperimentalFlexBoxApi Opt-in 으로 들어왔습니다.

 

저는 기존 측정 코드를 통째로 지우고 이렇게 줄였습니다.

 

@OptIn(ExperimentalFlexBoxApi::class)
@Composable
fun FilterChipGroup(tags: List<String>) {
    FlexBox(
        config = {
            direction(FlexDirection.Row)
            wrap(FlexWrap.Wrap)
            gap(8.dp)
            // 메인축/교차축 간격을 다르게 두려면
            // rowGap(12.dp); columnGap(8.dp) 형태로 분리
        },
    ) {
        tags.forEach { tag ->
            FilterChip(tag = tag)
        }
    }
}

 

wrap(FlexWrap.Wrap) 한 줄로 자동 줄바꿈이 들어가고, gap(8.dp) 한 줄로 칩·줄 간격이 깔립니다. 47줄짜리 측정 로직이 사라진 자리가 진짜 시원했어요.

 

특정 칩만 남는 공간을 다 채우게 하고 싶으면 자식에 Modifier.flex { grow(1f) } 를 붙이면 됩니다. CSS 의 flex: 1 1 auto 와 거의 같은 동작이라고 보시면 되겠습니다. 주축 정렬은 justifyContent(), 교차축은 alignItems(), 여러 줄일 때 줄 그룹 자체는 alignContent() — 이름이 길어서 처음엔 헷갈리는데 한 번 잡으면 빠르게 손에 붙어요.

 

 

FlowRow·LazyGrid 와 FlexBox 사용처 따로 잡기

그렇다고 기존 FlowRow 코드를 다 갈아엎으라는 얘기는 아닙니다. 구글 가이드가 새 코드는 FlexBox 쪽을 권장하는 방향이긴 한데, FlowRow 자체가 deprecated 된 건 아니에요. 잘 동작하는 화면을 마이그레이션 비용 들여 갈아엎을 이유는 없습니다.

 

제 기준은 이렇게 나눠두고 있어요.

 

  1. 칩·태그·토글 묶음처럼 아이템 20개 이하, 화면 폭에 따라 줄바꿈이 필요하면 FlexBox.
  2. 이미 FlowRow 로 안정적으로 도는 화면은 그대로 유지.
  3. 아이템이 50개를 넘어갈 가능성이 있으면 LazyVerticalStaggeredGrid 로 빠짐.

 

FlexBox 는 Lazy 미지원이라 첫 컴포지션에서 자식을 전부 측정합니다. 100개짜리 리스트를 무심코 넣으면 프레임 드롭이 생길 여지가 있는 편이에요. 개인적으로는 칩이 30개를 넘어갈 것 같은 구간엔 처음부터 Lazy 계열을 깔아두는 쪽을 추천합니다. 나중에 갈아엎는 비용보다 처음에 자리잡는 비용이 훨씬 싸거든요.

 

ExperimentalFlexBoxApi Opt-in, 도입 범위는 좁게

마지막으로 짚어둘 지점은 @ExperimentalFlexBoxApi Opt-in 표식입니다. 안정 버전에 들어왔지만 어노테이션이 붙어 있다는 건 시그니처가 바뀔 여지가 남아 있다는 뜻이에요. 공식 가이드에서 별도 측정 오버헤드 벤치마크 페이지는 아직 못 찾았습니다.

 

저는 디자인 시스템 라이브러리 안에 ChipGroup, TagCloud 같은 컴포저블 두 개만 FlexBox 로 감싸 두고, 화면 코드에서는 그 컴포저블만 불러 쓰는 쪽으로 도입 범위를 잡아뒀어요. 시그니처가 바뀌면 컴포저블 두 개만 손보면 되니까요.

 

47줄짜리 SubcomposeLayout 을 지운 그 금요일 저녁, PR 디프를 다시 열어보다가 한참 멍하니 들여다봤습니다. 깃 디프 왼쪽 빨간 영역에 측정 로직 47줄이 줄줄이 그어져 있고, 오른쪽 초록 영역에는 FlexBox 컨테이너 한 덩어리가 들어와 있던 그 화면. 그 자리에 그렇게 오래 머물러 있던 코드가, 알고 보니 컨테이너 한 줄로 대체될 자리였다는 걸 그제서야 받아들였습니다.

 

 

반응형
LIST