Accessibility Trait: esența, ce tipuri există și cum funcționează în dezvoltare

Autor: IT Sectr Publicat: 2026-05-16 Timp de citire: 9 min

Accessibility Trait — este o proprietate a elementului iOS care determină rolul și comportamentul său pentru VoiceOver. Traitul informează cititorul de ecran cum trebuie să fie sonorizat elementul și ce gesturi sunt disponibile: dacă este un buton, titlu, link sau câmp de căutare. Conform Apple UIAccessibilityTraits, 2024, sistemul suportă 15+ constante care pot fi combinate printr-o mască de biți. Un trait ales corect economisește până la 50% din timpul de navigare pentru utilizatorii VoiceOver.

Principalele puncte

  • Accessibility Trait — rolul elementului iOS pentru VoiceOver; se setează prin constantele UIAccessibilityTraits
  • Traiturile pot fi combinate prin operatorul | pentru a crea roluri complexe (buton + selectat)
  • Fiecare element poate avea mai multe traituri simultan, dar nu mai mult de 3-4 pentru a evita confuzia
  • Un trait greșit (de exemplu, StaticText pentru un buton) strică scenariul de interacțiune: utilizatorul nu știe dacă gestul este disponibil
  • În Android, analogul sunt atributele role și className în AccessibilityNodeInfo

Ce este Accessibility Trait

Accessibility Trait — un flag setat pe elementul UIView pentru a indica rolul său semantic pentru VoiceOver. Traitul este una dintre cele trei componente ale triadei accessibility Apple: Label (nume), Hint (descriere), Trait (rol). iOS folosește masca de biți UIAccessibilityTraits (UInt64), unde fiecare bit corespunde unui rol specific. VoiceOver citește rolul după Label și Hint: „Buton Trimite. Va deschide formularul” — „Buton” a fost adăugat datorită traitului UIAccessibilityTraitButton.

În mod implicit, UIButton primește UIAccessibilityTraitButton, UILabel — UIAccessibilityTraitStaticText, UIImageView — UIAccessibilityTraitImage. La utilizarea controalelor personalizate, dezvoltatorul este obligat să seteze manual traitul. Apple Human Interface Guidelines, 2024, numesc acest lucru „unul dintre cei mai critici pași în asigurarea accessibility”.

Fără un trait corect, utilizatorul nu știe ce gest să aplice: atingere simplă (activarea butonului), atingere dublă (mărire) sau gest de glisare (comutator). Traitul decide ce gesturi VoiceOver activează pe element.

Implementarea tehnică a UIAccessibilityTraits

UIAccessibilityTraits — este un typealias UInt64. Fiecare trait este o constantă în care este setat exact un bit. De exemplu, UIAccessibilityTraitButton = 0x0000000000000001, UIAccessibilityTraitLink = 0x0000000000000002, UIAccessibilityTraitHeader = 0x0000000000000008. Combinația se obține prin SAU bit cu bit: 0x0001 | 0x0008 = 0x0009. VoiceOver analizează masca și determină comportamentul.

Tipurile principale de traituri iOS

iOS oferă peste 15 constante de traituri. Să examinăm principalele, utilizate în 90% din scenarii:

TraitConstantăComportament VoiceOver
ButtonUIAccessibilityTraitButtonActivare prin atingere dublă
HeaderUIAccessibilityTraitHeaderNavigare rapidă prin titluri
LinkUIAccessibilityTraitLinkActivare ca link
StaticTextUIAccessibilityTraitStaticTextDoar citire, fără activare
SearchFieldUIAccessibilityTraitSearchFieldCâmp de căutare cu comportament special
ImageUIAccessibilityTraitImageImagine, fără gest de activare
SelectedUIAccessibilityTraitSelectedStarea „selectat”
PlaysSoundUIAccessibilityTraitPlaysSoundRedă sunet la activare
KeyboardKeyUIAccessibilityTraitKeyboardKeyTastă de tastatură
TabBarUIAccessibilityTraitTabBarElement de bară de file

Constantele sunt disponibile în UIKit din iOS 3.0. În iOS 14+ a fost adăugat suportul pentru UIAccessibilityTraits în SwiftUI prin modificatorul .accessibilityAddTraits().

Traituri rare dar utile

UIAccessibilityTraitAdjustable — pentru valori reglabile (glisiere, pickere, glisiere de volum). VoiceOver permite glisarea în sus/jos pentru a modifica valoarea cu pasul definit prin accessibilityIncrement și accessibilityDecrement. UIAccessibilityTraitUpdatesFrequently — pentru elemente cu valoare care se schimbă frecvent (timer, indicator de încărcare). VoiceOver nu citește valoarea la fiecare schimbare, ci face o pauză. UIAccessibilityTraitAllowsDirectInteraction — pentru elemente cu care utilizatorul poate interacționa direct (tastatură, unealtă de desen), ocolind gesturile VoiceOver.

Combinarea traiturilor

Un element poate avea mai multe traituri simultan — combinația se specifică prin SAU bit cu bit (|). Exemplu: un buton care este selectat în prezent — Button | Selected. VoiceOver va rosti: „Selectat. Filtrat după preț. Buton”.

Setarea traiturilor în cod:

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

// Sau prin mască:
filterButton.accessibilityTraits = [.button, .selected]

Pentru UIView-uri personalizate unde traitul nu este setat implicit:

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

Regula combinării: nu mai mult de 3-4 traituri pe element. Traiturile în exces (de exemplu, Button + Link + Header) fac declarația VoiceOver prea lungă și confuză. Potrivit Apple, „fiecare proprietate suplimentară crește încărcătura cognitivă a utilizatorului”.

SwiftUI: modificatorii de traituri

În SwiftUI, traiturile se setează prin modificatorii .accessibilityAddTraits() și .accessibilityRemoveTraits(). Exemplu: Text("Titlu").font(.largeTitle).accessibilityAddTraits(.isHeader). Modificatorul .isHeader adaugă UIAccessibilityTraitHeader. Lista traiturilor SwiftUI: .isButton, .isHeader, .isLink, .isSelected, .isImage, .isSearchField, .isKeyboardKey, .isStaticText, .isSummaryElement, .isToggle, .playsSound, .startsMediaSession, .updatesFrequently, .allowsDirectInteraction, .causesPageTurn, .isModal, .tabBar.

Greșeli tipice la alegerea traitului

StaticText în loc de Button — un control personalizat care arată vizual ca un buton primește implicit traitul StaticText. VoiceOver nu oferă un gest de activare, utilizatorul nu poate „apăsa” elementul. Soluție: setați explicit .button.

Image fără trait — UIImageView cu accessibility activat primește traitul Image, chiar dacă este de fapt un buton pentru mărirea fotografiei. Atribuiți .button și Label „Mărește fotografia”. Potrivit WWDC 2023, „Deliver an Exceptional Accessibility Experience”, 40% din regresiile de accessibility în versiunile noi ale aplicațiilor sunt cauzate tocmai de nepotrivirea traitului.

Header pe fiecare element — traitul Header este destinat titlurilor structurale ale ecranului. Dacă faceți fiecare UILabel un titlu, rotorul VoiceOver în modul „Titluri” va deveni inutil — se va opri pe fiecare cuvânt.

Cum să remediați: listă de verificare

  • Fiecare element personalizat interactiv primește traitul Button, Link sau Adjustable
  • Titlurile secțiunilor primesc traitul Header (nu StaticText)
  • Imaginile-buton primesc traitul Button + Selected în starea selected
  • Elementele fără gest — StaticText sau Image (doar citire)

Buguri de regresiune la schimbarea UIButton în UIControl

Cauza frecventă a pierderii traitului — refactorizarea: dezvoltatorul înlocuiește UIButton cu UIControl pentru afișare personalizată. UIButton primește automat traitul Button, UIControl — nu. După refactorizare, trebuie setat explicit accessibilityTraits = .button. Adăugați o verificare în code review: „Dacă ați înlocuit UIButton cu UIControl — verificați traitul”.

Traituri și stări dinamice

Pentru elementele cu stare variabilă (de exemplu, butonul de like), traitul trebuie să se schimbe dinamic. În starea „neapreciat” — Button, în starea „apreciat” — Button + Selected + Image (dacă există pictogramă). VoiceOver schimbă anunțul: „Apreciază. Buton” vs „Selectat. Apreciază. Buton”. Utilizați accessibilityValue pentru transmiterea stării, dacă traitul Selected nu este suficient. Relevant pentru butoanele de abonare, favorite, filtre și comutatoare.

Analog Android: role și className

În Android nu există un analog direct al traiturilor. În locul măștii de biți se folosesc:

  • className — valoarea AccessibilityNodeInfo.className (android.widget.Button, android.widget.TextView)
  • role — atribut în XML (rolul se determină prin tipul View)
  • stateDescription — analogul Selected: adăugarea descrierii stării (activat/dezactivat)

Pentru View-uri personalizate în Android trebuie suprascrisă 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
    }
}

Dezvoltatorii Flutter trebuie să folosească parametrul semanticsRole în widgetul Semantics: button, header, image, link, textField și altele. Suplimentar, sunt disponibile semanticsLabel și semanticsHint — analogul complet al triadei iOS Label + Hint + Trait.

Analogi web: rolul WAI-ARIA

Pentru versiunile web ale aplicațiilor mobile (PWA, WebView) se folosește atributul role din WAI-ARIA: role="button", role="heading", role="link". Acesta este analogul direct al accessibilityTraits. În aplicațiile hibride, verificați dacă WebView transmite rolurile ARIA în stratul nativ de accessibility. Pentru aceasta, utilizați protocolul UIAccessibilityContainerDataTable în iOS sau setAccessibilityDelegate în Android. WebView cu JavaScript activat poate să nu transmită corect rolurile ARIA — testați separat.

AccessibilityNodeInfo: acțiuni suplimentare

În Android se pot adăuga acțiuni personalizate în AccessibilityNodeInfo: AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK și ACTION_LONG_CLICK. Acesta este analogul traitului Button cu gesturi suplimentare. Pentru glisiere, utilizați ACTION_SET_PROGRESS — analogul Adjustable. Pentru Spinner și DatePicker — ACTION_SET_SELECTION, ACTION_SET_DATE și ACTION_SET_TIME.

Verificarea și testarea traiturilor

Xcode Accessibility Inspector — instrumentul principal pentru iOS: selectați elementul și vizualizați câmpul Traits. Acesta va arăta lista traiturilor setate. Rotorul VoiceOver în modul „Elemente” permite parcurgerea tuturor controalelor ecranului.

Test automatizat în Swift pentru verificarea traitului:

swift
func testSubmitButtonTrait() {
    let app = XCUIApplication()
    app.launch()
    let submitButton = app.buttons["Trimite"]
    XCTAssertTrue(submitButton.isEnabled)
    // XCUIElement nu oferă acces direct la traituri
    // Verificare prin activarea gestului
    submitButton.tap()
    XCTAssertTrue(app.staticTexts["Formular trimis"].exists)
}

Verificarea manuală prin VoiceOver: activați VoiceOver, deplasați degetul până la element, atingeți de două ori — elementul ar trebui să se activeze, dacă este Button. Dacă elementul nu reacționează la atingerea dublă, traitul este incorect. Utilizați gestul Rotor pentru a comuta între moduri („Titluri”, „Linkuri”, „Butoane”) — fiecare mod va afișa doar elementele cu traitul corespunzător.

Testare unitară a traiturilor în iOS

Înainte de iOS 14, testele unitare nu aveau acces direct la accessibilityTraits. Începând cu iOS 14, proprietatea este disponibilă: XCTAssertEqual(customButton.accessibilityTraits, .button). Utilizați acest lucru în testele modulare pentru verificarea controalelor personalizate. Se recomandă testarea fiecărui nou UIView personalizat pentru corectitudinea traitului, în special după refactorizare sau schimbarea clasei părinte.

Întrebări frecvente

Câte traituri pot fi setate pentru un element?

Până la 3-4 traituri pe element. Un număr mai mare face declarația VoiceOver redundantă. Utilizați combinații: Button + Selected, Header + StaticText.

Care este traitul implicit al UIButton?

UIAccessibilityTraitButton. iOS îl setează automat pentru toate instanțele UIButton. Dacă moșteniți de la UIView și simulați un buton, traitul trebuie setat manual.

Există traitul „Adjustable” și pentru ce este?

Da, UIAccessibilityTraitAdjustable — pentru elemente cu valoare reglabilă (glisiere, pickere, contoare). VoiceOver permite glisarea în sus/jos pentru a modifica valoarea și citește starea curentă.

Cum se verifică traiturile în SwiftUI?

Utilizați modificatorul .accessibilityAddTraits(): Text("Titlu").font(.title).accessibilityAddTraits(.isHeader). Metoda funcționează pe iOS 14+.

Ce se întâmplă dacă nu setez un trait pentru un control personalizat?

VoiceOver va atribui traitul None. Elementul nu va primi un rol — cititorul de ecran va citi doar Label fără a specifica tipul. Utilizatorul nu va ști dacă gestul de activare este disponibil.

Concluzii

  • Accessibility Trait — masca de biți UIAccessibilityTraits care determină rolul elementului iOS pentru VoiceOver (Button, Header, Link, StaticText și altele)
  • Traiturile se combină prin SAU bit cu bit ([] în Swift), maximum 3-4 pe element
  • UIView-urile personalizate trebuie să primească un trait explicit — implicit poate fi None sau Image
  • În Android, rolul se stabilește prin className în AccessibilityNodeInfo, în Flutter — prin semanticsRole
  • Un trait greșit (StaticText pentru un buton) strică scenariul VoiceOver: fără gest de activare
  • Verificați traiturile prin Accessibility Inspector în Xcode și rotorul VoiceOver
  • În SwiftUI, utilizați .accessibilityAddTraits() pentru setarea declarativă a traiturilor

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și