Ripristinare la messa a fuoco

Quando gli utenti navigano in interfacce utente complesse utilizzando una tastiera hardware o un D-pad, spesso si spostano 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 secondario precedentemente attivo e di ripristinare lo stato attivo su di esso quando lo stato attivo rientra nel contenitore.

Ripristina lo stato attivo nei contenitori scorrevoli

In Jetpack Compose, i contenitori scorrevoli come LazyColumn, LazyRow e LazyVerticalGrid fungono automaticamente da gruppi di selezione. Per attivare il ripristino dello stato attivo su un elenco o una griglia con caricamento lento, aggiungi il modificatore focusRestorer:

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

Quando lo stato attivo esce da LazyColumn, il container registra l'elemento attivo. Quando l'utente torna all'elenco, lo stato attivo viene ripristinato su quell'elemento anziché ricominciare dall'inizio.

Ripristina lo stato attivo in Riga e Colonna

A differenza dei container di layout con caricamento lento, i container di layout standard non scorrevoli come Row e Column non stabiliscono un confine di stato attivo per impostazione predefinita. Poiché non intercettano autonomamente gli eventi di attivazione dello stato attivo, l'applicazione del modificatore focusRestorer da solo non è sufficiente.

Per attivare il ripristino dello stato attivo 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 un elemento secondario precedentemente attivo. Compose segue l'ordine di selezione predefinito per determinare quale elemento secondario selezionare.

Puoi personalizzare l'elemento secondario che riceve lo stato attivo alla prima voce passando un FocusRequester di riserva a focusRestorer (o una funzione 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 nessun elemento secondario è stato selezionato in precedenza (o se il ripristino dello stato attivo non va a buon fine), 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 lo stato attivo si trovi sulla destinazione attualmente selezionata quando entrano nel componente dall'area dei contenuti.

Puoi indirizzare lo stato attivo 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)
    )
}

Ripristina lo stato attivo durante le transizioni tra le schermate

Quando un utente fa clic su un elemento per passare a una schermata dei dettagli e poi torna indietro utilizzando il pulsante o il gesto Indietro, 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().