react-native icon indicating copy to clipboard operation
react-native copied to clipboard

`KeyboardAvoidingView` do not keep input in view under Android 15 (target SDK 35)

Open dprevost-LMI opened this issue 10 months ago • 19 comments

Description

Under RN 0.77.1 and Android 15 with targetSdkVersion = 35, the KeyboardAvoidingView stopped working as expected. In the video below, we can see that clicking on the input brings the keyboard and makes the input disappear under the keyboard. However, just using targetSdkVersion = 34 fixed the issue.

Something is problematic under Android 15 SDK 35 and the KeyboardAvoidingView component.

Steps to reproduce

  1. Create an RN 77 project npx @react-native-community/cli init Rn77App --version 0.77.1
  2. Use an input wrapped in a KeyboardAvoidingView under the scroll view of the example app
  3. Make sure to use targetSdkVersion = 35
  4. Click on the input
  5. The input disappears under the keyboard
  6. Expected: The input moves up and stays in view, like when using targetSdkVersion = 34 or under RN 76

React Native Version

0.77.1

Affected Platforms

Runtime - Android

Output of npx @react-native-community/cli info

System:
  OS: macOS 15.3
  CPU: (12) arm64 Apple M2 Pro
  Memory: 1.65 GB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.20.4
    path: ~/.nvm/versions/node/v18.20.4/bin/node
  Yarn:
    version: 1.22.22
    path: ~/.nvm/versions/node/v18.20.4/bin/yarn
  npm:
    version: 10.7.0
    path: ~/.nvm/versions/node/v18.20.4/bin/npm
  Watchman:
    version: 2024.11.04.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /Users/dprevost/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.2
      - iOS 18.2
      - macOS 15.2
      - tvOS 18.2
      - visionOS 2.2
      - watchOS 11.2
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.2 AI-242.23726.103.2422.13016713
  Xcode:
    version: 16.2/16C5032a
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.13
    path: /usr/bin/javac
  Ruby:
    version: 3.3.3
    path: /Users/dprevost/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.0.1
    wanted: 15.0.1
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.77.1
    wanted: 0.77.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true

Stacktrace or Logs

None

Reproducer

https://github.com/dprevost-LMI/Rn77App

Screenshots and Videos

The below are from a physical Pixel 9

Working case under RN 76 Non-working case under RN 77 and SDK 35

https://github.com/user-attachments/assets/1463d622-c878-4291-8511-454abcc8b312

https://github.com/user-attachments/assets/1bc84f01-ecea-4ed4-b897-6a1bf378668f

dprevost-LMI avatar Mar 01 '25 14:03 dprevost-LMI

Facing same issue! Any solution or if anyone fixing it?

Acexhat avatar Mar 02 '25 08:03 Acexhat

facing same issue

JuEunSung avatar Mar 02 '25 11:03 JuEunSung

cc @alanleedev Could you briefly look into this one?

cortinico avatar Mar 03 '25 18:03 cortinico

Sorry for the delayed update. I was able to repro the issue but didn't have much chance to look into it yet.

alanleedev avatar Mar 10 '25 16:03 alanleedev

for me the issue was the react-native-safe-area-context library, i had recently updated from ^0.7.3 to 0.1.0.

once downgraded the issue was resolved

rizshivalli avatar Mar 16 '25 10:03 rizshivalli

Facing the same issue.

ashishmangukiya avatar Mar 30 '25 08:03 ashishmangukiya

https://github.com/software-mansion/react-native-screens/issues/1719 for me this helped. I created a patch for navigationBarColor so that it doesn't change how keyboard behave previously in the project. The reason it is related is because I have upgraded rn-screens, when upgrading to RN 0.77.0.

cdanielraducu avatar Apr 01 '25 14:04 cdanielraducu

The ~repo~ reproducable project is not having react-native-screen so if your issue is related to it, I suggest entering a new ticket!

dprevost-LMI avatar Apr 01 '25 14:04 dprevost-LMI

@dprevost-LMI, yes, sure! But this kind of bugs are hard to debug, so I guess people are coming firstly to ReactNative (myself included). But indeed I think the issue is not directly related to RN repo.

cdanielraducu avatar Apr 01 '25 15:04 cdanielraducu

Since Android API 35, I've noticed that adjustResize is no longer sufficient on its own, as described in this article. As an alternative, I set the IME padding manually in Kotlin, like

ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
   val innerPadding = insets.getInsets(
     WindowInsetsCompat.Type.ime()
 )
   rootView.setPadding(
     innerPadding.left,
     innerPadding.top,
     innerPadding.right,
     innerPadding.bottom)
   insets
}

Which worked fine. However, I think RN could perhaps handle this IME padding by default in KeyboardAvoidingView? I can make a PR if it's fine

sookcha avatar Apr 25 '25 05:04 sookcha

I'm facing same issues, It's working in android 14 devices, but not working in android 15.

Please resolve fast this issues.

iamnynvk avatar May 02 '25 18:05 iamnynvk

@cortinico @alanleedev Hi, any update on this? There’s a fix suggested in the comments that seems to work well. Would it be possible to get this implemented? Thanks!

CharlesGoto avatar May 05 '25 19:05 CharlesGoto

@cortinico @alanleedev Hi, any update on this? There’s a fix suggested in the comments that seems to work well. Would it be possible to get this implemented? Thanks!

If someone could send a PR with the fix, we could look into it

cortinico avatar May 07 '25 13:05 cortinico

Same problem here, not working in android 15

MGS-DEV avatar May 09 '25 14:05 MGS-DEV

Any update to this issue?

devyeshtandon avatar May 15 '25 13:05 devyeshtandon

For those using React Navigation (which I assume includes most of us), this approach might help resolve your KeyboardAvoidingView issues — especially on Android 15.

Do not wrap your individual components with <KeyboardAvoidingView>. Instead, wrap the entire <Tab.Navigator> with it.

Here’s what worked for me:


import { KeyboardAvoidingView, Platform } from 'react-native';

function TabNavigator() {
  return (
    <KeyboardAvoidingView
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      style={{ flex: 1 }}>
      <Tab.Navigator
        screenOptions={{
          headerShown: false,
        }}>
        <Tab.Screen name="Tab" component={StackContainer} />
      </Tab.Navigator>
    </KeyboardAvoidingView>
  );
}
"dependencies": {
    "@react-navigation/elements": "2.4.2",
    "@react-navigation/native": "^7.1.9",
    "@react-navigation/native-stack": "^7.3.13",
}

cl3i550n avatar May 20 '25 15:05 cl3i550n

Adding padding to bottom of the scrollview(only for android 15) on keyboard show/hide with keyboardAvoidingView(for android 14 and below) did the job for me.

import { useEffect, useState } from 'react';
import { Keyboard, Platform } from 'react-native';

export const useKeyboard = () => {
  const [keyboardHeight, setKeyboardHeight] = useState(0);

  useEffect(() => {
    function onKeyboardDidShow(e) {
      setKeyboardHeight(e.endCoordinates.height);
    }

    function onKeyboardDidHide() {
      setKeyboardHeight(0);
    }

    const showSubscription = Keyboard.addListener(
      'keyboardDidShow',
      onKeyboardDidShow,
    );
    const hideSubscription = Keyboard.addListener(
      'keyboardDidHide',
      onKeyboardDidHide,
    );

    return () => {
      showSubscription.remove();
      hideSubscription.remove();
    };
  }, []);

  if (Platform.Version <= 34) {
    return 0;
  }

  return keyboardHeight;
};

kanthvagale avatar May 21 '25 07:05 kanthvagale

@sookcha Thanks for sharing this fix. Since the RN team is asking for a PR, would you be able to open one with your solution?

CharlesGoto avatar May 22 '25 17:05 CharlesGoto

The above suggested change works for me too. I had to make that change in MainActivity.kt

import android.os.Build
import android.view.View
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

override fun onCreate(savedInstanceState: Bundle?) {
    RNBootSplash.init(this, R.style.BootTheme)
    super.onCreate(null)
    
    if (Build.VERSION.SDK_INT >= 35) {
        val rootView = findViewById<View>(android.R.id.content)
        ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
          val innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime())
          rootView.setPadding(
            innerPadding.left,
            innerPadding.top,
            innerPadding.right,
            innerPadding.bottom
          )
          insets
      }
    }
  }

vishalenrique avatar May 29 '25 10:05 vishalenrique

If you are still facing this issue, check whether the screen is from a stack navigator. Make sure you have wrapped your stack navigator inside a KeyboardAvoidingView, like this:

<KeyboardAvoidingView>
  <Stack.Navigator>...</Stack.Navigator>
</KeyboardAvoidingView>

mangBert avatar Jul 09 '25 21:07 mangBert

Chiming in for others who may be facing a similar issue: the ViewCompat.setOnApplyWindowInsetsListener workaround suggested here and here mostly worked for us. However, we also use Braze in-app messages, which overrides the same listener on the root View and thus nullifies the fix.

So, if you find that this fix does not work for you, it could be because something else is overriding the setOnApplyWindowInsetsListener on the root view. We ended up trying a fairly blunt hack to re-override the listener in Activity.onUserInteraction() as well. However, it seems like anything calling setOnApplyWindowInsetsListener risks conflicting with other callers and breaking something else, and I'm not sure how to mitigate that risk.

kbweaver avatar Jul 11 '25 14:07 kbweaver

I'm happy to look for a possible fix and contribute one, if someone can provide a reproducer for the latest main or v0.81.0-rc.1

volo-droid avatar Jul 20 '25 18:07 volo-droid

I tried both upgrading my existing project and a new one using the below command, but in both cases, I ended up with the same error (see below). I'll try again later

npx @react-native-community/cli init rn-81-rc1 --version 0.81.0-rc.1

Git/rn81rc1/node_modules/.generated/launchPackager.command ; exit;
error (0 , _util.styleText) is not a function.
TypeError: (0 , _util.styleText) is not a function
    at Object.runServer [as func] (/Git/rn81rc1/node_modules/@react-native/community-cli-plugin/dist/commands/start/runServer.js:74:25)
    at async Command.handleAction (/Git/rn81rc1/node_modules/@react-native-community/cli/build/index.js:139:9)
Process terminated. Press <enter> to close the window

dprevost-LMI avatar Jul 21 '25 00:07 dprevost-LMI

in styles.xml file path android/app/src/main/res/values/styles.xml just add this line, will fix

<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>

Note: No need to use react-native-safe-area-context

zahid502 avatar Aug 06 '25 19:08 zahid502

in styles.xml file path android/app/src/main/res/values/styles.xml just add this line, will fix

<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>

Note: No need to use react-native-safe-area-context

FYI https://developer.android.com/about/versions/16/behavior-changes-16. You will have to fix that when targeting 36

Image

roni-castro-shipt avatar Aug 07 '25 19:08 roni-castro-shipt

@roni-castro-shipt

Updated project configurations to support Android API Level 36 and improvements for keyboard handling I also tested with api 35

ext {
        buildToolsVersion = "36.0.0" 
        minSdkVersion = 24
        compileSdkVersion = 36
        targetSdkVersion = 36
        ndkVersion = "27.1.12297006" 
        kotlinVersion = "2.0.21"
    }

In my case For Android 15 (API Level 35), avoided using <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> due to layout issues caused by images in the status bar. Instead, I implemented the following Kotlin code to handle keyboard padding in MainActivity.kt

if (Build.VERSION.SDK_INT >= 35) {
    val rootView = findViewById<View>(android.R.id.content)
    ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
      val innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime())
      rootView.setPadding(
        innerPadding.left,
        innerPadding.top,
        innerPadding.right,
        innerPadding.bottom
      )
      insets
    }
}

This code resolves the keyboard issue and ensures proper padding for keyboard input in API Level 35 and 36.

After extensive testing, I found that API Level 36 works fine without the need for the <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> property in the styles.xml file. The app layout and design render correctly with safe area insets and no padding issues.

iOS Platform Considerations:

KeyboardAvoidingView may not work consistently in some cases on iOS, so it's recommended to use KeyboardAwareScrollView for better handling of keyboard input across both platforms.

SafeAreaView from react-native-safe-area-context is utilized to handle the safe areas for all screens, and I’ve used multiple solutions to ensure the app UI works across Android and iOS without issues.

Additional Notes:

If you encounter issues after changing the Gradle version, such as build errors, it is recommended to delete the .gradle folder from your project’s root directory and re-sync the Gradle dependencies.

Image

https://github.com/user-attachments/assets/2a4bedb4-d769-40fb-8538-2a26e84df488

zahid502 avatar Aug 08 '25 18:08 zahid502

@volo-droid please share we have a fix planned in any of the react native release.

ravindraguptacapgemini avatar Aug 13 '25 11:08 ravindraguptacapgemini

I tried both upgrading my existing project and a new one using the below command, but in both cases, I ended up with the same error (see below). I'll try again later

npx @react-native-community/cli init rn-81-rc1 --version 0.81.0-rc.1

Git/rn81rc1/node_modules/.generated/launchPackager.command ; exit;
error (0 , _util.styleText) is not a function.
TypeError: (0 , _util.styleText) is not a function
    at Object.runServer [as func] (/Git/rn81rc1/node_modules/@react-native/community-cli-plugin/dist/commands/start/runServer.js:74:25)
    at async Command.handleAction (/Git/rn81rc1/node_modules/@react-native-community/cli/build/index.js:139:9)
Process terminated. Press <enter> to close the window

@dprevost-LMI did you find a resolution this? I'm having the same issue

moulie415 avatar Aug 14 '25 20:08 moulie415

@moulie415 nope, I did not retry yet either! Good luck

dprevost-LMI avatar Aug 14 '25 20:08 dprevost-LMI

@dprevost-LMI ok updating from node 20.9.0 to latest stable worked for me. I only realised it was a node issue when I was going through the bug submission process, the "reproducer app" flagged that my node version was incompatible but that didn't happen in my project or in a fresh RN project so sounds like it could still be an issue

moulie415 avatar Aug 15 '25 08:08 moulie415