Focus Order — o que é, princípios e como configurar em aplicações móveis

Autor: IT Sectr Publicado: 2026-05-16 Tempo de leitura: 9 min

Focus Order é a sequência na qual os elementos da interface recebem foco ao navegar com um teclado, Switch Control, VoiceOver ou TalkBack. Em aplicações móveis, a ordem de foco determina como o utilizador se move entre os controlos através de gestos ou botões. De acordo com W3C WCAG 2.2, Success Criterion 2.4.3, 2023, o foco deve seguir uma ordem lógica que preserve o significado do conteúdo. A violação deste princípio é uma das causas comuns de falha numa auditoria de acessibilidade.

Pontos principais

  • Focus Order — a sequência de percorrer elementos interativos ao navegar com um teclado ou leitor de ecrã
  • O foco deve seguir a ordem visual (da esquerda para a direita, de cima para baixo) e preservar a lógica do conteúdo
  • No iOS, a ordem é controlada através de shouldGroupAccessibilityElement e do array accessibilityElements
  • No Android, os atributos nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight definem os vizinhos de foco
  • Ecrãs personalizados (mapas, canvas, jogos) requerem gestão programática do foco através de UIAccessibilityPostNotification

O que é Focus Order em acessibilidade

Focus Order é a sequência na qual o utilizador se move entre elementos interativos usando métodos de entrada alternativos: teclado (Tab), Switch Control (passo a passo), VoiceOver (deslizar direita/esquerda) ou TalkBack. Ao contrário de um rato ou ecrã tátil, onde o utilizador seleciona um elemento diretamente, a navegação por foco é linear — cada passo move o foco para o próximo elemento.

De acordo com Apple HIG, 2024, o VoiceOver utiliza a ordem dos elementos na árvore de acessibilidade, que é construída com base na localização visual: canto superior esquerdo → canto inferior direito. Se o ecrã tiver um layout complexo (colunas, Grid, ZStack), a árvore pode não corresponder à ordem visual.

Princípio da WCAG 2.4.3: “Se uma página web pode ser navegada sequencialmente através de secções e a ordem de foco afeta o significado, então o foco deve seguir uma ordem que preserve o significado e a operacionalidade”. Exceção: conteúdo dinâmico onde o foco pode saltar para chamar a atenção (alertas, janelas modais).

Por que o Focus Order é crítico para a acessibilidade

Um utilizador de Switch Control (pessoas com deficiências motoras) move-se pelos elementos automaticamente — ciclo após ciclo. Se a ordem estiver quebrada, o utilizador demora 3 vezes mais a preencher o formulário. De acordo com Deque University, 2024, um Focus Order correto reduz o tempo de preenchimento do formulário em 60% para utilizadores de tecnologias de assistência.

Focus Order e janelas modais

Atenção especial — janelas modais. Depois de abrir uma modal, o foco deve mover-se imediatamente para o primeiro elemento interativo dentro da modal (normalmente um botão “Fechar” ou “Confirmar”). Ao fechar — voltar ao elemento que acionou a modal. Este é um requisito da WCAG 2.4.3 e também um erro comum.

iOS: gestão da ordem de foco

No iOS, o VoiceOver constrói automaticamente a ordem com base na geometria: os elementos são ordenados por Y, depois por X. Para ecrãs com estrutura complexa, esta ordem pode estar incorreta — o desenvolvedor deve intervir.

Principais ferramentas:

  • shouldGroupAccessibilityElement — agrupa elementos filhos num bloco lógico
  • accessibilityElements — array que define a ordem personalizada dos elementos filhos
  • UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element) — movimento programático do foco

Exemplo de definição de ordem personalizada para um cartão de produto:

swift
class ProductCardView: UIView {
    let titleLabel = UILabel()
    let priceLabel = UILabel()
    let buyButton = UIButton()

    override var accessibilityElements: [Any]? {
        get {
            return [titleLabel!, priceLabel!, buyButton!]
        }
        set {}
    }
}

Para movimento programático do foco após uma ação:

swift
UIAccessibility.post(
    notification: .layoutChanged,
    argument: newlyAddedItem
)

shouldGroupAccessibilityElement na prática

A propriedade shouldGroupAccessibilityElement é útil para cartões em coleções. Se definida como true no cartão pai, o VoiceOver percebe o cartão inteiro como um único elemento. O utilizador pode tocar duas vezes para ativar o cartão completo, ou configurar o rotor para navegação interna. Recomendado para UICollectionViewCell e UITableViewCell.

Android: atributos de direção de foco

No Android, o TalkBack também utiliza a ordem geométrica, mas é dada prioridade aos atributos explícitos nextFocus*. Estes atributos são definidos em XML ou programaticamente:

AtributoPropósitoExemplo
nextFocusDownElemento ao navegar para baixo@+id/field_email
nextFocusUpElemento ao navegar para cima@+id/field_name
nextFocusLeftElemento à esquerda@+id/btn_back
nextFocusRightElemento à direita@+id/btn_next

Exemplo para um formulário de registo:

xml
<EditText
    android:id="@+id/field_email"
    android:nextFocusDown="@+id/field_password" />

<EditText
    android:id="@+id/field_password"
    android:nextFocusDown="@+id/btn_submit" />

Para RecyclerView, a ordem de foco é dinâmica — determinada pelo adaptador. Se as células tiverem uma estrutura complexa, defina descendantFocusability = “beforeDescendants” e defina a ordem no nó do item da lista. Para Jetpack Compose, a ordem de foco é definida através de Modifier.focusOrder() e FocusOrder. Prioridade: previous (filho), next (seguinte), chave personalizada.

TouchDelegate, área de impacto e área de foco

Se um elemento for demasiado pequeno para o foco (menor que 44pt), aumente a área de impacto através de TouchDelegate no iOS ou minWidth/minHeight no Android. De acordo com Google Material Design, 2024, a área tátil mínima é de 48×48dp. O VoiceOver e o TalkBack focam-se na caixa delimitadora do elemento. Elementos com menos de 30pt podem estar inacessíveis para o foco gestual — o utilizador fisicamente não consegue tocá-los.

Violações comuns da WCAG 2.4.3

Foco saltitante — quando após uma ação (por exemplo, eliminar um elemento) o foco se move para o início da lista ou para o botão “Voltar” do sistema. O utilizador do VoiceOver perde o contexto. Solução: mover programaticamente o foco para o elemento mais próximo do eliminado.

Foco invisível — um elemento recebe foco mas não há indicador visual (os utilizadores de teclado não veem onde estão). No iOS, verifique UIAccessibility.isVoiceOverRunning para indicadores personalizados. De acordo com Deque University, 2024, o foco invisível é a segunda causa mais comum de falha numa auditoria de acessibilidade.

Modais — o foco permanece no conteúdo de fundo após abrir uma modal. No iOS, a vista modal captura automaticamente o foco se modalPresentationStyle = .pageSheet estiver definido. No Android, use setFocusable(true) no contentor do diálogo.

Armadilha de foco

O problema inverso: o foco fica preso dentro de uma modal e não consegue sair (exceto fechando-a). Isto é aceitável apenas para janelas modais — o utilizador deve fechar a janela intencionalmente. Para ecrãs normais, a armadilha de foco é um erro crítico. Solução: certifique-se de que o último elemento da modal (o botão “Fechar”) devolve o foco.

Ecrãs personalizados e foco programático

Para ecrãs personalizados (mapas, canvas, jogos) a ordem geométrica automática não é aplicável. O desenvolvedor deve construir a árvore de acessibilidade manualmente. No iOS, o método UIAccessibilityContainer é sobrescrito para este fim.

Exemplo para um canvas personalizado:

swift
class CanvasView: UIView {
    var shapes: [ShapeView] = []

    override var accessibilityElements: [Any]? {
        get {
            // Ordenar formas por Z-index, não por geometria
            return shapes.sorted { $0.zIndex < $1.zIndex }
        }
        set {}
    }
}

No Android, para uma View personalizada, sobrescreva onInitializeAccessibilityNodeInfo:

kotlin
override fun onInitializeAccessibilityNodeInfo(
    info: AccessibilityNodeInfo
) {
    super.onInitializeAccessibilityNodeInfo(info)
    info.addChild(firstElement)
    info.addChild(secondElement)
    info.isFocusable = true
}

Para listas dinâmicas (chat, feed de notícias), depois de adicionar um elemento, mova o foco para o primeiro novo elemento. No iOS: UIAccessibility.post(notification: .layoutChanged, argument: newMessage). No Android: sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED).

AccessibilityFrame e geometria de foco

O iOS determina automaticamente a área de foco com base no frame do elemento. Se um elemento tiver uma transformação (transform, rotation), o VoiceOver pode focar a área errada. Defina explicitamente accessibilityFrame em coordenadas de ecrã: element.accessibilityFrame = UIAccessibility.convertToScreenCoordinates(element.bounds, in: element). Isto garante que o VoiceOver destaca a área correta.

UIKit Dynamics e acessibilidade

Para ecrãs animados (UIKit Dynamics, Lottie, SpriteKit), o foco programático é especialmente importante. O VoiceOver não consegue construir uma árvore de acessibilidade para elementos em movimento dinâmico. Defina isAccessibilityElement = false nos contentores de animação e true apenas nos elementos interativos no interior.

Testar a ordem de foco

Teste manual: ative o VoiceOver (iOS) ou TalkBack (Android), deslize para a direita por toda a sequência. O foco deve seguir a ordem visual — da esquerda para a direita, de cima para baixo. Cada elemento interativo deve receber foco exatamente uma vez.

Testes automatizados são difíceis mas possíveis:

swift
func testKeyboardFocusOrder() {
    let app = XCUIApplication()
    app.launch()
    app.textFields["Email"].tap()
    // Tab — apenas com teclado físico
}

Para Android, utilize o Accessibility Testing Framework:

kotlin
@Test
fun testFocusOrder() {
    onView(withId(R.id.fieldEmail))
        .check(matches(isFocusable()))
    onView(withId(R.id.fieldEmail))
        .perform(focus())
    onView(withId(R.id.fieldPassword))
        .check(matches(isFocused()))
}

O método mais fiável é um teste de cenário de UI: preencha o formulário passo a passo (Email → Palavra-passe → Enviar), verificando se cada passo é concluído com sucesso. Se a ordem de foco estiver quebrada, o cenário falhará ao tentar interagir com um elemento fora de foco.

Xcode Accessibility Inspector para depuração

A ferramenta Accessibility Inspector no Xcode mostra a árvore de acessibilidade completa. Pode percorrer os elementos na ordem do VoiceOver e ver o caminho de foco exato. Utilize o separador “Audit” para deteção automática de violações de Focus Order.

Perguntas frequentes

O que é a WCAG 2.4.3 e quais os requisitos de foco?

WCAG 2.4.3 (Focus Order) é um critério de sucesso de nível A. Requer que a ordem de foco preserve o significado do conteúdo durante a navegação sequencial. A violação é considerada crítica e bloqueia a certificação.

Como definir a ordem de foco para elementos ocultos por animações?

Os elementos ocultos devem ter isAccessibilityElement = false no iOS ou visibility = gone/invisible no Android. Quando aparecerem, mova programaticamente o foco através de UIAccessibility.post(notification: .layoutChanged).

Qual a diferença entre o foco no iOS e no Android?

O iOS gere através de accessibilityElements e shouldGroupAccessibilityElement, o Android através dos atributos nextFocus* e AccessibilityNodeInfo. O princípio é o mesmo: ordem geométrica por defeito com possibilidade de substituição.

O que fazer se o RecyclerView tiver uma ordem errada?

Defina descendantFocusability = “beforeDescendants” no elemento raiz e configure a ordem no adaptador através de onInitializeAccessibilityNodeInfo para cada célula.

Como testar o foco sem VoiceOver?

Conecte um teclado físico através de Bluetooth ou USB. No iOS prima Tab para mover o foco. No Android ative o TalkBack e use a tecla Tab e as setas.

Resumo

  • Focus Order — a sequência de percorrer elementos ao navegar com um teclado ou leitor de ecrã; baseado na WCAG 2.4.3
  • O foco deve seguir a ordem visual (da esquerda para a direita, de cima para baixo) — automaticamente no VoiceOver e TalkBack
  • No iOS, a ordem é controlada através de accessibilityElements e shouldGroupAccessibilityElement
  • No Android são usados os atributos nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight
  • Ecrãs personalizados (mapas, canvas) requerem gestão programática do foco através de UIAccessibilityPostNotification
  • A violação da ordem é um erro crítico na WCAG 2.4.3; os utilizadores perdem o contexto e não conseguem completar o cenário
  • Teste o foco através de gestos VoiceOver/TalkBack, teclado físico e cenários automatizados

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também