본문 바로가기

안드로이드/Compose UI

[안드로이드 Jetpack Compose UI] Row를 사용해서 HorizontalScrollView 구현하기


안녕하세요. 이번 포스팅에서는 안드로이드 Jetpack Compose에서 가로방향으로 아이템이 추가되는 HorizontalScrollView를 구현하겠습니다. Compose UI에서는 가로 방향으로 UI를 배치할 때 Row 컴포저블을 사용합니다. 이때, Row에 추가 옵션을 주면 아이템이 Row 컴포저블을 벗어나도 스크롤을 통해서 UI를 확인할 수 있습니다. 이제 간단한 예제를 통해 HorizontalScrollView를 구현하겠습니다.

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

1. Row를 사용해서 HorizontalScrollView 만들기

HorizontalScrollView 구현의 핵심은 Row 컴포저블과 horizontalScroll modifier의 조합입니다. Row는 자식 컴포저블들을 가로 방향으로 나열하며, horizontalScroll을 사용하면 가로로 스크롤 가능한 레이아웃을 만들 수 있습니다. 이렇게 하면 사용자가 스크롤을 통해 화면 너비를 초과하는 아이템들을 탐색할 수 있게 됩니다.

또한, Compose의 Arrangement.spacedBy를 사용해서 아이템 사이의 간격을 설정했습니다. Spacer를 추가해도 되지만 Arragement.spacedBy를 통해 가능하다는 점도 보여드리고 싶었습니다.

@Composable
fun CustomHorizontalScrollView(items: List<String>, scrollState: ScrollState) {
    Row(
        modifier = Modifier
            .fillMaxSize()
            .horizontalScroll(scrollState),
		horizontalArrangement = Arrangement.spacedBy(8.dp) // 여기에 간격 지정
    ) {
        for (item in items) {
            CustomCardView(item)
        }
    }
}

@Composable
fun CustomCardView(text: String) {
    Card(
        modifier = Modifier
            .width(150.dp)
            .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. Row를 HorizontalScrollView처럼 사용하기

HorizontalScrollView 구현의 다음 단계는 스크롤 상태 관리입니다. rememberScrollState 함수를 사용해 Row의 스크롤 상태를 추적하고 관리합니다. 이를 통해 사용자가 가로로 스크롤을 할 때 Row 내부의 아이템들이 원활하게 이동하도록 합니다.

CustomHorizontalScrollView는 필요에 따라 다양한 아이템을 동적으로 표시할 수 있습니다. 해당 예제에서 각 아이템은 CustomCardView를 통해 구현했고, 이런 방식으로 Compose를 사용하면 복잡한 리스트나 스크롤 뷰를 기존 안드로이드 레이아웃 XML 구현보다 간단하고 효율적으로 구현할 수 있습니다.

@Composable
fun HorizontalScrollViewScreen(
    mainNavController: NavHostController,
    viewModel: HorizontalScrollViewViewModel
) {
    val scrollState = rememberScrollState()
    val items = List(100) { it.toString() }

    Column(
        modifier = Modifier
            .fillMaxSize()
    ) {
        Spacer(modifier = Modifier.height(10.dp))

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

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

        CustomHorizontalScrollView(
            items = items,
            scrollState = scrollState
        )
    }
}

3. Row를 사용한 HorizontalScrollView의 한계

Row를 이용한 HorizontalScrollView 구현 방법은 매우 편리하고 간단하지만, 대량의 아이템을 다룰 경우 메모리 관리와 퍼포먼스 측면에서 한계를 갖게 됩니다. 각 아이템이 Row 내부에서 개별적으로 관리되기 때문에 아이템 수가 많을수록 메모리 사용량이 늘어납니다. 그래서 아이템이 많으면 많을수록 해당 페이지에 진입하는데 시간이 오래 걸리기도 하고 안드로이드 ANR 오류가 발생할 수 있습니다. 이런 경우, 안드로이드 Compose에서 RecyclerView에 해당되는 LazyRow를 사용해야 합니다.

4. 정리

안드로이드 Jetpack Compose를 사용하여 HorizontalScrollView를 구현하는 것은 Row 컴포저블과 함께 ScrollState를 사용하면, 손쉽게 가로 스크롤 가능한 뷰를 만들 수 있으며, Compose의 선언적 UI 패러다임을 통해 개발 과정을 단순화하고 효율적으로 만들 수 있습니다.

하지만 아이템의 개수가 많아지는 경우에는 모든 아이템이 메모리에 올라가기 때문에 아이템이 많은 경우에는 Row 기반의 HorizontalScrollView를 사용하면 안 됩니다. 이런 경우에는 RecyclerView처럼 작동하는 LazyRow를 사용해야 합니다.

이 글을 통해 안드로이드 Jetpack Compose UI에서 HorizontalScrollView를 만드는데 도움이 되기를 바랍니다. 다음 포스팅에서는 Row기반의 ScrollView 한계를 극복할 수 있는 LazyRow의 구현 방법에 대해 알아보겠습니다.