Ripristinare la messa a fuoco

Quando gli utenti navigano in interfacce utente complesse utilizzando una tastiera hardware o un D-pad, si spostano spesso tra diverse sezioni dello schermo, ad esempio passando da una barra di navigazione laterale a un elenco di contenuti, interagendo con un elemento e poi tornando indietro. Il ripristino dello stato attivo consente ai contenitori di ricordare l'elemento figlio precedentemente selezionato e di ripristinare lo stato attivo quando lo stato attivo rientra nel contenitore.

Ripristinare lo stato attivo nei contenitori scorrevoli

In Jetpack Compose, i contenitori scorrevoli come LazyColumn, LazyRow e LazyVerticalGrid fungono automaticamente da gruppi di messa a fuoco. Per attivare il ripristino dello stato attivo in un elenco o una griglia caricati in modalità differita, aggiungi il modificatore focusRestorer:

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

Quando il focus esce da LazyColumn, il contenitore registra l'elemento attivo. Quando l'utente torna all'elenco, lo stato attivo di selezione viene ripristinato sull'elemento invece di ripartire dall'inizio.

Ripristinare lo stato attivo in Riga e Colonna

A differenza dei contenitori di layout pigro, i contenitori di layout standard non scorrevoli come Row e Column non stabiliscono un limite di messa a fuoco per impostazione predefinita. Poiché non intercettano autonomamente gli eventi di inserimento del focus, l'applicazione del solo modificatore focusRestorer non è sufficiente.

Per attivare il ripristino della messa a fuoco su Row o Column, combina focusGroup con 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")
    }
}

Specifica un target di messa a fuoco di riserva

Quando lo stato attivo entra in un container per la prima volta, non esiste alcun elemento figlio precedentemente attivo. Compose segue l'ordine di messa a fuoco predefinito per determinare su quale bambino concentrarsi.

Puoi personalizzare il bambino a cui viene assegnato il focus nella prima voce passando un FocusRequester di riserva a focusRestorer (o una lambda che restituisce un FocusRequester nelle versioni precedenti di 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)
        }
    }
}

Se non è stato selezionato alcun elemento secondario in precedenza (o se il ripristino dello stato attivo non riesce), Compose sposta lo stato attivo sul target di riserva associato.

Nei componenti di navigazione come NavigationRail, NavigationBar, NavigationDrawer o TabRow, gli utenti si aspettano che il focus si sposti sulla destinazione attualmente selezionata quando accedono al componente dall'area dei contenuti.

Puoi indirizzare l'attenzione alla destinazione attiva combinando Modifier.focusGroup() con focusProperties e impostando la proprietà onEnter (o enter nelle versioni precedenti di 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)
    )
}

Ripristinare lo stato attivo durante le transizioni dello schermo

Quando un utente fa clic su un elemento per passare a una schermata dei dettagli e successivamente torna indietro utilizzando il pulsante Indietro o il gesto, puoi ripristinare lo stato attivo sull'elemento su cui ha fatto clic.

Per preservare e ripristinare lo stato attivo durante le transizioni tra le schermate:

  1. Associa il contenitore a un FocusRequester.
  2. Prima di attivare l'evento di navigazione, chiama saveFocusedChild() sul FocusRequester del contenitore.
  3. Quando l'utente torna alla schermata, richiedi lo stato attivo iniziale sul contenitore o chiama restoreFocusedChild().