Accessibility Trait — je vlastnost prvku iOS, která určuje jeho roli a chování pro VoiceOver. Trait informuje čtečku obrazovky, jak má být prvek namluven a jaká gesta jsou k dispozici: zda se jedná o tlačítko, nadpis, odkaz nebo vyhledávací pole. Podle Apple UIAccessibilityTraits, 2024 systém podporuje 15+ konstant, které lze kombinovat bitovou maskou. Správně zvolený trait šetří až 50 % času navigace uživatelům VoiceOver.
Hlavní body
Accessibility Trait — příznak nastavený na prvku UIView k označení jeho sémantické role pro VoiceOver. Trait je jednou ze tří složek triády accessibility Apple: Label (název), Hint (popis), Trait (role). iOS používá bitovou masku UIAccessibilityTraits (UInt64), kde každý bit odpovídá určité roli. VoiceOver čte roli po Label a Hint: „Tlačítko Odeslat. Otevře formulář“ — „Tlačítko“ bylo přidáno díky traitu UIAccessibilityTraitButton.
Ve výchozím nastavení získává UIButton UIAccessibilityTraitButton, UILabel — UIAccessibilityTraitStaticText, UIImageView — UIAccessibilityTraitImage. Při použití vlastních ovládacích prvků je vývojář povinen nastavit trait ručně. Apple Human Interface Guidelines, 2024, to nazývají „jedním z nejdůležitějších kroků při zajišťování přístupnosti“.
Bez správného traitu uživatel neví, které gesto použít: jednoduché klepnutí (aktivace tlačítka), dvojité klepnutí (zvětšení) nebo gesto přejetí (přepínač). Trait rozhoduje, která gesta VoiceOver na prvku aktivuje.
UIAccessibilityTraits — je typealias UInt64. Každý trait je konstanta, kde je nastaven přesně jeden bit. Například UIAccessibilityTraitButton = 0x0000000000000001, UIAccessibilityTraitLink = 0x0000000000000002, UIAccessibilityTraitHeader = 0x0000000000000008. Kombinace se dosahuje bitovým OR: 0x0001 | 0x0008 = 0x0009. VoiceOver analyzuje masku a určuje chování.
iOS poskytuje více než 15 konstant traitů. Pojďme se podívat na hlavní, které se používají v 90 % scénářů:
| Trait | Konstanta | Chování VoiceOver |
|---|---|---|
| Button | UIAccessibilityTraitButton | Aktivace dvojitým klepnutím |
| Header | UIAccessibilityTraitHeader | Rychlá navigace podle nadpisů |
| Link | UIAccessibilityTraitLink | Aktivace jako odkaz |
| StaticText | UIAccessibilityTraitStaticText | Pouze čtení, bez aktivace |
| SearchField | UIAccessibilityTraitSearchField | Vyhledávací pole se speciálním chováním |
| Image | UIAccessibilityTraitImage | Obrázek, bez gesta aktivace |
| Selected | UIAccessibilityTraitSelected | Stav „vybrán“ |
| PlaysSound | UIAccessibilityTraitPlaysSound | Při aktivaci přehrává zvuk |
| KeyboardKey | UIAccessibilityTraitKeyboardKey | Klávesa klávesnice |
| TabBar | UIAccessibilityTraitTabBar | Prvek panelu karet |
Konstanty jsou k dispozici v UIKit od iOS 3.0. V iOS 14+ byla přidána podpora UIAccessibilityTraits ve SwiftUI pomocí modifikátoru .accessibilityAddTraits().
UIAccessibilityTraitAdjustable — pro nastavitelné hodnoty (posuvníky, výběry, posuvníky hlasitosti). VoiceOver umožňuje přejetí nahoru/dolů pro změnu hodnoty s krokem definovaným pomocí accessibilityIncrement a accessibilityDecrement. UIAccessibilityTraitUpdatesFrequently — pro prvky s často se měnící hodnotou (časovač, indikátor načítání). VoiceOver nečte hodnotu při každé změně, ale dělá pauzu. UIAccessibilityTraitAllowsDirectInteraction — pro prvky, s nimiž může uživatel interagovat přímo (klávesnice, kreslicí nástroj), bez gest VoiceOver.
Jeden prvek může mít současně několik traitů — kombinace se určuje pomocí bitového OR (|). Příklad: tlačítko, které je aktuálně vybráno — Button | Selected. VoiceOver řekne: „Vybráno. Filtrováno podle ceny. Tlačítko“.
Nastavení traitů v kódu:
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)
// Nebo pomocí masky:
filterButton.accessibilityTraits = [.button, .selected]
Pro vlastní UIView, kde trait není ve výchozím nastavení nastaven:
class CustomToggle: UIControl {
override var accessibilityTraits: UIAccessibilityTraits {
get {
if isOn {
return [.button, .selected]
} else {
return .button
}
}
set {}
}
}
Pravidlo kombinování: ne více než 3-4 traity na prvek. Nadměrné traity (např. Button + Link + Header) činí oznámení VoiceOver příliš dlouhým a matoucím. Podle Apple, „každá další vlastnost zvyšuje kognitivní zátěž uživatele“.
Ve SwiftUI se traity nastavují pomocí modifikátorů .accessibilityAddTraits() a .accessibilityRemoveTraits(). Příklad: Text(„Nadpis“).font(.largeTitle).accessibilityAddTraits(.isHeader). Modifikátor .isHeader přidává UIAccessibilityTraitHeader. Seznam SwiftUI traitů: .isButton, .isHeader, .isLink, .isSelected, .isImage, .isSearchField, .isKeyboardKey, .isStaticText, .isSummaryElement, .isToggle, .playsSound, .startsMediaSession, .updatesFrequently, .allowsDirectInteraction, .causesPageTurn, .isModal, .tabBar.
StaticText místo Button — vlastní ovládací prvek, který vizuálně vypadá jako tlačítko, získá ve výchozím nastavení trait StaticText. VoiceOver nenabízí gesto aktivace, uživatel nemůže prvek „stisknout“. Řešení: explicitně nastavte .button.
Image bez traitu — UIImageView s povolenou přístupností získá trait Image, i když je to ve skutečnosti tlačítko pro zvětšení fotografie. Přiřaďte .button a Label „Zvětšit fotografii“. Podle WWDC 2023, „Deliver an Exceptional Accessibility Experience“ je 40 % regresí přístupnosti v nových verzích aplikací způsobeno právě nesouladem traitu.
Header na každém prvku — trait Header je určen pro strukturální nadpisy obrazovky. Pokud uděláte každý UILabel nadpisem, rotor VoiceOver v režimu „Nadpisy“ se stane nepoužitelným — bude se zastavovat na každém slově.
Častá příčina ztráty traitu — refaktorování: vývojář nahradí UIButton za UIControl pro vlastní zobrazení. UIButton automaticky získá trait Button, UIControl — ne. Po refaktorování je nutné explicitně nastavit accessibilityTraits = .button. Přidejte kontrolu do code review: „Pokud jste nahradili UIButton za UIControl — zkontrolujte trait“.
U prvků s měnícím se stavem (např. tlačítko like) by se trait měl měnit dynamicky. Ve stavu „nelajkováno“ — Button, ve stavu „lajkováno“ — Button + Selected + Image (pokud je ikona). VoiceOver mění oznámení: „Líbí se. Tlačítko“ vs „Vybráno. Líbí se. Tlačítko“. Pokud trait Selected nestačí, použijte accessibilityValue k předání stavu. Platí pro tlačítka odběru, oblíbených, filtrů a přepínačů.
V Androidu neexistuje přímá obdoba traitů. Místo bitové masky se používají:
Pro vlastní View v Androidu je třeba přepsat onInitializeAccessibilityNodeInfo:
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
}
}
Vývojáři Flutteru by měli použít parametr semanticsRole ve widgetu Semantics: button, header, image, link, textField a další. K dispozici jsou také semanticsLabel a semanticsHint — plná obdoba iOS triády Label + Hint + Trait.
Pro webové verze mobilních aplikací (PWA, WebView) se používá atribut role z WAI-ARIA: role="button", role="heading", role="link". To je přímá obdoba accessibilityTraits. V hybridních aplikacích zkontrolujte, zda WebView předává role ARIA do nativní vrstvy přístupnosti. K tomu použijte protokol UIAccessibilityContainerDataTable v iOS nebo setAccessibilityDelegate v Androidu. WebView s povoleným JavaScriptem nemusí role ARIA správně předávat — testujte samostatně.
V Androidu lze do AccessibilityNodeInfo přidat vlastní akce: AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK a ACTION_LONG_CLICK. To je obdoba traitu Button s dalšími gesty. Pro posuvníky použijte ACTION_SET_PROGRESS — obdoba Adjustable. Pro Spinner a DatePicker — ACTION_SET_SELECTION, ACTION_SET_DATE a ACTION_SET_TIME.
Xcode Accessibility Inspector — hlavní nástroj pro iOS: vyberte prvek a podívejte se na pole Traits. Zobrazí seznam nastavených traitů. Rotor VoiceOver v režimu „Prvky“ umožňuje procházet všechny ovládací prvky obrazovky.
Automatizovaný test v Swiftu pro kontrolu traitu:
func testSubmitButtonTrait() {
let app = XCUIApplication()
app.launch()
let submitButton = app.buttons["Odeslat"]
XCTAssertTrue(submitButton.isEnabled)
// XCUIElement neposkytuje přímý přístup k traitům
// Kontrola pomocí aktivace gesta
submitButton.tap()
XCTAssertTrue(app.staticTexts["Formulář odeslán"].exists)
}
Ruční kontrola přes VoiceOver: zapněte VoiceOver, přesuňte prst k prvku, dvakrát klepněte — prvek by se měl aktivovat, pokud se jedná o Button. Pokud prvek nereaguje na dvojité klepnutí, je trait nesprávný. Použijte gesto Rotor pro přepínání mezi režimy („Nadpisy“, „Odkazy“, „Tlačítka“) — každý režim zobrazí pouze prvky s odpovídajícím traitem.
Před iOS 14 neměly unit testy přímý přístup k accessibilityTraits. Od iOS 14 je vlastnost k dispozici: XCTAssertEqual(customButton.accessibilityTraits, .button). Použijte to v modulárních testech pro kontrolu vlastních ovládacích prvků. Doporučuje se testovat každý nový vlastní UIView na správnost traitu, zejména po refaktorování nebo změně nadřazené třídy.
Často kladené otázky
Až 3-4 traity na prvek. Větší počet činí oznámení VoiceOver nadbytečným. Používejte kombinace: Button + Selected, Header + StaticText.
UIAccessibilityTraitButton. iOS jej automaticky nastaví pro všechny instance UIButton. Pokud dědíte z UIView a simulujete tlačítko, trait je třeba nastavit ručně.
Ano, UIAccessibilityTraitAdjustable — pro prvky s nastavitelnou hodnotou (posuvníky, výběry, počítadla). VoiceOver umožňuje přejetí nahoru/dolů pro změnu hodnoty a čte aktuální stav.
Použijte modifikátor .accessibilityAddTraits(): Text(„Nadpis“).font(.title).accessibilityAddTraits(.isHeader). Metoda funguje na iOS 14+.
VoiceOver přiřadí trait None. Prvek nezíská roli — čtečka obrazovky přečte pouze Label bez uvedení typu. Uživatel nebude vědět, zda je gesto aktivace k dispozici.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také