본문 바로가기

안드로이드/Compose UI

[안드로이드 Jetpack Compose UI] Column을 사용해서 VerticalScrollView 구현하기


안녕하세요. 이번 포스팅에서는 안드로이드 Jetpack Compose에서 VerticalScrollView 만드는 방법에 대해 설명하겠습니다. Compose UI에서는 Column 컴포저블을 통해 세로로 UI를 배치할 수 있고, Column 컴포저블의 Modifier에 ScrollState를 전달해 줌으로써 Scrollable 하게 만들 수 있습니다.

안드로이드 Jetpack Compose에서 구현한 VerticalScrollView
안드로이드 Jetpack Compose에서 구현한 VerticalScrollView

 

1. Column을 사용해서 VerticalScrollView 만들기

안드로이드 Compose에서는 기존의 안드로이드 개발에서 보던 ScrollView와는 다른 접근 방식을 제공합니다. 가장 간단하게 세로 스크롤 뷰를 만드는 방법은 Column 컴포저블에 verticalScroll Modifier를 적용하는 것입니다. 해당 Scroll State를 통해 간단하게 스크롤뷰를 만들 수 있습니다.

아래 예제에서는 CustomCardView 컴포저블을 만들어서 간단한 리스트 아이템을 구성하고, Column 내부에 반복문을 실행해서 5000개의 아이템을 만들었습니다. 세로 스크롤을 통해 5000번째까지의 CustomCardView를 확인할 수 있습니다.

@Composable
fun CustomScrollView(items: List<String>, scrollState: ScrollState) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(scrollState),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        for (item in items) {
            CustomCardView(item)
        }
    }
}

@Composable
fun CustomCardView(text: String) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .height(60.dp),
        shape = RoundedCornerShape(10.dp),
        border = BorderStroke(1.dp, Color.LightGray),
        colors = CardDefaults.cardColors(
            containerColor = Color(0xFFFF5F5F),
        )
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight()
                .padding(start = 10.dp)
                .background(Color.White),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.Start
        ) {
            Text(
                modifier = Modifier.padding(start = 10.dp),
                textAlign = TextAlign.Center,
                text = "CardView $text"
            )
        }
    }
}

2. Column을 VerticalScrollView처럼 사용하기

호출자 컴포저블에서 rememberScrollState를 통해 ScrollState를 생성하고, CustomScrollView 컴포저블에 전달했습니다. 이렇게 함으로써 상태를 공유하고 스크롤 동작을 연동할 수 있습니다. 현재 예제에서는 수직 스크롤을 구현하고 있는데 수평 방향으로 스크롤이 되는 리스트뷰가 필요하다면 Column대신 Row를 사용하면 됩니다.

@Composable
fun ScrollViewScreen(
    mainNavController: NavHostController,
    viewModel: ScrollViewViewModel
) {
    val scrollState = rememberScrollState()
    val items = List(5000) { it.toString() }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(start = 10.dp, end = 10.dp)
    ) {
        Spacer(modifier = Modifier.height(10.dp))

        Text(
            text = "item's count : ${items.size}",
        )

        Spacer(modifier = Modifier.height(10.dp))

        CustomScrollView(
            items = items,
            scrollState = scrollState
        )
    }
}

 

3. Column을 사용한 VerticalScrollView의 한계

Column과 ScrollState를 사용하는 방법은 단순하고 직관적이지만 성능에 있어서 한계가 있습니다. 현재 예제에서는 5000개의 아이템을 렌더링 하고 있어서 해당 화면으로 진입할 때 약 3~4초의 딜레이가 발생하고 있습니다. 그래서 많은 수의 아이템을 렌더링 하는 경우에는 ANR(Application Not Responding) 오류가 발생할 수 있습니다. 이런 경우에는 LazyColumn을 사용하는 것이 좋습니다.

4. 정리

안드로이드 Jetpack Compose UI에서는 Column 컴포저블과 ScrollState를 사용해서 매우 간단하게 ScrollView를 구현할 수 있고, Column 컴포저블이 아닌 Row 컴포저블을 사용한다면 Horizontal ScrollView를 구현할 수 있습니다. 하지만 복잡한 레이아웃이나 아이템 수가 많은 경우에 Column 컴포저블과 ScrollState를 사용하면 모든 UI가 메모리에 올라가므로 성능에 좋지 않고 화면이 멈추는 등의 문제가 발생합니다. 그래서 Column과 ScrollState의 조합은 간단한 레이아웃을 구성하는데 스크롤이 필요한 경우에만 사용하는 것을 권장하고 있습니다.

다음 포스팅에서는 이러한 한계를 극복할 수 있는 LazyColumn을 사용한 안드로이드 Jetpack Compose에서의 RecyclerView 대해 포스팅하겠습니다.