Can I swich State Variable for Composable Function?

Viewed 302

I have a simple composable function as below

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            var isGrayScale by remember { mutableStateOf(false) }
            val colorChoice by remember(isGrayScale) {
                mutableStateOf(
                    if (isGrayScale)
                        ColorChoice(onColor = Color.White, offColor = Color.Black)
                    else
                        ColorChoice(onColor = Color.Green, offColor = Color.Red)
                )
            }
            Box(modifier = Modifier.fillMaxSize().background(colorChoice.color))
            Button(
                modifier = Modifier.padding(64.dp).fillMaxSize(),
                onClick = { colorChoice.toggle() }) {
                Text(
                    text = if (colorChoice.isOn) "On" else "Off",
                    color = colorChoice.color,
                    fontSize = 48.sp
                )
            }
            Switch(
                modifier = Modifier.padding(64.dp).fillMaxWidth(),
                checked = isGrayScale,
                onCheckedChange = {isGrayScale = !isGrayScale}
            )
        }
    }

    class ColorChoice(
        private val onColor: Color,
        private val offColor: Color
    ) {
        var isOn by mutableStateOf(false)
        var color by mutableStateOf(offColor)
        fun toggle() {
            isOn = !isOn
            color = if(isOn) {
                onColor
            } else {
                offColor
            }
        }
    }
}

The switch will change the composable function reference to a different State Variable. After switching, the composable function doesn't recompose any more when the state variable changed.

Is changing State Variable for Composable Function not supported? Or I did something wrong.

1 Answers

After some investigation, apparently, the issue lies in onClick = { colorChoice.toggle() } whereby when colorChoice changed, the lambda still store the old `colorChoice.

To correct it, replace onClick = { colorChoice.toggle() } with onClick = colorChoice::toggle. This ensure onClick will get the latest colorChoice

The full code as below

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            var isGrayScale by remember { mutableStateOf(false) }
            val colorChoice by remember(isGrayScale) {
                mutableStateOf(
                    if (isGrayScale)
                        ColorChoice(onColor = Color.White, offColor = Color.Black)
                    else
                        ColorChoice(onColor = Color.Green, offColor = Color.Red)
                )
            }
            Box(modifier = Modifier.fillMaxSize().background(colorChoice.color))
            Button(
                modifier = Modifier.padding(64.dp).fillMaxSize(),
                onClick = colorChoice::toggle) {
                Text(
                    text = if (colorChoice.isOn) "On" else "Off",
                    color = colorChoice.color,
                    fontSize = 48.sp
                )
            }
            Switch(
                modifier = Modifier.padding(64.dp).fillMaxWidth(),
                checked = isGrayScale,
                onCheckedChange = {isGrayScale = !isGrayScale}
            )
        }
    }

    class ColorChoice(
        private val onColor: Color,
        private val offColor: Color
    ) {
        var isOn by mutableStateOf(false)
        var color by mutableStateOf(offColor)
        fun toggle() {
            isOn = !isOn
            color = if(isOn) {
                onColor
            } else {
                offColor
            }
        }
    }
}
Related