C�mo compilar una IU con Glance

En esta p�gina, se describe c�mo manejar los tama�os y brindar respuestas flexibles y responsivas dise�os con Glance, usando los componentes existentes de Glance)

Usa Box, Column y Row

Vistazo tiene tres dise�os principales componibles:

  • Box: Coloca los elementos encima de otros. Se traduce en un RelativeLayout.

  • Column: Ubica los elementos uno detr�s de otro en el eje vertical. Traduce a un objeto LinearLayout con orientaci�n vertical.

  • Row: Ubica los elementos uno detr�s de otro en el eje horizontal. Traduce a un objeto LinearLayout con orientaci�n horizontal.

Vistazo compatible con objetos Scaffold. Coloca tu Column, Row y Elementos Box componibles dentro de un objeto Scaffold determinado

Imagen de un dise�o de columna, fila y cuadro.
Figura 1: Ejemplos de dise�os con Column, Row y Box.

Cada uno de estos elementos componibles te permite definir las alineaciones verticales y horizontales. de su contenido y las restricciones de ancho, alto, peso o relleno con modificadores. Adem�s, cada elemento secundario puede definir su modificador para cambiar el espacio y su ubicaci�n dentro del elemento superior.

En el siguiente ejemplo, se muestra c�mo crear un Row que se distribuya de manera uniforme horizontalmente, como se ve en la Figura 1:

Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) {
    val modifier = GlanceModifier.defaultWeight()
    Text("first", modifier)
    Text("second", modifier)
    Text("third", modifier)
}

El elemento Row ocupa el ancho m�ximo disponible y, debido a que cada elemento secundario tiene el mismo el peso, comparten de manera uniforme el espacio disponible. Puedes definir diferentes pesos, tama�os, rellenos o alineaciones para adaptar los dise�os a tus necesidades.

C�mo usar dise�os desplazables

Otra forma de proporcionar contenido responsivo es hacerlo que se pueda desplazar. Este es posible con el elemento LazyColumn componible. Este elemento componible te permite definir un conjunto de elementos que se mostrar�n dentro de un contenedor desplazable en el widget de la app.

Los siguientes fragmentos muestran distintas maneras de definir elementos dentro del LazyColumn

Puedes proporcionar la cantidad de elementos de las siguientes maneras:

// Remember to import Glance Composables
// import androidx.glance.appwidget.layout.LazyColumn

LazyColumn {
    items(10) { index: Int ->
        Text(
            text = "Item $index",
            modifier = GlanceModifier.fillMaxWidth()
        )
    }
}

Proporciona elementos individuales:

LazyColumn {
    item {
        Text("First Item")
    }
    item {
        Text("Second Item")
    }
}

Proporciona una lista o un array de elementos:

LazyColumn {
    items(peopleNameList) { name ->
        Text(name)
    }
}

Tambi�n puedes usar una combinaci�n de los ejemplos anteriores:

LazyColumn {
    item {
        Text("Names:")
    }
    items(peopleNameList) { name ->
        Text(name)
    }

    // or in case you need the index:
    itemsIndexed(peopleNameList) { index, person ->
        Text("$person at index $index")
    }
}

Ten en cuenta que el fragmento anterior no especifica el itemId. Especificar el valor itemId ayuda a mejorar el rendimiento y mantener el desplazamiento. de posici�n a trav�s de la lista y actualizaciones de appWidget a partir de Android 12 (para por ejemplo, cuando se agregan o quitan elementos de la lista). El siguiente ejemplo se muestra c�mo especificar un itemId:

items(items = peopleList, key = { person -> person.id }) { person ->
    Text(person.name)
}

Define el SizeMode

Los tama�os de AppWidget pueden variar seg�n el dispositivo, la elecci�n del usuario o el selector. por lo que es importante proporcionar dise�os flexibles como se describe en la secci�n C�mo proporcionar de widgets flexibles. La vista r�pida simplifica esto con el SizeMode definici�n y el valor LocalSize. En las siguientes secciones, se describen los tres modos.

SizeMode.Single

SizeMode.Single es el modo predeterminado. Indica que solo un tipo de se proporciona contenido. es decir, incluso si cambia el tama�o disponible de AppWidget, no se cambia el tama�o del contenido.

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Single

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the minimum size or resizable
        // size defined in the App Widget metadata
        val size = LocalSize.current
        // ...
    }
}

Cuando uses este modo, aseg�rate de lo siguiente:

  • Los valores de metadatos de tama�o m�nimo y m�ximo se definen correctamente seg�n el tama�o del contenido.
  • El contenido es lo suficientemente flexible dentro del rango de tama�o esperado.

En general, debes usar este modo en los siguientes casos:

a) AppWidget tiene un tama�o fijo. b) No cambia su contenido cuando se le cambia el tama�o.

SizeMode.Responsive

Este modo es el equivalente a proporcionar dise�os responsivos, que permite el GlanceAppWidget para definir un conjunto de dise�os responsivos delimitados por tama�os. Para cada tama�o definido, se crea el contenido y se asigna a la cuenta cuando se crea o actualiza AppWidget. A continuaci�n, el sistema selecciona m�s adecuada seg�n el tama�o disponible.

Por ejemplo, en nuestro AppWidget de destino, puedes definir tres tama�os y sus contenido:

class MyAppWidget : GlanceAppWidget() {

    companion object {
        private val SMALL_SQUARE = DpSize(100.dp, 100.dp)
        private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
        private val BIG_SQUARE = DpSize(250.dp, 250.dp)
    }

    override val sizeMode = SizeMode.Responsive(
        setOf(
            SMALL_SQUARE,
            HORIZONTAL_RECTANGLE,
            BIG_SQUARE
        )
    )

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be one of the sizes defined above.
        val size = LocalSize.current
        Column {
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            }
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width >= HORIZONTAL_RECTANGLE.width) {
                    Button("School")
                }
            }
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "provided by X")
            }
        }
    }
}

En el ejemplo anterior, se llama al m�todo provideContent tres veces. asignado al tama�o definido.

  • En la primera llamada, el tama�o se eval�a como 100x100. El contenido no incluir el bot�n extra, ni los textos de arriba o de abajo.
  • En la segunda llamada, el tama�o se eval�a como 250x100. El contenido incluye bot�n adicional, pero no los textos de la parte superior y la inferior.
  • En la tercera llamada, el tama�o se eval�a como 250x250. El contenido incluye el bot�n extra y ambos textos.

SizeMode.Responsive es una combinaci�n de los otros dos modos y te permite a definir el contenido responsivo dentro de los l�mites predefinidos. En general, este modo Funciona mejor y permite transiciones m�s fluidas cuando se cambia el tama�o de AppWidget.

En la siguiente tabla, se muestra el valor del tama�o, seg�n el SizeMode y el tama�o disponible de AppWidget:

Tama�o disponible 105 x 110 203 x 112 72 x 72 203 � 150
SizeMode.Single 110 x 110 110 x 110 110 x 110 110 x 110
SizeMode.Exact 105 x 110 203 x 112 72 x 72 203 � 150
SizeMode.Responsive 80 x 100 80 x 100 80 x 100 150 x 120
* Los valores exactos son solo para fines de demostraci�n.

SizeMode.Exact

SizeMode.Exact es el equivalente a proporcionar dise�os exactos, que solicita el contenido de GlanceAppWidget cada vez que el tama�o disponible de AppWidget cambia (por ejemplo, cuando el usuario cambia el tama�o de AppWidget en la pantalla principal).

Por ejemplo, en el widget de destino, se puede agregar un bot�n adicional si el elemento el ancho disponible es mayor que un valor determinado.

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Exact

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the size of the AppWidget
        val size = LocalSize.current
        Column {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width > 250.dp) {
                    Button("School")
                }
            }
        }
    }
}

Este modo proporciona m�s flexibilidad que los otros, pero incluye algunas advertencias:

  • El elemento AppWidget debe volver a crearse por completo cada vez que cambie el tama�o. Esta puede provocar problemas de rendimiento y saltos en la IU cuando el contenido es complejo.
  • El tama�o disponible puede variar seg�n la implementaci�n del selector. Por ejemplo, si el selector no proporciona la lista de tama�os, el tama�o m�nimo el tama�o posible.
  • En dispositivos con versiones anteriores a Android 12, es posible que la l�gica de c�lculo del tama�o no funcione en todos los casos. situaciones.

En general, debes usar este modo si no se puede usar SizeMode.Responsive. (es decir, un peque�o conjunto de dise�os adaptables no es factible).

Accede a recursos

Usa LocalContext.current para acceder a cualquier recurso de Android, como se muestra en la siguiente ejemplo:

LocalContext.current.getString(R.string.glance_title)

Te recomendamos que proporciones los IDs de recursos directamente para reducir el tama�o de la versi�n RemoteViews y para habilitar recursos din�micos, como los objetos de colores.

Los elementos componibles y los m�todos aceptan recursos que usan un "proveedor", como ImageProvider o con un m�todo de sobrecarga, como GlanceModifier.background(R.color.blue) Por ejemplo:

Column(
    modifier = GlanceModifier.background(R.color.default_widget_background)
) { /**...*/ }

Image(
    provider = ImageProvider(R.drawable.ic_logo),
    contentDescription = "My image",
)

C�mo procesar texto

Glance 1.1.0 incluye una API para configurar tus estilos de texto. Establecer estilos de texto con Atributos fontSize, fontWeight o fontFamily de la clase TextStyle

fontFamily admite todas las fuentes del sistema, como se muestra en el siguiente ejemplo, pero No se admiten las fuentes personalizadas en las apps:

Text(
    style = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 18.sp,
        fontFamily = FontFamily.Monospace
    ),
    text = "Example Text"
)

Cómo agregar botones compuestos

Los botones compuestos se introdujeron en Android 12. Vistazo hacia atrás compatibilidad para los siguientes tipos de botones compuestos:

Cada uno de estos botones compuestos muestra una vista en la que se puede hacer clic que representa la “marcado” para cada estado.

var isApplesChecked by remember { mutableStateOf(false) }
var isEnabledSwitched by remember { mutableStateOf(false) }
var isRadioChecked by remember { mutableStateOf(0) }

CheckBox(
    checked = isApplesChecked,
    onCheckedChange = { isApplesChecked = !isApplesChecked },
    text = "Apples"
)

Switch(
    checked = isEnabledSwitched,
    onCheckedChange = { isEnabledSwitched = !isEnabledSwitched },
    text = "Enabled"
)

RadioButton(
    checked = isRadioChecked == 1,
    onClick = { isRadioChecked = 1 },
    text = "Checked"
)

Cuando cambia el estado, se activa la expresión lambda proporcionada. Puedes almacenar el y verificar el estado, como se muestra en el siguiente ejemplo:

class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        val myRepository = MyRepository.getInstance()

        provideContent {
            val scope = rememberCoroutineScope()

            val saveApple: (Boolean) -> Unit =
                { scope.launch { myRepository.saveApple(it) } }
            MyContent(saveApple)
        }
    }

    @Composable
    private fun MyContent(saveApple: (Boolean) -> Unit) {

        var isAppleChecked by remember { mutableStateOf(false) }

        Button(
            text = "Save",
            onClick = { saveApple(isAppleChecked) }
        )
    }
}

Tambi�n puedes proporcionar el atributo colors a CheckBox, Switch y RadioButton para personalizar sus colores:

CheckBox(
    // ...
    colors = CheckboxDefaults.colors(
        checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight),
        uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked }
)

Switch(
    // ...
    colors = SwitchDefaults.colors(
        checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan),
        uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta),
        checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow),
        uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked },
    text = "Enabled"
)

RadioButton(
    // ...
    colors = RadioButtonDefaults.colors(
        checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow),
        uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue)
    ),

)

Componentes adicionales

Glance 1.1.0 incluye el lanzamiento de componentes adicionales, como se describe en la siguiente tabla:

Name Imagen V�nculo de referencia Notas adicionales
Bot�n relleno alt_text Componente
Botones con contorno alt_text Componente
Botones de �conos alt_text Componente Principal / secundario / Solo icono
Barra de t�tulo alt_text Componente
Scaffold El andamiaje y la barra de t�tulo est�n en la misma demostraci�n.

Para obtener m�s informaci�n sobre los detalles del dise�o, consulta los dise�os de componentes en esta kit de dise�o en Figma.