Principi per migliorare l'accessibilità delle app

Per assistere gli utenti con esigenze di accessibilità, il framework Android consente di creare un servizio di accessibilità in grado di presentare contenuti delle app agli utenti e di utilizzare le app per loro conto.

Android offre diversi servizi di accessibilità di sistema, tra cui:

  • TalkBack: aiuta le persone cieche o ipovedenti. Annuncia i contenuti con una voce sintetizzata ed esegue azioni su un'app in risposta ai gesti dell'utente.
  • Switch Access: aiuta le persone con disabilità motorie. evidenzia gli elementi interattivi ed esegue azioni in risposta alla pressione di un pulsante da parte dell'utente. Consente di controllare il dispositivo utilizzando solo uno o due pulsanti.

Per aiutare le persone con esigenze di accessibilità a utilizzare correttamente la tua app, questa deve seguire le best practice descritte in questa pagina, che si basano sulle linee guida descritte nella sezione Rendere le app più accessibili.

Ognuna di queste best practice, descritte nelle sezioni seguenti, può migliorare ulteriormente l'accessibilità della tua app:

Elementi di etichette
Gli utenti devono essere in grado di comprendere i contenuti e lo scopo di ogni elemento dell'interfaccia utente interattivo e significativo all'interno dell'app.
Aggiungere azioni di accessibilità
Aggiungendo azioni di accessibilità, puoi consentire agli utenti dei servizi di accessibilità di completare i flussi utente critici all'interno della tua app.
Estendi i widget di sistema
Utilizza gli elementi delle viste inclusi nel framework, anziché creare visualizzazioni personalizzate. Le classi di widget e visualizzazioni del framework forniscono già la maggior parte delle funzionalità di accessibilità necessarie per la tua app.
Utilizzare segnali diversi dal colore
In una UI, gli utenti devono essere in grado di distinguere chiaramente le categorie di elementi. Per farlo, usa pattern e posizione, insieme al colore, per esprimere queste differenze.
Rendere più accessibili i contenuti multimediali
Aggiungi descrizioni ai contenuti video o audio della tua app in modo che gli utenti che usufruiscano di questi contenuti non debbano fare affidamento su segnali interamente visivi o sonori.

Elementi di etichetta

È importante fornire agli utenti etichette utili e descrittive per ogni elemento interattivo dell'interfaccia utente dell'app. Ogni etichetta deve spiegare il significato e lo scopo di un determinato elemento. Gli screen reader come TalkBack possono annunciare queste etichette agli utenti.

Nella maggior parte dei casi, devi specificare la descrizione di un elemento UI nel file di risorse di layout che contiene l'elemento. In genere, si aggiungono etichette utilizzando l'attributo contentDescription, come spiegato nella guida per rendere le app più accessibili. Nelle sezioni seguenti sono descritte molte altre tecniche di etichettatura.

Elementi modificabili

Quando etichetti elementi modificabili, come oggetti EditText, è utile mostrare un testo che dia un esempio di input valido nell'elemento stesso, oltre a rendere questo testo di esempio disponibile agli screen reader. In questi casi, puoi utilizzare l'attributo android:hint, come mostrato nello snippet seguente:

<!-- The hint text for en-US locale would be
     "Apartment, suite, or building". -->
<EditText
   android:id="@+id/addressLine2"
   android:hint="@string/aptSuiteBuilding" ... />

In questo caso, l'attributo android:labelFor dell'oggetto View deve essere impostato sull'ID dell'elemento EditText. Per maggiori dettagli, consulta la sezione seguente.

Coppie di elementi in cui uno descrive l'altro

È comune che un elemento EditText abbia un oggetto View corrispondente che descrive ciò che gli utenti devono inserire nell'elemento EditText. Puoi indicare questa relazione impostando l'attributo android:labelFor dell'oggetto View.

Un esempio di etichettatura di queste coppie di elementi è riportato nel seguente snippet:


<!-- Label text for en-US locale would be "Username:" -->
<TextView
   android:id="@+id/usernameLabel" ...
   android:text="@string/username"
   android:labelFor="@+id/usernameEntry" />

<EditText
   android:id="@+id/usernameEntry" ... />

<!-- Label text for en-US locale would be "Password:" -->
<TextView
   android:id="@+id/passwordLabel" ...
   android:text="@string/password
   android:labelFor="@+id/passwordEntry" />

<EditText
   android:id="@+id/passwordEntry"
   android:inputType="textPassword" ... />

Elementi in una raccolta

Quando aggiungi etichette agli elementi di una raccolta, ogni etichetta deve essere univoca. In questo modo, i servizi di accessibilità del sistema possono fare riferimento a un solo elemento sullo schermo quando annuncia un'etichetta. Questa corrispondenza consente agli utenti di sapere quando scorrono l'interfaccia utente o quando spostano lo stato attivo su un elemento che hanno già scoperto.

In particolare, includi testo aggiuntivo o informazioni contestuali negli elementi all'interno di layout riutilizzati, come gli oggetti RecyclerView, in modo che ogni elemento secondario venga identificato in modo univoco.

A questo scopo, imposta la descrizione dei contenuti come parte dell'implementazione dell'adattatore, come mostrato nel seguente snippet di codice:

Kotlin

data class MovieRating(val title: String, val starRating: Integer)

class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
        RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {

    class MyRatingViewHolder(val ratingView: ImageView) :
            RecyclerView.ViewHolder(ratingView)

    override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
        val ratingData = myData[position]
        holder.ratingView.contentDescription = "Movie ${position}: " +
                "${ratingData.title}, ${ratingData.starRating} stars"
    }
}

Java

public class MovieRating {
    private String title;
    private int starRating;
    // ...
    public String getTitle() { return title; }
    public int getStarRating() { return starRating; }
}

public class MyMovieRatingsAdapter
        extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> {
    private MovieRating[] myData;


    public static class MyRatingViewHolder extends RecyclerView.ViewHolder {
        public ImageView ratingView;
        public MyRatingViewHolder(ImageView iv) {
            super(iv);
            ratingView = iv;
        }
    }

    @Override
    public void onBindViewHolder(MyRatingViewHolder holder, int position) {
        MovieRating ratingData = myData[position];
        holder.ratingView.setContentDescription("Movie " + position + ": " +
                ratingData.getTitle() + ", " + ratingData.getStarRating() +
                " stars")
    }
}

Gruppi di contenuti correlati

Se la tua app mostra diversi elementi dell'interfaccia utente che formano un gruppo naturale, ad esempio i dettagli di una canzone o gli attributi di un messaggio, organizza questi elementi all'interno di un contenitore, che in genere è una sottoclasse di ViewGroup. Imposta l'attributo android:screenReaderFocusable dell'oggetto container su true e l'attributo android:focusable di ogni oggetto interno su false. In questo modo, i servizi di accessibilità possono presentare le descrizioni dei contenuti degli elementi interni, uno dopo l'altro, in un unico annuncio. Questo consolidamento di elementi correlati consente agli utenti delle tecnologie per la disabilità di trovare le informazioni sullo schermo in modo più efficiente.

Lo snippet seguente contiene contenuti correlati l'uno all'altro, pertanto l'attributo android:screenReaderFocusable dell'elemento contenitore, un'istanza di ConstraintLayout, è impostato su true e l'attributo android:focusable interno è impostato su false:TextView

<!-- In response to a single user interaction, accessibility services announce
     both the title and the artist of the song. -->
<ConstraintLayout
    android:id="@+id/song_data_container" ...
    android:screenReaderFocusable="true">

    <TextView
        android:id="@+id/song_title" ...
        android:focusable="false"
        android:text="@string/my_song_title" />
    <TextView
        android:id="@+id/song_artist"
        android:focusable="false"
        android:text="@string/my_songwriter" />
</ConstraintLayout>

Poiché i servizi di accessibilità annunciano le descrizioni degli elementi interni in una singola frase, è importante mantenere ogni descrizione il più breve possibile, pur comunicando il significato dell'elemento.

Nota: in generale, evita di creare una descrizione dei contenuti per un gruppo aggregando il testo dei relativi elementi secondari. In questo modo la descrizione del gruppo diventa fragile e, quando il testo di un asset secondario cambia, la descrizione del gruppo potrebbe non corrispondere più al testo visibile.

In un contesto di elenco o griglia, uno screen reader può consolidare il testo dei nodi di testo secondari di un elenco o di un elemento della griglia. È meglio evitare di modificare questo annuncio.

Gruppi nidificati

Se l'interfaccia dell'app presenta informazioni multidimensionali, ad esempio un elenco giornaliero di eventi relativi a festival, utilizza l'attributo android:screenReaderFocusable nei contenitori dei gruppi interni. Questo schema di etichettatura offre un buon equilibrio tra il numero di annunci necessari per rilevare i contenuti dello schermo e la durata di ogni annuncio.

Il seguente snippet di codice mostra un metodo per etichettare i gruppi all'interno di gruppi più grandi:

<!-- In response to a single user interaction, accessibility services
     announce the events for a single stage only. -->
<ConstraintLayout
    android:id="@+id/festival_event_table" ... >
    <ConstraintLayout
        android:id="@+id/stage_a_event_column"
        android:screenReaderFocusable="true">

        <!-- UI elements that describe the events on Stage A. -->

    </ConstraintLayout>
    <ConstraintLayout
        android:id="@+id/stage_b_event_column"
        android:screenReaderFocusable="true">

        <!-- UI elements that describe the events on Stage B. -->

    </ConstraintLayout>
</ConstraintLayout>

Intestazioni all'interno del testo

Alcune app utilizzano le intestazioni per riepilogare i gruppi di testo che appaiono sullo schermo. Se un determinato elemento View rappresenta un'intestazione, puoi indicarne lo scopo per i servizi di accessibilità impostando l'attributo android:accessibilityHeading dell'elemento su true.

Gli utenti dei servizi di accessibilità possono scegliere di spostarsi tra le intestazioni anziché tra i paragrafi o tra le parole. Questa flessibilità migliora l'esperienza di navigazione testuale.

Titoli dei riquadri Accessibilità

In Android 9 (livello API 28) e versioni successive, puoi fornire titoli ottimizzati per l'accessibilità per i riquadro di uno schermo. Ai fini dell'accessibilità, un riquadro è una parte visivamente distinta di una finestra, come i contenuti di un frammento. Affinché i servizi di accessibilità possano comprendere il comportamento di un riquadro, assegna titoli descrittivi ai riquadri dell'app. I servizi di accessibilità possono quindi fornire informazioni più granulari agli utenti quando l'aspetto o i contenuti di un riquadro cambiano.

Per specificare il titolo di un riquadro, utilizza l'attributo android:accessibilityPaneTitle, come mostrato nello snippet seguente:

<!-- Accessibility services receive announcements about content changes
     that are scoped to either the "shopping cart view" section (top) or
     "browse items" section (bottom) -->
<MyShoppingCartView
     android:id="@+id/shoppingCartContainer"
     android:accessibilityPaneTitle="@string/shoppingCart" ... />

<MyShoppingBrowseView
     android:id="@+id/browseItemsContainer"
     android:accessibilityPaneTitle="@string/browseProducts" ... />

Elementi decorativi

Se un elemento dell'interfaccia utente esiste solo a scopo di spaziatura o di aspetto visivo, imposta il relativo attributo android:importantForAccessibility su "no".

Aggiungi azioni di accessibilità

È importante consentire agli utenti dei servizi di accessibilità di eseguire facilmente tutti i flussi utente all'interno della tua app. Ad esempio, se un utente può scorrere su un elemento in un elenco, questa azione può essere esposta anche ai servizi di accessibilità in modo che gli utenti abbiano un modo alternativo per completare la stessa procedura.

Rendi accessibili tutte le azioni

Un utente di TalkBack, Voice Access o Switch Access potrebbe aver bisogno di metodi alternativi per completare determinati flussi utente all'interno dell'app. Per le azioni associate a gesti come il trascinamento o lo scorrimento, la tua app può esporre le azioni in modo che siano accessibili agli utenti dei servizi di accessibilità.

Utilizzando le azioni di accessibilità, l'app può fornire agli utenti modi alternativi per completare un'azione.

Ad esempio, se la tua app consente agli utenti di scorrere su un elemento, puoi anche esporre la funzionalità tramite un'azione di accessibilità personalizzata, come questa:

Kotlin

ViewCompat.addAccessibilityAction(
    // View to add accessibility action
    itemView,
    // Label surfaced to user by an accessibility service
    getText(R.id.archive)
) { _, _ ->
    // Same method executed when swiping on itemView
    archiveItem()
    true
}

Java

ViewCompat.addAccessibilityAction(
    // View to add accessibility action
    itemView,
    // Label surfaced to user by an accessibility service
    getText(R.id.archive),
    (view, arguments) -> {
        // Same method executed when swiping on itemView
        archiveItem();
        return true;
    }
);

With the custom accessibility action implemented, users can access the action through the actions menu.

Make available actions understandable

When a view supports actions such as touch & hold, an accessibility service such as TalkBack announces it as "Double tap and hold to long press."

This generic announcement doesn't give the user any context about what a touch & hold action does.

To make this announcement more descriptive, you can replace the accessibility action’s announcement like so:

Kotlin

ViewCompat.replaceAccessibilityAction(
    // View that contains touch & hold action
    itemView,
    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK,
    // Announcement read by TalkBack to surface this action
    getText(R.string.favorite),
    null
)

Java

ViewCompat.replaceAccessibilityAction(
    // View that contains touch & hold action
    itemView,
    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK,
    // Announcement read by TalkBack to surface this action
    getText(R.string.favorite),
    null
);

This results in TalkBack announcing "Double tap and hold to favorite," helping users understand the purpose of the action.

Extend system widgets

Note: When you design your app's UI, use or extend system-provided widgets that are as far down Android's class hierarchy as possible. System-provided widgets that are far down the hierarchy already have most of the accessibility capabilities your app needs. It's easier to extend these system-provided widgets than to create your own from the more generic View, ViewCompat, Canvas, and CanvasCompat classes.

If you must extend View or Canvas directly, which might be necessary for a highly customized experience or a game level, see Make custom views more accessible.

This section uses the example of implementing a special type of Switch called TriSwitch while following best practices around extending system widgets. A TriSwitch object works similarly to a Switch object, except that each instance of TriSwitch allows the user to toggle among three possible states.

Extend from far down the class hierarchy

The Switch object inherits from several framework UI classes in its hierarchy:

View
↳ TextView
  ↳ Button
    ↳ CompoundButton
      ↳ Switch

È preferibile che la nuova classe TriSwitch si estenda direttamente dalla classe Switch. In questo modo, il framework di accessibilità di Android fornisce la maggior parte delle funzionalità di accessibilità di cui la classe TriSwitch ha bisogno:

  • Azioni di accessibilità: informazioni per il sistema su come i servizi di accessibilità possono emulare ogni possibile input utente eseguito su un oggetto TriSwitch. (Ereditato da View).
  • Eventi di accessibilità: informazioni per i servizi di accessibilità su ogni possibile modo in cui l'aspetto di un oggetto TriSwitch può cambiare quando lo schermo si aggiorna. (Ereditato da View).
  • Caratteristiche: dettagli relativi a ogni oggetto TriSwitch, come i contenuti del testo visualizzato. (Ereditato da TextView).
  • Informazioni sullo stato: descrizione dello stato attuale di un oggetto TriSwitch, ad esempio "selezionato" o "deselezionato". (Ereditato da CompoundButton).
  • Descrizione testuale dello stato: spiegazione testuale di ciò che rappresenta ogni stato. (Ereditato da Switch).

Questo comportamento di Switch e delle sue superclassi è quasi lo stesso per gli oggetti TriSwitch. Pertanto, la tua implementazione può concentrarsi sull'aumento del numero di stati possibili da due a tre.

Definisci eventi personalizzati

Quando estendi un widget di sistema, è probabile che modifichi un aspetto del modo in cui gli utenti interagiscono con il widget. È importante definire queste modifiche di interazione in modo che i servizi di accessibilità possano aggiornare il widget dell'app come se l'utente interagisse direttamente con il widget.

Di norma, per ogni callback basato sulle visualizzazioni che esegui l'override, devi anche ridefinire l'azione di accessibilità corrispondente eseguendo l'override di ViewCompat.replaceAccessibilityAction(). Nei test della tua app, puoi convalidare il comportamento di queste azioni ridefinite chiamando ViewCompat.performAccessibilityAction().

Come funziona questo principio per gli oggetti TriSwitch

A differenza di un oggetto Switch ordinario, quando tocchi un oggetto TriSwitch vengono visualizzati tre possibili stati. Pertanto, l'azione di accessibilità ACTION_CLICK corrispondente deve essere aggiornata:

Kotlin

class TriSwitch(context: Context) : Switch(context) {
    // 0, 1, or 2
    var currentState: Int = 0
        private set

    init {
        updateAccessibilityActions()
    }

    private fun updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label) {
            view, args -> moveToNextState()
        })
    }

    private fun moveToNextState() {
        currentState = (currentState + 1) % 3
    }
}

Java

public class TriSwitch extends Switch {
    // 0, 1, or 2
    private int currentState;

    public int getCurrentState() {
        return currentState;
    }

    public TriSwitch() {
        updateAccessibilityActions();
    }

    private void updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label, (view, args) -> moveToNextState());
    }

    private void moveToNextState() {
        currentState = (currentState + 1) % 3;
    }
}

Usa segnali diversi dal colore

Per assistere gli utenti con carenze nella visione dei colori, usa segnali diversi dal colore per distinguere gli elementi dell'interfaccia utente all'interno delle schermate della tua app. Queste tecniche possono includere l'utilizzo di diverse forme o dimensioni, la fornitura di pattern testuali o visivi o l'aggiunta di feedback audio o touch (aptico) per contrassegnare le differenze degli elementi.

La figura 1 mostra due versioni di un'attività. Una versione utilizza solo il colore per distinguere due possibili azioni in un flusso di lavoro. L'altra versione utilizza la best practice che prevede l'inclusione di forme e testo oltre al colore per evidenziare le differenze tra le due opzioni:

Figura 1. Esempi di creazione di elementi dell'interfaccia utente utilizzando solo il colore (sinistra) e l'utilizzo di colori, forme e testo (destra).

Rendere più accessibili i contenuti multimediali

Se stai sviluppando un'app che include contenuti multimediali, ad esempio un video clip o una registrazione audio, prova ad aiutare gli utenti con diversi tipi di esigenze di accessibilità nella comprensione di questo materiale. In particolare, ti invitiamo a:

  • Includi controlli che consentano agli utenti di mettere in pausa o interrompere i contenuti multimediali, regolare il volume e attivare/disattivare i sottotitoli (sottotitoli).
  • Se un video presenta informazioni essenziali per il completamento di un flusso di lavoro, fornisci gli stessi contenuti in un formato alternativo, ad esempio una trascrizione.

Risorse aggiuntive

Per scoprire di più su come rendere più accessibile la tua app, consulta le seguenti risorse aggiuntive:

Codelab

Post del blog