🤖 Compose

[Compose] Component 알아보기 - CheckBox

콩드로이드 2025. 1. 4. 13:15

CheckBox

Row(verticalAlignment = Alignment.CenterVertically) {
    Checkbox(checked = false, onCheckedChange = {

    })
    Text(text = "checkbox를 테스트해보자")
}

- 기존 안드로이드 view와는 달리 체크박스를 눌러도 ui상에 아무 변화가 없음

- checked 값이 바뀌어야만 ui가 갱신된다 

 

그럼 이렇게 하면 될까 ? 

❌ 변경되지 않는다 (primitive값만 바꾼다고 반영이 되는 게 아님)

compose에서는 Composable 함수 즉, recomposition을 시켜야만 반영된다 

var checked = false
Checkbox(checked = checked, onCheckedChange = {
    checked = !checked
})
Text(text = "checkbox를 테스트해보자")

 

 

그럼 상태를 변경시켜보자 

주의해야 할 점 아래와 같이 사용하면 

var checked = mutableStateOf(false)

위와 같은 에러가 뜬다 

Creating a state object during composition without using remember

Composable 함수 내에서 상태값을 생성하는데 remember를 쓰고 있지 않다 

발생원인 : Composable 내에서 ui가 그려질 때 조금 그려지다가 다시 그려질 수 있는데(recomposition이 언제 발생할지 알 수 없다), remember가 없다면 상태값이 날아가버린다 

즉, Composable은 언제든 다시 그려질 수 있다(recomposition) 그래서 상태값 주의해야한다 

 

다시 본문으로 돌아가 체크박스의 상태를 변화하려면 아래와 같이 사용해야한다 

Row(verticalAlignment = Alignment.CenterVertically) {

    var checked = remember { mutableStateOf(false) }

    Checkbox(checked = checked.value, onCheckedChange = {
        checked.value = !checked.value
    })
    Text(text = "checkbox를 테스트해보자")
}

 

만약 mutableStateOf의 값을 사용할 때 일일이 .value를 하기 번거롭다면

var checked by remember { mutableStateOf(false) }
Checkbox(checked = checked, onCheckedChange = {
    checked = !checked
})

Text(text = "checkbox를 테스트해보자")

 

이렇게 delegated 형식으로 사용하면 된다 아래의 방식을 사용하는 거라고 보면 된다 

/**
 * Permits property delegation of `var`s using `by` for [MutableState].
 *
 * @sample androidx.compose.runtime.samples.DelegatedStateSample
 */
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableState<T>.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
    this.value = value
}

 

 

구조분해 사용하기 

MutableState를 살펴보자면

- 값을 나타내는 value

- 값을 반환하는 component1 함수

-값을 설정하는 component2

@Stable
interface MutableState<T> : State<T> {
    override var value: T
    operator fun component1(): T
    operator fun component2(): (T) -> Unit
}

 

여기서 구조분해를 한다면 componentN에 해당하는 component1(getter), component2(setter)가 구조분해된다 

그래서 아래와 같은 형태로도 쓸 수 있다 

val (checked, setChecked) = remember { mutableStateOf(false) }

Checkbox(checked = checked, onCheckedChange = {
    //체크됐을 때 호출되므로 it 자체가 변경된 checked 값
    setChecked(it)
})

Text(text = "checkbox를 테스트해보자")