[Android Compose] LazyColumn에서 CheckBox의 체크 상태 유지하는 법
리사이클러뷰에서 아이템에 체크박스를 넣어 사용했듯 Compose에서도 같은 경우가 당연히 발생할 수 있다.
그러나 Compose에는 리사이클러뷰 대신 LazyColumn이 존재하고, 어댑터가 따로 존재하지 않는다. 이 상황에서 어떻게 체크박스를 만들고 체크 상태를 유지하게 할 수 있을까?
코드로는 아래와 같이 작성하면 스크롤하더라도 체크 상태가 유지되는 체크박스를 만들 수 있다.
@Composable
fun TodoCard(
modifier: Modifier = Modifier,
title: String,
content: String
) {
var checked by rememberSaveable { mutableStateOf(false) }
Card(modifier = modifier) {
Column(
modifier = Modifier.padding(start = 8.dp, top = 5.dp, bottom = 5.dp, end = 8.dp)
) {
Checkbox(
checked = checked,
onCheckedChange = {
checked = it
if (checked) {
Log.e("TodoCard", "체크박스 상태 : true")
} else {
Log.e("TodoCard", "체크박스 상태 : false")
}
}
)
Text(
text = title,
fontSize = 28.sp
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = content,
fontSize = 20.sp
)
}
}
}
그리고 이걸 사용하는 컴포저블 함수를 아래와 같이 예시로 작성한다.
@Composable
fun MyScreenContent() {
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState,
topBar = {},
floatingActionButton = {
FloatingActionButton(
onClick = {
lifecycleScope.launch {
//
}
}
) {
Icon(imageVector = Icons.Filled.Add, contentDescription = "")
}
}) { paddingValues ->
LazyColumn(contentPadding = paddingValues) {
items(100) {
TodoCard(
modifier = Modifier.fillMaxWidth().padding(start = 8.dp, top = 10.dp, bottom = 10.dp, end = 8.dp),
title = "제목 $it",
content = "내용 $it"
)
}
}
}
}
이제 onCreate()에 위 컴포저블 함수를 추가하고 앱을 실행하면 아래 카드들이 리스트로 표시될 것이다.
체크한 다음 스크롤해서 해당 체크박스가 안 보이게 했다가, 다시 스크롤을 올리면 체크된 상태로 남아있는 걸 볼 수 있다.
이제 어떻게 이게 가능한지 확인해 본다. 핵심은 TodoCard 컴포저블 함수에 있다.
@Composable
fun TodoCard(
modifier: Modifier = Modifier,
title: String,
content: String
) {
var checked by rememberSaveable { mutableStateOf(false) }
Card(modifier = modifier) {
Column(
modifier = Modifier.padding(start = 8.dp, top = 5.dp, bottom = 5.dp, end = 8.dp)
) {
Checkbox(
checked = checked,
onCheckedChange = {
checked = it
if (checked) {
Log.e("TodoCard", "체크박스 상태 : true")
} else {
Log.e("TodoCard", "체크박스 상태 : false")
}
}
)
Text(
text = title,
fontSize = 28.sp
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = content,
fontSize = 20.sp
)
}
}
}
TodoCard() 함수의 첫 코드에 주목해야 한다.
var checked by rememberSaveable { mutableStateOf(false) }
rememberSaveable 키워드에 대해선 이전에 작성한 적이 있다.
https://onlyfor-me-blog.tistory.com/731
그러나 체크박스와 연관지어서 포스팅한 적은 없기 때문에 이번 기회에 작성한다. 공식문서에서 설명하는 rememberSaveable은 아래와 같다.
https://developer.android.com/jetpack/compose/state?hl=ko
remember가 재구성 과정 전체에서 상태를 유지하는 데 도움은 되지만 구성 변경 전반에선 상태가 유지되지 않는다. 이 경우 rememberSaveable을 써야 한다. rememberSaveable은 Bundle에 저장할 수 있는 모든 값을 자동 저장한다
https://developer.android.com/codelabs/jetpack-compose-state?hl=ko#9
...(중략) 항목이 컴포지션을 종료하면 기억된 상태가 삭제된다는 문제가 있다. LazyColumn에 있는 항목의 경우 스크롤하면서 항목을 지나치면 항목이 컴포지션을 완전 종료하므로 더 이상 항목이 표시되지 않는다. rememberSaveable을 사용하라. 저장된 인스턴스 상태 매커니즘을 써서 액티비티 또는 프로세스 재생성 후에도 상태가 유지된다. rememberSaveable이 LazyList와 함께 작동하는 방식 덕분에 항목은 컴포지션을 종료해도 유지될 수 있다
LazyColumn을 스크롤하는 것이 구성 변경에 포함되지는 않는다. 하지만 0번 아이템에 체크 후 스크롤해서 0번 아이템이 사라지게 되면 해당 컴포저블의 컴포지션이 종료되면서 이것이 기억하고 있던 상태가 사라지게 된다.
그래서 이 경우에는 위처럼 rememberSaveable을 사용하면 체크박스에 체크 후 스크롤을 하더라도 저장된 상태는 사라지지 않고 유지된다.