Memulihkan fokus

Saat pengguna menavigasi antarmuka pengguna yang kompleks menggunakan keyboard hardware atau D-pad, mereka sering berpindah di antara berbagai bagian layar—seperti berpindah dari kolom samping navigasi 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 dalam 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 di Baris dan Kolom

Tidak seperti penampung tata letak lambat, penampung tata letak standar yang tidak dapat di-scroll seperti Row dan Column tidak menetapkan batas fokus secara default. Karena tidak menangkap peristiwa entri fokus sendiri, menerapkan 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 yang akan difokuskan.

Anda dapat menyesuaikan turunan mana yang menerima fokus pada entri pertama dengan meneruskan FocusRequester pengganti 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 difokuskan sebelumnya (atau jika pemulihan fokus gagal), Compose akan memindahkan fokus ke target penggantian terkait.

Dalam komponen navigasi seperti NavigationRail, NavigationBar, NavigationDrawer, atau TabRow, pengguna mengharapkan 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 menetapkan 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 diklik.

Untuk mempertahankan dan memulihkan fokus di seluruh transisi layar:

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