wandres.dev
WIDGETS CON GLANCE · fuera de la app

Diseño de widgets: tamaños, previsualización, tema y calidad

Un widget compite por el bien más escaso del dispositivo, que es el espacio de la pantalla de inicio, y esa competición se gana o se pierde en detalles que no tienen nada que ver con la lógica: si aparece con buen aspecto en el selector antes de ser instalado, si sobrevive a cualquier tamaño que el usuario le dé, si respeta el color y el radio de esquina que el sistema impone y si su contenido merece el hueco que ocupa. Esta lección cubre la cuadrícula de celdas y sus metadatos, los tres modos de tamaño de Glance con el análisis de coste del modo responsivo, las previsualizaciones estáticas y generadas, la integración con el tema dinámico del sistema y el modo claro y oscuro, y las guías de calidad con las que se evalúa un widget antes de publicarlo.

⏱ 20 min

La pantalla de inicio es el único territorio del dispositivo que el usuario ha organizado él mismo, con su propio criterio y su propia estética, y cada widget que coloca es una decisión de sacrificar espacio a cambio de algo. Esa transacción se juzga en dos momentos, y ninguno de los dos tiene que ver con la calidad de tu código. El primero ocurre en el selector, donde tu widget aparece junto a decenas de competidores y tiene que convencer con una imagen y una línea de texto antes de que nadie lo haya ejecutado. El segundo ocurre cuando el usuario lo arrastra, lo suelta y lo estira, y descubre en un par de segundos si esto se adapta con dignidad o si es una pantalla de móvil aplastada dentro de un rectángulo. Un widget técnicamente impecable que falla en cualquiera de esos dos momentos se desinstala y no vuelve, y por eso esta lección cierra el nivel: porque todo lo anterior era condición necesaria, y esto es lo que decide si el widget sobrevive a la primera semana.

🎯 Al terminar esta lección sabrás
  • Declarar tamaños en la cuadrícula de celdas y permitir el redimensionado con límites sensatos.
  • Elegir entre los tres modos de tamaño de Glance evaluando el coste de cada uno.
  • Proporcionar previsualizaciones estáticas y generadas que representen el widget real.
  • Integrar tema dinámico, modo oscuro y radios del sistema, y auditar contra las guías de calidad.

La cuadrícula, los metadatos y el redimensionado

El lanzador organiza el escritorio en celdas cuyo tamaño varía según el dispositivo, y tus metadatos declaran cuánto necesitas. Las versiones modernas permiten expresar el objetivo directamente en celdas, lo que evita la vieja aritmética de restar márgenes a múltiplos de setenta puntos independientes de densidad. Junto al tamaño objetivo se declaran el mínimo absoluto, el mínimo al redimensionar y los ejes en los que el redimensionado está permitido.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:minWidth="180dp"
    android:minHeight="110dp"
    android:minResizeWidth="110dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="400dp"
    android:maxResizeHeight="300dp"
    android:resizeMode="horizontal|vertical"
    android:description="@string/descripcion_widget"
    android:previewLayout="@layout/widget_preview"
    android:widgetFeatures="reconfigurable|configuration_optional" />

Conviene entender que ninguno de esos números es una promesa. El tamaño de celda difiere entre fabricantes, el usuario puede haber cambiado la densidad de la cuadrícula en los ajustes del lanzador, y un lanzador de terceros es libre de interpretar los metadatos como le parezca. Lo que declaras es una preferencia negociada, no una especificación, y la única defensa contra esa incertidumbre es que el diseño siga siendo legible en cualquier rectángulo comprendido entre tus mínimos y tus máximos.

Prohibir el redimensionado es casi siempre un error: el usuario que quiere estirar un widget y no puede concluye que la aplicación está mal hecha, y no se equivoca del todo. Lo correcto es permitirlo y declarar mínimos honestos, por debajo de los cuales el contenido dejaría de ser legible.

Los tres modos de tamaño

Glance ofrece tres estrategias y la elección tiene consecuencias medibles.

1️⃣

Único

Se compone una sola vez con el tamaño mínimo declarado. Barato y suficiente para widgets que solo escalan tipografía y espaciado.

🧩

Responsivo

Declaras un conjunto de tamaños y se compone uno por cada uno, de una vez. El anfitrión elige localmente el más adecuado al redimensionar, sin volver a despertarte.

📏

Exacto

Se compone con el tamaño real cada vez que cambia. Máxima precisión y máximo coste, porque cada arrastre del usuario provoca una composición y una transacción.

⚖️

El compromiso

Responsivo con tres o cuatro tamaños cubre casi todos los casos reales y mantiene el paquete dentro del límite de la transacción.

class TareasWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Responsive(
        setOf(
            DpSize(110.dp, 110.dp),
            DpSize(180.dp, 110.dp),
            DpSize(180.dp, 220.dp),
            DpSize(300.dp, 220.dp),
        ),
    )

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        provideContent {
            val ancho = LocalSize.current.width
            if (ancho < 180.dp) VistaCompacta() else VistaCompleta()
        }
    }
}
⚠️
El modo responsivo multiplica el tamaño del paquete

Cada tamaño declarado es un árbol completo traducido y enviado en la misma transacción. Cinco tamaños con una lista de diez elementos cada uno son cincuenta subárboles cruzando Binder a la vez, y el límite del búfer no distingue entre ambición y descuido. Si necesitas muchos tamaños, simplifica el contenido de los pequeños; si necesitas contenido rico, reduce el número de tamaños.

Adaptar el contenido, no solo escalarlo

Estirar tipografía y espaciado no es adaptarse. Un widget bien diseñado cambia lo que muestra según el espacio disponible, con una progresión pensada de antemano: en el tamaño mínimo, un solo dato y una sola acción; en el intermedio, ese dato con contexto y dos o tres acciones; en el grande, una lista corta con los elementos que de verdad importan. La pregunta que guía cada salto no es qué más cabe, sino qué merece entrar.

@Composable
private fun Contenido(resumen: ResumenTareas) {
    val tamano = LocalSize.current
    when {
        tamano.height < 130.dp -> UnaLinea(resumen.pendientes)
        tamano.width < 250.dp -> ResumenConAccion(resumen)
        else -> ListaCorta(resumen, maximo = 5)
    }
}

Al mismo problema pertenece el estado vacío, que casi siempre se resuelve por omisión y siempre mal. Un widget recién colocado, sin datos aún o sin configurar, es el primer contacto real del usuario con el producto en el escritorio, y una rueda girando o un rectángulo en blanco desperdician ese momento. Lo correcto es texto breve que explique qué aparecerá ahí y una acción que lleve a conseguirlo.

📝
El plegable convierte el redimensionado en algo cotidiano

En un dispositivo plegable, el mismo widget puede pasar del tamaño compacto al grande varias veces al día sin que nadie lo arrastre, porque el escritorio se reconfigura al abrir y cerrar. Eso convierte la calidad del comportamiento responsivo en algo visible a diario y no en un detalle de la instalación, y es el mejor banco de pruebas disponible para comprobar si la progresión de contenido que diseñaste tiene sentido.

Previsualización, tema y calidad

La previsualización es lo primero que el usuario ve y lo único que tiene para decidir. Durante años fue una imagen estática que envejecía en cuanto cambiaba el diseño; la plataforma moderna permite declarar un diseño real como previsualización, lo que garantiza coherencia visual, y las versiones más recientes permiten además generar previsualizaciones desde la propia aplicación en tiempo de ejecución, de modo que el selector muestre datos plausibles del usuario en lugar de cifras inventadas. La descripción textual acompaña a la imagen y debe explicar qué aporta, no repetir el nombre de la aplicación.

Hay una asimetría útil que casi nadie explota: la previsualización no tiene que ser un retrato fiel del estado vacío. Puede y debe mostrar el widget en su mejor momento, con datos realistas y con la densidad de información que tendrá cuando el usuario lleve una semana usándolo, porque su función no es informar sino contestar a la única pregunta que el usuario se hace en el selector, que es qué gano yo poniendo esto aquí.

El tema es la segunda mitad de la impresión. GlanceTheme expone la paleta dinámica derivada del fondo de pantalla en los dispositivos que la soportan y una alternativa propia en los que no, y resuelve por sí solo la variante clara y oscura si defines proveedores de color para ambas. Dos detalles se olvidan siempre: usar el color de fondo previsto para widgets en lugar del de superficie de la aplicación, y aplicar los radios de esquina del sistema al contenedor raíz, porque el anfitrión recorta con su propio radio y un fondo cuadrado asoma por las esquinas de forma inconfundible.

flowchart TD
A[El usuario abre el selector] --> B{La previsualizacion convence}
B -->|no| C[No se instala nunca]
B -->|si| D[Coloca el widget]
D --> E{Se adapta al estirarlo}
E -->|no| F[Se elimina en minutos]
E -->|si| G{El contenido merece el espacio}
G -->|no| H[Sobrevive dias y desaparece]
G -->|si| I[Se queda y se usa a diario]

La accesibilidad merece mención aparte porque en el escritorio se olvida más que en ninguna otra superficie. Toda imagen que aporte significado necesita descripción de contenido, todo elemento tocable necesita al menos cuarenta y ocho puntos independientes de densidad de objetivo táctil, y el contraste debe cumplirse contra el fondo del widget y no contra el que tú imaginabas, que en un escritorio con paleta dinámica puede ser cualquiera. El lector de pantalla recorre la descripción que enviaste, de modo que un widget cuya información viva únicamente en la posición relativa de los elementos resulta ininteligible al escucharlo.

Las guías de calidad con las que se evalúa un widget se resumen en un puñado de criterios verificables. Debe tener al menos un tamaño cómodo y adaptarse a los demás. Debe ofrecer una vía de configuración cuando el contenido dependa de una elección, y hacerla accesible después de colocado y no solo al principio. Debe mostrar algo útil desde el primer segundo, incluso sin datos, con un estado vacío que invite a actuar en lugar de una rueda girando. Debe respetar el tema, el radio y la accesibilidad, incluidas las descripciones de contenido y los objetivos táctiles de tamaño suficiente. Y debe llevar a alguna parte: cada zona tocable tiene que abrir la pantalla exacta que corresponde a lo que se ha tocado, nunca la pantalla principal genérica.

El escritorio no es una pantalla mas de tu aplicacion: es un espacio compartido donde tu app es invitada

Conviene terminar el nivel con la observación que ordena todas las decisiones de diseño de un widget y que casi ningún equipo formula explícitamente. Cuando diseñas una pantalla de tu aplicación, el usuario ha decidido entrar: te ha dedicado su atención completa, acepta tu tipografía, tu color y tus convenciones, y tú controlas cada píxel de lo que ve. Un widget se diseña en la situación exactamente contraria. Nadie ha decidido mirarlo; aparece en el campo visual del usuario decenas de veces al día mientras este busca otra cosa, rodeado de iconos que no controlas, sobre un fondo de pantalla que eligió otra persona, junto a widgets de la competencia que aplican su propio criterio estético, y sometido a un tema que el sistema impone y que puede cambiar de un día para otro. En ese contexto, la tentación de destacar es exactamente la estrategia equivocada. Un widget con la marca corporativa gritando, con la paleta de la aplicación impuesta sobre la del sistema y con la densidad de información de una pantalla completa no se percibe como potente sino como intruso, y los objetos que se perciben como intrusos en un espacio personal se eliminan sin remordimiento. La estrategia correcta es la contraria y resulta contraintuitiva para cualquiera que venga de marketing: el widget debe parecer parte del sistema operativo, no parte de tu aplicación. Debe adoptar el color dinámico del fondo del usuario, el radio de esquina del anfitrión, la tipografía del sistema y el peso visual de sus vecinos, y reservar su identidad para el contenido que aporta y no para el envoltorio que lo rodea. Hay una segunda mitad de esa idea, todavía más exigente, que tiene que ver con la economía de la atención. El espacio de la pantalla de inicio es finito, saturado y disputado, y el usuario evalúa constantemente y sin darse cuenta si lo que ocupa un hueco justifica el hueco. Un widget que muestra información que el usuario podría obtener abriendo la aplicación no justifica nada, porque abrir la aplicación cuesta un toque. Solo justifica su lugar lo que ahorra una decisión: el dato que hace innecesario entrar, o la acción que evita el viaje completo. Ese es el filtro que hay que aplicar antes de escribir una sola línea, y el que explica por qué los widgets que sobreviven en las pantallas de la gente son casi siempre los más pequeños y los más aburridos.

⚔️ Somete tu widget al juicio del escritorio
  1. Declara tamaño objetivo en celdas y redimensionado en ambos ejes, y prueba tu widget en un móvil pequeño, una tableta y un plegable abierto.
  2. Cambia del modo único al responsivo con cuatro tamaños, mide el tamaño del paquete resultante y comprueba si el redimensionado despierta o no tu proceso.
  3. Sustituye la imagen estática de previsualización por un diseño real y compara ambas en el selector con el tema oscuro activado.
  4. Cambia el fondo de pantalla por uno de color muy saturado y verifica que tu paleta dinámica, tus contrastes y tus esquinas siguen siendo correctos.
  5. Recorre las guías de calidad punto por punto sobre tu widget y elimina todo elemento que no ahorre al usuario ni una decisión ni un toque.