6 - Enviar estado a una función componible y elevar evento.

La filosofía de Jetpack Compose es muy distinta a la tecnología previa en el desarrollo de aplicaciones Android.

Cuando uno desarrolla una aplicación con Compose las funciones componibles superiores envían el estado a las funciones componibles inferiores, y de las inferiores disparan eventos a la funciones superiores para que actualicen su estado.

Veamos un ejemplo con dos funciones componibles que utilicen este principio.

Problema

Confeccionar una aplicación que mediante dos botones, uno que incremente en uno un texto y el otro botón lo disminuya en 1.

La interfaz visual debe ser:

Jetpack Compose elevar eventos pasar estados

Crearemos un proyecto llamado 'Compose8' e implementaremos el siguiente código:

package com.tutorialesprogramacionya.compose8

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SelectorNumerico()
        }
    }
}

@Composable
fun SelectorNumerico() {
    var valorActual by remember { mutableStateOf(0) }
    BotonesSelector(valorActual = valorActual,
        presion = {
            valorActual += it
        }
    )
}

@Composable
fun BotonesSelector(valorActual: Int, presion: (Int) -> Unit) {
    Column() {
        Button(onClick = { presion(1) }) {
            Text(text = "Incrementar")
        }
        Text(text = "$valorActual",fontSize = 30.sp)
        Button(onClick = { presion(-1) }) {
            Text(text = "Decrementar")
        }
    }
}

Hay que tener en claro que desde el MainActivity llamamos a la función componible 'SelectorNumerico':

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SelectorNumerico()
        }
    }
}

La primer función componible 'SelectorNumerico' administra el estado de nuestro selector numérico mediante la variable 'valorActual', luego llama a la segunda función componible llamada 'BotonesSelector' pansando el estado actual (es decir la variable valorActual) y la referencia de una función landa en el parámetro 'presion':

@Composable
fun SelectorNumerico() {
    var valorActual by remember { mutableStateOf(0) }
    BotonesSelector(valorActual = valorActual,
        presion = {
            valorActual += it
        }
    )
}

La segunda función componible recibe como parámetros, primero el valor que debe mostrar el selector numérico y el segundo parámetro la referencia a la función lambda que deberá llamar cuando se presione alguno de los dos botones que compone la función:

@Composable
fun BotonesSelector(valorActual: Int, presion: (Int) -> Unit) {
    Column() {
        Button(onClick = { presion(1) }) {
            Text(text = "Incrementar")
        }
        Text(text = "$valorActual",fontSize = 30.sp)
        Button(onClick = { presion(-1) }) {
            Text(text = "Decrementar")
        }
    }
}

El flujo de estado y eventos con este modelo de programación es:

Jetpack Compose elevar eventos pasar estados

Lo más importante en este ejemplo es entender que cuando alguno de los botones es presionado se llama a la función presión pasando el 1 o -1 según el botón presionado:

        Button(onClick = { presion(1) }) {
            Text(text = "Incrementar")
        }

Esto hace que se ejecute la función lambda que definimos en la primer función:

    BotonesSelector(valorActual = valorActual,
        presion = {
            valorActual += it
        }
    )

El parámetro it recibe el 1 o -1 según el botón presionado y procedemos a actualizar la variable que almacena el estado 'valorActual', luego de esto Compose se encarga de actualizar en pantalla todas las funciones componibles que muestran dicho valor, en nuestro caso la función Text definida dentro de la función 'BotonesSelectores' y se procede a recomponer o redibujar:

        Text(text = "$valorActual",fontSize = 30.sp)

Compose es muy eficiente cuando tiene que recomponer la pantalla, y en este caso no redibuja los dos botones, sino solo llama nuevamente a la función componible Text que reimprime el contendio de valorActual que ha sido modificado en la primer función.