Compose의 Lists란 무엇인가?
Compose의 Lists란 컴포넌트들을 Scrollable하게 수직 또는 수평으로 배치하는 Composable을 뜻한다. 이를 만들기 위해서는 Column 혹은 Row를 사용할 수 있다. 이번 글에서는 Column을 이용해 Lists를 만드는 작업을 한다.
Column을 Lists로 만들기 위해 어떤 작업이 필요한가?
Column은 모든 자식 Composable을 수직으로 배치하는 Compose Layout이다. Column을 List로 만들기 위해서는 몇가지 선행 작업이 필요하다. Column을 내부 컴포넌트를 배치하는 작업과 Column의 Modifier을 이용해 Column이 scroll 가능하게 만드는 작업이다.
*Column에 Scroll을 결합한 것은 xml의 ScrollView와 비슷하게 동작한다.
Column을 List로 만들기 위해 필요한 작업
1. 컴포넌트 배치
2. scroll 가능하게 변경
Column에 컴포저블 배치하기
사용할 컴포저블 정의
우리는 이번 글에서 다음의 컴포저블을 Column내부에 배치할 것이다. 이 컴포넌트는 order값이 올라갈 수록 Kotlin World 뒤의 숫자를 증가시킨다.
@Composable
fun KotlinWorldCard(order: Int) {
Card(
Modifier
.padding(12.dp)
.border(width = 4.dp, color = Color.Black)
.fillMaxWidth()
.height(100.dp)
) {
Box(contentAlignment = Alignment.Center) {
Text("Kotlin World ${order}")
}
}
}
Column에 Composable 배치
자 이제 위 카드를 for문을 이용해 Column에 50개 넣어보자.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column(
Modifier
.fillMaxSize()
.padding(12.dp)) {
for (i in 0..50) {
KotlinWorldCard(order = i) // 컴포저블 배치
}
}
}
}
}
Scroll이 동작 하지 않는 것을 확인할 수 있고, 6번째 컴포저블인 "Kotlin World 5"의 사각형이 짤린 것을 확인할 수 있다.
- Scroll이 동작하지 않는 이유는 Column에 Scroll동작이 정의되어 있지 않아 그런 것이다.
- 사각형이 짤린 이유는 Compose에서는 부모의 최대 높이를 계산한 후, 모든 자식 컴포저블의 크기를 측정(measurement)를 하여 들어갈 수 있는 자식까지만 UI를 그리기 때문이다. 이 때문에 Column의 최대 높이값에 들어갈 수 있는 6개의 컴포저블만 내보낸 것이며, 6번째 컴포저블은 높이값이 부족하기 때문에 height가 제한되었다.
Column을 Scrollable하게 만들기
위 두가지 문제의 해결 방법은 간단하다. Column의 Modifier에 Scroll 동작을 넣는 것이다. Column은 수직 방향으로 scroll되기 때문에 Modifier의 verticalScroll을 넣어주면 된다.
코드를 작성하기 전에 하나 더 알아두어야 할 것이 있다. Composable은 기본적으로 Stateless하기 때문에 ScrollState를 저장할 수 있는 객체가 필요하다. 우리는 이를 rememberScrollState()를 이용해 생성한다. 자 이제 코드를 작성해보자.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val scrollState = rememberScrollState() // ScrollState에 대한 remember
Column(
Modifier
.fillMaxSize()
.padding(12.dp)
.verticalScroll(scrollState) // Column에 ScrollState 설정
) {
for (i in 0..50) {
KotlinWorldCard(order = i)
}
}
}
}
}
위 코드를 실행하면 Scroll이 정상 동작하는 것을 확인할 수 있다.
왜 Column과 ScrollState를 이용해 Lists를 만드는 것의 한계점
위에서 Column과 Scroll State를 이용해 Lists를 만드는 것을 살펴보았다. 이러한 방식으로 Scrollable한 View를 만드는 것은 간단한 View를 만들 때는 강력한 도구가 된다. 예를 들어 안드로이드에서 내 정보를 보여주는 페이지나, 10개 이내의 자식 컴포저블이 있는 리스트를 만들 때는 이 방식을 사용하는 것이 효율적이고 유용하다.
하지만, 만약 만들어야 하는 자식 컴포저블이 100개 이상이거나 1000개 이상일 때는 이 컴포저블을 로드하는데 오랜 시간이 걸린다. 안드로이드의 메모리는 매우 부족하기 때문에 이렇게 많은 컴포저블을 로드하면 Out of Memory Exception이 날 수 있다. 혹은 UI 스레드가 대기 시간이 길어져 ANR(Android Not Responding) 오류가 생길 수 있다.
한 번 그려지는 아이템의 개수를 5000개로 수정해서 로딩시켜보자.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val scrollState = rememberScrollState()
Column(
Modifier
.fillMaxSize()
.padding(12.dp)
.verticalScroll(scrollState)
) {
for (i in 0..5000) {
KotlinWorldCard(order = i)
}
}
}
}
}
로딩이 10초 정도 걸리는 것을 확인할 수 있다.
따라서 컴포저블이 많을 때 로딩이 오래 걸리거나 ANR이 발생하는 문제를 방지하기 위해 화면 상에 표시되는 컴포저블만 로드하도록 하는 것이 필요하다.
따라서 다음 글에서는 화면 상에 표시되는 컴포저블만 로딩되도록 하는 방법에 대해 살펴볼 것이다.