Fokusziele für Gruppen

Mit dem Modifikator focusGroup können Sie mehrere Fokusziele gruppieren. Durch die Gruppierung können Sie Fokushierarchien verwalten, logische UI-Bereiche (z. B. Symbolleisten, Dialogaktionen oder Kartenlisten) isolieren und abfangen, wenn der Fokus in einen Bereich eintritt oder ihn verlässt.

Fokusgruppenkonzepte: Betreten, Verlassen und Standarddurchlauf

Eine Fokusgruppe legt eine zusammenhängende Navigationsgrenze um ihre untergeordneten Fokusziele fest. Um zu verstehen, wie sich der Fokus über diese Grenze bewegt, müssen Sie zwei wichtige Konzepte kennen:

  • Enter: Das Ereignis, das eintritt, wenn der Fokus von einem Element außerhalb der Fokusgruppe zu einem Element innerhalb der Gruppe wechselt.
  • Exit: Das Ereignis, das auftritt, wenn der Fokus das letzte interne Element der Gruppe verlässt und zu einem externen Fokusziel wechselt.
Diagramm, das die Übergänge „Enter“ und „Exit“ über die Grenze einer Fokusgruppe hinweg zeigt.
Abbildung 1. Fokusgruppe mit Ein- und Ausstiegsereignissen.

Standardverhalten beim Durchlaufen des Fokus

Wenn eine Fokusgruppe von außen fokussiert wird, gilt standardmäßig Folgendes:

  1. Gruppe betreten: Compose wählt automatisch ein internes untergeordnetes Fokusziel aus. Bei der eindimensionalen Navigation (Tab) wird das erste untergeordnete Element in der Reihenfolge der visuellen Darstellung ausgewählt. Bei der zweidimensionalen Navigation (Pfeiltasten oder Steuerkreuz) wird das untergeordnete Element ausgewählt, das der eingehenden Richtung geometrisch am nächsten ist.
  2. In der Gruppe navigieren: Durch wiederholtes Drücken der Navigationstaste wird der Fokus zwischen den gleichgeordneten Fokuszielen innerhalb der Gruppe verschoben.
  3. Gruppe verlassen: Sobald der Nutzer das letzte Fokusziel innerhalb der Gruppe passiert hat, wird die Gruppe beim nächsten Tastendruck verlassen und der Fokus auf das benachbarte Fokusziel außerhalb der Gruppe verschoben.

Weiterleitung für Fokuseintrag anpassen

In vielen UI-Designs ist das Standardziel für die Eingabe (z. B. das erste untergeordnete Element in der Reihenfolge der Darstellung) nicht die logischste oder bequemste Wahl für den Nutzer.

Absicht und Anwendungsfälle

Stellen Sie sich ein Bestätigungsdialogfeld mit der Schaltfläche „Abbrechen“ auf der linken Seite und der primären Schaltfläche „Bestätigen“ auf der rechten Seite vor. Wenn der Nutzer von einem Formularfeld nach unten zur Schaltflächenleiste navigiert:

  • Standardverhalten: Der Fokus würde auf „Abbrechen“ liegen, da dies die erste Schaltfläche in der visuellen Reihenfolge ist.
  • Beabsichtigtes Verhalten: Da „Bestätigen“ die primäre empfohlene Aktion ist, sollte der Fokus direkt auf „Bestätigen“ liegen, wenn die Schaltflächengruppe von früher in der Fokusreihenfolge aufgerufen wird. Der Nutzer sollte aber trotzdem die Möglichkeit haben, Links zu drücken, um bei Bedarf „Abbrechen“ auszuwählen.
Standardfokus-Eintrag in eine Schaltflächengruppe.
Abbildung 2. Abbrechen- und Bestätigen-Buttons mit Standardfokus-Eingabeziel.

Weitere häufige Anwendungsfälle:

  • Der Fokus wird direkt auf den aktuell ausgewählten Tab verschoben, wenn ein TabRow eingegeben wird.
  • Der Fokus wird direkt auf das Steuerelement „Wiedergabe / Pause“ verschoben, wenn eine Medienwiedergabeleiste aufgerufen wird.

Implementierung mit „onEnter“ und „FocusRequester“

So leiten Sie den Fokus beim Betreten einer Fokusgruppe um:

  1. Wende den Modifikator focusGroup auf den übergeordneten Container an, der die zugehörigen Fokussierungsziele enthält.
  2. Wenden Sie den Modifikator focusProperties auf den Container an und konfigurieren Sie den Callback onEnter.
  3. Rufen Sie im onEnter-Callback (beschränkt auf FocusEnterExitScope) requestFocus() für ein FocusRequester auf, das mit dem bevorzugten Standard-Child-Konto verknüpft ist, und verwenden Sie dazu focusRequester.

val defaultChildRequester = remember { FocusRequester() }

Row(
    modifier = Modifier
        .focusGroup()
        .focusProperties {
            // Intercept entry into this group and redirect focus to the primary action
            onEnter = {
                defaultChildRequester.requestFocus()
            }
        }
) {
    Button(onClick = { /* Cancel action */ }) {
        Text("Cancel")
    }
    Button(
        onClick = { /* Confirm action */ },
        modifier = Modifier.focusRequester(defaultChildRequester)
    ) {
        Text("Confirm (Default)")
    }
}

In onEnter und onExit können Sie auch cancelFocusChange() aufrufen, um Fokusübergänge über die Grenze vollständig zu blockieren, oder requestedFocusDirection prüfen, um das Routing anzupassen, je nachdem, ob der Nutzer mit der Tabulatortaste, der Abwärtspfeiltaste oder der Linkspfeiltaste navigiert hat.

Scrollbare Container sind standardmäßig Fokusgruppen

In Jetpack Compose fungieren scrollbare Container wie LazyRow, LazyColumn und LazyVerticalGrid automatisch als Fokusgruppen. Sie müssen den Modifikator focusGroup nicht explizit auf sie anwenden, um onEnter- oder onExit-Callbacks festzulegen.