Как закрыть виртуальную клавиатуру из текстового поля Jetpack Compose?

Я использую Jetpack Compose TextField и я хочу закрыть виртуальную клавиатуру, когда пользователь нажимает кнопку действия (imeActionPerformed параметр).

val text = +state { "" }
TextField(
    value = text.value,
    keyboardType = KeyboardType.Text,
    imeAction = ImeAction.Done,
    onImeActionPerformed = { 
        // TODO Close the virtual keyboard here <<<
    }
    onValueChange = { s -> text.value = s }
)

8 ответов

С 1.0.0-alpha01 вы можете использовать SoftwareKeyboardController класс:

var text by remember { mutableStateOf(TextFieldValue("Text")) }

TextField(
        value = text,
        onValueChange = {
            text = it
        },
        label = { Text("Label") },
        imeAction = ImeAction.Done,
        onImeActionPerformed = { action, softwareController ->
            if (action == ImeAction.Done) {
                softwareController?.hideSoftwareKeyboard()
            }
        }
)

По версии создания письма 1.0.0-alpha12onImeActionPerformed устарел, и предлагаемый подход заключается в использовании keyboardActions с комбинацией keyboardOptions:

          val focusManager = LocalFocusManager.current

    OutlinedTextField(
        value = ...,
        onValueChange = ...,
        label = ...,
        keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
        keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done, keyboardType = KeyboardType.Password),
    )

focusManager.clearFocus() позаботится об удалении мягкой клавиатуры.

В 1.0.0 вы можете использовать SoftwareKeyboardController или FocusManager сделать это.

Этот ответ фокусируется на их различиях.


Настраивать:

      var text by remember { mutableStateOf("")}

TextField(
    value = text,
    onValueChange = { text = it },
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
    keyboardActions = KeyboardActions(onDone = { /* TODO */ }),
)


SoftwareKeyboardController:

На основе @Gabriele Mariottis отвечать.

      val keyboardController = LocalSoftwareKeyboardController.current

// TODO =
keyboardController?.hide()

Это только закрывает клавиатуру, но НЕ очищает фокус от любого сфокусированного текстового поля (обратите внимание на толстое подчеркивание).


FocusManager:

На основе @azizbekians отвечать.

      val focusManager = LocalFocusManager.current

// TODO =
focusManager.clearFocus()

Это закрывает клавиатуру И очищает фокус от TextField.

Скрытие клавиатуры при нажатии кнопки

Чтобы добавить решение Габриэле Мариотти , если вы хотите условно скрыть клавиатуру, скажем, после нажатия кнопки, используйте это:

      keyboardController?.hide()

Например, скрыть клавиатуру после нажатия кнопки Добавить:

      var newWord by remember { mutableStateOf("") }
val keyboardController = LocalSoftwareKeyboardController.current

// Setup the text field with keyboard as provided by Gabriele Mariotti

...

Button(
        modifier = Modifier
                .height(56.dp),
        onClick = {
                if (!newWord.trim().isNullOrEmpty()) {
                        wordViewModel.onAddWord(newWord.trim())
                        newWord = ""
                        keyboardController?.hide()
                }
        ...

Есть два сценария

Сценарий 1. TextField в AlertDialog

Обязательно инициализируйте keyboard controllerили focus managerвнутри Dialog content scope

(Dialog имеет собственный контроллер клавиатуры)

      Dialog(
    onDismissRequest = {
       // on dismiss
    }
) {
   // initialise the keyboard controller and focus Manager inside the content scope
   val keyboardController = LocalSoftwareKeyboardController.current
   val focusManager = LocalFocusManager.current
}

скрыть клавиатуру

      keyboardController?.hide()
focusManager.clear()

Крайний регистр: закрыть диалоговое окно и скрыть клавиатуру.

При одновременном закрытии диалогового окна и клавиатуры может возникнуть проблема с мерцанием клавиатуры (быстрое скрытие и отображение клавиатуры).

Попробуйте сначала скрыть клавиатуру, а затем вызвать событие диалогового окна закрытия с задержкой.

      Dialog() {
    val keyboardController = LocalSoftwareKeyboardController.current
    val focusManager = LocalFocusManager.current

    Button(onClick = {
       keyboardController?.hide()
       focusManager.clear()

       // notify the view model to dismiss the dialog

       viewModel.onNegativeButtonClicked()
    })
}

Внутри модели представления

      ViewModel {
    
  fun onNegativeButtonClicked() {

     // trigger dismissDialog event with delay
  }

}

Сценарий 2 — только TextField (без диалогового окна)

      val keyboardController = LocalSoftwareKeyboardController.current
var text by rememberSaveable { mutableStateOf("") }
TextField(
    value = text,
    onValueChange = { text = it },
    label = { Text("Label") },
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
    keyboardActions = KeyboardActions(
        onDone = {
            keyboardController?.hide()
            // do something here
        }
    )
)

или вы можете просто использоватьkeyboardController focusManagerскрыть клавиатуру внутри события щелчка

      Button(onClick = {
    keyboardController?.hide()
})

Я нашел решение здесь:)

fun hideKeyboard(activity: Activity) {
    val imm: InputMethodManager = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
    var view = activity.currentFocus
    if (view == null) {
        view = View(activity)
    }
    imm.hideSoftInputFromWindow(view.windowToken, 0)
}

Мне просто нужно вызвать указанную выше функцию из моего компонента:

// getting the context
val context = +ambient(ContextAmbient)

// textfield state
val text = +state { "" }

TextField(
    value = text.value,
    keyboardType = KeyboardType.Text,
    imeAction = ImeAction.Done,
    onImeActionPerformed = { 
        if (imeAction == ImeAction.Done) {
            hideKeyboard(context as Activity)
        }
    }
    onValueChange = { s -> text.value = s }
)

Я нашел способ отключить его в CoreTextField, используя TextInputService для управления переключателем

      val focus = LocalTextInputService.current
var text by remember{ mutableStateOf("")}
TextField(
    value = text,
    onValueChange = { text = it },
    keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done, keyboardType = KeyboardType.Text),
    keyboardActions = KeyboardActions(onDone = { focus?.hideSoftwareKeyboard() }),
    singleLine = true
)

реализация 'androidx.compose.material3:material3:1.0.0-alpha02'

Текстовое поле со скрытой клавиатурой при действии Ime

      @OptIn(ExperimentalComposeUiApi::class)
    @Composable
    fun TextFieldWithHideKeyboardOnImeAction() {
        val keyboardController = LocalSoftwareKeyboardController.current
        var text by rememberSaveable { mutableStateOf("") }
        TextField(
            value = text,
            onValueChange = { text = it },
            label = { Text("Label") },
            keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
            keyboardActions = KeyboardActions(
                onDone = {
                    keyboardController?.hide()
                    // do something here
                }
            )
        )
    }

Другие вопросы по тегам