Princípios para melhorar a acessibilidade do app

Para ajudar os usuários com necessidades de acessibilidade, o framework do Android permite criar um serviço de acessibilidade que pode apresentar conteúdo de apps aos usuários e também operar apps em nome deles.

O Android fornece vários serviços de acessibilidade do sistema, incluindo:

  • TalkBack: ajuda pessoas com baixa visão ou cegas. Ele anuncia o conteúdo usando uma voz sintetizada e realiza ações em um app em resposta a gestos do usuário.
  • Acesso com interruptor: ajuda pessoas com deficiências motoras. Ele destaca elementos interativos e executa ações em resposta ao pressionamento de um botão. Ele permite controlar o dispositivo usando apenas um ou dois botões.

Para ajudar pessoas com necessidades de acessibilidade a usar seu app, ele precisa seguir as práticas recomendadas descritas nesta página, que se baseiam nas diretrizes descritas em Tornar os apps mais acessíveis.

Cada uma dessas práticas recomendadas, descritas nas seções a seguir, pode melhorar ainda mais a acessibilidade do seu app:

Elementos de etiqueta
Os usuários precisam entender o conteúdo e o propósito de cada elemento interativo e significativo da IU no app.
Adicionar ações de acessibilidade
Ao adicionar ações de acessibilidade, você pode permitir que os usuários dos serviços de acessibilidade concluam fluxos de usuário críticos no seu app.
Estender widgets do sistema
Crie com base nos elementos de visualização incluídos pelo framework, em vez de criar visualizações personalizadas. As classes de visualização e widget do framework já oferecem a maioria dos recursos de acessibilidade necessários para seu app.
Usar outras indicações além da cor
Os usuários precisam conseguir distinguir claramente as categorias de elementos em uma interface. Para fazer isso, use padrões e posicionamento junto à cor para expressar essas diferenças.
Tornar o conteúdo de mídia mais acessível
Adicione descrições ao conteúdo de vídeo ou áudio do seu app para que os usuários que consomem esse conteúdo não precisem depender de indicações totalmente visuais ou auditivas.

Elementos de etiqueta

É importante oferecer aos usuários rótulos úteis e descritivos para cada elemento interativo da IU do app. Cada rótulo precisa explicar o significado e o propósito de um determinado elemento. Leitores de tela como o TalkBack podem anunciar esses marcadores aos usuários.

Na maioria dos casos, a descrição de um elemento da interface é especificada no arquivo de recurso de layout que contém o elemento. Normalmente, você adiciona rótulos usando o atributo contentDescription, conforme explicado no guia sobre como tornar os apps mais acessíveis. Existem várias outras técnicas de rotulagem descritas nas seções a seguir.

Elementos editáveis

Ao rotular elementos editáveis, como objetos EditText, é útil mostrar um texto que dê um exemplo de entrada válida no próprio elemento, além de disponibilizar esse texto de exemplo para leitores de tela. Nessas situações, é possível usar o atributo android:hint, como mostrado no snippet a seguir:

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

Nessa situação, o objeto View precisa ter o atributo android:labelFor definido como o ID do elemento EditText. Para mais detalhes, consulte a seção a seguir.

Pares de elementos em que um descreve o outro

É comum que um elemento EditText tenha um objeto View correspondente que descreva o que os usuários precisam inserir no elemento EditText. Você pode indicar essa relação definindo o atributo android:labelFor do objeto View.

Um exemplo de classificação desses pares de elementos aparece no snippet a seguir:


<!-- 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" ... />

Elementos em uma coleção

Ao adicionar rótulos aos elementos de uma coleção, cada rótulo precisa ser exclusivo. Dessa forma, os serviços de acessibilidade do sistema podem se referir a exatamente um elemento na tela ao anunciar uma etiqueta. Essa correspondência permite que os usuários saibam quando eles percorrem a interface ou movem o foco para um elemento que já descobriram.

Especificamente, inclua mais texto ou informações contextuais em elementos dentro de layouts reutilizados, como objetos RecyclerView, para que cada elemento filho seja identificado de maneira exclusiva.

Para fazer isso, defina a descrição do conteúdo como parte da implementação do adaptador, conforme mostrado no snippet de código a seguir:

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")
    }
}

Grupos de conteúdo relacionado

Caso seu app exiba vários elementos de IU que formam um grupo natural, como detalhes de uma música ou atributos de uma mensagem, organize esses elementos em um contêiner, que geralmente é uma subclasse de ViewGroup. Defina o atributo android:screenReaderFocusable do objeto de contêiner como true e o atributo android:focusable de cada objeto interno como false. Dessa forma, os serviços de acessibilidade podem apresentar as descrições de conteúdo dos elementos internos, um após o outro, em um único anúncio. Essa consolidação de elementos relacionados ajuda os usuários de tecnologia adaptativa a descobrir as informações na tela com mais eficiência.

O snippet abaixo contém partes de conteúdo que se relacionam entre si. Portanto, o elemento de contêiner, uma instância de ConstraintLayout, tem o atributo android:screenReaderFocusable definido como true, e os elementos TextView internos têm o atributo android:focusable definido como false:

<!-- 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>

Como os serviços de acessibilidade anunciam as descrições dos elementos internos em uma única expressão, é importante manter cada descrição o mais curta possível, sem deixar de transmitir o significado do elemento.

Observação:em geral, para evitar criar uma descrição de conteúdo para um grupo, agregando o texto dos filhos. Isso torna a descrição do grupo instável e, quando o texto de um filho muda, a descrição do grupo pode não corresponder mais ao texto visível.

Em um contexto de lista ou grade, um leitor de tela pode consolidar o texto dos nós de texto filhos de um elemento de lista ou grade. É melhor evitar modificar esse aviso.

Grupos aninhados

Se a interface do app apresentar informações multidimensionais, como uma lista diária de eventos de um festival, use o atributo android:screenReaderFocusable nos contêineres do grupo interno. Esse esquema de rotulagem fornece um bom equilíbrio entre o número de anúncios necessários para descobrir o conteúdo da tela e a duração de cada anúncio.

O snippet de código a seguir mostra um método para classificar grupos dentro de outros maiores:

<!-- 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>

Títulos no texto

Alguns apps usam títulos para resumir grupos de texto que aparecem na tela. Se determinado elemento View representa um título, você pode indicar a finalidade dele para os serviços de acessibilidade definindo o atributo android:accessibilityHeading do elemento como true.

Os usuários de serviços de acessibilidade podem optar por navegar entre títulos em vez de entre parágrafos ou palavras. Essa flexibilidade melhora a experiência de navegação de texto.

Títulos do painel de acessibilidade

No Android 9 (API nível 28) ou versões mais recentes, você pode fornecer títulos de fácil acessibilidade para os painéis de uma tela. Para fins de acessibilidade, um painel é uma parte visualmente distinta de uma janela, como o conteúdo de um fragmento. Para que os serviços de acessibilidade entendam o comportamento semelhante a janelas de um painel, forneça títulos descritivos para os painéis do app. Os serviços de acessibilidade podem oferecer informações mais detalhadas aos usuários quando a aparência ou o conteúdo de um painel muda.

Para especificar o título de um painel, use o atributo android:accessibilityPaneTitle, conforme mostrado no snippet a seguir:

<!-- 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" ... />

Elementos decorativos

Se um elemento na sua IU existir apenas para fins de espaçamento visual ou aparência, defina o atributo android:importantForAccessibility como "no".

Adicionar ações de acessibilidade

É importante permitir que os usuários dos serviços de acessibilidade executem facilmente todos os fluxos de usuários no app. Por exemplo, se um usuário puder deslizar sobre um item em uma lista, essa ação também poderá ser exposta aos serviços de acessibilidade para que eles tenham uma maneira alternativa de concluir o mesmo fluxo de usuários.

Tornar todas as ações acessíveis

Um usuário do TalkBack, do Voice Access ou do acesso com interruptor pode precisar de outras formas para concluir determinados fluxos de usuários no app. Para ações associadas a gestos, como arrastar e soltar ou deslizar, o app pode expor as ações de uma maneira acessível aos usuários de serviços de acessibilidade.

Com as ações de acessibilidade, o app pode oferecer maneiras alternativas para os usuários concluirem uma ação.

Por exemplo, se o app permite que os usuários deslizem sobre um item, você também pode expor a funcionalidade com uma ação de acessibilidade personalizada, como esta:

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

É melhor que a nova classe TriSwitch seja estendida diretamente da classe Switch. Dessa forma, o framework de acessibilidade do Android oferece a maioria dos recursos de acessibilidade de que a classe TriSwitch precisa:

  • Ações de acessibilidade:informações para o sistema sobre como os serviços de acessibilidade podem emular cada entrada possível do usuário executada em um objeto TriSwitch. Configuração herdada de View.
  • Eventos de acessibilidade:informações para serviços de acessibilidade sobre todas as maneiras possíveis de mudar a aparência de um objeto TriSwitch quando a tela for atualizada ou atualizada. Configuração herdada de View.
  • Características:detalhes sobre cada objeto TriSwitch, como o conteúdo de qualquer texto exibido. Configuração herdada de TextView.
  • Informações de estado:descrição do estado atual de um objeto TriSwitch, como "marcado" ou "desmarcado". Configuração herdada de CompoundButton.
  • Descrição em texto do estado:explicação em texto do que cada estado representa. Configuração herdada de Switch.

Esse comportamento de Switch e das superclasses é quase o mesmo comportamento para objetos TriSwitch. Portanto, sua implementação pode se concentrar na expansão do número de estados possíveis de dois para três.

Definir eventos personalizados

Ao estender um widget do sistema, você provavelmente muda um aspecto de como os usuários interagem com esse widget. É importante definir essas mudanças de interação para que os serviços de acessibilidade possam atualizar o widget do app como se o usuário interagisse diretamente com o widget.

Uma diretriz geral é que, para cada callback baseado em visualização que você substituir, também será necessário redefinir a ação de acessibilidade correspondente substituindo ViewCompat.replaceAccessibilityAction(). Nos testes do app, você pode validar o comportamento dessas ações redefinidas chamando ViewCompat.performAccessibilityAction().

Como esse princípio pode funcionar para objetos TriSwitch

Ao contrário de um objeto Switch comum, tocar em um objeto TriSwitch alterna entre três estados possíveis. Portanto, a ação de acessibilidade ACTION_CLICK correspondente precisa ser atualizada:

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;
    }
}

Usar outras indicações além da cor

Para ajudar os usuários com deficiências visuais relacionadas a cores, use outros tipos de indicador para distinguir os elementos da IU nas telas do seu app. Essas técnicas podem incluir o uso de diferentes formas ou tamanhos, a exibição de textos ou padrões visuais ou a adição de retorno tátil ou de áudio ou toque para marcar as diferenças dos elementos.

A Figura 1 mostra duas versões de uma atividade. Uma versão usa somente cores para diferenciar duas ações possíveis em um fluxo de trabalho. A outra versão usa a prática recomendada de incluir formas e texto, além de cores, para destacar as diferenças entre as duas opções:

Figura 1. Exemplos de criação de elementos de IU usando apenas cores (à esquerda) e usando cores, formas e texto (à direita).

Tornar o conteúdo de mídia mais acessível

Se você estiver desenvolvendo um app que inclui conteúdo de mídia, como um trecho de vídeo ou gravação de áudio, faça o possível para ajudar os usuários com diferentes tipos de necessidades de acessibilidade a entender esse material. Em particular, recomendamos que você faça o seguinte:

  • Inclua controles que permitam aos usuários pausar ou interromper a mídia, mudar o volume e alternar as legendas.
  • Se um vídeo apresentar informações essenciais para a conclusão de um fluxo de trabalho, disponibilize o mesmo conteúdo em um formato alternativo, como uma transcrição.

Outros recursos

Para saber mais sobre como tornar seu app mais acessível, consulte estes recursos extras:

Codelabs

Postagens do blog