Przywracanie zaznaczenia

Gdy użytkownicy poruszają się po złożonych interfejsach za pomocą klawiatury sprzętowej lub pada kierunkowego, często przechodzą między różnymi sekcjami ekranu, np. przeskakują z paska nawigacyjnego z boku na listę treści, wchodzą w interakcję z elementem, a potem wracają. Przywracanie zaznaczenia umożliwia kontenerom zapamiętywanie wcześniej zaznaczonego elementu podrzędnego i przywracanie do niego zaznaczenia, gdy zaznaczenie ponownie wchodzi do kontenera.

Przywracanie zaznaczenia w kontenerach z paskami przewijania

W Jetpack Compose kontenery z możliwością przewijania, takie jak LazyColumn, LazyRow i LazyVerticalGrid, automatycznie działają jako grupy fokusowe. Aby włączyć przywracanie fokusu na liście lub siatce ładowanej na żądanie, dodaj modyfikator focusRestorer:

LazyColumn(
    modifier = Modifier.focusRestorer()
) {
    items(items) { item ->
        Button(onClick = { /* Handle click */ }) {
            Text(item)
        }
    }
}

Gdy fokus opuści element LazyColumn, kontener zapisuje, który element był aktywny. Gdy użytkownik wróci do listy, zaznaczenie zostanie przywrócone do tego elementu, a nie do początku listy.

Przywracanie ostrości w wierszu i kolumnie

W przeciwieństwie do kontenerów układu wczytywanego na żądanie standardowe kontenery układu bez możliwości przewijania, takie jak Row i Column, nie wyznaczają domyślnie granicy zaznaczenia. Ponieważ nie przechwytują one samodzielnie zdarzeń wejścia w stan aktywności, zastosowanie samego modyfikatora focusRestorer nie wystarczy.

Aby włączyć przywracanie ostrości na Row lub Column, połącz focusGroup z focusRestorer:

Row(
    modifier = Modifier
        .focusGroup()
        .focusRestorer()
) {
    Button(onClick = { /* Action 1 */ }) {
        Text("First item")
    }
    Button(onClick = { /* Action 2 */ }) {
        Text("Second item")
    }
    Button(onClick = { /* Action 3 */ }) {
        Text("Third item")
    }
}

Określanie zastępczego elementu docelowego ostrości

Gdy fokus po raz pierwszy znajdzie się w kontenerze, nie będzie w nim żadnego wcześniej wyróżnionego elementu podrzędnego. Kompozycja jest zgodna z domyślną kolejnością ostrości, aby określić, na którym elemencie podrzędnym ma się skupić.

Możesz dostosować, które dziecko ma być w centrum uwagi przy pierwszym wejściu, przekazując rezerwowy element FocusRequester do focusRestorer (lub lambdę zwracającą FocusRequester w starszych wersjach Compose):

val firstItemRequester = remember { FocusRequester() }

LazyColumn(
    modifier = Modifier.focusRestorer(firstItemRequester)
) {
    itemsIndexed(items) { index, item ->
        val itemModifier = if (index == 0) {
            Modifier.focusRequester(firstItemRequester)
        } else {
            Modifier
        }
        Button(
            onClick = { /* Handle click */ },
            modifier = itemModifier
        ) {
            Text(item)
        }
    }
}

Jeśli żadne dziecko nie było wcześniej zaznaczone (lub jeśli przywrócenie zaznaczenia się nie powiedzie), Compose przenosi zaznaczenie na powiązany element docelowy rezerwowy.

W komponentach nawigacyjnych, takich jak NavigationRail, NavigationBar, NavigationDrawer czy TabRow, użytkownicy oczekują, że po wejściu do komponentu z obszaru treści fokus zostanie przeniesiony na aktualnie wybrane miejsce docelowe.

Możesz skierować fokus na aktywne miejsce docelowe, łącząc Modifier.focusGroup() z focusProperties i ustawiając właściwość onEnter (lub enter w starszych wersjach Compose):

val (homeRequester, searchRequester, settingsRequester) = remember { FocusRequester.createRefs() }

val selectedRequester = when (currentDestination) {
    "home" -> homeRequester
    "search" -> searchRequester
    "settings" -> settingsRequester
    else -> homeRequester
}

NavigationRail(
    modifier = modifier
        .focusProperties {
            // Redirect focus to the selected item when focus enters the navigation rail
            onEnter = { selectedRequester.requestFocus() }
        }
        .focusGroup()
) {
    NavigationRailItem(
        selected = currentDestination == "home",
        onClick = { onNavigate("home") },
        icon = { Icon(Icons.Default.Home, contentDescription = "Home") },
        label = { Text("Home") },
        modifier = Modifier.focusRequester(homeRequester)
    )
    NavigationRailItem(
        selected = currentDestination == "search",
        onClick = { onNavigate("search") },
        icon = { Icon(Icons.Default.Search, contentDescription = "Search") },
        label = { Text("Search") },
        modifier = Modifier.focusRequester(searchRequester)
    )
    NavigationRailItem(
        selected = currentDestination == "settings",
        onClick = { onNavigate("settings") },
        icon = { Icon(Icons.Default.Settings, contentDescription = "Settings") },
        label = { Text("Settings") },
        modifier = Modifier.focusRequester(settingsRequester)
    )
}

Przywracanie fokusu podczas przejść między ekranami

Gdy użytkownik kliknie element, aby przejść do ekranu szczegółów, a następnie wróci za pomocą przycisku Wstecz lub gestu, możesz przywrócić fokus na kliknięty element.

Aby zachować i przywrócić fokus podczas przechodzenia między ekranami:

  1. Powiąż kontener z FocusRequester.
  2. Przed wywołaniem zdarzenia nawigacji wywołaj funkcję saveFocusedChild() na obiekcie FocusRequester kontenera.
  3. Gdy użytkownik wróci do ekranu, poproś o początkowe zaznaczenie kontenera lub wywołaj funkcję restoreFocusedChild().