He estado jugando con Jetpack Compose Desktop. Me di cuenta de algo que realmente no entiendo:
import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application @Composable @Preview fun App() { var text by mutableStateOf("Hello, World!") MaterialTheme { TextField(text, onValueChange = { text = it }) Button(onClick = { text = "Hello, Desktop!" }) { Text(text) } } } fun main() = application { Window(onCloseRequest = ::exitApplication) { App() } }¿Por qué puedo cambiar el texto en TextField? Pensé que en cada recomposición, el estado mutable se restablece con el valor inicial: por lo que el texto no debería poder cambiar
import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.Column import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application @Composable @Preview fun App() { var text by mutableStateOf("Hello, World!") Column { TextField(text, onValueChange = { text = it }) Button(onClick = { text = "Hello, Desktop!" }) { Text(text) } } } fun main() = application { Window(onCloseRequest = ::exitApplication) { App() } }Sin embargo, si reemplaza MaterialTheme con una columna, de repente funciona como se esperaba y no puede cambiar el texto en TextField.
¿Porqué es eso? ¿Es eso un error o una característica?
Pensé que en cada recomposición, el estado mutable se restablece con el valor inicial: por lo que el texto no debería poder cambiar
El objetivo de tener un estado al recomponer es evitar que una variable se reinicie. El estado inicial se usa solo una vez cuando ocurre la primera composición y no se vuelve a usar cuando ocurren más recomposiciones. Sin embargo, si el componible se elimina del árbol de la interfaz de usuario y luego se restablece, el estado de la variable se destruirá y se reiniciará, ya que esto no es realmente una recomposición sino una composición (como si estuviera sucediendo por primera vez).
Es una característica de Compose sobre alcance y recomposición inteligente. Puedes consultar mi respuesta detallada aquí .
Lo que realmente hace que todo Composable se recomponga es la Column que tiene una palabra clave en línea .
@Composable inline fun Column( modifier: Modifier = Modifier, verticalArrangement: Arrangement.Vertical = Arrangement.Top, horizontalAlignment: Alignment.Horizontal = Alignment.Start, content: @Composable ColumnScope.() -> Unit ) { val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment) Layout( content = { ColumnScopeInstance.content() }, measurePolicy = measurePolicy, modifier = modifier ) }Digamos que tiene un color de fondo de conjuntos Composable inicialmente en la composición y cambia en cada recomposición que crea su propio alcance. Lambda sin en línea se considera un alcance.
@Composable fun RandomColorColumn(content: @Composable () -> Unit) { Column( modifier = Modifier .padding(4.dp) .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp)) .background(getRandomColor()) .padding(4.dp) ) { content() } }Con
@Composable fun App2() { var text by mutableStateOf("Hello, World!") RandomColorColumn { TextField(text, onValueChange = { text = it }) Button(onClick = { text = "Hello, Desktop!" }) { Text(text) } } } Y uno con Column
@Composable fun App() { var text by mutableStateOf("Hello, World!") Column(modifier = Modifier.background(getRandomColor())) { TextField(text, onValueChange = { text = it }) Button(onClick = { text = "Hello, Desktop!" }) { Text(text) } } }Función de color aleatorio
fun getRandomColor() = Color( red = Random.nextInt(256), green = Random.nextInt(256), blue = Random.nextInt(256), alpha = 255 ) Verá que el color de fondo de la columna cambiará cada vez que cambie el texto, pero no con App2()