Addaw, ir a inicio Donar

Lección 7 de 10 · 13 min de lectura · Revisado el 26/10/2026

Componentes complejos: listas, pestañas, carruseles, mapas, gráficos y vídeo

Los botones y campos bien etiquetados resuelven la mayor parte de una app, pero las pantallas que más valor aportan suelen apoyarse en componentes complejos: listas largas con acciones, pestañas, carruseles, mapas, gráficos y reproductores de vídeo. Son también los que concentran los fallos que una auditoría marca como bloqueantes, porque no se arreglan con una etiqueta. En el nivel 3 viste sus equivalentes web con los patrones de la APG (se abre en una ventana nueva); aquí verás cómo se resuelven con las API nativas que ya conoces de las lecciones de iOS y Android.

Listas y colecciones

Una lista accesible permite saber cuántos elementos hay y en cuál estás, recorrerlos sin perderse y ejecutar las acciones de cada fila sin gestos especiales.

  • Posición y tamaño: RecyclerView, LazyColumn y LazyVerticalGrid exponen información de colección y TalkBack la usa para anunciar, por ejemplo, la entrada en una lista y su tamaño. Si construyes una lista o una cuadrícula a mano con Column o Row, añade Modifier.semantics { collectionInfo = CollectionInfo(rowCount = n, columnCount = 1) } al contenedor y collectionItemInfo a cada elemento. En iOS, cuando la posición sea relevante (resultados de búsqueda, pasos), inclúyela en el accessibilityValue: «3 de 12».
  • Acciones de fila: las acciones de deslizamiento de UITableView (trailingSwipeActionsConfiguration) y de .swipeActions en SwiftUI se ofrecen a VoiceOver como acciones del elemento. En Android, un ItemTouchHelper o un SwipeToDismissBox no son accesibles por sí solos: añade acciones personalizadas («Archivar», «Eliminar») y un menú visible (2.5.1 Gestos del puntero, 2.5.7 Movimientos de arrastre).
  • Desplazamiento infinito: si la lista carga más elementos al llegar al final, anuncia la carga («Cargando más resultados») y su resultado, y no coloques información esencial (contacto, aviso legal) en un pie de página al que nunca se llega.
  • Tirar para actualizar: ofrece además un botón o una acción «Actualizar»; el gesto de arrastre no puede ser la única vía.

Pestañas, controles segmentados e interruptores

Los componentes del sistema (UITabBarController, TabView, NavigationBar de Material, TabRow, UISegmentedControl) anuncian el rol, la posición y el estado seleccionado. Cuando el diseño exige una barra propia, hay que reconstruir esa información:

// Compose: barra de pestañas propia
Row(Modifier.selectableGroup()) {
    secciones.forEachIndexed { i, s ->
        Box(
            Modifier
                .selectable(
                    selected = i == actual,
                    onClick = { actual = i },
                    role = Role.Tab
                )
                .minimumInteractiveComponentSize()
        ) { Text(s.titulo) }
    }
}

// SwiftUI: botón de pestaña propio
Button(s.titulo) { actual = i }
    .accessibilityAddTraits(i == actual ? [.isSelected] : [])
// En UIKit, el contenedor de la barra propia lleva el rasgo .tabBar
barraPropia.accessibilityTraits = .tabBar

Para interruptores propios, usa Modifier.toggleable(value, role = Role.Switch) en Compose y, en SwiftUI, Toggle con un estilo personalizado antes que un botón que cambia de color. El estado nunca se transmite solo por el color del control (1.4.1 Uso del color, 1.4.11 Contraste no textual).

Carruseles y paginadores

En la lección de apps híbridas verás un carrusel resuelto como control ajustable en React Native. El mismo patrón existe en nativo: rasgo .adjustable con accessibilityIncrement() y accessibilityDecrement() en UIKit, o .accessibilityAdjustableAction en SwiftUI; en Android, ViewPager2 y HorizontalPager exponen acciones de desplazamiento, y conviene añadir un stateDescription «Página 2 de 6». Las reglas de fondo no cambian: sin autoavance o con pausa visible (2.2.2 Pausar, detener, ocultar), flechas con nombre y 48 dp, e indicadores de página que no sean solo puntos de color.

Error frecuente

Un carrusel de ofertas que avanza solo cada cinco segundos: con TalkBack, el foco salta a la tarjeta siguiente a mitad de lectura, o el contenido cambia bajo el dedo de quien usa Switch Access antes de que pueda seleccionarlo. Detén el avance automático cuando haya un lector de pantalla, cuando el sistema indique reducir movimiento y siempre que el carrusel reciba foco, y ofrece un botón de pausa visible.

Mapas y ubicación

Un mapa es contenido no textual (1.1.1 Contenido no textual) y, si se usa para elegir un punto, una interacción por arrastre. Para que una tarea basada en mapa sea accesible:

  1. Alternativa en lista: los resultados representados con marcadores (oficinas, paradas, puntos de recarga) están también en una lista ordenable, con nombre, dirección y distancia.
  2. Marcadores con nombre: en MapKit, la anotación expone su título; en otros SDK de mapas el soporte varía, así que verifica con VoiceOver y TalkBack qué se anuncia y, si no basta, oculta el mapa a la tecnología de apoyo y remite a la lista.
  3. Elegir ubicación sin arrastrar: además de mover el mapa hasta colocar el punto, permite escribir una dirección, usar la ubicación actual o elegir de una lista de direcciones recientes (2.5.7 Movimientos de arrastre).
  4. Zoom con botones: «+» y «−» como alternativa a la pinza (2.5.1), como viste en la primera lección.

Gráficos y visualización de datos

Un gráfico de gastos, de consumo eléctrico o de pasos necesita, como mínimo, una descripción textual de lo que muestra (la idea principal y los datos clave) y, si los datos importan, una forma de consultarlos uno a uno o en tabla. Las plataformas ofrecen herramientas distintas:

  • iOS: Swift Charts genera elementos accesibles para las marcas del gráfico. Para gráficos propios, un AXChartDescriptor (iOS 15), asignado a la propiedad accessibilityChartDescriptor de la vista, permite describir ejes y series; VoiceOver lo usa para ofrecer los Audio Graphs (gráficos sonoros), que representan los valores con tonos. En SwiftUI, el modificador .accessibilityChartDescriptor lo conecta a la vista.
  • Android: no existe un equivalente del sistema. En Views, ExploreByTouchHelper permite crear nodos virtuales para cada barra o punto de una vista dibujada con Canvas; en Compose, superpone elementos con semántica propia o expón una lista de valores con contentDescription y stateDescription.
  • En todas: no codifiques series solo por color (1.4.1), asegura 3:1 en líneas y barras frente al fondo (1.4.11) y ofrece la tabla de datos con un botón «Ver datos».

Ejemplo

App de una comercializadora eléctrica: el gráfico de consumo por horas se resume como «Consumo de ayer: 9,4 kWh; máximo a las 21:00 con 1,2 kWh; mínimo entre las 3:00 y las 6:00». En iOS, las barras exponen un AXChartDescriptor para explorar con Audio Graphs; en Android, cada barra es un nodo virtual con «21:00, 1,2 kWh, tramo punta». Un botón «Ver como tabla» abre los 24 valores con el tramo de cada hora en texto, no solo en color.

Vídeo, audio y retroalimentación

Las apps que reproducen vídeo heredan los criterios 1.2.x de multimedia vistos en el nivel 2. En el entorno nativo:

  • Subtítulos y preferencias del sistema: AVPlayerViewController muestra las pistas de subtítulos del contenido y aplica el estilo que la persona elige en los ajustes de subtítulos de iOS. En Android, Media3 (ExoPlayer) puede seleccionar la pista de texto según las preferencias del CaptioningManager y aplicar su estilo. Respeta esas preferencias en lugar de imponer un estilo propio.
  • Audiodescripción: si el contenido incluye pistas de audiodescripción, ofrécelas en el selector de audio con un nombre comprensible; AVFoundation identifica estas pistas con la característica describesVideoForAccessibility.
  • Controles: todos con nombre y estado («Pausar», «Subtítulos, activados»), sin desaparecer mientras el lector de pantalla está activo y sin reproducción automática con sonido (1.4.2 Control del audio).
  • Retroalimentación háptica y sonora: una vibración o un sonido al completar una acción son útiles como refuerzo, pero el resultado debe comunicarse también en texto y como mensaje de estado (1.3.3, 4.1.3).

Pruébalo tú

En una app con mapa (transporte, comida a domicilio, alquiler de patinetes), intenta elegir una dirección de destino sin tocar el mapa y con VoiceOver o TalkBack activo. Si solo puedes hacerlo moviendo el mapa con el dedo, acabas de encontrar un incumplimiento de 2.5.7 y, muy probablemente, una tarea bloqueada para quien usa lector de pantalla.

Resumen

  • Las listas exponen posición y tamaño, sus acciones de deslizamiento tienen alternativa accesible y la carga infinita no esconde información esencial.
  • Pestañas, segmentados e interruptores propios reconstruyen rol, estado y grupo (Role.Tab, selectableGroup, .isSelected, .tabBar); mejor aún, usa los del sistema.
  • Carruseles como controles ajustables, sin autoavance o con pausa visible; mapas con lista alternativa y elección de ubicación sin arrastre.
  • Gráficos con resumen textual, datos consultables (AXChartDescriptor, nodos virtuales, tabla) y sin depender del color.
  • Vídeo con subtítulos que siguen las preferencias del sistema, audiodescripción cuando exista y controles etiquetados; la vibración o el sonido nunca son la única respuesta.

Comprueba lo que has aprendido

Esta lección se puede leer libremente. Para hacer su test de 3 preguntas, los ejercicios prácticos con páginas reales, guardar tu avance y optar al examen y al certificado, matricúlate en el curso.

Matricularme · nivel 6 (119 €)