안드로이드 시스템·Compose 용어 사전
ComposeLazyRow · items · contentPadding

LazyColumn

보이는 항목만 구성하는 목록. RecyclerView에 대응한다.

보이는 항목만 구성하는 목록. View 시스템의 RecyclerView에 대응한다.

LazyColumn(
    state = listState,
    contentPadding = PaddingValues(16.dp),
    verticalArrangement = Arrangement.spacedBy(8.dp)
) {
    item { Header() }
    items(users, key = { it.id }) { user -> UserRow(user) }
    items(10) { index -> Placeholder(index) }
}

왜 Column을 쓰면 안 되나

Column(Modifier.verticalScroll(rememberScrollState())) {

  • users.forEach { UserRow(it) } }

  • 1,000개면 1,000개를 전부 구성하고 측정하고 배치한다

  • 첫 프레임이 수백 ms 걸리고 메모리가 폭발한다

LazyColumn 은 화면에 보이는 것 + 약간의 여유만 구성한다

key가 왜 거의 항상 필요한가

items(users, key = { it.id }) { ... }

key 가 없으면 위치(index) 로 항목을 식별한다

목록 맨 앞에 항목을 하나 추가하면

  • 모든 항목의 index 가 밀린다
  • Compose 는 "전부 바뀌었다" 고 판단한다
  • 각 항목의 remember 상태(펼침·애니메이션 진행) 가 엉뚱한 항목으로 옮겨간다
  • 스크롤 위치가 튄다

key 를 주면 항목의 정체가 유지된다

  • 애니메이션(animateItem) 도 이때만 올바르게 동작한다
key 는 안정적이고 유일해야 한다
  ❌ key = { it.hashCode() }   내용이 바뀌면 달라진다
  ❌ key = { index }           key 없는 것과 같다
  ✅ key = { it.id }

스크롤 상태

val listState = rememberLazyListState()
val showTopButton by remember {
    derivedStateOf { listState.firstVisibleItemIndex > 5 }
}

derivedStateOf 없이 firstVisibleItemIndex 를 직접 읽으면

  • 스크롤 픽셀마다 리컴포지션이 돈다 감싸면 Boolean 결과가 바뀔 때만 돈다

무한 스크롤 — Paging 3

val items = viewModel.pagedFlow.collectAsLazyPagingItems()
LazyColumn {
    items(items.itemCount, key = items.itemKey { it.id }) { i ->
        items[i]?.let { UserRow(it) }
    }
    if (items.loadState.append is LoadState.Loading) item { LoadingRow() }
}

Paging 3 이 주는 것

  • 페이지 요청·중복 방지·재시도
  • RemoteMediator 로 네트워크 + Room 캐시 결합
  • 로딩/에러 상태를 loadState 로 노출

직접 구현하면 스크롤 중 중복 요청과 경합을 다 다뤄야 한다

면접 함정

  • LazyColumn 안에 LazyColumn을 중첩한다 → 높이가 무한이 돼 예외가 난다. item으로 펼치거나 중첩 스크롤을 설계한다.
  • "key는 애니메이션용" → 상태 보존과 스크롤 안정성이 더 큰 이유다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — Compose 리스트 — LazyColumn·key·성능