How to detect when soft-keyboard opened/closed?
# compose
k
How to detect when soft-keyboard opened/closed?
s
What do you need this information for? Depending on the reason you may get different answers.
k
I wanna hide/show
submit
button when keyboard is opened/closed.
Main reason for this is that sometimes
submit
button changes a for cause of the
windowSoftInputMode
adjustResize
value that we have.
s
Didn’t quite get the second message, but for the first one, could you give
WindowInsets.isImeVisible
a try? It’s part of the new compose 1.2 inset APIs.
k
Yea, tried it, but they seem to not provide a
State
, but just a
Boolean
value. So I should still have sort of callback to react to keyboard state change.
s
WindowInsets.isImeVisible
is a composable function, aka you’ll always be getting the latest value. It’s kind of like
State<Boolean>
, but you don’t see it, you see just a
Boolean
, and get the observability for free since you’re inside a composable function.
I’m curious to see how you’re calling that function and why it doesn’t work for you. It’s possibly me who’s misunderstanding something.
k
I see. I was trying to debug it before and was getting that initial
false
value only. Having
WindowInsets.isImeVisible
inside the composable function and opening and closing the keyboard should be enough to recompose that
isImeVisible
and return true when I open keyboard?
s
Yeah that should be the case indeed
k
Maybe I did something wrong, I'll check that out again, tnx.
s
It’s here in the getter
Copy code
@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
    @ExperimentalLayoutApi
    @Composable
    @NonRestartaleComposable
    get() = WindowInsetsHolder.current().ime.isVisible
the getter is a composable function, aka you get this observability. Take a look at this post from @Zach Klippenstein (he/him) [MOD] at the section
Snapshot state: Observation
Copy code
Composable functions already have this implicit observation logic wired up, which is why code like this would just work:

@Composable fun CounterButton(counter: Counter) {
  Text("${counter.label}: ${counter.value}")
}

The Compose compiler wraps the body of this CounterButton function with code that effectively observes any and all MutableStates that happen to be read inside the function.
And
isVisible
is in fact a
State
object as seen here, so it works. That’s my understanding of all this at least, I hope I’m not giving you any wrong information here 😊
a
I was looking the same yesterday and I've found this
k
@Alejandro Rios Tried that example today. This example has a slight delay with a callback, and for my use case I had an issue. Button that I need to hide when keyboard opens is at the bottom-end of a screen. Opening a keyboard animates a button for a small amount of time before button disappears.
a
Yes, @Stylianos Gakis is right,
WindowInsets.isImeVisible
is snapshot state backed, so it will automatically update when the keyboard is opening and closing. Are you using
WindowCompat.setDecorFitsSytemWindows(window, false)
and
adjustResize
? (I think you mentioned
adjustResize
)
k
@Alex Vanyo Yes, I'm using
WindowCompat.setDecorFitsSytemWindows(window, false)
, but dynamically change boolean value, depending on a navigation `route`where I'm at, and I do use
adjustResize
Alright, in this particular case it was set to
true
, and I wasn't getting the keyboard state. Setting it to
false
gives me value re-actively as @Stylianos Gakis suggested.
a
Yeah, that’s unfortunate but makes sense. If the app doesn’t get as much information about it can about the insets it may not be able to know as accurately if the keyboard is open or not
k
Thanks for clarification Alex.
a
Your best bet will probably be to do
WindowCompat.setDecorFitsSytemWindows(window, false)
on that screen (handling the insets there yourself) and then getting the accurate value for
WindowInsets.isImeVisible
k
Was thinking of that, will try that tomorrow. Tnx
1431 Views