name: portada class: portada-slide, center, middle # Compose .footnote[<%= teacher_name%>] <%= teacher_slides_start %> --- # Compose tree .fullscreen[![](files/compose/composeTree.svg)] --- # Modificar vista - Intent fallit ``` @Composable fun App() { // This does not work var text = "Hello world" Button(onClick = { text = "Hello, Desktop!" }) { Text(text) } } ``` --- # Modificar vista ``` @Composable fun App() { var text = remember { mutableStateOf("Hello, World!") } Button(onClick = { text.value = "Hello, Desktop!" }) { Text(text.value) } } ``` --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_1.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_2.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_3.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_4.png)] --- # MutableState - És una classe que es refereix a un tipus __observable__ - LiveData o Flow són també observables - Una funció composable que llegeix un state value direm que està subscrita a un state value observable - Qualsevol __canvi de l'state__ value llança (__trigger__) la recomposició de totes les funcions subscrites. - mutableStateOf("Hello, World!") crea un MutableState
amb l'estat "HelloWorld!" --- # Remember - Li diu al Compose que ha de recordar el valor quan es faci la recomposició, i que no executi la lambda. --- # Exemple sense remember ``` @Composable fun App() { // No funciona var text = mutableStateOf("Hello, World!") Button(onClick = { text.value = "Hello, Desktop!" }) { Text(text.value) } } ``` --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_1.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_2.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_3.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_noremember_4.png)] --- # Immutabilitat - error ``` data class Message(var text: String) @Composable fun App() { // No funciona var message = remember { mutableStateOf(Message("Hello, World!")) } Button(onClick = { message.value.text = "Hello, Desktop!" }){ Text(message.value.text) } } ``` --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail1_1.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail1_2.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail1_3.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail1_4.png)] --- # Immutabilitat - error ``` data class Message(var text: String) @Composable fun App() { // No funciona var message = remember { mutableStateOf(Message("Hello, World!")) } Button(onClick = { val newMessage = message.value newMessage.text = "Hello, Desktop!" message.value = newMessage }){ Text(message.value.text) } } ``` --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail2_1.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail2_2.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail2_3.png)] --- .fullscreen[![](files/compose/StateDiagramOnHelloButton_fail2_4.png)] --- # Immutabilitat - correcte ``` data class Message(val text: String) @Composable fun App() { // Així si que funciona var message by remember { mutableStateOf(Message("Hello, World!")) } Button(onClick = { message = Message("Hello, Desktop!") // o message = message.copy(text = "Hello, Desktop!") }){ Text(message.text) } } ``` --- # State by ``` @Composable fun App() { var text by remember { mutableStateOf("Hello, World!") } Button(onClick = { text = "Hello, Desktop!" // instead of text.value }) { Text(text) // instead of text.value } } ``` --- # Under the hood ```kotlin var text by remember { mutableStateOf("Hello, World!") } ``` - __mutableStateOf__("Hello, World!") Produeix un estat MutableState amb l'estat "HelloWorld!" - __remember__ : Li diu al Compose que ha de recordar el valor quan es faci la recomposició, i que no executi la lambda. - __by__ és la keyword per delegar, amaga el fet que en retorna un MutableState --- # TextField ``` @Composable fun App() { var text by remember { mutableStateOf("") } TextField(text, label = { Text("write here") }, onValueChange = { text = it }) } ``` --- # AlertDialog ``` var showDialog by remember { mutableStateOf(false) } if(showDialog) AlertDialog( onDismissRequest={showDialog = false}, confirmButton={}, text = {Text("Dialog contents")} ) ``` --- # Toast ```kotlin val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } Scaffold( snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ){ padding -> Button(modifier = Modifier.padding(padding), onClick = { scope.launch { snackbarHostState.showSnackbar("Hello!") } }){ Text("Say hello") } } ``` --- # Exercicis Exercicis state --- # Exemples Incorrecte ```kotlin @Composable fun BadExample() { var text by remember { mutableStateOf("") } val sendEmail = remember { mutableStateOf(false) } if(sendEmail.value){ println("SEND EMAIL") } Column(Modifier.padding()) { TextField(text, onValueChange = { text = it }) Button(onClick = { sendEmail.value = true }){ Text("Send") } } } ``` --- # Exemple incorrecte ```kotlin @Composable fun BadExample() { var text by remember { mutableStateOf("") } var text2 by remember { mutableStateOf("0") } val scope = rememberCoroutineScope() val snackbarHostState = remember { SnackbarHostState() } Scaffold( snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { padding -> Column(Modifier.padding(padding)) { TextField(text, onValueChange = { text = it }) TextField(text2, onValueChange = { text2 = it }) if (text2.toIntOrNull() == null) { scope.launch { snackbarHostState.showSnackbar("Not an Int!") } } } } } ```