67

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

73

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 } 
Sign up to request clarification or add additional context in comments.

9 Comments

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.
I don't think "true" is a possible value for this field (which is misspelled)
this is the correct answer , no need any more to 3rd library ... tested right now, imePadding do the job very well
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
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...
|
41

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 Comments

It did the trick, android:windowSoftInputMode="adjustResize" (that which you hinted at) works as well. Thank you very much!
Setting the flag in the manifest is the same as setting it in code just your preference I guess.
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.
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 ?
SOFT_INPUT_ADJUST_RESIZE is deprecated, any updates on that?
|
24

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 Comments

I only used ProvideWindowInsets(windowInsetsAnimationsEnabled = true) in a Jetpack compose TextField as explained in the answer and it worked for me.
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.
it's not for sroll layouts
What if in 1 compose screen I want to adjust resize and in another not?
9

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 Comment

imePadding() also requires .fillMaxHeight()
6

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

Comments

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

Comments

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

Comments

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.

Comments

2
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.

Comments

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" 

Comments

-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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.