Home > Software engineering >  How to toggle IME keyboard open/close in Compose?
How to toggle IME keyboard open/close in Compose?

Time:11-05

In my app, I have a TextField and a button which should show/hide the IME keyboard. I have read all about controlling the soft keyboard and how to show or hide it, but not how to toggle. This SO post is related, but not exactly what I'm asking for.

The problem I have is that I need to keep track of when the keyboard has been opened and closed. It's possible to open the keyboard by tapping on the TextField of course, and it's possible to close it by pressing the back button. I can't find any hooks or callbacks for those actions, so I can assign isKeyboardOpen boolean.

Because of that, I can toggle the keyboard from the Toggle keyboard! button, but as soon as I "manually" open it (tap on the text field) or close it (press the back button), the toggle button state can't be updated and I need to press it twice for it to show/hide the keyboard.

So far I had tried the following:

  1. BackHandler - no effect
  2. Modifier.pointerInput(Unit) with detectTapGestures - those callbacks are never hit on tapping the TextField
  3. onKeyEvent and onPreviewKeyEvent - they seem to be for hardware keyboard key presses only. I tried to intercept the back press, as we'd done it in the Android Views world: action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK, but no luck

Here's the code for those two elements, as illustrated in the gif below:

                Surface {

                var isKeyboardOpen by remember { mutableStateOf(false) }
                val keyboardController = LocalSoftwareKeyboardController.current

                Column {
                    Button(onClick = {
                        isKeyboardOpen = !isKeyboardOpen
                        if (isKeyboardOpen) keyboardController?.show() else keyboardController?.hide()
                    }
                    ) {
                        Text("Toggle keyboard!")
                    }

                    //...

                    BackHandler(isKeyboardOpen) {
                        Log.d("TextField", "backPressed - never called")
                    }

                    var text by remember { mutableStateOf("") }

                    TextField(
                        value = text,
                        onValueChange = { text = it },
                        modifier = Modifier.pointerInput(Unit) {
                            detectTapGestures(
                                onTap = { Log.d("TextField", "onTap - never called") },
                                onPress = { Log.d("TextField", "onPress - never called") },
                            )
                        }.onKeyEvent { event ->
                            // callback never hit
                            if (event.type == KeyEventType.KeyUp && event.key == Key.Back) {
                                //....
                            }
                            true
                        }
                    )
                }
            }

Gif of trying to toggle keyboard open/closed from a button

How can I implement keyboard toggle button in compose? Is it even possible?

CodePudding user response:

You can use WindowInsets to detect whether keyboard is open or close.

Follow these instructions to add and setup Accompanist Insets Library.

Once set up you can create you button like this.

val insets = LocalWindowInsets.current
val keyboardController = LocalSoftwareKeyboardController.current

Button(onClick = {
    if (insets.ime.isVisible) keyboardController?.hide() else keyboardController?.show()
}) {
    Text("Toggle keyboard!")
}

CodePudding user response:

You can use the KeyboardVisibilityEvent library for that

KeyboardVisibilityEvent.setEventListener(
    getActivity(),
    new KeyboardVisibilityEventListener() {
        @Override
        public void onVisibilityChanged(boolean isOpen) {
           // do your thing here !!
        }
    });
  • Related