Aiemmassa blogipostauksessa kerroimme, millaisia saavutettavuusvaatimuksia mobiilisovelluksiin liittyy. Tässä postauksessa astumme askelen syvemmälle, ja pääsemme tutkailemaan pienten koodiesimerkkien kera, kuinka toteuttaa vaatimuksia. Esimerkkejä on tarjoiltu sekä React Native -koodina että natiivina iOS- ja Android-koodeina.

Komponenttien saavutettavat nimet

Kaikilla ruudulla näkyvillä komponenteilla pitää olla saavutettava nimi avustaville ohjelmille. Komponentin teksti yleensä toimii sellaisenaan, mutta saavutettava nimi pitää lisätä, jos komponentissa ei ole mitään tekstiä, kuten painikkeissa, joissa ruudulla on vain jokin ikoni. Saavutettavaan nimeen ei kirjoiteta komponentin tyyppiä, pelkästään sen "kuvaus". Saavutettavaa nimeä ei näytetä visuaalisesti.

React native

<Button
    accessibilityLabel="Info"
    ...
    <Icon ... />
</Button>

Android

<ImageButton
    ....
    android:contentDescription="@string/Info" />

iOS

<let myButton = UIButton(type: .custom)
    ...
    myButton.accessibilityLabel = "info"
    <myButton.setImage (...)

Saavutettava nimi on tarpeen myös lomake-elementeille, kuten tekstikentille ja valintaruuduille. Lomake-elementtien kohdalla on tärkeää muistaa, että saavutettava nimi tulee olla sama kuin visuaalisesti näkyvä nimilappu. Jos ohjelma on kirjoitettu React Nativella, edeltävässä koodiesimerkissä käytetty "accessibilityLabel" toimii myös lomake-elementeille; vastaavasti natiivin iOS-koodin kanssa.

Androidissa nimilapun ja lomake-elementin yhdistäminen tehdään kuitenkin poikkeavasti: se vastaa verkkosivuilla tehtävää nimilapun ja komponentin yhdistämistä for- ja id-attribuuteilla.

<TextView
    ...
    android:labelFor=”@+id/edit_text” />
   <EditText android:id=”@+id/edit_text”/>

Semanttinen rooli

Saavutettavan sovelluksen tekemisessä pääsee ehdottomasti helpommalla, kun käyttää tarjolla olevia natiivielementtejä. Mutta teitkö oman kustomin komponentin? Uupps! Älä tee sitä!

Okei, virhe on jo tapahtunut, joten vedetäänpä rauhassa henkeä ja mennään tutkimaan, miten voidaan tehdä omasta komponentista saavutettava.

React Native ja roolit

React Native tarjoaa mahdollisuuden kertoa avustaville ohjelmille komponentin merkityksestä accessibilityRole-määritelmän avulla. Mahdollisia vaihtoehtoja on yhteensä 27.

<CustomSlider
    accessibilityRole="progressbar"
    ...
   />

React Nativen documentaatiossa jätetään kuitenkin kertomatta, että sellaisenaan accessibilityRole ei vielä ihan riitä: jos sovelluksen kieli on jokin muu kuin englanti, komponenttien roolit vaativat vielä käännöksiä. Android tai iOS eivät kumpikaan tue natiivisti sellaisenaan tietoa käyttöliittymäkomponenttien rooleista. Käytännössä "accessibilityRole"-arvo on siis vain komponenttiin liitetty tekstijono, jolla ei ole suoraan lokalisoituja käännöksiä.

Esimerkin "progressbar" on vielä itsessään suhteellisen yksinkertainen, sillä se ei vaadi toiminnallisuutta. Jos komponenttimme on jonkinlainen kontrolleri, täytyy varmistaa sen toimivan oikein muutenkin kuin tavallisella kosketuksella.

iOS

Oman komponentin muokkaaminen saavutettavaksi iOS-ympäristössä vaatii komponentille saavutettavuusattribuutteja:

  • isAccessibilityElement: true. Jos arvo on 'false', ei VoiceOver pysty kohdistamaan elementtiin.
  • accessibilityLabel: elementtiä kuvaava teksti.
  • accessibilityTraits: kertoo elementin semanttisen roolin, esim "button" tai "image".

Jos elementti on sellainen, jonka kanssa käyttäjän pitäisi vuorovaikuttaa pyyhkäisemällä, napauttamalla, raahaamalla tai millä tahansa muulla keinolla, pitää äskeisten tietojen lisäksi toteuttaa kyseiset vuorovaikutustavat käyttämällä iOSin Accessibility-apia. Tarvittavat metodit löytyvät Applen dokumentaatiosta.

Android 

Jotta kustomista komponentistamme saadaan saavutettava, tulee:

  • varmistaa, että klikkaukset käsitellään oikein
  • toteuttaa Accessibility API:n metodit
  • lähettää ja vastaanottaa accessibilityEvent-objekti sekä
  • antaa muuta infoa komponentista.

Tarkemmin kaikki tämä on kuvattu Android Developers -dokumentaatiossa.

Suosittelen tässä kohtaa miettimään vielä pari kertaa uudestaan, olisiko kuitenkin mahdollista käyttää natiivikomponentteja.

Lukemisjärjestys

Mobiilisovelluksissa avustava teknologia päättelee yleisesti lukemisjärjestyksen varsin onnistuneesti mm. sen perusteella, kuinka elementit sijaitsevat ruudulla. Jos lukemisjärjestyksessä on häikkää, kannattaa ensimmäiseksi varmistaa, että koodissa elementit tuodaan näkymään loogisesti siinä järjestyksessä, kuin ne tulisi lukea.

Jos lukemisjärjestyksessä on yhä jotain korjattavaa, on sitä mahdollista fiksata käsin – React Native ei tosin tarjoa tähän mahdollisuutta.

iOS

Listaamalla näkymän elementit oikeassa järjestyksessä accessibilityElements-objektiin, saadaan lukemisjärjestys korjattua.

view.accessibilityElements = @[elementti1, elementti2, elementti3];

Android 

XML-tiedostossa voidaan antaa elementeille tieto siitä, mihin seuraavaksi kohdistaa. Android tarjoaa tähän attribuutteja nextFocusDown, nextFocusRight, nextFocusUp ja nextFocusLeft, jotka vastaavat nuolinäppäimiä. TalkBackin pyyhkäisyeleillä voi liikkua vain edelliseen tai seuraavaan elementtiin, mutta pyyhkäisy oikealle ("seuraava") vastaa attribuutteja nextFocusRight ja nextFocusDown.

<Button
  android:id="@+id/btn1"
  android:nextFocusDown="@+id/btn2"
  ... 
/>

<Button
android:id="@+id/btn2"
android:nextFocusDown="@+id/btn3"
...
/>

Tekstikoon muuttaminen

Käyttäjän pitää pystyä muuttamaan tekstin kokoa ilman, että sovelluksen toiminnallisuus kärsii. Mobiililaitteissa tekstikoon muuttaminen onnistuu asetuksista, ja sovellusten tulee mahdollistaa se aina 200% suurentamiseen asti.

iOS

label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true

Jotta tekstikoko skaalautuu käyttäjän valinnan mukaan, koodipätkän toinen rivi on pakollinen. Jos käytät jotain omaa fonttityyliä, varmista, että sille on määritelty oikein myös pieni ja suuri fontti. Kun muokattu fontti tehdään UIFontMetrics-objektina , onnistuu sen skaalaaminen käyttäjän valinnan mukaan.

Android

Käyttämällä relatiivisia yksiköitä voidaan sallia Androidissa tekstikoon mukautuminen käyttäjän asetuksiin.

<TextView
  android:layout_width=”match_parent”
  android:layout_height=”wrap_content"
  android:textSize="20sp" />

Saavutettavuuden testaaminen

Sovelluksen saavutettavuutta on kannattavaa testata monessa vaiheessa. Yksi äärimmäisen hyvä tapa testaamiseen on käyttää puhelimen ruudunlukuohjelmaa (VoiceOver tai TalkBack), ja kokeilla sillä itse käytännössä sovelluksen toimintaa.

Applen kehitysympäristössä on "Accessibility inspector", joka toimii iOS-simulaattorissa. Sen avulla voi bongata ongelmakohtia jo ennen laitteella testaamista.

Androidille saavutettavuuden testaukseen puhelimessa on tarjolla sovellus Accessibility Scanner, joka mm. tarkistaa kontrastin ja kosketusalueiden koon.

Loppusanat

Tämä blogikirjoitus oli pintaraapaisu mobiilisovellusten saavutettavuuden toteuttamiseen. Yksityiskohtaisempi paneutuminen kuhunkin esimerkkiaiheeseen vaatisi oman tekstinsä. Toivon kirjoituksen konkreettisten esimerkkien kuitenkin auttavan liikkeelle saavutettavan mobiilisovelluksen toteuttamisessa.

Linkkejä aiheen syventämiseen:

Paranna sovelluksesi saavutettavuutta ja käytettävyyttä