Wenn für Ihre Anwendung eine benutzerdefinierte Ansichtskomponente erforderlich ist, müssen Sie die Barrierefreiheit der Ansicht verbessern. Mit den folgenden Schritten können Sie die Barrierefreiheit Ihrer benutzerdefinierten Ansicht verbessern (siehe Beschreibung auf dieser Seite):
- Umgang mit Klicks von Richtungscontrollern.
- Implementieren Sie Accessibility API-Methoden.
- Senden Sie
AccessibilityEvent
-Objekte, die für Ihre benutzerdefinierte Ansicht spezifisch sind. - Füllen Sie
AccessibilityEvent
undAccessibilityNodeInfo
für Ihre Ansicht aus.
Klicks von Richtungscontrollern verarbeiten
Auf den meisten Geräten wird durch Klicken auf eine Ansicht mit einem Richtungscontroller ein KeyEvent
mit KEYCODE_DPAD_CENTER
an die aktuell fokussierte Ansicht gesendet. In allen Standard-Android-Ansichten wird KEYCODE_DPAD_CENTER
entsprechend verarbeitet. Wenn Sie ein benutzerdefiniertes View
-Steuerelement erstellen, achten Sie darauf, dass dieses Ereignis denselben Effekt hat wie das Tippen auf die Ansicht auf dem Touchscreen.
Das benutzerdefinierte Steuerelement muss das Ereignis KEYCODE_ENTER
wie KEYCODE_DPAD_CENTER
behandeln. Dies vereinfacht die Interaktion mit
einer vollständigen Tastatur für die Nutzenden.
Accessibility API-Methoden implementieren
Bedienungshilfen sind Meldungen zu den Interaktionen von Nutzern mit den Komponenten der visuellen Benutzeroberfläche Ihrer App. Diese Nachrichten werden von Bedienungshilfen verarbeitet, die die Informationen in diesen Ereignissen verwenden, um zusätzliches Feedback und zusätzliche Aufforderungen zu geben. Die Bedienungshilfen sind Teil der Klassen View
und View.AccessibilityDelegate
. Folgende Methoden sind verfügbar:
dispatchPopulateAccessibilityEvent()
onPopulateAccessibilityEvent()
für diese Ansicht und dann die dispatchPopulateAccessibilityEvent()
-Methode für jedes untergeordnete Element dieser Ansicht auf. onInitializeAccessibilityEvent()
TextView
oder Button
auch interaktive Steuerelemente bietet, überschreiben Sie diese Methode und legen Sie mit dieser Methode die zusätzlichen Informationen zu der Ansicht fest, z. B. Passwortfeldtyp, Kästchentyp oder Status, die Nutzerinteraktionen oder Feedback zum Ereignis ermöglichen. Wenn Sie diese Methode überschreiben, rufen Sie die zugehörige Superimplementierung auf und ändern Sie nur Attribute, die nicht von der übergeordneten Klasse festgelegt werden.onInitializeAccessibilityNodeInfo()
View
verfügt über einen Standardsatz von Ansichtseigenschaften. Wenn Ihre benutzerdefinierte Ansicht jedoch interaktive Steuerungsmöglichkeiten bietet, die über eine einfache TextView
oder Button
hinausgehen, überschreiben Sie diese Methode und legen die zusätzlichen Informationen über die Ansicht in das AccessibilityNodeInfo
-Objekt fest, das mit dieser Methode verarbeitet wird.onPopulateAccessibilityEvent()
AccessibilityEvent
für die Ansicht festgelegt. Sie wird auch aufgerufen, wenn die Ansicht einer Ansicht untergeordnet ist, die ein Bedienungshilfen-Ereignis generiert.
onRequestSendAccessibilityEvent()
AccessibilityEvent
generiert. In diesem Schritt kann der Termin zur Barrierefreiheit in der übergeordneten Ansicht um zusätzliche Informationen ergänzt werden. Implementieren Sie diese Methode nur, wenn Ihre benutzerdefinierte Ansicht untergeordnete Ansichten haben kann und die übergeordnete Ansicht Kontextinformationen für das Bedienungshilfen-Ereignis bereitstellen kann, die für Bedienungshilfen nützlich sind.sendAccessibilityEvent()
- Das System ruft diese Methode auf, wenn ein Nutzer eine Aktion für eine Ansicht ausführt. Das Ereignis wird mit einem Nutzeraktionstyp wie
TYPE_VIEW_CLICKED
klassifiziert. Im Allgemeinen müssen Sie immer dann einAccessibilityEvent
senden, wenn sich der Inhalt der benutzerdefinierten Ansicht ändert. sendAccessibilityEventUnchecked()
- Diese Methode wird verwendet, wenn der aufrufende Code die Prüfung der Barrierefreiheit auf dem Gerät direkt steuern muss (
AccessibilityManager.isEnabled()
). Wenn Sie diese Methode implementieren, führen Sie den Aufruf unabhängig von der Systemeinstellung so aus, als ob die Bedienungshilfen aktiviert sind. In der Regel müssen Sie diese Methode für eine benutzerdefinierte Ansicht nicht implementieren. 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
- Generieren Sie ein entsprechendes
AccessibilityEvent
-Objekt für die interpretierte Klickaktion. - Aktivieren Sie Bedienungshilfen, damit diese die benutzerdefinierte Klickaktion für Nutzer ausführen können, die keinen Touchscreen verwenden können.
Um die Barrierefreiheit zu unterstützen, überschreiben und implementieren Sie die vorherigen Bedienungshilfen direkt in Ihrer benutzerdefinierten Ansichtsklasse.
Implementieren Sie mindestens die folgenden Bedienungshilfen für Ihre benutzerdefinierte Ansichtsklasse:
Weitere Informationen zum Implementieren dieser Methoden finden Sie im Abschnitt zum Ausfüllen von Bedienungshilfen-Ereignissen.
Bedienungshilfen-Ereignisse senden
Abhängig von den Besonderheiten Ihrer benutzerdefinierten Ansicht müssen möglicherweise zu verschiedenen Zeiten oder für Ereignisse, die nicht von der Standardimplementierung verarbeitet werden, AccessibilityEvent
-Objekte gesendet werden. Die Klasse View
bietet eine Standardimplementierung für diese Ereignistypen:
Im Allgemeinen müssen Sie immer dann eine AccessibilityEvent
senden, wenn sich der Inhalt der benutzerdefinierten Ansicht ändert. Wenn Sie beispielsweise eine benutzerdefinierte Schiebereglerleiste implementieren, mit der der Nutzer durch Drücken der Links- oder Rechtspfeiltaste einen numerischen Wert auswählen kann, muss Ihre benutzerdefinierte Ansicht das Ereignis TYPE_VIEW_TEXT_CHANGED
ausgeben, wenn sich der Wert des Schiebereglers ändert. Im folgenden Codebeispiel wird die Verwendung der Methode sendAccessibilityEvent()
zum Melden dieses Ereignisses veranschaulicht.
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; } ... }
Ereignisse zur Barrierefreiheit ausfüllen
Jedes AccessibilityEvent
hat eine Reihe von erforderlichen Attributen, die den aktuellen Status der Ansicht beschreiben. Zu diesen Attributen gehören beispielsweise der Klassenname der Ansicht, die Inhaltsbeschreibung und der Status „Prüfung“. Die spezifischen Attribute, die für jeden Ereignistyp erforderlich sind, sind in der Referenzdokumentation zu AccessibilityEvent
beschrieben.
Die View
-Implementierung stellt Standardwerte für diese erforderlichen Attribute bereit. Viele dieser Werte, einschließlich des Klassennamens und des Ereigniszeitstempels, werden automatisch bereitgestellt. Wenn Sie eine benutzerdefinierte Ansichtskomponente erstellen, müssen Sie Informationen zum Inhalt und zu den Eigenschaften der Ansicht angeben. Diese Informationen können einfach ein Schaltflächenlabel sein und zusätzliche Statusinformationen enthalten, die Sie dem Ereignis hinzufügen möchten.
Mit den Methoden onPopulateAccessibilityEvent()
und onInitializeAccessibilityEvent()
können Sie die Informationen in einem AccessibilityEvent
eintragen oder ändern. Verwenden Sie die Methode onPopulateAccessibilityEvent()
speziell zum Hinzufügen oder Ändern des Textinhalts des Ereignisses, der von Bedienungshilfen wie TalkBack in hörbare Aufforderungen umgewandelt wird. Verwenden Sie die Methode onInitializeAccessibilityEvent()
, um zusätzliche Informationen zum Ereignis einzugeben, z. B. den Auswahlstatus der Ansicht.
Implementieren Sie außerdem die Methode onInitializeAccessibilityNodeInfo()
. Bedienungshilfen verwenden die AccessibilityNodeInfo
-Objekte, die mit dieser Methode ausgefüllt werden, um die Ansichtshierarchie zu untersuchen, die ein Bedienungshilfen-Ereignis nach Empfang generiert, und um Nutzern angemessenes Feedback zu geben.
Das folgende Codebeispiel zeigt, wie diese drei Methoden in der Ansicht überschrieben werden können:
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); } }
Sie können diese Methoden direkt in Ihrer benutzerdefinierten Ansichtsklasse implementieren.
Angepassten Kontext zur Barrierefreiheit bereitstellen
Bedienungshilfen können die Hierarchie der zugehörigen Ansicht einer Komponente der Benutzeroberfläche prüfen, die ein Bedienungshilfen-Ereignis generiert. Auf diese Weise können Bedienungshilfen umfassendere Kontextinformationen zur Unterstützung der Nutzer bereitstellen.
Es gibt Fälle, in denen Bedienungshilfen keine angemessenen Informationen aus der Ansichtshierarchie abrufen können. Ein Beispiel hierfür ist ein benutzerdefiniertes UI-Steuerelement mit zwei oder mehr separat anklickbaren Bereichen, z. B. einem Kalendersteuerelement. In diesem Fall können die Dienste keine angemessenen Informationen abrufen, da die anklickbaren Unterabschnitte nicht Teil der Ansichtshierarchie sind.
Im Beispiel in Abbildung 1 ist der gesamte Kalender als einzelne Ansicht implementiert, sodass Bedienungshilfen nur dann genügend Informationen über den Inhalt der Ansicht und die Auswahl des Nutzers in der Ansicht erhalten, wenn der Entwickler zusätzliche Informationen bereitstellt. Wenn ein Nutzer beispielsweise auf den Tag mit dem Label 17 klickt, erhält das Framework für Barrierefreiheit nur die Beschreibungsinformationen für das gesamte Kalendersteuerelement. In diesem Fall kündigt die TalkBack-Bedienungshilfe „Kalender“ oder „Kalender für April“ an und der Nutzer weiß nicht, welcher Tag ausgewählt ist.
Um in solchen Situationen geeignete Kontextinformationen für Bedienungshilfen bereitzustellen, ermöglicht das Framework die Festlegung einer virtuellen Ansichtshierarchie. Mit einer virtuellen Ansichtshierarchie können App-Entwickler eine ergänzende Ansichtshierarchie zu den Bedienungshilfen bereitstellen, die den Informationen auf dem Bildschirm besser entspricht. Auf diese Weise können Bedienungshilfen nützliche Kontextinformationen für Nutzer bereitstellen.
Eine weitere Situation, in der eine Hierarchie für eine virtuelle Ansicht erforderlich sein kann, ist eine Benutzeroberfläche mit einer Reihe von View
-Steuerelementen mit eng verbundenen Funktionen. Eine Aktion für ein Steuerelement wirkt sich auf den Inhalt eines oder mehrerer Elemente aus, z. B. eine Zahlenauswahl mit separaten Aufwärts- und Abwärtspfeilen. In diesem Fall können die Bedienungshilfen keine angemessenen Informationen abrufen, da durch eine Aktion an einem Steuerelement Inhalte in einem anderen geändert werden und die Beziehung dieser Steuerelemente für den Dienst möglicherweise nicht offensichtlich ist.
Gruppieren Sie in diesem Fall die zugehörigen Steuerelemente mit einer beinhaltenden Ansicht und stellen Sie eine virtuelle Ansichtshierarchie aus diesem Container bereit, um die Informationen und das Verhalten der Steuerelemente klar darzustellen.
Wenn Sie eine virtuelle Ansichtshierarchie für eine Ansicht bereitstellen möchten, überschreiben Sie die Methode getAccessibilityNodeProvider()
in der benutzerdefinierten Ansicht oder Ansichtsgruppe und geben Sie eine Implementierung von AccessibilityNodeProvider
zurück.
Sie können eine Hierarchie für virtuelle Ansichten implementieren, indem Sie die Supportbibliothek mit der Methode ViewCompat.getAccessibilityNodeProvider()
verwenden und eine Implementierung mit AccessibilityNodeProviderCompat
bereitstellen.
Sie können stattdessen ExploreByTouchHelper
implementieren, um die Bereitstellung von Informationen für Bedienungshilfen und die Verwaltung des Barrierefreiheitsfokus zu vereinfachen.
Sie stellt ein AccessibilityNodeProviderCompat
bereit und kann durch Aufrufen von setAccessibilityDelegate
als AccessibilityDelegateCompat
einer Ansicht angehängt werden.
Ein Beispiel finden Sie unter ExploreByTouchHelperActivity
.
ExploreByTouchHelper
wird auch von Framework-Widgets wie CalendarView
über die untergeordnete Ansicht SimpleMonthView
verwendet.
Benutzerdefinierte Touch-Ereignisse verarbeiten
Für die Steuerelemente der benutzerdefinierten Ansicht ist möglicherweise ein nicht standardmäßiges Verhalten bei Touch-Ereignissen erforderlich, wie in den folgenden Beispielen veranschaulicht.
Klickbasierte Aktionen definieren
Wenn Ihr Widget die Schnittstelle OnClickListener
oder OnLongClickListener
verwendet, verarbeitet das System die Aktionen ACTION_CLICK
und ACTION_LONG_CLICK
für Sie. Wenn Ihre App ein stärker angepasstes Widget verwendet, das auf der Schnittstelle OnTouchListener
basiert, definieren Sie benutzerdefinierte Handler für die klickbasierten Bedienungshilfen. Rufen Sie dazu für jede Aktion die Methode replaceAccessibilityAction()
auf, wie im folgenden Code-Snippet gezeigt:
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()); }
Benutzerdefinierte Klickereignisse erstellen
Ein benutzerdefiniertes Steuerelement kann mit der Listener-Methode onTouchEvent(MotionEvent)
die Ereignisse ACTION_DOWN
und ACTION_UP
erkennen und ein spezielles Klickereignis auslösen. Um die Kompatibilität mit Bedienungshilfen zu gewährleisten, muss der Code, der dieses benutzerdefinierte Klickereignis verarbeitet, Folgendes tun:
Um diese Anforderungen effizient zu erfüllen, muss Ihr Code die Methode performClick()
überschreiben, die die Superimplementierung dieser Methode aufrufen und dann alle für das Klickereignis erforderlichen Aktionen ausführen muss. Wenn die benutzerdefinierte Klickaktion erkannt wird, muss dieser Code dann die Methode performClick()
aufrufen. Das folgende Codebeispiel veranschaulicht dieses Muster.
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; } }
Mit dem vorherigen Muster wird sichergestellt, dass das benutzerdefinierte Klickereignis mit Bedienungshilfen kompatibel ist. Dazu wird mit der Methode performClick()
ein Bedienungshilfenereignis generiert und ein Einstiegspunkt für Bedienungshilfen bereitgestellt, damit diese im Namen eines Nutzers handeln können, der das benutzerdefinierte Klickereignis ausführt.