Odağı geri yükleme

Kullanıcılar, donanım klavyesi veya d-pad kullanarak karmaşık kullanıcı arayüzlerinde gezinirken ekranın farklı bölümleri arasında sık sık geçiş yapar. Ö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ını ve odak kapsayıcıya yeniden girdiğinde odağı bu öğeye geri yüklemesini sağlar.

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 odak grubu görevi görür. Yavaş listelerde veya ızgaralarda odak 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 bu öğeye geri yüklenir.

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

Yavaş düzen kapsayıcılarının aksine, Row ve Column gibi standart kaydırılamayan düzen kapsayıcıları varsayılan olarak odak sınırı oluşturmaz. Odak girişi etkinliklerini kendi başlarına engellemedikleri için yalnızca focusRestorer değiştiricisini uygulamak yeterli değildir.

Row veya Column üzerinde odak geri yüklemeyi etkinleştirmek için focusGroup ile focusRestorer öğesini birleştirin:

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 bir kapsayıcıya ilk kez girdiğinde, daha önce odaklanılmış bir alt öğe yoktur. Compose, hangi alt öğeye odaklanılacağını belirlemek için varsayılan odak sırasını kullanır.

focusRestorer öğesine yedek bir FocusRequester (veya önceki Compose sürümlerinde FocusRequester döndüren bir lambda) ileterek ilk girişte hangi alt öğenin 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 odaklanılmış bir alt öğe yoksa (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 o anda seçili olan hedefe gelmesini 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

Kullanıcı bir öğeyi tıklayarak ayrıntı ekranına gittiğinde ve ardından geri düğmesini veya hareketini kullanarak geri döndüğünde, odağı tıkladığı öğeye 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. Gezinme etkinliğini tetiklemeden önce kapsayıcının FocusRequester öğesinde saveFocusedChild() yöntemini çağırın.
  3. Kullanıcı ekrana geri döndüğünde kapsayıcıya ilk odaklanmayı isteyin veya restoreFocusedChild() yöntemini çağırın.