55

I'm using the Jetpack Compose TextField and I want to close the virtual keyboard when the user press the the action button (imeActionPerformed parameter).

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 }
)
azizbekian
  • 58,054
  • 12
  • 164
  • 238
nglauber
  • 9,971
  • 2
  • 44
  • 50

7 Answers7

117

You can use the LocalSoftwareKeyboardController class to control the current software keyboard and then use the hide method:

var text by remember { mutableStateOf(TextFieldValue("Text")) }
val keyboardController = LocalSoftwareKeyboardController.current

TextField(
        value = text,
        onValueChange = {
            text = it
        },
        label = { Text("Label") },
        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
        keyboardActions = KeyboardActions(
                onDone = {keyboardController?.hide()})
)

This solution closes the keyboard without removing the focus from the current TextField.

Just to highlight the difference with:

val focusManager = LocalFocusManager.current
focusManager.clearFocus()

This code closes the keyboard removing the focus from the TextField.

Gabriele Mariotti
  • 250,295
  • 77
  • 670
  • 690
  • 34
    This is every Android Developer's dream – Andrew Chelix Apr 14 '21 at 10:29
  • 3
    What are the differences between this and the focusManager approach (https://stackoverflow.com/a/66259111/2911458)? When should we use each? – stkent May 22 '21 at 23:10
  • 2
    @stkent this solution only hides the keyboard. The other solution also removes the focus from the current TextField (the cursor is still showing, it might still be highlighted, etc.) – m.reiter Aug 04 '21 at 09:25
  • 1
    When choosing between both solutions please also watch ux-continuity: The default-behavior: swiping back once hides the keyboard, and second swipe clears the focus. – m.reiter Aug 04 '21 at 09:31
  • Thanks, @m.reiter! – stkent Aug 04 '21 at 14:18
  • 1
    @stkent for additional details, see my answer below https://stackoverflow.com/a/68650009/12871582 – m.reiter Aug 04 '21 at 14:58
  • @Gabriele Mariotti How can I set up a TextField to **never invoking** the virtual keyboard at all? [Click on here to go to that question of mine.](https://stackoverflow.com/questions/71535062/how-to-disable-showing-the-virtual-keyboard-when-tapping-on-a-textfield) – Jorge Luiz Mar 20 '22 at 03:52
65

Starting from compose 1.0.0-alpha12 (and still valid in compose 1.2.0) the onImeActionPerformed is deprecated and suggested approach is to use keyboardActions with combination of 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() will take care of dismissing the soft keyboard.

azizbekian
  • 58,054
  • 12
  • 164
  • 238
13

In 1.0.0 you can either use SoftwareKeyboardController or FocusManager to do this.

This answer focuses on their differences.


Setup:

var text by remember { mutableStateOf("")}

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

setup


SoftwareKeyboardController:

Based on @Gabriele Mariottis answer.

val keyboardController = LocalSoftwareKeyboardController.current

// TODO =
keyboardController?.hide()

This only closes the keyboard, but does NOT clear the focus from any focused TextField (note the cursor & thick underline).

Using Keyboard Controller


FocusManager:

Based on @azizbekians answer.

val focusManager = LocalFocusManager.current

// TODO =
focusManager.clearFocus()

Using Focus Manager

This closes the keyboard AND clears the focus from the TextField.

m.reiter
  • 987
  • 6
  • 21
6

Hiding the keyboard on button click

To add with Gabriele Mariotti's solution, if you want to hide the keyboard conditionally, say after a button click, use this:

keyboardController?.hide()

For example, hide the keyboard after clicking the Add button:

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()
                }
        ...
Hasan
  • 309
  • 4
  • 10
3

Edit after alpha-12 release: See @azizbekian response.

Pre-alpha-12 response

I found the solution here :)

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)
}

I just need to call the function above from my component:

// 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 }
)
nglauber
  • 9,971
  • 2
  • 44
  • 50
0

implementation 'androidx.compose.material3:material3:1.0.0-alpha02'

Text Field With Hide Keyboard On Ime Action

@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
                }
            )
        )
    }

Text Field With Hide Keyboard On Ime Action

Hari Shankar S
  • 3,330
  • 4
  • 19
  • 36
0

I found a way to shut him down in the CoreTextField,use TextInputService to control the switch

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
)
Yshh
  • 353
  • 7
  • See "[Explaining entirely code-based answers](https://meta.stackoverflow.com/q/392712/128421)". While this might be technically correct, it doesn't explain why it solves the problem or should be the selected answer. We should educate along with helping solve the problem. – the Tin Man Mar 22 '22 at 04:48