Wartości docelowe grupy

Możesz zgrupować wiele elementów docelowych za pomocą modyfikatora focusGroup. Grupy umożliwiają zarządzanie hierarchiami fokusu, wyodrębnianie logicznych regionów interfejsu (takich jak paski narzędzi, działania w oknie dialogowym lub listy kart) oraz przechwytywanie momentów, w których fokus wchodzi do regionu lub go opuszcza.

Koncepcje grupy fokusowej: wejście, wyjście i domyślne przechodzenie

Grupa fokusowa wyznacza spójną granicę nawigacji wokół podrzędnych elementów docelowych. Aby zrozumieć, jak przenosi się zaznaczenie w tym obszarze, musisz poznać 2 kluczowe pojęcia:

  • Enter: zdarzenie, które występuje, gdy fokus przechodzi z dowolnego elementu poza grupą fokusową na element w tej grupie.
  • Wyjście: zdarzenie, które występuje, gdy zaznaczenie opuści ostatni wewnętrzny element grupy i przejdzie do zewnętrznego elementu docelowego.
Diagram przedstawiający przejścia Enter i Exit przez granicę grupy fokusowej.
Rysunek 1. Grupa fokusowa ze zdarzeniami wejścia i wyjścia.

Domyślne zachowanie podczas przechodzenia między elementami

Domyślnie, gdy grupa fokusowa otrzymuje fokus z zewnątrz:

  1. Wchodzenie do grupy: funkcja tworzenia automatycznie wybiera wewnętrzny element podrzędny jako cel. W przypadku nawigacji jednowymiarowej (Tab) wybiera pierwsze dziecko w kolejności wizualnej. W przypadku nawigacji dwuwymiarowej (za pomocą klawiszy strzałek lub pada kierunkowego) wybiera element podrzędny, który jest geometrycznie najbliższy kierunkowi przychodzącemu.
  2. Poruszanie się w grupie: wielokrotne naciśnięcie klawisza nawigacji powoduje przenoszenie zaznaczenia między elementami w grupie.
  3. Opuszczanie grupy: gdy użytkownik przejdzie do ostatniego elementu, na którym można ustawić fokus, w grupie, naciśnięcie klawisza spowoduje opuszczenie grupy i przeniesienie fokusu na sąsiedni element, na którym można ustawić fokus, poza grupą.

Dostosowywanie przekierowania po wejściu w stan skupienia

W wielu projektach interfejsu domyślny cel wejścia (np. pierwszy element podrzędny w kolejności wyświetlania) nie jest najbardziej logicznym ani wygodnym wyborem dla użytkownika.

Zastosowanie i przypadki użycia

Rozważ wyświetlenie okna potwierdzenia z przyciskiem „Anuluj” po lewej stronie i głównym przyciskiem „Potwierdź” po prawej. Gdy użytkownik przechodzi z pola formularza do paska przycisków:

  • Domyślne działanie: fokus zostanie przeniesiony na przycisk „Anuluj”, ponieważ jest on pierwszym przyciskiem w kolejności wizualnej.
  • Oczekiwane działanie: ponieważ „Potwierdź” jest głównym zalecanym działaniem, możesz chcieć, aby po wejściu do grupy przycisków z wcześniejszego miejsca w kolejności fokusowania fokus był od razu ustawiany na przycisku „Potwierdź”, ale jednocześnie aby użytkownik mógł w razie potrzeby nacisnąć strzałkę w lewo i wybrać „Anuluj”.
Domyślne zaznaczenie w grupie przycisków.
Rysunek 2. Przyciski Anuluj i Potwierdź z domyślnym elementem docelowym wejścia fokusu.

Inne typowe przypadki użycia to:

  • Przenoszenie zaznaczenia bezpośrednio na aktualnie wybraną kartę po wpisaniu znaku TabRow.
  • Przenoszenie fokusu bezpośrednio na element sterujący „Odtwórz / Wstrzymaj” po wejściu na pasek odtwarzania multimediów.

Implementacja z użyciem funkcji onEnter i FocusRequester

Aby przekierować zaznaczenie po wejściu do grupy fokusowej:

  1. Zastosuj modyfikator focusGroup do kontenera nadrzędnego zawierającego powiązane elementy docelowe.
  2. Zastosuj do kontenera modyfikator focusProperties i skonfiguruj wywołanie zwrotne onEnter.
  3. W wywołaniu zwrotnym onEnter (w zakresie FocusEnterExitScope) wywołaj requestFocus() na obiekcie FocusRequester powiązanym z preferowanym domyślnym elementem podrzędnym za pomocą 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)")
    }
}

W przypadku onEnter i onExit możesz też wywołać cancelFocusChange(), aby całkowicie zablokować przejścia fokusu przez granicę, lub sprawdzić requestedFocusDirection, aby dostosować routing w zależności od tego, czy użytkownik nawigował za pomocą klawiszy Tab, Down czy Left.

Kontenery z paskami przewijania są domyślnie grupami zaznaczenia

W Jetpack Compose kontenery z możliwością przewijania, takie jak LazyRow, LazyColumn i LazyVerticalGrid, automatycznie działają jako grupy fokusowe. Aby ustawić wywołania zwrotne onEnter lub onExit, nie musisz wyraźnie stosować do nich modyfikatora focusGroup.