Se la tua applicazione richiede un componente di visualizzazione personalizzato, devi rendere la visualizzazione più accessibile. I seguenti passaggi possono migliorare l'accessibilità della visualizzazione personalizzata, come descritto in questa pagina:
- Consente di gestire i clic del controller direzionale.
- Implementare i metodi dell'API Accessibility.
- Invia
AccessibilityEvent
oggetti specifici della visualizzazione personalizzata. - Compila i campi
AccessibilityEvent
eAccessibilityNodeInfo
per la visualizzazione.
Gestire i clic del controller direzionale
Sulla maggior parte dei dispositivi, se fai clic su una visualizzazione mediante un controller direzionale viene inviato un elemento
KeyEvent
con
KEYCODE_DPAD_CENTER
alla visualizzazione attualmente attiva. Tutte le visualizzazioni Android standard gestiscono
KEYCODE_DPAD_CENTER
in modo appropriato. Quando crei un controllo View
personalizzato, assicurati che questo evento abbia lo stesso effetto del tocco della vista sul touchscreen.
Il controllo personalizzato deve considerare l'evento KEYCODE_ENTER
come se fosse KEYCODE_DPAD_CENTER
. In questo modo le interazioni con una
tastiera completa diventano più semplici per gli utenti.
Implementa i metodi dell'API Accessibility
Gli eventi di accessibilità sono messaggi relativi alle interazioni degli utenti con i componenti dell'interfaccia visiva della tua app. Questi messaggi vengono gestiti dai servizi di accessibilità, che utilizzano le informazioni in questi eventi per produrre feedback e prompt supplementari. I metodi
di accessibilità fanno parte delle classi View
e
View.AccessibilityDelegate
. I metodi sono i seguenti:
dispatchPopulateAccessibilityEvent()
onPopulateAccessibilityEvent()
per questa vista e poi il metodo dispatchPopulateAccessibilityEvent()
per ciascuna vista secondaria. onInitializeAccessibilityEvent()
TextView
o
Button
, sostituisci questo metodo
e imposta le informazioni aggiuntive sulla visualizzazione, ad esempio il tipo di campo password, il tipo di casella
di casella di controllo o gli stati che forniscono l'interazione dell'utente o il feedback sull'evento, utilizzando questo
metodo. Se esegui l'override di questo metodo, chiama la super-implementazione e modifica solo le proprietà che non sono impostate dalla superclasse.onInitializeAccessibilityNodeInfo()
View
ha un insieme standard di proprietà di visualizzazione, ma se la visualizzazione personalizzata fornisce un controllo interattivo oltre a un semplice TextView
o Button
, sostituisci questo metodo e imposta le informazioni aggiuntive sulla vista nell'oggetto AccessibilityNodeInfo
gestito da questo metodo.onPopulateAccessibilityEvent()
AccessibilityEvent
per la visualizzazione. Viene chiamata anche se la vista è secondaria di una vista che genera un evento di accessibilità.
onRequestSendAccessibilityEvent()
AccessibilityEvent
. Questo passaggio consente alla vista padre di modificare l'evento di accessibilità con informazioni aggiuntive. Implementa questo metodo solo se la visualizzazione personalizzata può avere viste secondarie e se la vista principale può fornire informazioni di contesto all'evento di accessibilità che è 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 dell'utente, come
TYPE_VIEW_CLICKED
. In generale, devi inviare unAccessibilityEvent
ogni volta che i contenuti della visualizzazione personalizzata cambiano. sendAccessibilityEventUnchecked()
- Questo metodo viene utilizzato quando il prefisso telefonico deve controllare direttamente il controllo dell'abilitazione
dell'accessibilità sul dispositivo
(
AccessibilityManager.isEnabled()
). Se implementi questo metodo, esegui la chiamata come se l'accessibilità fosse abilitata, indipendentemente dall'impostazione di sistema. In genere, non è necessario implementare questo metodo per una visualizzazione personalizzata. dispatchPopulateAccessibilityEvent()
onInitializeAccessibilityEvent()
onInitializeAccessibilityNodeInfo()
onPopulateAccessibilityEvent()
TYPE_VIEW_CLICKED
TYPE_VIEW_FOCUSED
TYPE_VIEW_HOVER_ENTER
TYPE_VIEW_HOVER_EXIT
TYPE_VIEW_LONG_CLICKED
TYPE_VIEW_SCROLLED
- Genera un valore
AccessibilityEvent
appropriato per l'azione di clic interpretata. - Attiva i servizi di accessibilità per eseguire l'azione di clic personalizzata per gli utenti che non sono in grado di utilizzare un touchscreen.
Per supportare l'accessibilità, esegui l'override e l'implementazione dei metodi di accessibilità precedenti direttamente nella classe delle visualizzazioni personalizzate.
Implementa almeno i seguenti metodi di accessibilità per la classe visualizzazione personalizzata:
Per ulteriori informazioni sull'implementazione di questi metodi, consulta la sezione relativa alla compilazione degli eventi di accessibilità.
Invia eventi di accessibilità
A seconda delle specifiche della visualizzazione personalizzata, potrebbe essere necessario inviare AccessibilityEvent
oggetti in momenti diversi o per eventi non gestiti dall'implementazione predefinita. La classe View
fornisce un'implementazione predefinita per questi tipi di eventi:
In generale, devi inviare un AccessibilityEvent
ogni volta che i contenuti della visualizzazione personalizzata cambiano. Ad esempio, se stai implementando una barra di scorrimento personalizzata che consente all'utente di selezionare un valore numerico premendo il tasto Freccia sinistra o destra, la visualizzazione personalizzata deve emettere un evento di TYPE_VIEW_TEXT_CHANGED
ogni volta che il valore del dispositivo di scorrimento cambia. Il seguente esempio di codice mostra l'utilizzo del metodo sendAccessibilityEvent()
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; } ... }
Completa gli eventi di accessibilità
Ogni AccessibilityEvent
ha un insieme di proprietà obbligatorie che descrivono lo stato
attuale della vista. Queste proprietà includono elementi come il nome della classe della vista, la descrizione dei contenuti e lo stato selezionato. Le proprietà specifiche richieste per ogni tipo di evento sono descritte nella documentazione di riferimento AccessibilityEvent
.
L'implementazione View
fornisce valori predefiniti per queste
proprietà obbligatorie. Molti di questi valori, inclusi il nome della classe e il timestamp dell'evento, vengono forniti automaticamente. Se crei un componente di una visualizzazione personalizzata, devi fornire informazioni sui contenuti e sulle caratteristiche della vista. Queste informazioni possono essere semplici come l'etichetta
di un pulsante e includere informazioni aggiuntive sullo stato da aggiungere all'evento.
Utilizza i metodi onPopulateAccessibilityEvent()
e onInitializeAccessibilityEvent()
per inserire o modificare le informazioni in un AccessibilityEvent
. Utilizza il metodo onPopulateAccessibilityEvent()
specificamente per aggiungere o modificare i contenuti testuali dell'evento, che viene trasformato in prompt udibili dai servizi di accessibilità come TalkBack. Utilizza il metodo onInitializeAccessibilityEvent()
per inserire ulteriori informazioni sull'evento, ad esempio lo stato di selezione della vista.
Inoltre, implementa il metodo onInitializeAccessibilityNodeInfo()
. I servizi di accessibilità utilizzano gli oggetti AccessibilityNodeInfo
compilati con questo metodo per esaminare la gerarchia delle visualizzazioni che genera un evento di accessibilità dopo la ricezione e fornire un feedback appropriato agli utenti.
Il seguente esempio di codice 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 Visualizzazione personalizzata.
Fornisci un contesto personalizzato per l'accessibilità
I servizi di accessibilità possono esaminare la gerarchia delle viste contenitore di un componente dell'interfaccia utente che genera un evento di accessibilità. Ciò consente ai servizi di accessibilità di fornire informazioni contestuali più complete per aiutare gli utenti.
In alcuni casi i servizi di accessibilità non riescono a ottenere informazioni adeguate dalla gerarchia delle viste. Un esempio è costituito da un controllo dell'interfaccia personalizzata con due o più aree selezionabili separatamente, come il controllo del calendario. In questo caso, i servizi non possono ricevere informazioni adeguate perché le sottosezioni cliccabili non fanno parte della gerarchia delle visualizzazioni.
![](https://developer.android.com/static/guide/topics/ui/accessibility/calendar.png?authuser=8&hl=it)
Figura 1. Una visualizzazione personalizzata del calendario con elementi giornalieri selezionabili.
Nell'esempio nella figura 1, l'intero calendario è implementato come un'unica visualizzazione, pertanto i servizi di accessibilità non ricevono informazioni sufficienti sui contenuti della visualizzazione e sulla selezione da parte dell'utente all'interno della visualizzazione a meno che lo sviluppatore non fornisca informazioni aggiuntive. Ad esempio, se un utente fa clic sul giorno 17, il framework di accessibilità riceve solo le informazioni della descrizione per l'intero controllo del calendario. In questo caso, il servizio di accessibilità TalkBack annuncia "Calendar" o "Calendario di aprile" e l'utente non sa quale giorno viene selezionato.
Per fornire informazioni di contesto adeguate per i servizi di accessibilità in situazioni come questa, il framework fornisce un modo per specificare una gerarchia di visualizzazioni virtuali. Una gerarchia di visualizzazioni virtuali è un modo in cui gli sviluppatori di app possono fornire una gerarchia di viste complementare ai servizi di accessibilità che corrisponda più strettamente alle informazioni sullo schermo. Questo approccio consente ai servizi di accessibilità di fornire informazioni contestuali più utili agli utenti.
Un'altra situazione in cui potrebbe essere necessaria una gerarchia di visualizzazioni virtuali è un'interfaccia utente contenente un insieme di controlli View
con funzioni strettamente correlate, dove un'azione su un controllo influisce sui contenuti di uno o più elementi, ad esempio un selettore di numeri con pulsanti Su e Giù separati. In questo caso, i servizi di accessibilità non possono ricevere informazioni adeguate perché un'azione su un controllo cambia i contenuti in un altro e la relazione di questi controlli potrebbe non essere chiara al servizio.
Per gestire questa situazione, raggruppa i controlli correlati con una vista contenitore e fornisci una gerarchia di visualizzazioni virtuali da questo container per rappresentare chiaramente le informazioni e il comportamento forniti dai controlli.
Per fornire una gerarchia di visualizzazioni virtuali per una vista, esegui l'override del metodo getAccessibilityNodeProvider()
nel gruppo di visualizzazioni o visualizzazioni personalizzate e restituisci un'implementazione di AccessibilityNodeProvider
.
Puoi implementare una gerarchia di visualizzazioni virtuali utilizzando la Support Library con il metodo ViewCompat.getAccessibilityNodeProvider()
e fornire un'implementazione con AccessibilityNodeProviderCompat
.
Per semplificare il compito di fornire informazioni ai servizi di accessibilità e gestire l'obiettivo dell'accessibilità, puoi implementare ExploreByTouchHelper
.
Fornisce un AccessibilityNodeProviderCompat
e può essere allegato come AccessibilityDelegateCompat
di una vista chiamando
setAccessibilityDelegate
.
Per un esempio, vedi
ExploreByTouchHelperActivity
.
ExploreByTouchHelper
è utilizzato anche da widget framework come CalendarView
, attraverso la sua vista secondaria
SimpleMonthView
.
Gestire gli eventi tocco personalizzati
I controlli delle visualizzazioni personalizzate potrebbero richiedere un comportamento degli eventi touch non standard, come dimostrato nei seguenti esempi.
Definisci azioni basate sui clic
Se il widget utilizza l'interfaccia OnClickListener
o OnLongClickListener
, il sistema gestisce per te le azioni ACTION_CLICK
e ACTION_LONG_CLICK
. Se la tua app utilizza un widget più personalizzato che si basa sull'interfaccia OnTouchListener
, definisci gestori personalizzati per le azioni di accessibilità basate sui clic. A questo scopo, chiama il metodo
replaceAccessibilityAction()
per ogni azione, come mostrato nel seguente snippet di codice:
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()); }
Creare eventi di clic personalizzati
Un controllo personalizzato può utilizzare il metodo di ascolto onTouchEvent(MotionEvent)
per rilevare gli eventi ACTION_DOWN
e ACTION_UP
e attivare un evento di clic speciale. Per mantenere la compatibilità con i servizi di accessibilità, il codice che gestisce questo evento di clic personalizzato deve:
Per gestire questi requisiti in modo efficiente, il codice deve sostituire il metodo performClick()
, che deve chiamare la super-implementazione di questo metodo ed eseguire le azioni richieste dall'evento clic. Quando viene rilevata l'azione di clic personalizzata, questo codice deve chiamare il tuo
metodo performClick()
. L'esempio di codice riportato di seguito illustra 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 di clic personalizzato sia compatibile con i servizi di accessibilità utilizzando il metodo performClick()
per generare un evento di accessibilità e fornire un punto di ingresso affinché i servizi di accessibilità agiscano per conto di un utente che esegue l'evento di clic personalizzato.