react-native
react-native copied to clipboard
KeyboardAvoidingView mistakingly adds white space on screen bottom after being untangled
[Description]
I wrapped a view as a footer inside KeyboardAvoidingView. It works properly before the keyboard has been untoggled. However, after the keyboard is untoggled, it adds a white space on the bottom of the screen. The height of the white space is as big as the keyboardVerticalOffset. This white space shouldn't exist.
React Native version:
System: OS: macOS 10.15.6 CPU: (8) x64 Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz Memory: 28.43 MB / 16.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 12.18.1 - /usr/local/bin/node Yarn: Not Found npm: 6.14.5 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.9.3 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2 Android SDK: Not Found IDEs: Android Studio: Not Found Xcode: 11.6/11E708 - /usr/bin/xcodebuild Languages: Java: 14.0.1 - /usr/bin/javac Python: 2.7.16 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: ~16.11.0 => 16.11.0 react-native: https://github.com/expo/react-native/archive/sdk-38.0.1.tar.gz => 0.62.2 npmGlobalPackages: react-native: Not Found
Steps To Reproduce
Provide a detailed list of steps that reproduce the issue.
- Use KeyboardAvoidingView, set keyboardVerticalOffset to any value
- Put a view inside KeyboardAvoidingView, set the position as absolute, and set the bottom to 0
Expected Results
The white space for keyboardVerticalOffset should only exist when the keyboard is toggled.
Snack, code example, screenshot, or link to a repository:
<KeyboardAvoidingView
behavior={Platform.OS == "ios" ? "padding" : "height"}
keyboardVerticalOffset={48}
style={{width: "100%",
height: "100%",
position: "absolute",
zIndex: 1,}}
>
<View
style={{width: "100%",
position: "absolute",
height: 56,
bottom: 0,}}
>
<SubmitButton/>
</View>
</KeyboardAvoidingView>
This looks similar to the sample for KeyboardAvoidingView. We're having trouble reproducing your snippet in a Snack. Mind helping refine this so we can get the repro? Have this so far, which more like the docs sample has the page content as well as the button inside the KeyboardAvoidingView.
Thanks for responding and creating this snack. I just tried what you created. Try to add this prop
keyboardVerticalOffset={100}
to KeyboardAvoidingView and run it on iOS. You'll see how the button is pushed up after the keyboard gets toggled then dismissed. It works properly in Android.
hey, guys, the same issue here, did you solve it?
I'm having same trouble. In this example, when my screen is fit and no need to scroll it works perfectly. But when my screen has scrollable content, it adds white spaces in every input focusing under the <Button>
component.
Note: With padding
IOS
platform works perfect.
Multiple input with behavior: "height"

Multiple Input with behavior: "padding"
Only one Input with behavior: "height"


My example Code:
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={Platform.OS === 'ios' ? (isIphoneX() ? 88 : 64) : StatusBar.currentHeight + 50} // 50 is Button height
enabled>
<ScrollView contentContainerStyle={{ flexGrow: 1 }} keyboardShouldPersistTaps={'handled'}>
<Input />
</ScrollView>
<Button
onPress={() => {}}
style={{ justifyContent: 'flex-end' }}
text={"Confirm"}
/>
</KeyboardAvoidingView>
I need a help for general solution. 🚀
@keremcubuk Did you find a solution?
Here's my solution, I can't promise it will work for everyone and in all situations but it's working where it needs to in my current project, it involves replacing 'flex: 1' with the window height minus the status bar height and setting the behavior to position. Hope it helps.
<KeyboardAvoidingView
behavior="position"
style={{
height: Platform.OS === 'android' ? Dimensions.get('window').height - StatusBar.currentHeight : '100%',
alignItems: 'center',
}}
>
....
</KeyboardAvoidingView>
Thanks F3WS, but that solution not working for me. Anyone had any success using different workaround?
any solution?
facing the same problem, did anyone find a solution?
Any solution?
In my case I added behavior={isAndroid ? 'height' : 'position'}
and also needed to add different keyboardVerticalOffset
for android, iPhoneX and normal iPhone
const calculateKeyboardVerticalOffset = () => {
if (isAndroid) return StatusBar.currentHeight;
if (isIphoneX()) return -100;
return 0;
};
<KeyboardAvoidingView
behavior={isAndroid ? 'height' : 'position'}
enabled
keyboardVerticalOffset={calculateKeyboardVerticalOffset()}
>
Hope this helps @talaviad5
@annaostapenko22 still doesn't work, but thanks
i fixed it too with
const additionHeight=Platform.OS=='ios'?0:StatusBar.currentHeight;
<KeyboardAvoidingView behavior={(Platform.OS === 'ios') ? "margin" :'padding'} contentContainerStyle={{ flex: 1 }} keyboardVerticalOffset={Platform.select({ios: 2, android: -additionHeight})}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'} keyboardVerticalOffset={-900}
this will fix your issue
still have the issue, any solution ?
Still not resolved.
import {
KeyboardAvoidingView,SafeAreaView,TouchableWithoutFeedback,....
} from 'react-native';
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={(Platform.OS === 'ios') ? "padding" : null}
keyboardVerticalOffset={Platform.select({ios: 80, android: 500})} enabled>
<SafeAreaView style={styles.container}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={{flex:1,padding:20}}>
<TextInput maxLength={50} value={this.getVal('name')} onChangeText={(txt)=>{
....
}}
</View>
</TouchableWithoutFeedback>
</SafeAreaView>
</KeyboardAvoidingView>
Edit your AndroidManifest.xml
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:windowSoftInputMode="adjustResize"
android:exported="true"
>
this will do the job
I had same issue and my style for KAV was:
flex: 1
Inner ScrollView
had flex: 1
too.
Just changing KAV style to flexGrow: 1
fixed the issue.
i replace my keyboardavoidingview with
https://github.com/APSL/react-native-keyboard-aware-scroll-view
and solved.
I'm facing the same issue.
I'm facing the same issue only on iOS. It adds a lot of whitespace at the bottom of a ScrollView and every time I blur and focus on the input again, it adds even more whitespace.
I think this is a major bug that needs to be addressed. The whitespace needs to be removed after the keyboard hides.
Try to set the behavior on iOS as "height"
@abumubarak-dev height not working as excepted also
Who know workaround? Because i have problem only when keyboard open and then hide. Empty space equal keyboardVerticalOffset not removed
running into this issue too. Appears in sample code too
import React from 'react';
import {
View,
KeyboardAvoidingView,
TextInput,
StyleSheet,
Text,
Platform,
TouchableWithoutFeedback,
Button,
Keyboard,
} from 'react-native';
const KeyboardAvoidingComponent = () => {
return (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={500}
style={styles.container}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.inner}>
<Text style={styles.header}>Header</Text>
<TextInput placeholder="Username" style={styles.textInput} />
<View style={styles.btnContainer}>
<Button title="Submit" onPress={() => null} />
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
inner: {
padding: 24,
flex: 1,
justifyContent: 'space-around',
},
header: {
fontSize: 36,
marginBottom: 48,
},
textInput: {
height: 40,
borderColor: '#000000',
borderBottomWidth: 1,
marginBottom: 36,
},
btnContainer: {
backgroundColor: 'white',
marginTop: 12,
},
});
export default KeyboardAvoidingComponent;
I added in app.json
"android": { "softwareKeyboardLayoutMode": "pan" }
It solved
I frequently encounter this bug and am forced to use react-native-keyboard-aware-scroll-view, but it doesn't work in all situations (like if I want to nest virtualized lists). It's hard to believe this core component is still so buggy.
Potentially related, I frequently run into keyboard dismissal bugs like this in apps from the iOS App Store on my iPhone 12 mini (including big names like Discord, which is known to be mostly built in React Native). Super frustrating stuff.
I did a little more digging. While debugging I noticed that on keyboard close, the event received from iOS (keyboardWillChangeFrame) incorrectly returns (0, 0) as the new coordinates of the keyboard. The correct value (if using the same coordinate system as RN) should be (0, screen height). As a result, this throws off the bottom height calculation done here, resulting in the view's content being pushed up significantly.
It's possible that this would be fixed by changing RN's native bridge code to instead use UIKeyboardLayoutGuide as recommended in Apple's docs.
I don't know if I'll have time to post a PR for that myself, but it would be awesome if someone could try that out.
I had same issue and my style for KAV was:
flex: 1
Inner
ScrollView
hadflex: 1
too. Just changing KAV style toflexGrow: 1
fixed the issue.
This fixed it for me, and it's so much nicer than adding some extra library 🔥 Thanks!

I faced a similar issue and I'll share my solution here in case this helps anyone.
Context
Note: this only happened in iOS (not Android).
In my case, when the keyboard was visible and I clicked a CTA to go to the next screen, I would get the extra white space (equal to the KeyboardAvoidingView
's keyboardVerticalOffset
) at the bottom of the next screen.
Clicking on the CTA dismissed the keyboard, however while the keyboard was still being dismissed the navigation to the next page started (calling push
from solito/router
). Basically, the user arrived at the next screen while the keyboard was not fully dismissed. Therefore it seems the KeyboardAvoidingView
kept applying the keyboardVerticalOffset
even though the keyboard was eventually dismissed.
In fact, waiting for the keyboard to be dismissed before navigating to the next screen solved the issue. As did wrapping the call to router.push
in a setTimeout
(with even just a 50ms
delay).
Solution
The main idea is to disable the KeyboardAvoidingView
as soon as we know the keyboard will be hidden:
export const MyKeyboardAvoidingView = ({ behavior, children }: Props) => {
const headerHeight = useHeaderHeight()
const [enabled, setEnabled] = useState(false)
useEffect(() => {
const showSubscription = Keyboard.addListener('keyboardWillShow', () => {
setEnabled(true)
})
const hideSubscription = Keyboard.addListener('keyboardWillHide', () => {
setEnabled(false)
})
return () => {
showSubscription.remove()
hideSubscription.remove()
}
}, [])
return (
<KeyboardAvoidingView
behavior={behavior}
enabled={enabled}
keyboardVerticalOffset={headerHeight}
>
{children}
</KeyboardAvoidingView>
)
}