Admite contenido escalable para el usuario

Implementa gestos de pellizcar para hacer zoom y admitir contenido escalable en tu app. Este es el método estándar y coherente con la plataforma para mejorar la accesibilidad, ya que permite a los usuarios ajustar de forma intuitiva el tamaño del texto y los elementos de la IU para que se adapten a sus necesidades. Tu app puede definir un comportamiento de ajuste personalizado con un control detallado y un comportamiento contextual que ofrece una experiencia que los usuarios suelen descubrir más rápido que una función a nivel del sistema, como la ampliación de pantalla.

Elige una estrategia de escalamiento

Las estrategias que se abordan en esta guía hacen que la IU se reorganice y se adapte para ajustarse al ancho de la pantalla. Esto proporciona un beneficio de accesibilidad significativo, ya que elimina la necesidad de realizar un desplazamiento horizontal y el frustrante movimiento en "zig-zag" que, de lo contrario, sería necesario para leer líneas de texto largas.

Lectura adicional: La investigación confirma que, para los usuarios con visión reducida, el reflujo de contenido es mucho más legible y fácil de navegar que las interfaces que requieren desplazamiento panorámico bidimensional. Para obtener más información, consulta A Comparison of Pan-and-Scan and Reflowable Content on Mobile Devices (Comparación del contenido de paneo y escaneo y del contenido adaptable en dispositivos móviles).

Ajustar la escala de todos los elementos o solo de los elementos de texto

En la siguiente tabla, se muestra el efecto visual de cada estrategia de ajuste.

Estrategia Ajuste de la densidad Ajuste de la fuente

Comportamiento

Escala todo de forma proporcional. El contenido se redistribuye para ajustarse a su contenedor, de modo que el usuario no necesita desplazarse horizontalmente para ver todo el contenido.

Solo afecta a los elementos de texto. El diseño general y los componentes que no son de texto conservan el mismo tamaño.

Qué escalas

Todos los elementos visuales: Texto, componentes (botones, íconos), imágenes y espaciado del diseño (padding, márgenes)

Solo texto

Demostración

Recomendaciones

Ahora que viste las diferencias visuales, la siguiente tabla te ayudará a sopesar las ventajas y desventajas, y a elegir la mejor estrategia para tu contenido.

Tipo de IU

Estrategia recomendada

Motivo

Diseños con mucha lectura

Ejemplos: Artículos de noticias, apps de mensajería

Ajuste de densidad o de fuente

Se prefiere el ajuste de escala de densidad para ajustar el tamaño de toda el área de contenido, incluidas las imágenes intercaladas.

El ajuste de escala de la fuente es una alternativa sencilla si solo se necesita ajustar la escala del texto.

Diseños estructurados visualmente

Ejemplos: Tiendas de aplicaciones, feeds de redes sociales

Ajuste de densidad

Conserva las relaciones visuales entre las imágenes y el texto en los carruseles o las cuadrículas. La naturaleza de reflujo evita el desplazamiento horizontal, que entraría en conflicto con los elementos de desplazamiento anidados.

Cómo detectar gestos de ajuste en Jetpack Compose

Para admitir contenido escalable por el usuario, primero debes detectar los gestos multitáctiles. En Jetpack Compose, puedes hacerlo con Modifier.transformable.

El modificador transformable es una API de alto nivel que proporciona el delta de zoomChange desde el último evento de gesto. Esto simplifica la lógica de actualización del estado para la acumulación directa (por ejemplo, scale *= zoomChange), lo que la hace ideal para las estrategias de ajuste adaptable que se describen en esta guía.

Ejemplos de implementación

En los siguientes ejemplos, se muestra cómo implementar las estrategias de ajuste de densidad y de fuentes.

Ajuste de la densidad

Este enfoque ajusta la escala del density base de un área de la IU. Como resultado, todas las mediciones basadas en el diseño, incluidos el padding, el espaciado y los tamaños de los componentes, se escalan como si hubiera cambiado el tamaño o la resolución de la pantalla. Dado que el tamaño del texto también depende de la densidad, también se ajusta de forma proporcional. Esta estrategia es eficaz cuando deseas agrandar de manera uniforme todos los elementos dentro de un área específica, manteniendo el ritmo visual general y las proporciones de tu IU.

private class DensityScalingState(
    // Note: For accessibility, typical min/max values are ~0.75x and ~3.5x.
    private val minScale: Float = 0.75f,
    private val maxScale: Float = 3.5f,
    private val currentDensity: Density
) {
    val transformableState = TransformableState { zoomChange, _, _ ->
        scaleFactor.floatValue =
            (scaleFactor.floatValue * zoomChange).coerceIn(minScale, maxScale)
    }
    val scaleFactor = mutableFloatStateOf(1f)
    fun scaledDensity(): Density {
        return Density(
            currentDensity.density * scaleFactor.floatValue,
            currentDensity.fontScale
        )
    }
}

Ajuste de la fuente

Esta estrategia es más segmentada, ya que solo modifica el factor fontScale. El resultado es que solo los elementos de texto crecen o se reducen, mientras que todos los demás componentes de diseño, como los contenedores, el padding y los íconos, conservan un tamaño fijo. Esta estrategia es adecuada para mejorar la legibilidad del texto en apps con mucho contenido de lectura.

class FontScaleState(
    // Note: For accessibility, typical min/max values are ~0.75x and ~3.5x.
    private val minScale: Float = 0.75f,
    private val maxScale: Float = 3.5f,
    private val currentDensity: Density
) {
    val transformableState = TransformableState { zoomChange, _, _ ->
        scaleFactor.floatValue =
            (scaleFactor.floatValue * zoomChange).coerceIn(minScale, maxScale)
    }
    val scaleFactor = mutableFloatStateOf(1f)
    fun scaledFont(): Density {
        return Density(
            currentDensity.density,
            currentDensity.fontScale * scaleFactor.floatValue
        )
    }
}

IU de demostración compartida

Este es el elemento DemoCard componible compartido que usan los dos ejemplos anteriores para destacar los diferentes comportamientos de escalamiento.

@Composable
private fun DemoCard() {
    Card(
        modifier = Modifier
            .width(360.dp)
            .padding(16.dp),
        shape = RoundedCornerShape(12.dp)
    ) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            Text("Demo Card", style = MaterialTheme.typography.headlineMedium)
            var isChecked by remember { mutableStateOf(true) }
            Row(verticalAlignment = Alignment.CenterVertically) {
                Text("Demo Switch", Modifier.weight(1f), style = MaterialTheme.typography.bodyLarge)
                Switch(checked = isChecked, onCheckedChange = { isChecked = it })
            }
            Row(verticalAlignment = Alignment.CenterVertically) {
                Icon(Icons.Filled.Person, "Icon", Modifier.size(32.dp))
                Spacer(Modifier.width(8.dp))
                Text("Demo Icon", style = MaterialTheme.typography.bodyLarge)
            }
            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                Box(
                    Modifier
                        .width(100.dp)
                        .weight(1f)
                        .height(80.dp)
                        .background(Color.Blue)
                )
                Box(
                    Modifier
                        .width(100.dp)
                        .weight(1f)
                        .height(80.dp)
                        .background(Color.Red)
                )
            }
            Text(
                "Demo Text: Lorem ipsum dolor sit amet, consectetur adipiscing elit," +
                    " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
                style = MaterialTheme.typography.bodyMedium,
                textAlign = TextAlign.Justify
            )
        }
    }
}

Sugerencias y consideraciones

Para crear una experiencia más refinada y accesible, ten en cuenta las siguientes recomendaciones:

  • Considera ofrecer controles de escala que no sean gestuales: Algunos usuarios pueden tener dificultades con los gestos. Para ayudar a estos usuarios, considera proporcionar una forma alternativa de ajustar o restablecer la escala que no dependa de los gestos.
  • Compila para todas las escalas: Prueba tu IU con el ajuste de escala en la app y con la configuración de fuente o pantalla en todo el sistema. Verifica que los diseños de tu app se adapten correctamente sin interrumpir, superponer ni ocultar contenido. Obtén más información para compilar diseños adaptables.