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 bocznego paska nawigacyjnego do listy treści, wchodzą w interakcję z elementem, a następnie wracają. Przywracanie zaznaczenia umożliwia kontenerom zapamiętywanie wcześniej zaznaczonego elementu podrzędnego i przywracanie zaznaczenia, gdy zaznaczenie ponownie wejdzie do kontenera.

Przywracanie zaznaczenia w kontenerach z możliwością przewijania

W Jetpack Compose kontenery, które można przewijać, takie jak LazyColumn, LazyRow i LazyVerticalGrid, automatycznie działają jako grupy zaznaczenia. Aby włączyć przywracanie zaznaczenia na liście lub siatce z opóźnionym wczytywaniem, dołącz modyfikator focusRestorer:

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

Gdy fokus opuści element LazyColumn, kontener rejestruje, który element był aktywny. Gdy użytkownik wróci do listy, zaznaczenie zostanie przywrócone na tym elemencie, zamiast zaczynać się od góry.

Przywracanie zaznaczenia wiersza i kolumny

W przeciwieństwie do kontenerów układu z opóźnionym wczytywaniem standardowe kontenery układu, których nie można przewijać, takie jak Row i Column, nie ustanawiają domyślnie granicy zaznaczenia. Ponieważ nie przechwytują one zdarzeń wejścia fokusu, samo zastosowanie modyfikatora focusRestorer nie wystarczy.

Aby włączyć przywracanie zaznaczenia w 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 zaznaczenia

Gdy fokus po raz pierwszy przechodzi do kontenera, nie ma żadnego elementu podrzędnego, który był wcześniej zaznaczony. Compose określa, który element podrzędny ma być zaznaczony, zgodnie z domyślną kolejnością zaznaczania.

Możesz dostosować, który element podrzędny zostanie zaznaczony przy pierwszym wejściu, przekazując zastępczy element FocusRequester do focusRestorer (lub funkcję lambda zwracającą FocusRequester we wcześniejszych 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 żaden element podrzędny nie był wcześniej zaznaczony (lub jeśli przywrócenie zaznaczenia się nie powiedzie), Compose przenosi zaznaczenie na powiązany element zastępczy.

W komponentach nawigacyjnych takich jak NavigationRail, NavigationBar, NavigationDrawer czy TabRow użytkownicy oczekują, że po przejściu do komponentu z obszaru treści zaznaczony zostanie aktualnie wybrany element docelowy.

Możesz skierować zaznaczenie na aktywne miejsce docelowe, łącząc Modifier.focusGroup() z focusProperties i ustawiając właściwość onEnter (lub enter we wcześniejszych 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ć zaznaczenie klikniętego elementu.

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

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