react-native: Bug in KeyboardAvoidingView on Android
Description
Hi, there is a problem with KeyboardAvoidingView on Android which is best presented by the screenshots below:
Without keyboard:
With keyboard:
It just adds too much padding to the view. On iOS it works correctly. I’ve also tried different behaviors: height
, position
but with the same effect.
Reproduction
Here is my JSX:
<KeyboardAvoidingView behavior="padding" style={{
flex: 1
}}>
<View style={{
flex: 0,
height: 50,
backgroundColor: 'skyblue'
}}>
<Text>Header</Text>
</View>
<ScrollView style={{
flex: 2,
padding: 10
}}>
<Text>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</Text>
</ScrollView>
<View style={{
flex: 0,
height: 50,
backgroundColor: 'orange'
}}>
<TextInput
style={{
marginLeft: 10,
height: 50
}}
ref="input"
placeholder="Your message here..."
returnKeyType="send"
underlineColorAndroid="transparent"
/>
</View>
</KeyboardAvoidingView>
Additional Information
- React Native version: 0.39.2
- Platform: Android
- Operating System: MacOS
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 97
- Comments: 77 (3 by maintainers)
Hey Guys
My solution is very simple. KeyboardAvoidingView is englobing my
<Router>
and writen just one time in my application See below:I got bitten by this on android. My workaround was to edit
AndroidManifest.xml
:And only use
KeyboardAvoidingView
on iOS. YMMV. Would of course be very nice if KeyboardAvoidingView worked perfectly on both platforms 😃.The only solution I found for now is to define keyboardVerticalOffset and put everything in a ScrollView
keyboardVerticalOffset={-500}
For me, if I don’t specified
behavior
props on Android, it works !For me it was solved using
const offset = (Platform.OS === 'android') ? -200 : 0;
and thenkeyboardVerticalOffset={offset}
to adjust the keyboard` spacing.This is fixed/explained in the upcoming release (v0.42) of RN https://github.com/facebook/react-native/commit/e3d4ace3ae46e3e4046e1ec5a201b92033deb24a
I’m on 0.53.0… I hate bots.
Thanks for posting this! It looks like you may not be using the latest version of React Native, v0.53.0, released on January 2018. Can you make sure this issue can still be reproduced in the latest version?
I am going to close this, but please feel free to open a new issue if you are able to confirm that this is still a problem in v0.53.0 or newer.
How to Contribute • What to Expect from Maintainers
@eflath I’ve got it working quite nicely with a react navigation TabNavigator:
android:windowSoftInputMode="adjustPan"
I don’t yet understand why 25 works. My tab bar is 50. I’m half anticipating finding out that it shouldn’t be 25 and should be something else, but atm it seems to work.
@djw27 that fix does not solve a problem 😕
For me works by passing
null
to android:behavior={Platform.OS === 'ios' ? 'padding' : null}
Needs to be reopened as this issue is present in 0.53.0
As I said in https://github.com/facebook/react-native/issues/11681#issuecomment-360712806, we cannot keep on using black magic platform-dependant tricks to develop applications in this framework which is supposed to be platform seamless, this issue #2852 has to be re-opened.
If opening keyboard with the setting
android:windowSoftInputMode="adjustNone"
fires keyboard events, then,KeyboardAvoidingView
components could catch them and resize anyView
regardless of the platform and without keeping glitch exploits in the code. This is the proper way of handling this issue.Same issue here, keyboard avoiding view seems a bit unpredictable - probably the biggest pain point faced with core react native right now. Setting null behaviour for android and an arbitrary padding for ios has given me the result I wanted in the end
I’ve noticed that not specifying
behavior
will get different results from explicitly setting any one of the three behaviors mentioned on the doc page.OK. Please, stop commenting Expo code “solutions” since the problem comes only from native projects. The problem is that on iOS the keyboard “hovers” the app so you need a
KeyboardAvoidingView
to resize the viewport, BUT in Android, theandroid:windowSoftInputMode="adjustResize"
property does it automatically. Usingandroid:windowSoftInputMode="adjustPan"
only pans the viewport to avoid the kayboard andandroid:windowSoftInputMode="adjustNone"
does nothing AND does not fire Keyboard events in opposite of the previous two, which is problematic. That’s the reason you disable theKeyboardAvoidingView
in Android but not on iOS using a ternary like in https://github.com/facebook/react-native/issues/11681#issuecomment-320236475 and useandroid:windowSoftInputMode="adjustResize"
for the moment.EDIT: There is an issue #2852 (also #9640) for that specific problem that would resolve everything, it needs to be re-opened.
I ended up using
<KeyboardAvoidingView keyboardVerticalOffset={-200}>
and changing in theAndroidManifext.xml
android:windowSoftInputMode="adjustPan"
It is by no means a fix, but have you tried making your own KeyboardAvoidingView? I had to create a chatview for a project of mine and it works like a charm, maybe this will help you:
Of course you will still need to implement
Keyboard.removeListener
oncomponentWillUnmount
.note the:
Funny enough, when I tried to use
paddingBottom
for Android, I recreated the same bug as the react-native KeyboardAvoidingView that @jagi adresses. I think this has something to do with the fact thatandroid:windowSoftInputMode
in AndroidManifest.xml is set to"adjustResize"
by default now. e3d4ace3ae46e3e4046e1ec5a201b92033deb24aFor those wondering, there is an “enabled” prop that can be used to disable the component on specific platform
<KeyboardAvoidingView ... enabled={Platform.OS === 'ios'} />
Really hope this gets prioritised - keyboard handling is always such a nightmare
Using
behavior={(Platform.OS === 'ios') ? 'padding' : null}
as commented above solved the problem for me.@martinezguillaume it doesn’t quite work the same without the behavior prop. It only looks right if KeyboardAvoidingView is a full-screen view. If the KeyboardAvoidingView is nested in a view with a tabbar fixed to the bottom, for instance, the intended behavior is for the keyboard to hide the tab bar and push up the KeyboardAvoidingView. This works on iOS (with behavior=‘padding’ ) but does not work if you remove the behavior prop (on either platform)
Even stranger fix.
If I don’t set a container view for Android it works but breaks on iOS. Opposite is true if I do use a container view.
For example:
I got the same error and this saved me:
Change those values to fit your necessities on your platform, whether android or iOS
Here’s what we’re doing for our cross-platform solution. it’s been working fine for a long while:
In place of KeyboardAvoidingView, we use our own component that looks like
Then make sure In the AndroidManifest.xml you have
So in other words we’re using the react-native KeyboardAvoidingView for iOS but a plain old view on Android. As others have mentioned, the components who use the KeyboardAvoidingView should be the ones inside the Tab Navigator. This way the padding will be applied to the child page and the keyboard will properly cover the tabbar.
In my case, I was wrapping a login form in a
KeyboardAvoidingView
. Everything is working fine on IOS but the padding is too much on Android. I solved this by providing a wrapper component like this:And then wrapped my form content in this wrapper:
And the padding looks perfect on both devices. Not sure if this works in other cases though.
Android is working out of the box for us, no keyboardAvoidingView used or change to manifest.xml
Solution we’re using is - Component file having a separate
.ios.js
version withAnd just to be safe - make the change in Android’s manifest.xml, adding
android:windowSoftInputMode="adjustPan"
Going to test this thoroughly but initially seems good
I had the same problem. The bug was solved after removing
keyboardDidShow
andkeyboardDidHide
listeners.If adjustNothing would fire the events, that would be great, since we don’t have to keep a ternary in the KeyboardAvoingView behavior and keep the same keyboard behavior in the whole app
Seems RN has a few ways to solve this, such as changing the KeyboardAvoidingView behavior to specify a negative
bottom
style in addition to height/padding, or making KeyboardAvoidingView work with the “adjustNothing” mode (currently it depends on Keyboard events that simply aren’t fired with “adjustNothing”).Until it’s fixed, the only stable solution appears to be using “adjustResize”, which of course causes other problems, e.g. when using a bottom navbar (the navbar will be resized along with everything else).
So… any updates about this?
android:windowSoftInputMode="stateAlwaysVisible"
<KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : null} enabled >...</KeyboardAvoidingView>
it’s works for me.
This is working for me on both Platforms:
Same here, when i added justifyContent:‘flex-end’ it worked
For me the reason where my styles.
If I gave the
<KeyboardAvoidingView />
the following styles:It didn’t work. But when I changed
justifyContent
tocenter
it works on Android!Same problem here, padding doubles height of the keyboard
In my case KeyboardAvoidingView with behavior=‘padding’ didn’t work. It look likes react-native uses twice the height of the keyboard. https://preview.ibb.co/n3xS3G/Schermafbeelding_2017_11_13_om_14_10_34.png
My app has a StackNavigator inside a TabNavigator
import { TabNavigator, StackNavigator } from 'react-navigation'
wrapped by Provider fromreact-redux
as main entry point. What worked for me was to wrap whatever the components (that are being routed by the StackNavigator or TabNavigator, the ones with the input text inside) were rendering, with only one KeyboardAvoidingView withbehavior='padding
and also make it the main container for that component. For example:Not sure why but my Android manifest.xml solution stopped working a few weeks ago, and nothing I try seems to bring back the adjustPan behavior I want.
How great and React-like would it be if Keyboard just exposed some kind of dead-simple State boolean that we could rely on in layouts.
@clovs This actually worked ! , however to run successfully on android I needed to change behavior to “padding” in both platforms
behavior= {"padding"}
I encounter the exam same problem. Have you found a fix? I use React Native 0.40.0