9

When I click on TextField, I need to scroll UI upwards to show login button to the user and not hide it behind keyboard.

I am using RelocationRequester for the same.

I am using this for detecting keyboard show/hide event:

fun listenKeyboard() { val activityRootView = (requireActivity().findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) activityRootView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { private var wasOpened = false private val DefaultKeyboardDP = 100 private val EstimatedKeyboardDP = DefaultKeyboardDP + 48 private val r: Rect = Rect() override fun onGlobalLayout() { val estimatedKeyboardHeight = TypedValue .applyDimension( TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP.toFloat(), activityRootView.resources.displayMetrics ) .toInt() activityRootView.getWindowVisibleDisplayFrame(r) val heightDiff: Int = activityRootView.rootView.height - (r.bottom - r.top) val isShown = heightDiff >= estimatedKeyboardHeight if (isShown == wasOpened) { return } wasOpened = isShown keyboardVisibleState(isShown) } }) } 

and once the keyboard is visible, I am calling the relocationRequestor's bringIntoView().

coroutineScope.launch { delay(250) relocationRequester.bringIntoView() } 

Its behaving randomly, working on some devices and not on others. Is there any better solution to deal with this issue?

1
  • 1
    WindowInsets.isImeVisible Commented Jan 17, 2023 at 22:11

3 Answers 3

14

Since Compose 1.2.0, Accompanist Insets was mostly moved into Compose Foundation, check out migration guide for more details. The main changes to below answer is that ProvideWindowInsets is no longer needed and some imports should be replaced.


You can use accompanist insets. You'll be able to check if keyboard is presented using LocalWindowInsets.current.ime.isVisible or add .imePadding() to your screen container.

This works great. But to make it work you'll have to disable window decor fitting:

This library does not disable window decor fitting. For your view hierarchy to able to receive insets, you need to make sure to call: WindowCompat.setDecorFitsSystemWindows(window, false) from your Activity. You also need to set the system bar backgrounds to be transparent, which can be done with our System UI Controller library.

If you don't want to do this, you will have to look for another solution.


Example in onCreate:

WindowCompat.setDecorFitsSystemWindows(window, false) setContent { ProvideWindowInsets { ComposePlaygroundTheme { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .fillMaxWidth() .statusBarsPadding() .navigationBarsWithImePadding() .padding(10.dp) ) { TextField(value = "", onValueChange = {}) Spacer(Modifier.weight(1f)) Button(onClick = {}) { Text(text = "Proceed") } } } } } 


p.s. Also this won't help with lazy views: it's gonna decrease container size, but won't scroll to selected item. Waiting this issue to be resolved

Sign up to request clarification or add additional context in comments.

4 Comments

By lazy views, you mean this won't work with LazyColumn?
@Ali_Waris yes, as I've said this modifier will work - it'll decrease view size, but it won't change scroll position, so visually there'll be no effect. Have to wait for compose maintainers to make some workaround. As a tmp solution you can try listen to LocalWindowInsets.current.ime.isVisible and scroll to item by index.
LocalWindowInsets.current.ime.isVisible Even listening for this, do I have to disable the window decor fitting?
@Ali_Waris yes.
6

Edit July 2024:

WindowInsets.isImeVisible, imeAnimationSource and imeAnimationTarget can be used nowadays.

See below for the March 2022 answer.


As the insets from accompanist are deprecated, the ones at androidx.compose.foundation should be used.

I was able to use WindowInsets.Companion.ime.getBottom(LocalDensity.current) > 0 to check whether the IME is shown or not. Otherwise Modifier.imePadding() can also be used if it fits your usecase better. I am not exactly sure whether this properly works for landscape mode & other weird keyboard combinations, but it seems to work in portrait mode with a "bottom" keyboard.

The "official" API for this is still in the Feature Request stage, it's on the issue tracker: https://issuetracker.google.com/issues/217770337

2 Comments

If you use Modifier.imePadding(), remember to add android:windowSoftInputMode="adjustResize" in the manifest.
the manifest part is fundamental to make it work, thanks @Pitos for pointing out!
0

You can also just add the following line to your Manifest in the activity part :

android:windowSoftInputMode="adjustResize"

Like in this example:

 <activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.MyApp"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="android.app.lib_name" android:value="" /> </activity> 

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.