Wartości docelowe grupy

Możesz grupować wiele elementów zaznaczenia za pomocą modyfikatora focusGroup. Grupowanie umożliwia zarządzanie hierarchiami zaznaczenia, izolowanie logicznych obszarów interfejsu (takich jak paski narzędzi, działania w oknach czy listy kart) oraz przechwytywanie momentu, gdy zaznaczenie wchodzi do obszaru lub go opuszcza.

Pojęcia związane z grupą fokusową: wejście, wyjście i domyślne przechodzenie

Grupa fokusowa tworzy spójną granicę nawigacji wokół podrzędnych elementów docelowych zaznaczenia. Zrozumienie, jak zaznaczenie przemieszcza się przez tę granicę, opiera się na 2 kluczowych pojęciach:

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

Domyślne zachowanie podczas przechodzenia fokusu

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

  1. Wchodzenie do grupy: Compose automatycznie wybiera wewnętrzny podrzędny element docelowy zaznaczenia. W przypadku nawigacji jednowymiarowej (Tab) wybiera pierwszy element podrzędny w kolejności wizualnej. W przypadku nawigacji dwuwymiarowej (klawisze strzałek lub pad kierunkowy) wybiera element podrzędny, który jest geometrycznie najbliżej kierunku przychodzącego.
  2. Poruszanie się w obrębie grupy: wielokrotne naciskanie klawiszy nawigacyjnych powoduje przenoszenie zaznaczenia między elementami docelowymi w grupie.
  3. Opuszczanie grupy: gdy użytkownik przejdzie poza ostatni element zaznaczenia w grupie, kolejne naciśnięcie klawisza spowoduje opuszczenie grupy i przeniesienie zaznaczenia na sąsiedni element zaznaczenia poza grupą.

Dostosowywanie przekierowania po zaznaczeniu

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.

Intencje i przypadki użycia

Weźmy na przykład okno potwierdzenia z przyciskiem „Anuluj” po lewej stronie i głównym przyciskiem „Potwierdź” po prawej stronie. Gdy użytkownik przechodzi z pola formularza do paska przycisków:

  • Działanie domyślne: fokus zostanie ustawiony na przycisku „Anuluj”, ponieważ jest to pierwszy przycisk w kolejności wizualnej.
  • Zamierzone działanie: ponieważ „Potwierdź” jest głównym zalecanym działaniem, możesz chcieć, aby fokus lądował bezpośrednio na przycisku „Potwierdź” po wejściu do grupy przycisków z wcześniejszego miejsca w kolejności fokusu, jednocześnie umożliwiając użytkownikowi naciśnięcie klawisza w lewo, aby w razie potrzeby wybrać „Anuluj”.
Domyślny wpis zaznaczenia w grupie przycisków.
Rysunek 2. Przyciski Anuluj i Potwierdź z domyślnym celem zaznaczenia.

Inne typowe przypadki użycia:

  • Przenoszenie zaznaczenia bezpośrednio na aktualnie wybraną kartę po wejściu do TabRow.
  • Przenoszenie zaznaczenia bezpośrednio do elementu sterującego „Odtwórz / Wstrzymaj” po wejściu na pasek odtwarzania multimediów.

Implementacja z onEnter i FocusRequester

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

  1. Zastosuj modyfikator focusGroup do kontenera nadrzędnego, który zawiera powiązane elementy docelowe zaznaczenia.
  2. Zastosuj modyfikator focusProperties do kontenera i skonfiguruj wywołanie zwrotne onEnter.
  3. W wywołaniu zwrotnym onEnter (w zakresie FocusEnterExitScope) wywołaj requestFocus() na 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)")
    }
}

Wewnątrz onEnter i onExit możesz też wywołać cancelFocusChange(), aby całkowicie zablokować przenoszenie zaznaczenia przez granicę, lub sprawdzić requestedFocusDirection, aby dostosować routing w zależności od tego, czy użytkownik nawigował za pomocą klawisza Tab, Strzałka w dół czy Strzałka w lewo.

Kontenery z paskami przewijania są domyślnie grupami fokusowymi

W Jetpack Compose kontenery, które można przewijać, takie jak LazyRow, LazyColumn i LazyVerticalGrid, automatycznie działają jako grupy zaznaczenia. Nie musisz stosować do nich modyfikatora focusGroup, aby ustawić wywołania zwrotne onEnter lub onExit.