Memulihkan fokus

Saat pengguna menavigasi antarmuka pengguna yang kompleks menggunakan keyboard hardware atau D-pad, mereka sering berpindah-pindah di antara berbagai bagian layar—seperti berpindah dari panel navigasi samping ke daftar konten, berinteraksi dengan item, lalu berpindah kembali. Pemulihan fokus memungkinkan penampung mengingat elemen turunan yang sebelumnya difokuskan dan memulihkan fokus ke elemen tersebut saat fokus kembali memasuki penampung.

Memulihkan fokus di penampung yang dapat di-scroll

Di Jetpack Compose, penampung yang dapat di-scroll seperti LazyColumn, LazyRow, dan LazyVerticalGrid otomatis bertindak sebagai grup fokus. Untuk mengaktifkan pemulihan fokus pada daftar atau petak lambat, lampirkan pengubah focusRestorer:

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

Saat fokus keluar dari LazyColumn, penampung akan mencatat item mana yang aktif. Saat pengguna kembali ke daftar, fokus akan dipulihkan ke item tersebut, bukan dimulai ulang di bagian atas.

Memulihkan fokus dalam Baris dan Kolom

Tidak seperti penampung tata letak lambat, penampung tata letak standar yang tidak dapat di-scroll seperti Row dan Column tidak membuat batas fokus secara default. Karena tidak mencegat peristiwa entri fokus dengan sendirinya, penerapan pengubah focusRestorer saja tidak cukup.

Untuk mengaktifkan pemulihan fokus di Row atau Column, gabungkan focusGroup dengan 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")
    }
}

Menentukan target fokus penggantian

Saat fokus memasuki penampung untuk pertama kalinya, tidak ada turunan yang sebelumnya difokuskan. Compose mengikuti urutan fokus default untuk menentukan turunan mana yang akan difokuskan.

Anda dapat menyesuaikan turunan mana yang menerima fokus pada entri pertama dengan meneruskan FocusRequester penggantian ke focusRestorer (atau lambda yang menampilkan FocusRequester pada versi Compose sebelumnya):

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)
        }
    }
}

Jika tidak ada turunan yang sebelumnya difokuskan (atau jika pemulihan fokus gagal), Compose akan memindahkan fokus ke target penggantian terkait.

Pada komponen navigasi seperti NavigationRail, NavigationBar, NavigationDrawer, atau TabRow, pengguna berharap fokus mendarat di tujuan yang saat ini dipilih saat memasuki komponen dari area konten.

Anda dapat mengarahkan fokus ke tujuan aktif dengan menggabungkan Modifier.focusGroup() dengan focusProperties dan menyetel properti onEnter (atau enter pada versi Compose sebelumnya):

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)
    )
}

Memulihkan fokus di seluruh transisi layar

Saat pengguna mengklik item untuk membuka layar detail dan kemudian kembali menggunakan tombol kembali atau gestur, Anda dapat memulihkan fokus ke item yang dikliknya.

Untuk mempertahankan dan memulihkan fokus di seluruh transisi layar:

  1. Kaitkan penampung dengan FocusRequester.
  2. Sebelum memicu peristiwa navigasi, panggil saveFocusedChild() di FocusRequester penampung.
  3. Saat pengguna kembali ke layar, minta fokus awal pada penampung atau panggil restoreFocusedChild().