Как программно установить фокус на TextField в Jetpack Compose?
Правильное управление фокусом через FocusRequester
В Jetpack Compose для программного управления фокусом используется механизм FocusRequester. Это аналог requestFocus() из View-системы, но с важными нюансами. Давайте разберём вашу задачу по шагам.
Базовое решение для вашего примера
@Composable
fun SearchScreen() {
var query by remember { mutableStateOf("") }
val focusRequester = remember { FocusRequester() }
// Важно: FocusRequester нужно привязать через модификатор
TextField(
value = query,
onValueChange = { query = it },
label = { Text("Поиск") },
modifier = Modifier.focusRequester(focusRequester)
)
Button(onClick = {
query = ""
focusRequester.requestFocus() // Возвращаем фокус
}) {
Text("Сбросить и сфокусироваться")
}
// Автофокус при первом появлении
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
Ключевые моменты:
remember { FocusRequester() }создаёт объект, который живёт всё время существования компонентаModifier.focusRequester()связывает этот объект с конкретным TextFieldLaunchedEffect(Unit)— корутина, которая выполняется один раз при входе в композицию- Вызов
requestFocus()должен происходить после того, как TextField уже отрисован
Почему у вас не работало?
Самая частая ошибка — попытка вызвать requestFocus() до того, как элемент появился на экране. Compose — декларативный, и фокус можно запрашивать только когда элемент уже в иерархии. LaunchedEffect гарантирует, что вызов произойдёт в правильный момент жизненного цикла.
Продвинутый вариант с обработкой ошибок
Если фокус может не установиться (например, элемент скрыт), используйте безопасный вызов:
@Composable
fun SafeSearchScreen() {
var query by remember { mutableStateOf("") }
var isVisible by remember { mutableStateOf(true) }
val focusRequester = remember { FocusRequester() }
Column {
if (isVisible) {
TextField(
value = query,
onValueChange = { query = it },
label = { Text("Поиск") },
modifier = Modifier
.focusRequester(focusRequester)
.focusable() // Явно указываем, что элемент может получать фокус
)
}
Button(onClick = { isVisible = !isVisible }) {
Text(if (isVisible) "Скрыть поле" else "Показать поле")
}
// Запрос фокуса только когда поле видимо
LaunchedEffect(isVisible) {
if (isVisible) {
// Задержка для гарантии отрисовки
delay(100)
focusRequester.requestFocus()
}
}
}
}
Работа с клавиатурой
Часто вместе с фокусом нужно показать клавиатуру. Для этого используйте SoftwareKeyboardController:
val keyboardController = LocalSoftwareKeyboardController.current
// Внутри обработчика кнопки:
focusRequester.requestFocus()
keyboardController?.show()
Важные замечания
- Не используйте
focusRequesterвнутриLaunchedEffectс бесконечным циклом — это приведёт к бесконечной перерисовке - Для нескольких полей создавайте отдельные
FocusRequesterдля каждого - В Compose Multiplatform (Desktop, Web)
SoftwareKeyboardControllerможет быть недоступен - Если фокус не работает, проверьте, не перехватывает ли его другой элемент (например, модальное окно)
Теперь ваш код будет работать как ожидалось: поле поиска автоматически получит фокус при открытии экрана, а кнопка вернёт фокус после сброса текста.
<<Альтернативный подход: FocusManager
Иногда удобнее использовать FocusManager вместо FocusRequester, особенно когда нужно перемещать фокус между несколькими полями или сбрасывать его.
@Composable
fun AlternativeSearchScreen() {
var query by remember { mutableStateOf("") }
val focusManager = LocalFocusManager.current
TextField(
value = query,
onValueChange = { query = it },
label = { Text("Поиск") },
modifier = Modifier
.onFocusChanged { state ->
if (state.isFocused) {
println("Поле получило фокус")
}
}
)
Button(onClick = {
query = ""
// Очищаем фокус со всех полей
focusManager.clearFocus()
}) {
Text("Сбросить и убрать фокус")
}
// Для автофокуса используем FocusRequester,
// но FocusManager удобен для навигации
Button(onClick = {
// Перемещение фокуса на следующее поле
focusManager.moveFocus(FocusDirection.Next)
}) {
Text("Следующее поле")
}
}
Когда использовать FocusManager:
- Для навигации между полями (Tab, стрелки)
- Для программного сброса фокуса
- В формах с множеством полей ввода
Обратите внимание: FocusManager не умеет напрямую устанавливать фокус на конкретное поле — для этого всё равно нужен FocusRequester. Но в паре они дают полный контроль над фокусом.
Совет: для автофокуса при запуске всегда используйте LaunchedEffect — это самый надёжный способ, проверенный тысячами разработчиков.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Tutorplace.ru: Ваш путь к новым знаниям и навыкам через онлайн-курсы