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:
- Gestisci i clic del controller direzionale.
- Implementa i metodi dell'API di accessibilità.
- Invia
AccessibilityEventoggetti specifici per la visualizzazione personalizzata. - Compila
AccessibilityEventeAccessibilityNodeInfoper la visualizzazione.
Gestisci i clic del controller direzionale
Nella maggior parte dei dispositivi, quando si fa clic su una visualizzazione utilizzando un controller direzionale, viene inviato un KeyEvent con KEYCODE_DPAD_CENTER alla visualizzazione attualmente attiva. Tutte le visualizzazioni Android standard gestiscono correttamente KEYCODE_DPAD_CENTER. Quando crei un controllo View personalizzato, assicurati che questo evento abbia lo stesso effetto del tocco della visualizzazione sul touchscreen.
Il controllo personalizzato deve trattare l'evento KEYCODE_ENTER allo stesso modo di KEYCODE_DPAD_CENTER. In questo modo, le interazioni con una tastiera completa sono più semplici per gli utenti.
Implementa i metodi dell'API di accessibilità
Gli eventi di accessibilità sono messaggi relativi alle interazioni degli utenti con i componenti dell'interfaccia visiva dell'app. Questi messaggi vengono gestiti dai servizi di accessibilità, che
utilizzano le informazioni contenute in questi eventi per produrre feedback e prompt supplementari. I metodi di accessibilità fanno parte delle View e
View.AccessibilityDelegate
classi. I metodi sono i seguenti:
dispatchPopulateAccessibilityEvent()onPopulateAccessibilityEvent() per questa visualizzazione
e poi il metodo dispatchPopulateAccessibilityEvent() per ogni elemento secondario di questa
visualizzazione. onInitializeAccessibilityEvent()TextView o
Button, esegui l'override di questo metodo
e imposta le informazioni aggiuntive sulla visualizzazione, ad esempio il tipo di campo password, il tipo di casella di controllo
o gli stati che forniscono interazione o feedback dell'utente nell'evento, utilizzando questo
metodo. Se esegui l'override di questo metodo, chiama la relativa implementazione super e modifica solo le proprietà
che non sono impostate dalla superclasse.onInitializeAccessibilityNodeInfo()View ha un insieme standard di proprietà della visualizzazione, ma se la
visualizzazione personalizzata fornisce un controllo interattivo oltre a un semplice TextView o
Button, esegui l'override di questo metodo e imposta le informazioni aggiuntive sulla visualizzazione
nell'oggetto AccessibilityNodeInfo gestito da questo metodo.onPopulateAccessibilityEvent()AccessibilityEvent per la tua
visualizzazione. Viene chiamato anche se la visualizzazione è un elemento secondario di una visualizzazione che genera un evento di accessibilità.
onRequestSendAccessibilityEvent()AccessibilityEvent. Questo passaggio consente alla vista genitore di modificare l'evento di accessibilità
con informazioni aggiuntive. Implementa questo metodo solo se la visualizzazione personalizzata può avere
visualizzazioni secondarie e se la vista genitore può fornire informazioni di contesto all'evento di accessibilità
utili per i servizi di accessibilità.sendAccessibilityEvent()- Il sistema chiama questo metodo quando un utente esegue un'azione su una visualizzazione. L'evento viene classificato con
un tipo di azione utente, ad esempio
TYPE_VIEW_CLICKED. In generale, devi inviare unAccessibilityEventogni volta che il contenuto della visualizzazione personalizzata cambia. sendAccessibilityEventUnchecked()- Questo metodo viene utilizzato quando il codice chiamante deve controllare direttamente la verifica dell'attivazione dell'accessibilità sul dispositivo (
AccessibilityManager.isEnabled()). Se implementi questo metodo, esegui la chiamata come se l'accessibilità fosse attivata, indipendentemente dall'impostazione di sistema. In genere non è necessario implementare questo metodo per una visualizzazione personalizzata. dispatchPopulateAccessibilityEvent()onInitializeAccessibilityEvent()onInitializeAccessibilityNodeInfo()onPopulateAccessibilityEvent()TYPE_VIEW_CLICKEDTYPE_VIEW_FOCUSEDTYPE_VIEW_HOVER_ENTERTYPE_VIEW_HOVER_EXITTYPE_VIEW_LONG_CLICKEDTYPE_VIEW_SCROLLED- Genera un
AccessibilityEventappropriato per l'azione di clic interpretata. - Consenti ai servizi di accessibilità di eseguire l'azione di clic personalizzata per gli utenti che non sono in grado di utilizzare un touch screen.
Per supportare l'accessibilità, esegui l'override e implementa i metodi di accessibilità precedenti direttamente nella classe di visualizzazione personalizzata.
Come minimo, implementa i seguenti metodi di accessibilità per la classe di visualizzazione personalizzata:
Per saperne di più 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 oggetti AccessibilityEvent 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 il contenuto della visualizzazione personalizzata cambia. Ad esempio, se implementi una barra di scorrimento personalizzata che consente all'utente di selezionare un valore numerico premendo il tasto Freccia sinistra o Freccia destra, la visualizzazione personalizzata deve emettere un evento di TYPE_VIEW_TEXT_CHANGED ogni volta che il valore della barra 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; } ... }
Compila eventi di accessibilità
Ogni AccessibilityEvent ha un insieme di proprietà obbligatorie che descrivono lo stato attuale della visualizzazione. Queste proprietà includono elementi come il nome della classe della visualizzazione, la descrizione del contenuto e lo stato di selezione. Le proprietà specifiche richieste per ogni tipo di evento sono descritte nella documentazione di riferimento di 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 visualizzazione personalizzato, devi fornire informazioni sul contenuto e sulle caratteristiche della visualizzazione. Queste informazioni possono essere semplici come l'etichetta di un pulsante e possono includere informazioni sullo stato aggiuntive che vuoi aggiungere all'evento.
Utilizza i metodi
onPopulateAccessibilityEvent()
e
onInitializeAccessibilityEvent()
per compilare o modificare le informazioni in un AccessibilityEvent. Utilizza il metodo onPopulateAccessibilityEvent() in modo specifico per aggiungere o modificare il contenuto di testo dell'evento, che viene trasformato in prompt audio dai servizi di accessibilità come TalkBack. Utilizza il metodo onInitializeAccessibilityEvent() per compilare informazioni aggiuntive sull'evento, ad esempio lo stato di selezione della visualizzazione.
Inoltre, implementa il metodo onInitializeAccessibilityNodeInfo(). I servizi di accessibilità utilizzano gli oggetti AccessibilityNodeInfo compilati da questo metodo per esaminare la gerarchia di oggetti View 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 visualizzazione:
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 di accessibilità personalizzato
I servizi di accessibilità possono esaminare la gerarchia di oggetti View contenenti di un componente dell'interfaccia utente che genera un evento di accessibilità. In questo modo, i servizi di accessibilità possono fornire informazioni contestuali più ricche per aiutare gli utenti.
In alcuni casi, i servizi di accessibilità non riescono a ottenere informazioni adeguate dalla gerarchia delle visualizzazioni. Un esempio è un controllo dell'interfaccia personalizzato con due o più aree su cui è possibile fare clic separatamente, ad esempio un controllo del calendario. In questo caso, i servizi non possono ottenere informazioni adeguate perché le sottosezioni su cui è possibile fare clic non fanno parte della gerarchia di oggetti View.
Figura 1. Una visualizzazione del calendario personalizzata con elementi di giorno selezionabili.
Nell'esempio della figura 1, l'intero calendario viene implementato come una singola visualizzazione, quindi i servizi di accessibilità non ricevono informazioni sufficienti sul contenuto della visualizzazione e sulla selezione dell'utente all'interno della visualizzazione, a meno che lo sviluppatore non fornisca informazioni aggiuntive. Ad esempio, se un utente fa clic sul giorno con l'etichetta 17, il framework di accessibilità riceve solo le informazioni sulla descrizione 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 informazioni di contesto adeguate per i servizi di accessibilità in situazioni come questa, il framework offre un modo per specificare una gerarchia di oggetti View virtuali. Una gerarchia di oggetti View virtuali è un modo per gli sviluppatori di app di fornire ai servizi di accessibilità una gerarchia di oggetti View complementare che corrisponda più da vicino alle informazioni sullo schermo. Questo approccio consente ai servizi di accessibilità di fornire agli utenti informazioni di contesto più utili.
Un'altra situazione in cui potrebbe essere necessaria una gerarchia di oggetti View virtuali è un'interfaccia utente contenente un insieme di controlli View con funzioni strettamente correlate, in cui un'azione su un controllo influisce sui contenuti di uno o più elementi, ad esempio un selettore di numeri con pulsanti di aumento e diminuzione separati. In questo caso, i servizi di accessibilità non possono ottenere informazioni adeguate perché un'azione su un controllo modifica il contenuto di un altro e la relazione tra questi controlli potrebbe non essere evidente per il servizio.
Per gestire questa situazione, raggruppa i controlli correlati con una visualizzazione contenente e fornisci una gerarchia di oggetti View virtuali da questo contenitore per rappresentare chiaramente le informazioni e il comportamento forniti dai controlli.
Per fornire una gerarchia di oggetti View virtuali per una visualizzazione, esegui l'override del
getAccessibilityNodeProvider()
metodo nella visualizzazione personalizzata o nel gruppo di oggetti View e restituisci un'implementazione di
AccessibilityNodeProvider.
Puoi implementare una gerarchia di oggetti View virtuali utilizzando la Support Library con il metodo ViewCompat.getAccessibilityNodeProvider() e fornire un'implementazione con AccessibilityNodeProviderCompat.
Per semplificare l'attività di fornire informazioni ai servizi di accessibilità e gestire lo stato attivo dell'accessibilità, puoi invece implementare ExploreByTouchHelper.
Fornisce un AccessibilityNodeProviderCompat e può essere collegato come
AccessibilityDelegateCompat di una visualizzazione chiamando
setAccessibilityDelegate.
Per un esempio, vedi ExploreByTouchHelperActivity.
ExploreByTouchHelper viene utilizzato anche dai widget del framework come CalendarView, tramite la vista bambino SimpleMonthView.
Gestisci eventi touch personalizzati
I controlli di visualizzazione personalizzati potrebbero richiedere un comportamento degli eventi touch non standard, come illustrato negli esempi seguenti.
Definisci azioni basate sui clic
Se il widget utilizza l'interfaccia
OnClickListener o
OnLongClickListener, il sistema gestisce le azioni
ACTION_CLICK
e
ACTION_LONG_CLICK
per te. Se la tua app utilizza un widget più personalizzato che si basa sull'
OnTouchListener interfaccia,
definisci gestori personalizzati per le azioni di accessibilità basate sui clic. Per farlo, chiama il
replaceAccessibilityAction()
metodo 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()); }
Crea eventi di clic personalizzati
Un controllo personalizzato può utilizzare il metodo del listener 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 eseguire le seguenti operazioni:
Per gestire questi requisiti in modo efficiente, il codice deve eseguire l'override del metodo performClick(), che deve chiamare l'implementazione super di questo metodo ed eseguire le azioni richieste dall'evento di clic. Quando viene rilevata l'azione di clic personalizzata, il codice deve chiamare il metodo performClick(). Il seguente esempio di codice mostra 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 contribuisce 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 per i servizi di accessibilità per agire per conto di un utente che esegue l'evento di clic personalizzato.