Wenn Ihre Anwendung eine benutzerdefinierte Ansichtskomponente erfordert, müssen Sie die Ansicht zugänglicher machen. Die folgenden Schritte können die Zugänglichkeit Ihrer benutzerdefinierten Ansicht verbessern, wie auf dieser Seite beschrieben:
- Klicks auf Richtungstasten verarbeiten
- Methoden der Accessibility API implementieren
AccessibilityEvent-Objekte senden, die für Ihre benutzerdefinierte Ansicht spezifisch sindAccessibilityEventundAccessibilityNodeInfofür Ihre Ansicht ausfüllen
Klicks auf Richtungstasten verarbeiten
Auf den meisten Geräten wird durch Klicken auf eine Ansicht mit einer Richtungstaste ein KeyEvent mit KEYCODE_DPAD_CENTER an die Ansicht gesendet, die gerade im Vordergrund ist. Alle Standardansichten von Android verarbeiten KEYCODE_DPAD_CENTER entsprechend. Wenn Sie ein benutzerdefiniertes View-Steuerelement erstellen, muss dieses Ereignis dieselbe Wirkung haben wie das Tippen auf die Ansicht auf dem Touchscreen.
Ihr benutzerdefiniertes Steuerelement muss das Ereignis KEYCODE_ENTER genauso behandeln wie KEYCODE_DPAD_CENTER. Dadurch wird die Interaktion mit einer vollständigen Tastatur für Nutzer einfacher.
Methoden der Accessibility API implementieren
Barrierefreiheitsereignisse sind Nachrichten über die Interaktionen von Nutzern mit den visuellen Schnittstellenkomponenten Ihrer App. Diese Nachrichten werden von Bedienungshilfen verarbeitet, die
die Informationen in diesen Ereignissen verwenden, um zusätzliches Feedback und zusätzliche Eingabeaufforderungen zu generieren. Die Methoden für Bedienungshilfen sind Teil der View und
View.AccessibilityDelegate
Klassen. Die Methoden sind wie folgt:
dispatchPopulateAccessibilityEvent()onPopulateAccessibilityEvent() für diese Ansicht
und dann die Methode dispatchPopulateAccessibilityEvent() für jedes untergeordnete Element dieser
Ansicht auf. onInitializeAccessibilityEvent()TextView oder
Button hinausgeht, überschreiben Sie diese Methode
und legen Sie die zusätzlichen Informationen zu Ihrer Ansicht fest, z. B. den Typ des Passwortfelds, den Typ des Kontrollkästchens
oder Status, die Nutzerinteraktion oder Feedback in das Ereignis liefern. Wenn Sie diese Methode überschreiben, rufen Sie die Super-Implementierung auf und ändern Sie nur Eigenschaften
die nicht von der Superklasse festgelegt werden.onInitializeAccessibilityNodeInfo()View enthält eine Reihe von Ansichtseigenschaften. Wenn Ihre
benutzerdefinierte Ansicht jedoch eine interaktive Steuerung bietet, die über ein einfaches TextView oder
Button hinausgeht, überschreiben Sie diese Methode und legen Sie die zusätzlichen Informationen zu Ihrer Ansicht
im AccessibilityNodeInfo-Objekt fest, das von dieser Methode verarbeitet wird.onPopulateAccessibilityEvent()AccessibilityEvent für Ihre
Ansicht festgelegt. Sie wird auch aufgerufen, wenn die Ansicht ein untergeordnetes Element einer Ansicht ist, die ein Barrierefreiheits
ereignis generiert.
onRequestSendAccessibilityEvent()AccessibilityEvent generiert. Mit diesem Schritt kann die Elternansicht das Barrierefreiheitsereignis mit zusätzlichen Informationen ergänzen. Implementieren Sie diese Methode nur, wenn Ihre benutzerdefinierte Ansicht untergeordnete Ansichten haben kann und wenn die Elternansicht Kontextinformationen für das Barrierefreiheitsereignis bereitstellen kann, die für Bedienungshilfen nützlich sind.sendAccessibilityEvent()- Das System ruft diese Methode auf, wenn ein Nutzer eine Aktion in einer Ansicht ausführt. Das Ereignis wird mit
einem Nutzeraktionstyp klassifiziert, z. B.
TYPE_VIEW_CLICKED. Im Allgemeinen müssen Sie einAccessibilityEventsenden, wenn sich der Inhalt Ihrer benutzerdefinierten Ansicht ändert. sendAccessibilityEventUnchecked()- Diese Methode wird verwendet, wenn der aufrufende Code die Überprüfung, ob die Bedienungshilfen auf dem Gerät aktiviert sind (
AccessibilityManager.isEnabled()), direkt steuern muss. Wenn Sie diese Methode implementieren, führen Sie den Aufruf so aus, als wären die Bedienungshilfen aktiviert, unabhängig von der Systemeinstellung. Normalerweise müssen Sie diese Methode nicht für eine benutzerdefinierte Ansicht implementieren. dispatchPopulateAccessibilityEvent()onInitializeAccessibilityEvent()onInitializeAccessibilityNodeInfo()onPopulateAccessibilityEvent()TYPE_VIEW_CLICKEDTYPE_VIEW_FOCUSEDTYPE_VIEW_HOVER_ENTERTYPE_VIEW_HOVER_EXITTYPE_VIEW_LONG_CLICKEDTYPE_VIEW_SCROLLED- Ein entsprechendes
AccessibilityEventfür die interpretierte Klickaktion generieren. - Bedienungshilfen ermöglichen, die benutzerdefinierte Klickaktion für Nutzer auszuführen, die keinen Touchscreen verwenden können.
Um Bedienungshilfen zu unterstützen, überschreiben und implementieren Sie die oben genannten Methoden für Bedienungshilfen direkt in Ihrer benutzerdefinierten Ansichtsklasse.
Implementieren Sie mindestens die folgenden Methoden für Bedienungshilfen für Ihre benutzerdefinierte Ansichtsklasse:
Weitere Informationen zum Implementieren dieser Methoden finden Sie im Abschnitt zum Ausfüllen von Barrierefreiheitsereignissen.
Barrierefreiheitsereignisse senden
Je nach den Besonderheiten Ihrer benutzerdefinierten Ansicht müssen möglicherweise AccessibilityEvent-Objekte zu unterschiedlichen Zeiten oder für Ereignisse gesendet werden, die von der Standardimplementierung nicht verarbeitet werden. Die Klasse View bietet eine Standardimplementierung für diese Ereignistypen:
Im Allgemeinen müssen Sie ein AccessibilityEvent senden, wenn sich der Inhalt Ihrer benutzerdefinierten Ansicht ändert. Wenn Sie beispielsweise eine benutzerdefinierte Schiebereglerleiste implementieren, mit der der Nutzer einen numerischen Wert auswählen kann, indem er die linke oder rechte Pfeiltaste drückt, muss Ihre benutzerdefinierte Ansicht ein Ereignis vom Typ TYPE_VIEW_TEXT_CHANGED ausgeben, wenn sich der Wert des Schiebereglers ändert. Das folgende Codebeispiel zeigt die Verwendung der Methode sendAccessibilityEvent() zum Melden dieses Ereignisses.
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; } ... }
Barrierefreiheitsereignisse ausfüllen
Jedes AccessibilityEvent hat eine Reihe erforderlicher Eigenschaften, die den aktuellen Status der Ansicht beschreiben. Zu diesen Eigenschaften gehören beispielsweise der Klassenname, die Inhaltsbeschreibung und der Status „Checked“ der Ansicht. Die für jeden Ereignistyp erforderlichen Eigenschaften sind in der Referenzdokumentation zu AccessibilityEvent beschrieben.
Die View-Implementierung bietet Standardwerte für diese erforderlichen Eigenschaften. 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 so einfach wie eine Schaltflächenbeschriftung sein und zusätzliche Statusinformationen enthalten, die Sie dem Ereignis hinzufügen möchten.
Verwenden Sie die
onPopulateAccessibilityEvent()
und
onInitializeAccessibilityEvent()
Methoden, um die Informationen in einem AccessibilityEventauszufüllen oder zu ändern. Verwenden Sie die Methode onPopulateAccessibilityEvent() speziell zum Hinzufügen oder Ändern des Textinhalts des Ereignisses, der von Bedienungshilfen wie TalkBack in hörbare Eingabeaufforderungen umgewandelt wird. Verwenden Sie die Methode onInitializeAccessibilityEvent(), um zusätzliche Informationen zum Ereignis auszufüllen, z. B. den Auswahlstatus der Ansicht.
Implementieren Sie außerdem die Methode onInitializeAccessibilityNodeInfo(). Bedienungshilfen verwenden die AccessibilityNodeInfo-Objekte, die von dieser Methode ausgefüllt werden, um die Ansichtshierarchie zu untersuchen, die ein Barrierefreiheitsereignis generiert, nachdem es empfangen wurde, und um Nutzern entsprechendes Feedback zu geben.
Das folgende Codebeispiel zeigt, wie Sie diese drei Methoden in Ihrer Ansicht überschreiben:
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.
Benutzerdefinierten Barrierefreiheitskontext bereitstellen
Bedienungshilfen können die enthaltende Ansichtshierarchie einer Benutzeroberflächenkomponente untersuchen, die ein Barrierefreiheitsereignis generiert. So können Bedienungshilfen Nutzern umfassendere Kontextinformationen zur Verfügung stellen.
In einigen Fällen können Bedienungshilfen keine ausreichenden Informationen aus der Ansichtshierarchie abrufen. Ein Beispiel dafür ist ein benutzerdefiniertes Steuerelement der Benutzeroberfläche mit zwei oder mehr separat anklickbaren Bereichen, z. B. ein Kalendersteuerelement. In diesem Fall können die Dienste keine ausreichenden Informationen abrufen, da die anklickbaren Unterabschnitte nicht Teil der Ansichtshierarchie sind.
Abbildung 1 : Eine benutzerdefinierte Kalenderansicht mit auswählbaren Tagelementen.
Im Beispiel in Abbildung 1 ist der gesamte Kalender als eine einzelne Ansicht implementiert. Bedienungshilfen erhalten daher nicht genügend Informationen zum Inhalt der Ansicht und zur Auswahl des Nutzers in der Ansicht, es sei denn, der Entwickler stellt zusätzliche Informationen bereit. Wenn ein Nutzer beispielsweise auf den Tag mit der Beschriftung 17 klickt, erhält das Barrierefreiheitsframework nur die Beschreibungsinformationen für das gesamte Kalendersteuerelement. In diesem Fall gibt die Bedienungshilfe TalkBack „Kalender“ oder „April-Kalender“ aus und der Nutzer weiß nicht, welcher Tag ausgewählt ist.
Um in solchen Situationen angemessene Kontextinformationen für Bedienungshilfen bereitzustellen, bietet das Framework eine Möglichkeit, eine virtuelle Ansichtshierarchie anzugeben. Eine virtuelle Ansichtshierarchie ist eine Möglichkeit für App-Entwickler, Bedienungshilfen eine ergänzende Ansichtshierarchie zur Verfügung zu stellen, die besser zu den Informationen auf dem Bildschirm passt. So können Bedienungshilfen Nutzern nützlichere Kontextinformationen zur Verfügung stellen.
Eine weitere Situation, in der eine virtuelle Ansichtshierarchie erforderlich sein kann, ist eine Benutzeroberfläche mit einer Reihe von View-Steuerelementen mit eng verwandten Funktionen, bei denen eine Aktion in einem Steuerelement die Inhalte eines oder mehrerer Elemente beeinflusst, z. B. eine Ziffernauswahl mit separaten Schaltflächen zum Erhöhen und Verringern. In diesem Fall können Bedienungshilfen keine ausreichenden Informationen abrufen, da eine Aktion in einem Steuerelement den Inhalt in einem anderen ändert und die Beziehung zwischen diesen Steuerelementen für den Dienst möglicherweise nicht offensichtlich ist.
Um diese Situation zu bewältigen, gruppieren Sie die zugehörigen Steuerelemente mit einer enthaltenden Ansicht und stellen Sie eine virtuelle Ansichtshierarchie aus diesem Container bereit, um die von den Steuerelementen bereitgestellten Informationen und das Verhalten klar darzustellen.
Um eine virtuelle Ansichtshierarchie für eine Ansicht bereitzustellen, überschreiben Sie die
getAccessibilityNodeProvider()
Methode in Ihrer benutzerdefinierten Ansicht oder Ansichtsgruppe und geben Sie eine Implementierung von
AccessibilityNodeProviderzurück.
Sie können eine virtuelle Ansichtshierarchie mit der Support Library und der Methode ViewCompat.getAccessibilityNodeProvider() implementieren und eine Implementierung mit AccessibilityNodeProviderCompat bereitstellen.
Um die Aufgabe, Bedienungshilfen Informationen bereitzustellen und den Fokus für Bedienungshilfen zu verwalten, zu vereinfachen, können Sie stattdessen ExploreByTouchHelper implementieren.
Es bietet ein AccessibilityNodeProviderCompat und kann als
AccessibilityDelegateCompat einer Ansicht angehängt werden, indem Sie
setAccessibilityDelegate aufrufen.
Ein Beispiel finden Sie unter ExploreByTouchHelperActivity.
ExploreByTouchHelper wird auch von Framework-Widgets wie CalendarView über die Kinderansicht SimpleMonthView verwendet.
Benutzerdefinierte Touch-Ereignisse verarbeiten
Benutzerdefinierte Ansichtssteuerelemente erfordern möglicherweise ein nicht standardmäßiges Touch-Event-Verhalten, wie in den folgenden Beispielen gezeigt.
Klickbasierte Aktionen definieren
Wenn Ihr Widget die
OnClickListener oder
OnLongClickListener
Schnittstelle verwendet, verarbeitet das System die
ACTION_CLICK
und
ACTION_LONG_CLICK
Aktionen für Sie. Wenn Ihre App ein benutzerdefiniertes Widget verwendet, das auf der
OnTouchListener Schnittstelle basiert,
definieren Sie benutzerdefinierte Handler für die klickbasierten Bedienungshilfen. Rufen Sie dazu für jede Aktion die
replaceAccessibilityAction()
Methode 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 die Listener-Methode onTouchEvent(MotionEvent) verwenden, um die Ereignisse ACTION_DOWN und ACTION_UP zu erkennen und ein spezielles Klickereignis auszulösen. Um die Kompatibilität mit Bedienungshilfen aufrechtzuerhalten, muss der Code, der dieses benutzerdefinierte Click-Event verarbeitet, Folgendes tun:
Um diese Anforderungen effizient zu erfüllen, muss Ihr Code die Methode performClick() überschreiben. Diese Methode muss die Super-Implementierung dieser Methode aufrufen und dann alle Aktionen ausführen, die für das Click-Event erforderlich sind. Wenn die benutzerdefinierte Klickaktion erkannt wird, muss dieser Code dann Ihre Methode performClick() aufrufen. Das folgende Codebeispiel zeigt 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; } }
Das oben genannte Muster trägt dazu bei, dass das benutzerdefinierte Click-Event mit Bedienungshilfen kompatibel ist, indem die Methode performClick() verwendet wird, um ein Barrierefreiheitsereignis zu generieren und einen Einstiegspunkt für Bedienungshilfen bereitzustellen, um im Namen eines Nutzers zu agieren, der das benutzerdefinierte Click-Event ausführt.