Как программно скрыть клавиатуру в Jetpack Compose при работе с TextField
Всем привет! Я начал изучать Jetpack Compose и столкнулся с такой проблемой: после того как пользователь ввел текст в TextField, клавиатура не закрывается автоматически. Мне нужно, чтобы она скрывалась по нажатию кнопки "Готово" или после отправки формы. В классическом View это делалось через InputMethodManager, но в Compose это не работает напрямую.
Вот мой текущий код:
@Composable
fun LoginScreen() {
var text by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize().padding(16.dp)
) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Введите имя") },
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
// Здесь нужно скрыть клавиатуру
Log.d("TAG", "Отправка: $text")
}
) {
Text("Отправить")
}
}
}
Я пробовал использовать LocalContext.current и получать InputMethodManager, но клавиатура не скрывается. Подскажите, как правильно это сделать в Compose? Нужно ли как-то по-особому получать контекст или есть другой подход?
Заранее спасибо за помощь!
<<Решение: скрытие клавиатуры через LocalSoftwareKeyboardController
В Jetpack Compose есть встроенный способ управления клавиатурой — SoftwareKeyboardController. Его можно получить через LocalSoftwareKeyboardController в CompositionLocal. Этот способ работает нативно и не требует прямого доступа к InputMethodManager.
Вот исправленный код:
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
@Composable
fun LoginScreen() {
var text by remember { mutableStateOf("") }
val keyboardController = LocalSoftwareKeyboardController.current
Column(
modifier = Modifier.fillMaxSize().padding(16.dp)
) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Введите имя") },
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
keyboardController?.hide() // Скрываем клавиатуру
Log.d("TAG", "Отправка: $text")
}
) {
Text("Отправить")
}
}
}
Ключевые моменты:
LocalSoftwareKeyboardController— это CompositionLocal, который предоставляет контроллер клавиатуры для текущего Compose-контекста.- Метод
hide()скрывает клавиатуру. Он безопасен для вызова, даже если клавиатура уже скрыта (просто ничего не произойдет). - Контроллер может быть
null, если клавиатура недоступна (например, на устройстве без экранной клавиатуры). Поэтому используйте?.для безопасного вызова.
Что делать, если клавиатура всё ещё не скрывается?
Иногда проблема может быть в том, что TextField теряет фокус после скрытия клавиатуры, но клавиатура остаётся. В таких случаях можно дополнительно сбросить фокус с поля ввода:
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
@Composable
fun LoginScreen() {
var text by remember { mutableStateOf("") }
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
Column(
modifier = Modifier.fillMaxSize().padding(16.dp)
) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Введите имя") },
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester)
)
Button(
onClick = {
keyboardController?.hide()
focusRequester.freeFocus() // Снимаем фокус
Log.d("TAG", "Отправка: $text")
}
) {
Text("Отправить")
}
}
}
Метод freeFocus() сбрасывает фокус с текущего элемента, что гарантирует скрытие клавиатуры в сложных сценариях (например, при использовании нескольких TextField).
Альтернативный способ: скрытие по нажатию "Done" на клавиатуре
Если нужно скрывать клавиатуру при нажатии кнопки "Готово" на самой клавиатуре, используйте KeyboardActions:
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("Введите имя") },
keyboardActions = KeyboardActions(
onDone = { keyboardController?.hide() }
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done)
)
Этот подход удобен для полей ввода, где не требуется кнопка отправки.
<<Использование InputMethodManager в Compose
Если по какой-то причине SoftwareKeyboardController не подходит (например, вы работаете с устаревшей версией Compose), можно использовать классический InputMethodManager через LocalContext:
@Composable
fun LoginScreen() {
var text by remember { mutableStateOf("") }
val context = LocalContext.current
Button(
onClick = {
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val view = (context as? Activity)?.currentFocus ?: View(context)
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
Log.d("TAG", "Отправка: $text")
}
) {
Text("Отправить")
}
}
Важно: этот способ требует получения текущего View с фокусом. В Compose это может быть проблематично, так как нет прямого доступа к View. Поэтому предпочтительнее использовать SoftwareKeyboardController.
Дополнительный совет
Если вы используете TextField внутри LazyColumn или Dialog, убедитесь, что клавиатура не блокируется родительскими элементами. В таких случаях добавьте Modifier.imePadding() к корневому модификатору, чтобы Compose правильно обрабатывал отступы при появлении клавиатуры.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги