Eine Komposition beschreibt die UI Ihrer Anwendung und wird durch Ausführen von zusammensetzbaren Funktionen erstellt. Die Zusammensetzung ist eine Baumstruktur, die aus zusammensetzbaren Funktionen besteht, die Ihre UI beschreiben.
Neben der Zusammensetzung befindet sich ein paralleler Baum, der als Semantikbaum bezeichnet wird. Dieser Baum beschreibt Ihre UI auf eine alternative Art und Weise, die für Bedienungshilfen-Dienste und das Testing-Framework verständlich ist. Bedienungshilfen verwenden den Baum, um die App für Nutzer mit bestimmten Anforderungen zu beschreiben. Das Test-Framework verwendet den Baum, um mit Ihrer Anwendung zu interagieren und Aussagen dazu zu machen. Die Semantikstruktur enthält nicht die Informationen zum Zeichnen von zusammensetzbaren Funktionen, jedoch Informationen zur semantischen Bedeutung.
Wenn Ihre Anwendung aus zusammensetzbaren Funktionen und Modifikatoren aus der Compose-Foundation und der Materialbibliothek besteht, wird der Semantics-Baum automatisch für Sie gefüllt und generiert. Wenn Sie jedoch benutzerdefinierte zusammensetzbare Funktionen auf unterer Ebene hinzufügen, müssen Sie ihre Semantik manuell angeben. Es kann auch vorkommen, dass Ihre Baumstruktur die Bedeutung der Elemente auf dem Bildschirm nicht richtig oder nicht vollständig darstellt. In diesem Fall können Sie den Baum anpassen.
Sehen Sie sich zum Beispiel diese zusammensetzbare Funktion aus benutzerdefinierten Kalendern an:
In diesem Beispiel ist der gesamte Kalender als einzelne zusammensetzbare Funktion auf unterer Ebene implementiert, wobei die zusammensetzbare Funktion Layout
verwendet und direkt in Canvas
gezeichnet wird.
Wenn Sie nichts weiter tun, erhalten die Bedienungshilfen nicht genügend Informationen über den Inhalt der zusammensetzbaren Funktion und die Auswahl des Nutzers im Kalender. Wenn ein Nutzer beispielsweise auf den Tag mit 17 klickt, erhält das Framework für Barrierefreiheit nur die Beschreibung für das gesamte Kalendersteuerelement. In diesem Fall sagt die TalkBack-Bedienungshilfe „Kalender“ oder, nur geringfügig besser, „Kalender für April“ an und der Nutzer würde sich fragen, welcher Tag ausgewählt wurde. Um diese zusammensetzbare Funktion zugänglicher zu machen, müssen Sie semantische Informationen manuell hinzufügen.
Semantikeigenschaften
Alle Knoten im UI-Baum mit einer semantischen Bedeutung haben einen parallelen Knoten im Semantikbaum. Der Knoten in der Semantikstruktur enthält die Eigenschaften, die die Bedeutung der entsprechenden zusammensetzbaren Funktion vermitteln. Die zusammensetzbare Funktion Text
enthält beispielsweise das semantische Attribut text
, da dies die Bedeutung dieser zusammensetzbaren Funktion ist. Ein Icon
enthält eine contentDescription
-Eigenschaft (falls vom Entwickler festgelegt), die in Text die Bedeutung von Icon
vermittelt. Zusammensetzbare Funktionen und Modifikatoren, die auf der Foundation-Bibliothek aufbauen, legen die relevanten Eigenschaften bereits für Sie fest. Optional können Sie die Attribute mit den Modifikatoren semantics
und clearAndSetSemantics
festlegen oder überschreiben. Beispielsweise können Sie einem Knoten benutzerdefinierte Aktionen für Bedienungshilfen hinzufügen, eine alternative Statusbeschreibung für ein ein-/ausschaltbares Element angeben oder angeben, dass eine bestimmte zusammensetzbare Textfunktion als Überschrift betrachtet werden soll.
Sie können den Semantics-Baum mit dem Tool Layout Inspector oder der Methode printToLog()
in Tests visualisieren. Damit wird der aktuelle Semantik-Baum
in Logcat ausgegeben.
class MyComposeTest { @get:Rule val composeTestRule = createComposeRule() @Test fun MyTest() { // Start the app composeTestRule.setContent { MyTheme { Text("Hello world!") } } // Log the full semantics tree composeTestRule.onRoot().printToLog("MY TAG") } }
Das Ergebnis dieses Tests wäre:
Printing with useUnmergedTree = 'false'
Node #1 at (l=0.0, t=63.0, r=221.0, b=120.0)px
|-Node #2 at (l=0.0, t=63.0, r=221.0, b=120.0)px
Text = '[Hello world!]'
Actions = [GetTextLayoutResult]
Sehen Sie sich an, wie semantische Attribute die Bedeutung einer zusammensetzbaren Funktion vermitteln. Beispiel: Switch
. So sieht das für den Nutzer aus:
Um die Bedeutung dieses Elements zu beschreiben, könnten Sie Folgendes sagen: "Dies ist ein Schalter, bei dem es sich um ein ein-/ausschaltbares Element im Status 'An' handelt. Sie können darauf klicken, um mit ihr zu interagieren.“
Genau dafür werden die semantischen Attribute verwendet. Der Semantikknoten dieses Switch-Elements enthält die folgenden Eigenschaften, wie sie im Layout Inspector dargestellt werden:
Role
gibt den Elementtyp an. Unter StateDescription
wird beschrieben, wie auf den Status „An“ verwiesen werden soll. Standardmäßig ist dies eine lokalisierte Version des Wortes „An“, aber dies kann je nach Kontext spezifischer werden (z. B. „Aktiviert“). ToggleableState
ist der aktuelle Status des Switches. Die Eigenschaft OnClick
verweist auf die Methode, die zur Interaktion mit diesem Element verwendet wird. Eine vollständige Liste der semantischen Attribute finden Sie im Objekt SemanticsProperties
. Eine vollständige Liste der möglichen Aktionen für Bedienungshilfen finden Sie im Objekt SemanticsActions
.
Wenn Sie die semantischen Attribute jeder zusammensetzbaren Funktion in Ihrer App im Auge behalten, eröffnen sich zahlreiche leistungsstarke Möglichkeiten. Hier ein paar Beispiele:
- TalkBack liest mithilfe der Eigenschaften vor, was auf dem Bildschirm angezeigt wird, und ermöglicht dem Nutzer eine reibungslose Interaktion. Bei der zusammensetzbaren Funktion „Wechsel“ könnte TalkBack Folgendes sagen: „Ein; Schalter; zum Umschalten doppeltippen.“. Der Nutzer kann auf das Display doppeltippen, um den Schalter zu deaktivieren.
-
Das Test-Framework verwendet die Attribute, um Knoten zu finden, mit ihnen zu interagieren und Assertions zu erstellen. Hier ein Beispieltest für den Switch:
val mySwitch = SemanticsMatcher.expectValue( SemanticsProperties.Role, Role.Switch ) composeTestRule.onNode(mySwitch) .performClick() .assertIsOff()
Zusammengeführter und nicht zusammengeführter Semantics-Baum
Wie bereits erwähnt, können für jede zusammensetzbare Funktion im UI-Baum null oder mehr Semantik-Attribute festgelegt sein. Wenn für eine zusammensetzbare Funktion keine semantischen Attribute festgelegt wurden, ist sie nicht in die Semantikstruktur aufgenommen. Auf diese Weise enthält der Semantikbaum nur die Knoten, die tatsächlich eine semantische Bedeutung haben. Um die korrekte Bedeutung dessen zu vermitteln, was auf dem Bildschirm angezeigt wird, ist es jedoch auch hilfreich, bestimmte Unterstrukturen von Knoten zusammenzuführen und als einen zu behandeln. Auf diese Weise können Sie eine Gruppe von Knoten als Ganzes bedenken, anstatt sich mit jedem untergeordneten Knoten einzeln befassen zu müssen. Als Faustregel gilt, dass jeder Knoten in dieser Struktur bei der Verwendung von Bedienungshilfen ein fokussierbares Element darstellt.
Ein Beispiel für eine solche zusammensetzbare Funktion ist Button
. Sie können eine Schaltfläche als einzelnes Element begründen, auch wenn sie mehrere untergeordnete Knoten enthalten kann:
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
In der Semantikstruktur werden die Eigenschaften der Nachfolgerelemente der Schaltfläche zusammengeführt und die Schaltfläche wird als einzelne Blattknoten im Baum angezeigt:
Zusammensetzbare Funktionen und Modifikatoren können durch Aufrufen von Modifier.semantics
(mergeDescendants = true) {}
angeben, dass sie die semantischen Attribute ihrer Nachfolger zusammenführen möchten. Wenn dieses Attribut auf true
gesetzt wird, bedeutet das, dass die semantischen Attribute zusammengeführt werden sollen. Im Beispiel Button
verwendet die zusammensetzbare Funktion Button
intern den clickable
-Modifikator, der diesen semantics
-Modifikator enthält. Daher werden die untergeordneten Knoten der Schaltfläche zusammengeführt.
In der Dokumentation zur Barrierefreiheit erfahren Sie, wann Sie das Zusammenführungsverhalten in einer zusammensetzbaren Funktion ändern sollten.
Diese Eigenschaft ist für mehrere Modifikatoren und zusammensetzbare Funktionen in den Bibliotheken „Foundation“ und „Material Compose“ festgelegt. Die Modifikatoren clickable
und toggleable
führen beispielsweise automatisch ihre Nachfolger zusammen. Außerdem führt die zusammensetzbare Funktion ListItem
auch ihre Nachfolger zusammen.
Bäume inspizieren
Der Semantikbaum besteht eigentlich aus zwei unterschiedlichen Bäumen. Es gibt einen zusammengeführten Semantikbaum, der untergeordnete Knoten zusammenführt, wenn mergeDescendants
auf true
gesetzt ist.
Es gibt auch einen nicht zusammengeführten Semantics-Baum, in dem die Zusammenführung nicht angewendet wird, aber jeder Knoten intakt bleibt. Bedienungshilfen verwenden die noch nicht zusammengeführte Struktur und wenden eigene Zusammenführungsalgorithmen unter Berücksichtigung des Attributs mergeDescendants
an. Das Test-Framework verwendet standardmäßig den zusammengeführten Baum.
Sie können beide Bäume mit der Methode printToLog()
untersuchen. Standardmäßig, wie in den vorherigen Beispielen, wird der zusammengeführte Baum protokolliert. Wenn Sie stattdessen die nicht zusammengeführte Struktur ausgeben möchten, legen Sie den Parameter useUnmergedTree
des onRoot()
-Matchers auf true
fest:
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
Mit dem Layout Inspector können Sie sowohl den zusammengeführten als auch den nicht zusammengeführten Semantikbaum aufrufen. Wählen Sie dazu im Ansichtsfilter den bevorzugten Baum aus:
Der Layout Inspector zeigt für jeden Knoten in der Baumstruktur sowohl die zusammengeführte als auch die auf diesem Knoten festgelegte Semantik im Eigenschaftenbereich an:
Standardmäßig verwenden Abgleicher im Test-Framework die zusammengeführte Semantik-Struktur.
Aus diesem Grund können Sie mit einem Button
interagieren, indem Sie den darin enthaltenen Text abgleichen:
composeTestRule.onNodeWithText("Like").performClick()
Sie können dieses Verhalten überschreiben, indem Sie den useUnmergedTree
-Parameter der Abgleichausdrücke auf true
setzen, wie beim onRoot
-Matcher.
Zusammenführungsverhalten
Wie genau wird bei einer zusammensetzbaren Funktion angegeben, dass ihre Nachfolger zusammengeführt werden sollen?
Für jedes semantische Attribut gibt es eine definierte Zusammenführungsstrategie. Das Attribut ContentDescription
fügt beispielsweise alle untergeordneten ContentDescription-Werte in eine Liste ein. Prüfen Sie die Zusammenführungsstrategie eines semantischen Attributs, indem Sie dessen mergePolicy
-Implementierung in SemanticsProperties.kt
prüfen. Attribute können den übergeordneten oder untergeordneten Wert übernehmen, die Werte in einer Liste oder einem String zusammenführen, das Zusammenführen überhaupt nicht zulassen und stattdessen eine Ausnahme ausgeben, oder eine andere benutzerdefinierte Zusammenführungsstrategie verwenden.
Wichtiger Hinweis: Nachfolgerelemente, für die mergeDescendants
= true
festgelegt wurde, werden nicht in die Zusammenführung einbezogen. Hier ein Beispiel:
Hier ist ein anklickbarer Listeneintrag. Wenn der Nutzer auf die Zeile klickt, gelangt er zur Seite mit den Artikeldetails, auf der er den Artikel lesen kann. Im Listenelement befindet sich eine Schaltfläche, über die Sie den Artikel als Lesezeichen speichern können. Sie bilden ein verschachteltes anklickbares Element, sodass die Schaltfläche separat in der zusammengeführten Struktur angezeigt wird. Der Rest des Inhalts in der Zeile wird zusammengeführt:
Semantikbaum anpassen
Wie bereits erwähnt, können Sie bestimmte semantische Attribute überschreiben oder löschen oder das Zusammenführungsverhalten der Struktur ändern. Dies ist besonders relevant, wenn Sie Ihre eigenen benutzerdefinierten Komponenten erstellen. Ohne die richtigen Eigenschaften und das Zusammenführungsverhalten ist Ihre Anwendung möglicherweise nicht zugänglich und Tests verhalten sich möglicherweise anders als erwartet. Weitere Informationen zu häufigen Anwendungsfällen, bei denen Sie die Semantikstruktur anpassen sollten, finden Sie in der Dokumentation zur Barrierefreiheit. Weitere Informationen zu Tests findest du im Testleitfaden.
Weitere Informationen
- Barrierefreiheit:Diese grundlegenden Konzepte und Techniken, die bei der Entwicklung von Android-Apps üblich sind
- Accessible Apps erstellen:Wichtige Schritte, mit denen Sie die Barrierefreiheit Ihrer App verbessern können
- Prinzipien zur Verbesserung der Barrierefreiheit von Apps:Wichtige Prinzipien, die Sie bei der Verbesserung der Barrierefreiheit Ihrer App beachten sollten
- Test auf Barrierefreiheit:Testprinzipien und -tools für Android-Bedienungshilfen
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Bedienungshilfen in der Funktion „Compose“
- Material Design 2 in Compose
- Layout von „Compose“ testen