Восстановить фокус

При навигации по сложным пользовательским интерфейсам с помощью аппаратной клавиатуры или D-pad пользователи часто перемещаются между различными разделами экрана — например, переходят от боковой панели навигации к списку контента, взаимодействуют с элементом, а затем возвращаются обратно. Функция восстановления фокуса позволяет контейнерам запоминать ранее сфокусированный дочерний элемент и восстанавливать фокус на нем, когда фокус снова попадает в контейнер.

Восстанавливать фокус в прокручиваемых контейнерах

В Jetpack Compose прокручиваемые контейнеры, такие как LazyColumn , LazyRow и LazyVerticalGrid , автоматически выступают в роли групп фокуса. Чтобы включить восстановление фокуса для ленивого списка или сетки, добавьте модификатор focusRestorer :

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

Когда фокус покидает LazyColumn , контейнер записывает, какой элемент был активен. Когда пользователь возвращается в список, фокус возвращается к этому элементу, а не начинается заново с самого начала.

Восстановить фокус в строке и столбце

В отличие от контейнеров с отложенной компоновкой, стандартные контейнеры компоновки без прокрутки, такие как Row и Column по умолчанию не устанавливают границу фокуса. Поскольку они сами по себе не перехватывают события получения фокуса, применения одного только модификатора focusRestorer недостаточно.

Чтобы включить восстановление фокуса для Row или Column , объедините focusGroup с 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")
    }
}

Укажите резервный целевой объект фокусировки

Когда фокус впервые попадает в контейнер, ранее сфокусированного дочернего элемента не существует. Compose следует порядку фокусировки по умолчанию, чтобы определить, на какой дочерний элемент следует сфокусироваться.

Вы можете настроить, какой дочерний элемент получит фокус на первом элементе, передав резервный FocusRequester в focusRestorer (или лямбда-функцию, возвращающую FocusRequester в более ранних версиях 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)
        }
    }
}

Если ранее фокус не был направлен ни на один дочерний элемент (или если восстановление фокуса не удалось), Compose перемещает фокус на соответствующий резервный целевой объект.

В навигационных компонентах, таких как NavigationRail , NavigationBar , NavigationDrawer или TabRow , пользователи ожидают, что при входе в компонент из области контента фокус будет установлен на выбранном в данный момент элементе.

Вы можете перенаправить фокус на активное место назначения, объединив Modifier.focusGroup() с focusProperties и установив свойство onEnter (или enter в более ранних версиях 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)
    )
}

Восстановление фокуса при переходе между экранами

Когда пользователь нажимает на элемент, чтобы перейти к подробному описанию, а затем возвращается, используя кнопку «Назад» или другой жест, вы можете восстановить фокус на элементе, на который он нажал.

Для сохранения и восстановления фокуса при переходах между экранами:

  1. Свяжите контейнер с объектом FocusRequester .
  2. Перед запуском события навигации вызовите метод saveFocusedChild() для объекта FocusRequester контейнера.
  3. Когда пользователь вернется на предыдущий экран, запросите первоначальную фокусировку на контейнере или вызовите метод restoreFocusedChild() .
{% verbatim %} {% endverbatim %} {% verbatim %} {% endverbatim %}