Rendere più accessibili le visualizzazioni personalizzate

Se la tua applicazione richiede un componente di visualizzazione personalizzata, devi rendere la vista più accessibile. I seguenti passaggi possono migliorare la visualizzazione personalizzata accessibilità, come descritto in questa pagina:

  • Gestisci i clic direzionali del controller.
  • Implementare i metodi dell'API Accessibility.
  • Invia AccessibilityEvent oggetti specifici della tua vista personalizzata.
  • Compila i campi AccessibilityEvent e AccessibilityNodeInfo per la tua vista.

Gestire i clic direzionali del controller

Sulla maggior parte dei dispositivi, quando si fa clic su una visualizzazione utilizzando un controller direzionale, KeyEvent con KEYCODE_DPAD_CENTER alla vista attualmente a fuoco. Handle di tutti gli handle delle visualizzazioni Android standard KEYCODE_DPAD_CENTER in modo appropriato. Quando crei un'immagine View assicurati che l'evento abbia lo stesso effetto del tocco della visualizzazione sul touchscreen.

Il controllo personalizzato deve trattare KEYCODE_ENTER lo stesso evento di KEYCODE_DPAD_CENTER. In questo modo le interazioni con una tastiera completa per gli utenti.

Implementare i metodi dell'API Accessibility

Gli eventi di accessibilità sono messaggi relativi agli utenti Interazioni con l'interfaccia visiva della tua app componenti. Questi messaggi sono gestiti dai servizi di accessibilità, che Utilizzare le informazioni in questi eventi per produrre feedback e prompt aggiuntivi. L'accessibilità fanno parte di View e View.AccessibilityDelegate . I metodi sono i seguenti:

dispatchPopulateAccessibilityEvent()
Il sistema chiama questo metodo quando la visualizzazione personalizzata genera un evento di accessibilità. Il valore predefinito implementazione di questo metodo chiama onPopulateAccessibilityEvent() per questa vista e poi il metodo dispatchPopulateAccessibilityEvent() per ogni elemento secondario vista.
onInitializeAccessibilityEvent()
Il sistema chiama questo metodo per ottenere ulteriori informazioni sullo stato della vista oltre contenuti testuali. Se la visualizzazione personalizzata offre un controllo interattivo al di là di una TextView o Button, sostituisci questo metodo e impostare le informazioni aggiuntive sulla visualizzazione, ad esempio tipo di campo password, casella di controllo o gli stati che forniscono l'interazione o il feedback dell'utente in merito all'evento, utilizzando . Se sostituisci questo metodo, richiama la relativa implementazione principale e modifica solo le proprietà che non sono impostati dalla super classe.
onInitializeAccessibilityNodeInfo()
Questo metodo fornisce ai servizi di accessibilità informazioni sullo stato della vista. La l'implementazione predefinita di View ha un insieme standard di proprietà di vista, ma se le tue la visualizzazione personalizzata offre un controllo interattivo oltre a un semplice TextView o Button, sostituisci questo metodo e imposta le informazioni aggiuntive sulla tua vista nell'oggetto AccessibilityNodeInfo gestito da questo metodo.
onPopulateAccessibilityEvent()
Questo metodo imposta il prompt di testo vocale dell'AccessibilityEvent per il tuo vista. Viene chiamato anche se la vista è secondaria rispetto a una che genera un'accessibilità .
onRequestSendAccessibilityEvent()
Il sistema chiama questo metodo quando un elemento secondario della tua vista genera AccessibilityEvent. Questo passaggio consente alla vista genitore di modificare l'accessibilità con informazioni aggiuntive. Implementa questo metodo solo se la tua visualizzazione personalizzata può avere viste secondarie e se la vista principale è in grado di fornire informazioni di contesto all'accessibilità utile per i servizi di accessibilità.
sendAccessibilityEvent()
Il sistema chiama questo metodo quando un utente esegue un'azione su una vista. L'evento è classificato con un tipo di azione utente, ad esempio TYPE_VIEW_CLICKED. In generale, devi inviare AccessibilityEvent ogni volta che i contenuti della visualizzazione personalizzata cambiano.
sendAccessibilityEventUnchecked()
Questo metodo viene usato quando il codice chiamante deve controllare direttamente la verifica di l'attivazione dell'accessibilità sul dispositivo (AccessibilityManager.isEnabled()). Se implementi questo metodo, esegui la chiamata come se l'accessibilità fosse abilitata, indipendentemente dal impostazione di sistema. In genere, non è necessario implementare questo metodo per una visualizzazione personalizzata.

Per supportare l'accessibilità, sostituisci e implementa i metodi di accessibilità precedenti direttamente nel la tua classe di visualizzazione personalizzata.

Implementa almeno i seguenti metodi di accessibilità per la classe di visualizzazione personalizzata:

  • dispatchPopulateAccessibilityEvent()
  • onInitializeAccessibilityEvent()
  • onInitializeAccessibilityNodeInfo()
  • onPopulateAccessibilityEvent()

Per ulteriori informazioni sull'implementazione di questi metodi, consulta la sezione su compilazione degli eventi di accessibilità.

Invia eventi di accessibilità

A seconda delle specifiche della visualizzazione personalizzata, potrebbe essere necessario inviare AccessibilityEvent di oggetti in momenti diversi o per eventi non gestiti per impostazione predefinita implementazione. La classe View fornisce un'implementazione predefinita per questo evento tipi:

di Gemini Advanced.

In generale, devi inviare un AccessibilityEvent ogni volta che i contenuti dei tuoi visualizzare le modifiche. Ad esempio, se stai implementando una barra di scorrimento personalizzata che consente all'utente di selezionare valore numerico premendo il tasto Freccia sinistra o Freccia destra; la visualizzazione personalizzata deve emettere un evento TYPE_VIEW_TEXT_CHANGED ogni volta che il valore del cursore cambia. Il seguente esempio di codice illustra l'utilizzo del sendAccessibilityEvent() metodo per segnalare questo evento.

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
    return when(keyCode) {
        KeyEvent.KEYCODE_DPAD_LEFT -> {
            currentValue--
            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)
            true
        }
        ...
    }
}

Java

@Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
        currentValue--;
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
        return true;
    }
    ...
}

Compilare gli eventi di accessibilità

Ogni AccessibilityEvent ha un insieme di proprietà obbligatorie che descrivono la configurazione attuale lo stato della vista. Queste proprietà includono, ad esempio, il nome della classe, i contenuti e descrizione e lo stato selezionato. Vengono descritte le proprietà specifiche obbligatorie per ogni tipo di evento nel AccessibilityEvent documentazione di riferimento.

L'implementazione View fornisce valori predefiniti per questi proprietà obbligatorie. Molti di questi valori, inclusi il nome della classe e il timestamp dell'evento, fornita automaticamente. Se crei un componente di visualizzazione personalizzato, devi fornire informazioni sui contenuti e sulle caratteristiche della vista. Queste informazioni possono essere semplici come pulsanti, e può includere altre informazioni sullo stato da aggiungere all'evento.

Utilizza la onPopulateAccessibilityEvent() e onInitializeAccessibilityEvent() per compilare o modificare le informazioni in un AccessibilityEvent. Utilizza la Metodo onPopulateAccessibilityEvent() specifico per l'aggiunta o la modifica del testo contenuti dell'evento, che vengono trasformati in messaggi udibili dai servizi di accessibilità quali TalkBack. Utilizza il metodo onInitializeAccessibilityEvent() per compilare ulteriori informazioni sull'evento, ad esempio lo stato di selezione della vista.

Inoltre, implementa onInitializeAccessibilityNodeInfo() . I servizi di accessibilità usano gli oggetti AccessibilityNodeInfo compilati da questo per esaminare la gerarchia delle viste che genera un evento di accessibilità dopo che viene ricevuto e fornire feedback appropriati agli utenti.

Il codice di esempio riportato di seguito mostra come eseguire l'override di questi tre metodi nella vista:

Kotlin

override fun onPopulateAccessibilityEvent(event: AccessibilityEvent?) {
    super.onPopulateAccessibilityEvent(event)
    // Call the super implementation to populate its text for the
    // event. Then, add text not present in a super class.
    // You typically only need to add the text for the custom view.
    if (text?.isNotEmpty() == true) {
        event?.text?.add(text)
    }
}

override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) {
    super.onInitializeAccessibilityEvent(event)
    // Call the super implementation to let super classes
    // set appropriate event properties. Then, add the new checked
    // property that is not supported by a super class.
    event?.isChecked = isChecked()
}

override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) {
    super.onInitializeAccessibilityNodeInfo(info)
    // Call the super implementation to let super classes set
    // appropriate info properties. Then, add the checkable and checked
    // properties that are not supported by a super class.
    info?.isCheckable = true
    info?.isChecked = isChecked()
    // You typically only need to add the text for the custom view.
    if (text?.isNotEmpty() == true) {
        info?.text = text
    }
}

Java

@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
    super.onPopulateAccessibilityEvent(event);
    // Call the super implementation to populate its text for the
    // event. Then, add the text not present in a super class.
    // You typically only need to add the text for the custom view.
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        event.getText().add(text);
    }
}

@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
    super.onInitializeAccessibilityEvent(event);
    // Call the super implementation to let super classes
    // set appropriate event properties. Then, add the new checked
    // property that is not supported by a super class.
    event.setChecked(isChecked());
}

@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    super.onInitializeAccessibilityNodeInfo(info);
    // Call the super implementation to let super classes set
    // appropriate info properties. Then, add the checkable and checked
    // properties that are not supported by a super class.
    info.setCheckable(true);
    info.setChecked(isChecked());
    // You typically only need to add the text for the custom view.
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        info.setText(text);
    }
}

Puoi implementare questi metodi direttamente nella classe di visualizzazione personalizzata.

Fornisci un contesto personalizzato per l'accessibilità

I servizi di accessibilità possono esaminare la gerarchia della vista contenitore di un componente dell'interfaccia utente che genera un evento di accessibilità. Ciò consente ai servizi di accessibilità di fornire più informazioni informazioni per aiutare gli utenti.

In alcuni casi i servizi di accessibilità non sono in grado di ottenere informazioni adeguate dalla vista nella gerarchia. Un esempio è un controllo di un'interfaccia personalizzata che ha due o più elementi separatamente aree cliccabili, come un controllo calendario. In questo caso, i servizi non possono essere adeguati informazioni perché le sottosezioni cliccabili non fanno parte della gerarchia di visualizzazione.

Figura 1. Una visualizzazione personalizzata del calendario con elementi del giorno selezionabili.

Nell'esempio nella figura 1, l'intero calendario è implementato come un'unica visualizzazione, quindi servizi non ricevono informazioni sufficienti sui contenuti della visualizzazione e sulla selezione dell'utente all'interno della vista, a meno che lo sviluppatore non fornisca informazioni aggiuntive. Ad esempio, se un utente fa clic il giorno etichettato come 17, il framework di accessibilità riceve soltanto le informazioni descrittive per l'intero controllo del calendario. In questo caso, il servizio di accessibilità TalkBack annuncia "Calendario" o "Calendario di aprile", e l'utente non sa quale giorno è selezionato.

Per fornire adeguate informazioni di contesto per i servizi di accessibilità in situazioni come questa, il consente di specificare una gerarchia di visualizzazione virtuale. Una gerarchia di visualizzazione virtuale è una agli sviluppatori di app di fornire una gerarchia di visualizzazione complementare ai servizi di accessibilità che molto simile alle informazioni sullo schermo. Questo approccio consente ai servizi di accessibilità di offrire di più informazioni di contesto utili agli utenti.

Un altro caso in cui potrebbe essere necessaria una gerarchia di visualizzazione virtuale è un'interfaccia utente contenente un insieme di controlli View con funzioni strettamente correlate, in cui viene eseguita un'azione su influisce sui contenuti di uno o più elementi, ad esempio un selettore di numeri con funzioni e i pulsanti Giù. In questo caso, i servizi di accessibilità non possono ricevere informazioni adeguate perché l'azione su un controllo modifica i contenuti di un altro e la relazione tra questi controlli potrebbe non evidente al servizio.

Per gestire questa situazione, raggruppa i controlli correlati con una vista contenitore e fornisci una la gerarchia di questo contenitore per rappresentare chiaramente le informazioni e il comportamento forniti i controlli di sicurezza.

Per fornire una gerarchia di viste virtuali per una vista, sostituisci la getAccessibilityNodeProvider() nella visualizzazione personalizzata o nel gruppo di viste personalizzate e restituiscono un'implementazione del AccessibilityNodeProvider. Puoi implementare una gerarchia di visualizzazione virtuale utilizzando la libreria di supporto con ViewCompat.getAccessibilityNodeProvider() e fornire un'implementazione AccessibilityNodeProviderCompat.

Semplificare il compito di fornire informazioni ai servizi di accessibilità accessibilità, puoi implementare ExploreByTouchHelper. Fornisce un AccessibilityNodeProviderCompat e può essere allegata come AccessibilityDelegateCompat chiamando setAccessibilityDelegate Per un esempio, vedi ExploreByTouchHelperActivity. ExploreByTouchHelper viene utilizzato anche dai widget del framework come CalendarView, tramite vista bambino SimpleMonthView.

Gestire gli eventi tocco personalizzati

I controlli della visualizzazione personalizzata potrebbero richiedere un comportamento dell'evento tocco non standard, come mostrato i seguenti esempi.

Definisci azioni basate sui clic

Se il widget utilizza il OnClickListener oppure OnLongClickListener a riga di comando, il sistema gestisce ACTION_CLICK e ACTION_LONG_CLICK azioni per te. Se la tua app utilizza un widget più personalizzato che si basa sui Interfaccia di OnTouchListener, definire gestori personalizzati per le azioni di accessibilità basate sui clic. A questo scopo, richiama il metodo replaceAccessibilityAction() per ogni azione, come mostrato nello snippet di codice riportato di seguito:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    // Assumes that the widget is designed to select text when tapped, and selects
    // all text when tapped and held. In its strings.xml file, this app sets
    // "select" to "Select" and "select_all" to "Select all".
    ViewCompat.replaceAccessibilityAction(
        binding.textSelectWidget,
        ACTION_CLICK,
        getString(R.string.select)
    ) { view, commandArguments ->
        selectText()
    }

    ViewCompat.replaceAccessibilityAction(
        binding.textSelectWidget,
        ACTION_LONG_CLICK,
        getString(R.string.select_all)
    ) { view, commandArguments ->
        selectAllText()
    }
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // Assumes that the widget is designed to select text when tapped, and select
    // all text when tapped and held. In its strings.xml file, this app sets
    // "select" to "Select" and "select_all" to "Select all".
    ViewCompat.replaceAccessibilityAction(
            binding.textSelectWidget,
            ACTION_CLICK,
            getString(R.string.select),
            (view, commandArguments) -> selectText());

    ViewCompat.replaceAccessibilityAction(
            binding.textSelectWidget,
            ACTION_LONG_CLICK,
            getString(R.string.select_all),
            (view, commandArguments) -> selectAllText());
}

Crea eventi di clic personalizzati

Un controllo personalizzato può usare onTouchEvent(MotionEvent) il metodo listener per rilevare ACTION_DOWN e Eventi ACTION_UP e attivare un evento di clic speciale. Per mantenere la compatibilità con i servizi di accessibilità, il codice che gestisce questo evento clic personalizzato, deve:

  1. Genera un valore AccessibilityEvent appropriato per l'azione di clic interpretata.
  2. Abilita i servizi di accessibilità per eseguire l'azione di clic personalizzata per gli utenti che non sono in grado di farlo usare un touchscreen.

Per gestire questi requisiti in modo efficiente, il codice deve eseguire l'override performClick() metodo, che deve chiamare la super-implementazione di questo metodo ed eseguire le azioni richiesta dall'evento clic. Quando viene rilevata l'azione di clic personalizzata, il codice deve chiamare la tua performClick(). Il seguente esempio di codice dimostra questo pattern.

Kotlin

class CustomTouchView(context: Context) : View(context) {

    var downTouch = false

    override fun onTouchEvent(event: MotionEvent): Boolean {
        super.onTouchEvent(event)

        // Listening for the down and up touch events.
        return when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downTouch = true
                true
            }

            MotionEvent.ACTION_UP -> if (downTouch) {
                downTouch = false
                performClick() // Call this method to handle the response and
                // enable accessibility services to
                // perform this action for a user who can't
                // tap the touchscreen.
                true
            } else {
                false
            }

            else -> false  // Return false for other touch events.
        }
    }

    override fun performClick(): Boolean {
        // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any.
        super.performClick()

        // Handle the action for the custom click here.

        return true
    }
}

Java

class CustomTouchView extends View {

    public CustomTouchView(Context context) {
        super(context);
    }

    boolean downTouch = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        // Listening for the down and up touch events
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downTouch = true;
                return true;

            case MotionEvent.ACTION_UP:
                if (downTouch) {
                    downTouch = false;
                    performClick(); // Call this method to handle the response and
                                    // enable accessibility services to
                                    // perform this action for a user who can't
                                    // tap the touchscreen.
                    return true;
                }
        }
        return false; // Return false for other touch events.
    }

    @Override
    public boolean performClick() {
        // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any.
        super.performClick();

        // Handle the action for the custom click here.

        return true;
    }
}

Il pattern precedente aiuta a garantire che l'evento clic personalizzato sia compatibile con le funzioni di accessibilità utilizzando il metodo performClick() per generare un evento di accessibilità e fornire un punto di accesso ai servizi di accessibilità per agire per conto di un utente che esegue evento di clic.