I'm struggling with keyboard/WindowInsets. A lot o...
# compose-android
t
I'm struggling with keyboard/WindowInsets. A lot of the stuff out on the web references outdated code from Accompanist. For an experiment, I put together the following: • Big Box • Column with TextField, and 2 dividers below the text field My goal is: • Change the background color of the box when the keyboard opens • Move not only the input field up but also keep the middle divider (but not the lower one) exposed when the keyboard opens My attached snippet fails to do either 😕 I tried to put the color in a remember/derivedState, but apparently WindowInsets.Companion access are @Composable. But if that's the case, I hoped it would recompose when that value would change. I tried to add imePadding to the first divider, but it just seems to blow me off and do it's own thing. I'm running it as "Run Preview"; my Manifest has the adjustResize entry in it.
Screenshot 2023-04-27 at 3.24.58 PM.png
s
As a sanity check, have you made sure to call
WindowCompat.setDecorFitsSystemWindows(window, false)
on your activity?
Ah, but of course 😅 You’re adding the padding on the Divider, but that only “inner” padding inside that 40.dp you are giving it. In fact, if you replace
.imePadding()
with for example
.padding(bottom = 300.dp)
you’ll see that you simply get this pic as a result
You can instead add the IME height as height to the item itself, which will push your item as high as the IME is high, something like
Copy code
Divider(
  modifier = Modifier.height(40.dp + with(density) { WindowInsets.ime.getBottom(this).toDp() }),
  color = Color.Red,
)
will result in this pic
And then you may wonder, damn, I don’t want the FULL keyboard insets, since I am already 40 + 40 dp high (since the two items exist there). Well, there’s an API for that too, you can yourself exclude part of the insets, and then receive the REST after you’ve already consumed those. Could look something like this
Copy code
Divider(
  modifier = Modifier
    .height(
      40.dp + with(density) { WindowInsets.ime.exclude(WindowInsets(bottom = 80.dp)).getBottom(this).toDp() },
    ),
  color = Color.Red,
)
Definitely some room for improvement in here, especially this hard-coded 80dp may be brittle to changes but if you know what these two dividers height really is you can be sure you’re not doing something wrong. And in general, you can take this information and do what you are trying to do I think.
Oh, and
density
is just
val density = LocalDensity.current
t
Regarding
WindowCompat.setDecorFitsSystemWindows(window, false)
, I have that turned on in my Activity. But I've just been experimenting with this in a single file with an @Preview and then hitting the little "Run Preview" option at the top right of the preview screen in split mode. I'm unclear of how that option conditions the activity wrapping around the preview screen.
It must NOT do that, because when I modify my MainActivity to launch the KeyboardExpScreen, it all gets hidden, because I've not eaten up the systemBars padding. 🙂
Another interesting artifact of "coded into an Activity" vs "Run Preview" is that the color switching now works?! Gaining a distrust of this Run Preview tool now..
s
I really don't know how that preview works, but I highly doubt it's propagating window insets properly as that's a very per-device specific thing. What insets would it even use, isn't that preview a window without anything like system bars etc?
t
I think it just goes with whatever the "defaults" are. And since we have to add code to setDecor... that's not a default.
Thank you for the bit on the height adjustment. It took me a bit to understand why my divider got so big per your first code. What I think happens, is that the way the keyboard exposure works, is that it resizes the screen such that the target input field remains inside the visible rectangle. So we basically have to back out our distance from the bottom. That seems convoluted to me and unfortunate. Ultimately, my field might be in a scrollable column so I don't know how far it is currently from the bottom of the screen. But sticking with experiment, I thought that if I changed my windowSoftInputMode to
adjustNothing
, then it would behave as expected, without having to back out/accomodate the movement caused by the resize. Unfortunately, that makes no real difference on this S20. It behaves as if the two modes are the same. Or if it is different, it's not apparent how they're differing.
s
No, don’t change that, keep adjustResize, I’ve heard that being the correct suggestion various times in this channel https://kotlinlang.slack.com/archives/CJLTWPH7S/p1678484416932819?thread_ts=1678303192.301849&cid=CJLTWPH7S And no, what happens isn’t that it resizes the screen such as that the input field remains inside the visible rectangle, at least it doesn’t do it in this case when you are not inside a scrollable container anyway. What happens is more straightforward than that. The window insets that you get back from
WindowInsets.ime.getBottom(this).toDp()
is literally the DP value of how hight the IME is. So your divider then is starting from the bottom and it goes as high as it does because: + 40dp higher than the bottom since there is another divider down there + 40dp more since it has the height of 40dp itself + the IME height, however much that is. So it ends up being as high as the IME is +80dp, and with that you get the image here https://kotlinlang.slack.com/archives/C04TPPEQKEJ/p1682681469774739?thread_ts=1682634176.948959&cid=C04TPPEQKEJ Hence consuming 80dp of that from the insets fixes this and makes it go exactly above the IME.
a
When you run a
@Preview
on a device, it embeds it in this `PreviewActivity`: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]Activity.kt;l=49;drc=66e8c2d5eaf727c44779ddb7bc4e0298e4d7b1d0 For most composables that’s fine, but yeah when behavior is dependent on window flags it can be a bit confusing, since that activity won’t have
windowSoftInputMode
adjustments or
WindowCompat
calls.
today i learned 1
t
I posted a "taken to the next level" question on SO for this subject: https://stackoverflow.com/questions/76133723/can-a-compose-lazylist-be-scrolled-to-adjust-for-keyboard
It has more pictures 😄
124 Views