65

Suppose I have some activity with a jetpack-compose content

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ScrollableColumn(
                modifier = Modifier
                    .fillMaxSize()
                    .border(4.dp, Color.Red)
            ) {
                val (text, setText) = remember { mutableStateOf("") }

                TextField(
                    value = text,
                    onValueChange = setText,
                    label = {},
                    modifier = Modifier
                        .fillMaxWidth()
                )

                for (i in 0..100) {
                    Text("Item #$i")
                }
            }
        }
    }

}

If I were to launch this activity and focus on the TextField a software keyboard would pop up.

The interface, however, would not react to it. ScrollableColumn's bottom border (.border(4.dp, Color.Red)) would not be visible, as well as 100th item (Text("Item #$i")).

In other words, software keyboard overlaps content.

How can I make jetpack compose respect visible area changes (due to software keyboard)?

11 Answers 11

69

Besides Compose, no external libraries are needed for this now. Set android:windowSoftInputMode=adjustResize on the activity in your manifest file

e.g.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application>
        <activity
            android:name=".MyActivity"
            android:windowSoftInputMode="adjustResize"/>
    </application>

</manifest>

Then for the composable that you want the UI to react to, you can use Modifier.imePadding() which reacts to IME visibility

Box(Modifier.imePadding()) {
  // content
}
9
  • Hello In my case, I have to handle both the scenario in my project: Example: Case 1: Need to resize the screen (AdjustResize) Case 2: No need to resize the screen (AdjustResize) If we give this in the manifest and activity how can I handle these two scenarios in my project: Note: Assume that both are different composes and screens. Commented Oct 28, 2022 at 5:39
  • I don't think "true" is a possible value for this field (which is misspelled) Commented Dec 26, 2022 at 17:01
  • 1
    this is the correct answer , no need any more to 3rd library ... tested right now, imePadding do the job very well
    – issamux
    Commented Jan 7, 2023 at 5:25
  • it means that you may forget about adding .imePadding() for each screens where keyboard can be shown... because with android:windowSoftInputMode="adjustResize" the system doesn't put the content above the keyboard automatically
    – user924
    Commented May 1, 2023 at 16:59
  • 1
    also what to do you if some screens may not have scrolling attribute (the content is adaptive)? but we set adjustResize for the whole activity, which means it effects all screens...
    – user924
    Commented May 1, 2023 at 17:22
38

You can use the standard android procedure, but I don't know if a Compose specific way exists.

If you set the SoftInputMode to SOFT_INPUT_ADJUST_RESIZE, the Layout will resize on keyboard change.

class YourActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        
        setContent { /* Composable Content */ }
    }
}

otherwise, you could use the flags in the manifest. See here for more information: Move layouts up when soft keyboard is shown?

15
  • 10
    It did the trick, android:windowSoftInputMode="adjustResize" (that which you hinted at) works as well. Thank you very much!
    – Nycta
    Commented Sep 25, 2020 at 2:44
  • Setting the flag in the manifest is the same as setting it in code just your preference I guess.
    – 2jan222
    Commented Sep 25, 2020 at 10:10
  • 3
    I think this only set bottom inset when keyboard popup, but the content could still not fully visible after keyboard popup, unless ScrollableColumn would keep the focus item scrolling to visible position.
    – Yu-Hsuan
    Commented Dec 19, 2020 at 15:53
  • 4
    thanks but on keyboard ime next button click, the text field still not visible, ie the scrollable column not scrolled, any idea how to solve this ?
    – Hoby
    Commented Jan 25, 2021 at 19:20
  • 8
    SOFT_INPUT_ADJUST_RESIZE is deprecated, any updates on that? Commented Apr 8, 2022 at 23:28
23

You can use Accompanist's inset library https://google.github.io/accompanist/insets

first use ProvideWindowInsets at the root of your composable hierarchy most of the time below your app theme compose and set windowInsetsAnimationsEnabled true

ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
// content  }

The use navigationBarsWithImePadding() modifier on TextField

OutlinedTextField(
// other params,
modifier = Modifier.navigationBarsWithImePadding() )

Finaly make sure to call WindowCompat.setDecorFitsSystemWindows(window, false) from your activity(inside onCreate). If you want Software keyboard on/off to animate set your activity's windowSoftInputMode adjustResize in AndroidManifests

<activity
  android:name=".MyActivity"
  android:windowSoftInputMode="adjustResize">
5
  • I only used ProvideWindowInsets(windowInsetsAnimationsEnabled = true) in a Jetpack compose TextField as explained in the answer and it worked for me. Commented Sep 5, 2021 at 21:36
  • works very good for me, the first answer was not enough for me since I had something below the text field which I wanted to move above keyboard too. Commented Sep 6, 2021 at 9:34
  • it's not for sroll layouts
    – jgnt32
    Commented Feb 25, 2022 at 12:46
  • What if in 1 compose screen I want to adjust resize and in another not? Commented Aug 5, 2022 at 11:05
  • 2
    Deprecated. See stackoverflow.com/a/74036164/4897831 Commented Jan 8, 2023 at 18:10
8

Use the modifier imePadding(). This will allow the specific compositions to adjust themselves when the keyboard pops up. This does not require you to set any flag on the activity

1
  • 4
    imePadding() also requires .fillMaxHeight() Commented May 4, 2023 at 11:46
5

I faced the same problem.

Use OnGlobalLayoutListener which will observe the actual IME rect size and will be triggered when the soft keyboard is fully visible.

Worked solution for me:

val bringIntoViewRequester = remember { BringIntoViewRequester() }
val scope = rememberCoroutineScope()
val view = LocalView.current
DisposableEffect(view) {
    val listener = ViewTreeObserver.OnGlobalLayoutListener {
        scope.launch { bringIntoViewRequester.bringIntoView() }
    }
    view.viewTreeObserver.addOnGlobalLayoutListener(listener)
    onDispose { view.viewTreeObserver.removeOnGlobalLayoutListener(listener) }
}
TextField(
    modifier = Modifier.bringIntoViewRequester(bringIntoViewRequester),
    ...
)

Origin here

4

Fix: Use Modifier.imePadding() on your main layout.

This adds automatic padding to push your content up, keeping it visible above the keyboard. It's like adding a spacer that grows with the keyboard size.

Example:

LazyColumn(modifier = Modifier.imePadding()) {
    TextField(...)
    
    ...
}
0
2

I came up with idea of using accompanist insets library.

Someone could be interested because my approach does not modificate the contents of an application.

I link my post below:

(Compose UI) - Keyboard (IME) overlaps content of app

2

In my case just adding android:windowSoftInputMode="adjustResize" to activity was enough to solve the problem.
It depends on how you build your UI. If yours screen's root is a vertically scrollable container or a Box, the keyboard resize might get managed automatically.

1
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

Is deprecated now in compose use below way for make screen resizable on keyboard Open.

First, add below code in your manifest (add in all activities if have more activities)

<activity
  android:name=".MyActivity"
  android:windowSoftInputMode="adjustResize"
/>

Now, in your views of screens where you want to resize add below:

Column(modifier = Modifier.imePadding()) {

}

Instead of column you can use Box, Row etc.

0

If you want your TextField scroll up when keyboard appears. The following it work for me. You need to add these

class YourActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    
    window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    
    setContent { /* Composable Content */ }
}

And add this to your app/build.gradle

implementation "com.google.accompanist:accompanist-insets-ui:0.24.7-alpha"
-1

In my edge-to-edge application I just use Spacer(8.dp + Modifier.height(WindowInsets.safeDrawing.asPaddingValues().calculateBottomPadding())) at the bottom of the screen. It adds padding for the navbar, or keyboard if it is open, to ensure that the bottom elements do not overlap.

It should also works in non-edge-to-edge apps.

Not the answer you're looking for? Browse other questions tagged or ask your own question.