Android/Compose

[Android Compose] Column과 Row는 어떻게 스크롤할 수 있는가?

참깨빵위에참깨빵_ 2023. 2. 5. 15:50
728x90
반응형

LazyHorizontalGrid와 LazyRow, LazyColumn을 쓰면 스크롤 가능한 뷰를 만들 수 있다. 그래서 이번 포스팅에선 Lazy 종류 레이아웃들이 왜 나왔는지 알아보기 위해 Column과 Row를 스크롤 가능하게 구현하고, 이렇게 구현 시 발생하는 일들을 확인한다.

 

먼저 적당히 화면을 만들어준다.

 

@Composable
fun ScrollableColumn(
    modifier: Modifier = Modifier
) {
    val scrollState = rememberScrollState()
    Column(
        modifier = modifier
            .fillMaxSize()
            .padding(12.dp)
            .verticalScroll(scrollState)
    ) {
        for (i in 0..100) {
            TextCard(index = i)
        }
    }
}

@Composable
fun TextCard(index: Int) {
    Card(
        Modifier
            .padding(20.dp)
            .border(width = 1.dp, color = Color.Black)
            .background(color = Color.Blue)
            .fillMaxWidth()
            .height(200.dp)
    ) {
        Box(contentAlignment = Alignment.Center) {
            Text("Text $index")
        }
    }
}

 

또는 Row를 사용한다면 아래 코드를 사용할 수 있다. Column을 Row로 바꾸고 fillMaxWidth()을 fillMaxHeight()로 바꾼 것 뿐이다.

 

@Composable
fun ScrollableColumn(
    modifier: Modifier = Modifier
) {
    val scrollState = rememberScrollState()
    Row(
        modifier = modifier
            .fillMaxSize()
            .padding(12.dp)
            .horizontalScroll(scrollState)
    ) {
        for (i in 0..1000) {
            TextCard(index = i)
        }
    }
}

@Composable
fun TextCard(index: Int) {
    Card(
        Modifier
            .padding(20.dp)
            .border(width = 1.dp, color = Color.Black)
            .background(color = Color.Blue)
            .fillMaxHeight()
            .height(200.dp)
    ) {
        Box(contentAlignment = Alignment.Center) {
            Text("Text $index")
        }
    }
}

 

첫 번째 코드를 복붙하면 프리뷰에 아래처럼 표시될 것이다.

 

 

실행하거나 상호작용 모드를 켜면 스크롤되는 걸 확인할 수 있다. 여기서 Column이 어떻게 스크롤 가능하게 됐는가?

rememberScrollState()를 Column의 Modifier.verticalScroll() 안에 넣어서 가능하다. 이게 무엇인지 확인해 보기 전에 rememberScrollState()는 ScrollState라는 리턴타입을 갖는다.

 

 

그리고 ScrollState는 ScrollableState 인터페이스를 구현한다. 아래는 안드로이드 스튜디오에서 확인한 ScrollState와 ScrollableState 코드의 일부분이다.

 

 

이걸 보면 rememberScrollState()보다 ScrollState, ScrollableState를 확인하는 게 먼저일 것 같다.

디벨로퍼에서 설명하는 ScrollableState와 ScrollState는 아래와 같다.

 

https://developer.android.com/reference/kotlin/androidx/compose/foundation/gestures/ScrollableState

 

ScrollableState  |  Android Developers

androidx.car.app.managers

developer.android.com

스크롤할 수 있는 아이템을 나타내는 객체다. 이 인터페이스는 스크롤을 통해 하위 수준의 스크롤 제어를 제공하고 상위 수준의 스크롤 기능을 허용하기 위해 LazyListState 또는 ScrollState와 같은 스크롤 가능 컨테이너의 상태로 구현된다. ScrollableState에서 확장 함수로 구현되는 animateScrollBy와 같다

 

https://developer.android.com/reference/kotlin/androidx/compose/foundation/ScrollState

 

ScrollState  |  Android Developers

androidx.car.app.managers

developer.android.com

스크롤의 상태. 개발자가 이 객체에 대한 메서드를 호출해 스크롤 위치를 바꾸거나 현재 상태를 가져올 수 있다. 호스트되고 verticalScroll 또는 horizontalScroll에 전달된다. 기본 매개변수로 ScrollState를 생성하고 자동으로 기억하려면 rememberScrollState를 사용하라

 

ScrollState를 쓰면 스크롤 위치 변경이나 현재 스크롤 상태를 가져올 수 있는데 이게 가능한 건 ScrollableState 인터페이스를 구현하고 있기 때문이라고 이해했다. 그렇다면 rememberScrollState()도 이런 일을 할 수 있도록 해주는 메서드가 아닐까 유추해볼 수 있다.

이제 rememberScrollState에 대해 확인해본다.

 

https://developer.android.com/reference/kotlin/androidx/compose/foundation/package-summary#rememberScrollState(kotlin.Int) 

 

androidx.compose.foundation  |  Android Developers

androidx.car.app.managers

developer.android.com

스크롤 위치를 변경하거나 스크롤 동작을 관찰할 수 있도록 현재 적절한 스크롤 구성을 기반으로 ScrollState를 만들고 기억한다

 

스크롤할 수 있도록 구성하고, 현재 스크롤 상태를 기억하는 것이 rememberScrollState()의 역할인 걸 볼 수 있다. 그래서 Column의 Modifier 중 verticalScroll() 안에 이것을 넣으면 스크롤할 수 있게 된다.

그러나 이 방식은 내 컴퓨터의 에뮬레이터 기준으로 아이템 100개 정도를 렌더링할 때도 속도가 제법 느리고, 1000개 이상부터는 화면이 표시되기까지 3초 이상 걸린다. 때문에 10개 이하 정도의 단순한 아이템을 보여줄 때는 Column을 써도 상관없겠지만 아이템 레이아웃이 복잡하거나 10개 이상 표시해야 한다면 Lazy류의 레이아웃을 써서 스크롤 가능하도록 화면을 만드는 것이 좋을 듯하다.

반응형