Jetpack Compose

Jak označit text jako nadpis (Jetpack Compose)

TalkBack umí přeskakovat po nadpisech stejně jako čtečky obrazovky na webu po <h1><h6> — jenže v Jetpack Compose žádné <h1> neexistuje. Vizuálně velké a tučné písmo z MaterialTheme.typography.headlineX je jen styl, ne sémantika — TalkBack ho jako nadpis nepřečte, dokud mu to neřeknete výslovně.

1. Jak na to

import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.semantics

Text(
    text = "Nadpis sekce",
    style = MaterialTheme.typography.headlineMedium,
    modifier = Modifier.semantics { heading() }
)

heading() je funkce, kterou zavoláte uvnitř semantics { } bloku na modifieru daného Text (nebo jiného composable). Nastaví v sémantickém stromu příznak, díky kterému TalkBack prvek rozpozná a zpřístupní ho navigaci po nadpisech (gesto pro změnu granularity čtení → „Nadpisy" → přeskakování mezi nimi).

2. Co to dělá a co ne

  • heading() je čistě binární příznak — buď prvek nadpisem je, nebo není. Na rozdíl od HTML tu neexistuje úroveň nadpisu (žádná obdoba h1 vs. h2 vs. h3). Vizuální hierarchii (headlineLarge vs. headlineSmall vs. titleMedium...) sice pořád můžete a měli byste používat pro vzhled, ale TalkBack z ní žádnou úroveň nevyčte — všechny označené nadpisy jsou si z pohledu navigace rovny.
  • Neexistuje ani Role.Heading — možná byste čekali, že nadpis půjde nastavit stejně jako Role.Button nebo Role.Checkbox přes role = ..., ale sada rolí v Compose nadpis vůbec neobsahuje. Heading je samostatný sémantický klíč, ne role.

3. Nejčastější chyba

Použít jen velký/tučný styl a myslet si, že tím je nadpis hotový:

// TOHLE NESTAČÍ — je to jen vizuál, TalkBack o tom neví
Text(
    text = "Nadpis sekce",
    style = MaterialTheme.typography.headlineMedium
)

Přesně stejná past jako na webu, kde velké tučné písmo taky není nadpis, dokud nejde o skutečný <h1><h6> prvek (nebo role="heading" s aria-level). Vzhled a sémantika jsou tu dvě oddělené věci, které je potřeba nastavit obě.

4. Jak si to ověřit

  • Layout Inspector v Android Studiu — vyberte si composable a v panelu Attributes uvidíte, jestli mezi jeho sémantickými vlastnostmi je Heading.
  • Ručně s TalkBackem — zapněte TalkBack, přepněte granularitu čtení na „Nadpisy" a projeďte gestem obrazovku; správně označený prvek se objeví v tomhle přeskakování.
  • Accessibility Test Framework (součást Compose testů od verze 1.8.0, balíček ui-test-junit4-accessibility) — automatizované kontroly přímo v testech:
    composeTestRule.enableAccessibilityChecks()
    composeTestRule.onRoot().tryPerformAccessibilityChecks()

    Nekontroluje přímo „je tohle nadpis", ale odchytí širší okruh problémů (kontrast, velikost dotykové plochy, chybějící popisky) v rámci běžného testovacího běhu.

Proč to takhle je

  • Compose odděluje vzhled (TextStyle) od sémantiky (Modifier.semantics) úplně stejně, jako to dělá HTML/ARIA na webu — vizuální styl nikdy sám o sobě nic neříká asistivní technologii, musí se to napsat výslovně.
  • Chybějící úroveň nadpisu je vědomé zjednodušení Compose sémantiky oproti HTML — u složitější stránky/obrazovky s víceúrovňovou hierarchií to znamená, že se spolehnout jen na navigaci „po nadpisech" nemusí stačit k pochopení struktury tak dobře, jako to jde na webu.

Pravidla

  • Analogie WCAG 2.4.6 (Nadpisy a popisky) a 1.3.1 (Info a vztahy) — i když se WCAG formálně vztahuje na web, princip (struktura obsahu musí být zjistitelná programově, ne jen vizuálně) je stejný a Google se jím v Android accessibility guidelines výslovně řídí.
  • Google Android accessibility: text musí nést svůj význam i mimo vizuální prezentaci — přesně tohle heading() řeší.

Zdroje

Štítky

Komentáře

Zatím zde nejsou žádné komentáře. Buďte první, kdo napíše svůj názor.

Přidat komentář k „Jak označit text jako nadpis (Jetpack Compose)“