Odağı geri yükleme

Kullanıcılar, donanım klavyesi veya D-pad kullanarak karmaşık kullanıcı arayüzlerinde gezinirken genellikle ekranın farklı bölümleri arasında hareket eder. Örneğin, yan gezinme çubuğundan içerik listesine atlar, bir öğeyle etkileşim kurar ve ardından geri döner. Odak geri yükleme, kapsayıcıların daha önce odaklanılan alt öğeyi hatırlamasına ve odak kapsayıcıya tekrar girdiğinde odağı geri yüklemesine olanak tanır.

Kaydırılabilir kapsayıcılarda odağı geri yükleme

Jetpack Compose'da LazyColumn, LazyRow ve LazyVerticalGrid gibi kaydırılabilir kapsayıcılar otomatik olarak odaklanma grubu görevi görür. Geç yüklenen bir listede veya kılavuzda odaklanma geri yüklemeyi etkinleştirmek için focusRestorer değiştiricisini ekleyin:

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

Odak LazyColumn öğesinden çıktığında kapsayıcı, hangi öğenin etkin olduğunu kaydeder. Kullanıcı listeye geri döndüğünde odak, en baştan başlamak yerine söz konusu öğeye geri yüklenir.

Satır ve sütunda odağı geri yükleme

Tembel düzen kapsayıcılarının aksine, Row ve Column gibi standart kaydırılamayan düzen kapsayıcıları varsayılan olarak odaklanma sınırı oluşturmaz. Odak girişi etkinliklerini kendi başlarına engellemediklerinden, tek başına focusRestorer değiştiricisini uygulamak yeterli değildir.

Row veya Column üzerinde odak geri yüklemeyi etkinleştirmek için focusGroup ile focusRestorer tuşlarını birlikte kullanın:

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

Yedek odak hedefi belirtme

Odak ilk kez bir kapsayıcıya girdiğinde, önceden odaklanılmış bir alt öğe yoktur. Compose, hangi alt öğeye odaklanacağını belirlemek için varsayılan odak sırasını izler.

focusRestorer'ye (veya önceki Compose sürümlerinde FocusRequester döndüren bir lambda) yedek FocusRequester ileterek ilk girişte hangi çocuğun odaklanacağını özelleştirebilirsiniz:

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

Daha önce herhangi bir çocuğa odaklanılmadıysa (veya odak geri yükleme başarısız olursa) Compose, odağı ilişkili yedek hedefe taşır.

NavigationRail, NavigationBar, NavigationDrawer veya TabRow gibi gezinme bileşenlerinde kullanıcılar, içerik alanından bileşene girerken odağın şu anda seçili olan hedefte olmasını bekler.

Modifier.focusGroup() ile focusProperties öğesini birleştirip onEnter özelliğini (veya önceki Compose sürümlerinde enter) ayarlayarak odağı etkin hedefe yönlendirebilirsiniz:

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

Ekran geçişlerinde odağı geri yükleme

Bir kullanıcı, ayrıntı ekranına gitmek için bir öğeyi tıkladıktan sonra geri düğmesini veya hareketini kullanarak geri döndüğünde, tıkladığı öğeye odaklanmayı geri yükleyebilirsiniz.

Ekran geçişlerinde odağı korumak ve geri yüklemek için:

  1. Kapsayıcıyı bir FocusRequester ile ilişkilendirin.
  2. Geçiş etkinliğini tetiklemeden önce kapsayıcının FocusRequester üzerinde saveFocusedChild() işlevini çağırın.
  3. Kullanıcı ekrana geri döndüğünde kapsayıcıya ilk odağı isteyin veya restoreFocusedChild() işlevini çağırın.