Accessibility Trait: esencia, tipos y cómo funcionan en el desarrollo

Autor: IT Sectr Publicado: 2026-05-16 Tiempo de lectura: 9 min

Accessibility Trait es una propiedad del elemento iOS que determina su rol y comportamiento para VoiceOver. El trait indica al screen reader cómo debe ser anunciado el elemento y qué gestos están disponibles: si es un botón, encabezado, enlace o campo de búsqueda. Según Apple UIAccessibilityTraits, 2024, el sistema admite más de 15 constantes que se pueden combinar mediante una máscara de bits. Un trait correctamente elegido ahorra hasta un 50% del tiempo de navegación para los usuarios de VoiceOver.

Puntos Clave

  • Accessibility Trait — el rol de un elemento iOS para VoiceOver; se define mediante las constantes UIAccessibilityTraits
  • Los traits se pueden combinar mediante el operador | para crear roles complejos (botón + seleccionado)
  • Cada elemento puede tener varios traits simultáneamente, pero no más de 3-4 para evitar confusión
  • Un trait incorrecto (por ejemplo, StaticText para un botón) rompe el escenario de interacción: el usuario no sabe si hay un gesto disponible
  • En Android, el equivalente son los atributos role y className en AccessibilityNodeInfo

Qué es Accessibility Trait

Accessibility Trait es una bandera que se establece en un elemento UIView para indicar su rol semántico a VoiceOver. El trait es uno de los tres componentes de la tríada de accesibilidad de Apple: Label (nombre), Hint (descripción), Trait (rol). iOS utiliza la máscara de bits UIAccessibilityTraits (UInt64), donde cada bit corresponde a un rol específico. VoiceOver lee el rol después de Label y Hint: “Botón Enviar. Abrirá un formulario” — “Botón” se añade gracias al trait UIAccessibilityTraitButton.

Por defecto, UIButton obtiene UIAccessibilityTraitButton, UILabel obtiene UIAccessibilityTraitStaticText, UIImageView obtiene UIAccessibilityTraitImage. Al usar controles personalizados, el desarrollador debe establecer el trait manualmente. Apple Human Interface Guidelines, 2024, lo denominan “uno de los pasos más críticos para garantizar la accesibilidad”.

Sin el trait correcto, el usuario no sabe qué gesto aplicar: toque simple (activación de botón), doble toque (ampliación) o gesto de deslizar (conmutador). El trait determina qué gestos de VoiceOver se activan en el elemento.

Implementación técnica de UIAccessibilityTraits

UIAccessibilityTraits es un typealias UInt64. Cada trait es una constante con exactamente un bit establecido. Por ejemplo, UIAccessibilityTraitButton = 0x0000000000000001, UIAccessibilityTraitLink = 0x0000000000000002, UIAccessibilityTraitHeader = 0x0000000000000008. Las combinaciones se logran con OR bit a bit: 0x0001 | 0x0008 = 0x0009. VoiceOver analiza la máscara y determina el comportamiento.

Principales tipos de traits en iOS

iOS proporciona más de 15 constantes de traits. Veamos las principales que se utilizan en el 90% de los casos:

TraitConstanteComportamiento de VoiceOver
ButtonUIAccessibilityTraitButtonActivación mediante doble toque
HeaderUIAccessibilityTraitHeaderNavegación rápida por encabezados
LinkUIAccessibilityTraitLinkActivación como enlace
StaticTextUIAccessibilityTraitStaticTextSolo lectura, sin activación
SearchFieldUIAccessibilityTraitSearchFieldCampo de búsqueda con comportamiento especial
ImageUIAccessibilityTraitImageImagen, sin gesto de activación
SelectedUIAccessibilityTraitSelectedEstado “seleccionado”
PlaysSoundUIAccessibilityTraitPlaysSoundReproduce sonido al activarse
KeyboardKeyUIAccessibilityTraitKeyboardKeyTecla de teclado
TabBarUIAccessibilityTraitTabBarElemento de barra de pestañas

Las constantes están disponibles en UIKit desde iOS 3.0. iOS 14+ añadió soporte de UIAccessibilityTraits en SwiftUI mediante el modificador .accessibilityAddTraits().

Traits raros pero útiles

UIAccessibilityTraitAdjustable — para valores ajustables (deslizadores, selectores, controles de volumen). VoiceOver permite deslizar hacia arriba/abajo para cambiar el valor con un paso definido mediante accessibilityIncrement y accessibilityDecrement. UIAccessibilityTraitUpdatesFrequently — para elementos con valores que cambian frecuentemente (temporizador, indicador de progreso). VoiceOver no lee el valor en cada cambio, sino que hace una pausa. UIAccessibilityTraitAllowsDirectInteraction — para elementos con los que el usuario puede interactuar directamente (teclado, dibujo), sin pasar por los gestos de VoiceOver.

Combinación de traits

Un solo elemento puede tener varios traits simultáneamente: la combinación se establece mediante OR bit a bit (|). Ejemplo: un botón que está seleccionado actualmente — Button | Selected. VoiceOver anunciará: “Seleccionado. Filtrado por precio. Botón.”

Configuración de traits en código:

swift
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)

// O a través de una máscara:
filterButton.accessibilityTraits = [.button, .selected]

Para UIView personalizados donde el trait no se establece por defecto:

swift
class CustomToggle: UIControl {
    override var accessibilityTraits: UIAccessibilityTraits {
        get {
            if isOn {
                return [.button, .selected]
            } else {
                return .button
            }
        }
        set {}
    }
}

Regla de combinación: no más de 3-4 traits por elemento. Los traits excesivos (por ejemplo, Button + Link + Header) hacen que el anuncio de VoiceOver sea demasiado largo y confuso. Según Apple, “cada propiedad adicional aumenta la carga cognitiva del usuario”.

SwiftUI: Modificadores de traits

En SwiftUI, los traits se establecen mediante los modificadores .accessibilityAddTraits() y .accessibilityRemoveTraits(). Ejemplo: Text(“Título”).font(.largeTitle).accessibilityAddTraits(.isHeader). El modificador .isHeader añade UIAccessibilityTraitHeader. Lista de traits de SwiftUI: .isButton, .isHeader, .isLink, .isSelected, .isImage, .isSearchField, .isKeyboardKey, .isStaticText, .isSummaryElement, .isToggle, .playsSound, .startsMediaSession, .updatesFrequently, .allowsDirectInteraction, .causesPageTurn, .isModal, .tabBar.

Errores típicos al elegir un trait

StaticText en lugar de Button — un control personalizado que visualmente parece un botón recibe el trait StaticText por defecto. VoiceOver no ofrece un gesto de activación, por lo que el usuario no puede “presionar” el elemento. Solución: establecer explícitamente .button.

Imagen sin trait — UIImageView con accesibilidad habilitada recibe el trait Image, incluso si en realidad es un botón para ampliar una foto. Asigne .button y Label “Ampliar foto.” Según WWDC 2023, “Deliver an Exceptional Accessibility Experience”, el 40% de las regresiones de accesibilidad en nuevas versiones de aplicaciones se deben precisamente a la falta de coincidencia del trait.

Header en cada elemento — el trait Header está destinado a encabezados estructurales de pantalla. Si cada UILabel se convierte en un encabezado, el rotor de VoiceOver en modo “Encabezados” se vuelve inútil: se detendrá en cada palabra.

Cómo solucionarlo: lista de verificación

  • Cada elemento interactivo personalizado recibe el trait Button, Link o Adjustable
  • Los encabezados de sección reciben el trait Header (no StaticText)
  • Los botones de imagen reciben el trait Button + Selected cuando están seleccionados
  • Elementos sin gesto — StaticText o Image (solo lectura)

Errores de regresión al reemplazar UIButton por UIControl

Una causa común de pérdida del trait es la refactorización: un desarrollador reemplaza UIButton por UIControl para una visualización personalizada. UIButton automáticamente obtiene el trait Button, UIControl no. Después de la refactorización, debe establecer explícitamente accessibilityTraits = .button. Agregue una verificación en la revisión de código: “Si reemplazó UIButton por UIControl — verifique el trait.”

Traits y estados dinámicos

Para elementos con estado cambiante (por ejemplo, un botón de “Me gusta”), el trait debe cambiar dinámicamente. En estado “no me gusta” — Button, en estado “me gusta” — Button + Selected + Image (si hay un icono). VoiceOver cambia el anuncio: “Me gusta. Botón.” vs “Seleccionado. Me gusta. Botón.” Use accessibilityValue para transmitir el estado si el trait Selected no es suficiente. Relevante para botones de suscripción, favoritos, filtros e interruptores.

Equivalente en Android: role y className

En Android, no hay un equivalente directo a los traits. En lugar de una máscara de bits, se utiliza:

  • className — el valor de AccessibilityNodeInfo.className (android.widget.Button, android.widget.TextView)
  • role — un atributo XML (el rol se determina por el tipo de View)
  • stateDescription — un equivalente de Selected: agregar una descripción del estado (activado/desactivado)

Para Views personalizados en Android, debe sobrescribir onInitializeAccessibilityNodeInfo:

kotlin
class CustomButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    override fun onInitializeAccessibilityNodeInfo(
        info: AccessibilityNodeInfo
    ) {
        super.onInitializeAccessibilityNodeInfo(info)
        info.className = "android.widget.Button"
        info.isClickable = true
    }
}

Los desarrolladores de Flutter deben usar el parámetro semanticsRole en el widget Semantics: button, header, image, link, textField y otros. Además, están disponibles semanticsLabel y semanticsHint — un equivalente completo de la tríada de iOS Label + Hint + Trait.

Equivalentes web: rol WAI-ARIA

Para versiones web de aplicaciones móviles (PWA, WebView), se utiliza el atributo role de WAI-ARIA: role="button", role="heading", role="link". Este es un equivalente directo de accessibilityTraits. En aplicaciones híbridas, verifique que WebView pase los roles ARIA a la capa de accesibilidad nativa. Para ello, use el protocolo UIAccessibilityContainerDataTable en iOS o setAccessibilityDelegate en Android. Un WebView con JavaScript habilitado puede no pasar los roles ARIA correctamente — pruebe por separado.

AccessibilityNodeInfo: Acciones adicionales

En Android, puede agregar acciones personalizadas a AccessibilityNodeInfo: AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK y ACTION_LONG_CLICK. Esto es equivalente al trait Button con gestos adicionales. Para deslizadores, use ACTION_SET_PROGRESS — equivalente a Adjustable. Para Spinner y DatePicker — ACTION_SET_SELECTION, ACTION_SET_DATE y ACTION_SET_TIME.

Verificación y pruebas de traits

Xcode Accessibility Inspector es la herramienta principal para iOS: seleccione un elemento y vea el campo Traits. Mostrará la lista de traits establecidos. El rotor de VoiceOver con el modo “Elementos” permite navegar por todos los controles de la pantalla.

Prueba automatizada en Swift para verificar un trait:

swift
func testSubmitButtonTrait() {
    let app = XCUIApplication()
    app.launch()
    let submitButton = app.buttons["Enviar"]
    XCTAssertTrue(submitButton.isEnabled)
    // XCUIElement no proporciona acceso directo a los traits
    // Verificación mediante activación de gesto
    submitButton.tap()
    XCTAssertTrue(app.staticTexts["Formulario enviado"].exists)
}

Verificación manual mediante VoiceOver: active VoiceOver, deslice hasta el elemento, toque dos veces: el elemento debería activarse si es un Button. Si el elemento no responde al doble toque, el trait es incorrecto. Use el gesto Rotor para cambiar entre modos (“Encabezados”, “Enlaces”, “Botones”) — cada modo mostrará solo los elementos con el trait correspondiente.

Pruebas unitarias de traits en iOS

Antes de iOS 14, las pruebas unitarias no tenían acceso directo a accessibilityTraits. A partir de iOS 14, la propiedad está disponible: XCTAssertEqual(customButton.accessibilityTraits, .button). Utilice esto en pruebas unitarias para verificar controles personalizados. Se recomienda probar cada nuevo UIView personalizado para verificar la corrección del trait, especialmente después de refactorizaciones o cambios de clase padre.

Preguntas Frecuentes

¿Cuántos traits se pueden asignar a un solo elemento?

Hasta 3-4 traits por elemento. Una mayor cantidad hace que el anuncio de VoiceOver sea redundante. Use combinaciones: Button + Selected, Header + StaticText.

¿Cuál es el trait predeterminado de UIButton?

UIAccessibilityTraitButton. iOS lo establece automáticamente para todas las instancias de UIButton. Si hereda de UIView y simula un botón, el trait debe establecerse manualmente.

¿Existe un trait “Adjustable” y para qué sirve?

Sí, UIAccessibilityTraitAdjustable — para elementos con valores ajustables (deslizadores, selectores, contadores). VoiceOver permite deslizar hacia arriba/abajo para cambiar el valor y lee el estado actual.

¿Cómo verificar traits en SwiftUI?

Use el modificador .accessibilityAddTraits(): Text(“Título”).font(.title).accessibilityAddTraits(.isHeader). El método funciona en iOS 14+.

¿Qué sucede si no asigno un trait a un control personalizado?

VoiceOver asignará el trait None. El elemento no tendrá un rol: el screen reader solo leerá la Label sin indicar el tipo. El usuario no sabrá si hay un gesto de activación disponible.

Resumen

  • Accessibility Trait — una máscara de bits UIAccessibilityTraits que define el rol de un elemento iOS para VoiceOver (Button, Header, Link, StaticText y otros)
  • Los traits se combinan mediante OR bit a bit ([] en Swift), no más de 3-4 por elemento
  • Los UIView personalizados deben recibir un trait explícito — por defecto puede ser None o Image
  • En Android, el rol se define mediante className en AccessibilityNodeInfo, en Flutter — mediante semanticsRole
  • Un trait incorrecto (StaticText para un botón) rompe el escenario de VoiceOver: no hay gesto de activación
  • Verifique los traits mediante Accessibility Inspector en Xcode y el rotor de VoiceOver
  • En SwiftUI, use .accessibilityAddTraits() para configurar traits de forma declarativa

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también