-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KeyboardAvoidingView mistakingly adds white space on screen bottom after being untangled #29614
Comments
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 |
hey, guys, the same issue here, did you solve it? |
@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.
|
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
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' ? 'padding' : 'height'} this will fix your issue |
still have the issue, any solution ? |
Still not resolved. |
Edit your AndroidManifest.xml
this will do the job |
I had same issue and my style for KAV was:
Inner |
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" |
I faced a similar issue and I'll share my solution here in case this helps anyone. ContextNote: 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 Clicking on the CTA dismissed the keyboard, however while the keyboard was still being dismissed the navigation to the next page started (calling In fact, waiting for the keyboard to be dismissed before navigating to the next screen solved the issue. As did wrapping the call to SolutionThe main idea is to disable the 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>
)
} |
Thank you! This solution works perfectly for me @arthwood |
@taylorkangbeck I have the same issue, and none of the solutions work for me. Did you find out how we can overcome this? edit: I am making a chat app, so doesn't help with this neither. |
for me the problem was only android side, so what i actually did is this and i hope it helps someone maybe
don't forget to import Platform using
|
Can't believe this issue was happening in 3 year ago, and then I came across here today. alpalla's solution works but I have some CSS change,
|
If you are having this issue on ios today, my solution was applying @arthwood solution with some changes. I am not using a scroll view, just a simple view and a TouchableWithoutFeedback <KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={Platform.OS === 'ios' ? 80 : 0}
style={{flex: 1}}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View className="flex-1 grow "> // flexGrow: 1 and flex-1 |
Amazing, worked for me as well. So, why did it work, could someone explain? |
Hello ! I'm still having this issue but I can't remove the ScrollView component as I need my screen to be scrollable, anyone with a solution ? |
I finally gave up using KeyboardAvodingView as it seems to be very buggy and non-consistent across ios/android and use useKeyboard() from react-native-community/hooks and manually adjust all margins and paddings according to keyboardHeight or keyboardShown returned values along with keyboard object from useKeyboard() |
Another solution that worked for me on both Android and IOS was the code below. export const KeyBoardAvoidingViewLayout = ({
header,
children,
}: KeyBoardAvoidingViewLayoutProps) => {
return (
<View className="flex-1 bg-brand">
{header}
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={Platform.OS === 'ios' ? 60 : 0}
className="mt-8 w-full flex-1 items-center rounded-t-2xl bg-white px-2">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View className="w-full flex-1">{children}</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
</View>
);
}; |
It doesn't change anything for me, and it also cancels the |
Please, put your code on a snack to see what's going on |
Can't believe this issue is still here, and it's 2024 now. |
I can't believe that I'm still facing the same issue in the era of gpt 👀 |
Facing the same issue, but only in the emulator 🤔 on a real device (expo server and local production build works fine...) |
I tried this approach and it worked for my case: First I saved the const KEYBOARD_OFFSET = 100
const KeyboardAvoidingBase: React.FC<KeyboardAvoidingViewProps> = ({
children,
style,
...props
}) => {
const [offset, setOffset] = useState(0)
const onLayout = () => {
setOffset(currentOffset => currentOffset === KEYBOARD_OFFSET ? 0 : KEYBOARD_OFFSET)
}
return (
<KeyboardAvoidingView
testID='keyboard-avoiding-base'
behavior='padding'
onLayout={onLayout}
keyboardVerticalOffset={offset}
style={[styles.container, style]}
{...props}>
{children}
</KeyboardAvoidingView>
)
} I haven't tested it on orientation change (I have the app set to portrait mode only), or on mounting new nodes in the render tree, so not sure if the EDIT:I noticed a small issue which is causing the I did some changes and tested on a physical device (iPhone 11 pro max) and the below solution works like a charm. import React, { useEffect, useRef, useState } from 'react'
import {
Keyboard,
KeyboardAvoidingView,
KeyboardAvoidingViewProps,
} from 'react-native'
import DimensionHelper from 'Helpers/DimensionHelper'
import styles from './styles'
const KEYBOARD_OFFSET_SIZE = 100
const DISBALED_OFFSET = 0
const KEYBOARD_OFFSET = DimensionHelper.getHeight(KEYBOARD_OFFSET_SIZE)
const KeyboardAvoidingBase: React.FC<KeyboardAvoidingViewProps> = ({
children,
style,
...props
}) => {
const [offset, setOffset] = useState(KEYBOARD_OFFSET)
const lastUpdateRef = useRef('hide')
useEffect(() => {
const keyboardWillShowListener = Keyboard.addListener('keyboardWillShow', () => {
if (lastUpdateRef.current === 'show') {
return
}
lastUpdateRef.current = 'show'
setOffset(DISBALED_OFFSET)
})
const keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', () => {
lastUpdateRef.current = 'hide'
setOffset(KEYBOARD_OFFSET)
})
return () => {
keyboardWillShowListener.remove()
keyboardWillHideListener.remove()
}
}, [offset])
return (
<KeyboardAvoidingView
testID='keyboard-avoiding-base'
behavior={'padding'}
keyboardVerticalOffset={offset}
style={[styles.container, style]}
{...props}>
{children}
</KeyboardAvoidingView>
)
}
export default KeyboardAvoidingBase NOTE: the above solution doesn't solve the issue on simulators, but it works for physical devices. |
On android I set "behavior" prop to "undefined". On IOS I set "behavior" to "padding". According to the RN documentation behavior is just required on IOS.
It solved the issue on Android for me. EDIT : Apologize, RN Documentation contrary to what I said recommend to set behavior for both IOS and Android. |
I solved like this. Hope it works for you guys. const [keyboardStatus, setKeyboardStatus] = useState(1);
useEffect(() => {
const showSubscription = Keyboard.addListener('keyboardDidShow', () => {
setKeyboardStatus(1);
});
const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardStatus(0);
});
return () => {
showSubscription.remove();
hideSubscription.remove();
};
}, []);
<KeyboardAvoidingView
style={{ flex: 1, height:'100%' }}
contentContainerStyle={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
enabled
keyboardVerticalOffset={Platform.OS === 'ios' ? 88 : keyboardStatus === 1 ? 64 : 0} >
</KeyboardAvoidingView> |
Thanks! This works, but a noticed that if a want to increase the gap between the top of the kayboard and the content I must change the |
Hi @enmanuelmag, Thanks for your feedback on my solution! I also faced the same issue with the white space. As a workaround, I switched to using the react-native-keyboard-aware-scroll-view library, which provides more flexibility and avoids the problem with the white space. I know this GitHub issue is regarding KeyboardAvoidingView, but I recommend switching to this package. Here's an example of how you can implement it: return (
<View style={loginStyles.container}>
{/* Status Bar */}
<StatusBar
barStyle={isDarkMode ? "light-content" : "dark-content"}
hidden={false}
backgroundColor={isDarkMode ? "#000" : "#fff"}
/>
{/* App Header */}
<Header disableButtons={!!(isButtonLocked)} />
{/* Keyboard Aware Scroll */}
<KeyboardAwareScrollView
contentContainerStyle={{ flexGrow: 1 }}
keyboardShouldPersistTaps={'handled'}
enableOnAndroid={true}
extraScrollHeight={Platform.select({ ios: 80, android: 40 })}
extraHeight={180}
keyboardOpeningTime={0}
enableAutomaticScroll={Platform.OS === 'ios'}
enableResetScrollToCoords={false} >
<View style={loginStyles.loginFormBox}>
{/* Screen Title */}
<View style={loginStyles.screenTitleBox}>
<AbelProText textColor='gray' familyStyle={'bold'} size={selectedFont.size + 4}>USER LOGIN</AbelProText>
</View>
{/* Input Box */}
<View>
{errorStatus && (
<View style={loginStyles.alertBox_Error}>
<MaterialIcon name='error' color={'red'} size={selectedFont.size} style={loginStyles.formErrorIcon} />
<NunitoSansText textColor='red' style={loginStyles.messages} size={selectedFont.size}>{errorStatus}</NunitoSansText>
</View>
)}
{/* Email TextInput */}
<View>
<TextInput
inputMode="email"
placeholder="Enter Username"
style={[loginStyles.input, {
borderWidth: formData.email.error ? 1 : 0,
borderColor: "red",
marginBottom: formData.email.error ? 10 : 20,
}]}
keyboardType="email-address"
autoComplete="off"
autoCorrect={false}
placeholderTextColor="#000"
ref={emailInput}
returnKeyType="next"
onSubmitEditing={() => passwordInput.current?.focus()}
blurOnSubmit={false}
onChangeText={onChangeEmail}
value={formData.email.value}
autoCapitalize="none"
/>
{formData.email.error && (
<View style={loginStyles.formErrorBox}>
<MaterialIcon name='error' color={'red'} size={selectedFont.size} style={loginStyles.formErrorIcon} />
<NunitoSansText textColor='red' size={selectedFont.size - 2} style={loginStyles.formError}>{formData.email.error}</NunitoSansText>
</View>
)}
</View>
{/* Password TextInput */}
<View>
<TextInput
inputMode="text"
placeholder="Password"
style={[loginStyles.input, {
borderWidth: formData.password.error ? 1 : 0,
borderColor: "red",
marginBottom: formData.password.error ? 10 : 20,
}]}
keyboardType="default"
autoComplete="off"
autoCorrect={false}
placeholderTextColor="#000"
ref={passwordInput}
returnKeyType="next"
onSubmitEditing={Keyboard.dismiss}
blurOnSubmit={false}
onChangeText={onChangePassword}
value={formData.password.value}
secureTextEntry={true}
autoCapitalize="none"
/>
{formData.password.error && (
<View style={loginStyles.formErrorBox}>
<MaterialIcon name='error' color={'red'} size={selectedFont.size} style={loginStyles.formErrorIcon} />
<NunitoSansText textColor='red' size={selectedFont.size - 2} style={loginStyles.formError}>{formData.password.error}</NunitoSansText>
</View>
)}
</View>
</View>
{/* Submit Button */}
<View>
<Pressable onPress={handleLogin} disabled={isButtonLocked}>
{({ pressed }) => (
<LinearGradient
colors={!pressed ? ['rgb(0,177,205)', 'rgb(0,144,216)'] : ['rgb(0,144,216)', 'rgb(0,177,205)']}
start={{ x: 0.0, y: 1.0 }} end={{ x: 1.0, y: 1.0 }}
style={{ height: 45, justifyContent: "center", alignItems: "center" }}>
<AbelProText
style={{ textAlign: "center" }}
familyStyle={'bold'} textColor={"#fff"}
size={selectedFont.size}>
{isLoading ? <ActivityIndicator size={selectedFont.size + 4} color='#fff' /> : "SUBMIT"}
</AbelProText>
</LinearGradient>
)}
</Pressable>
</View>
<View style={[loginStyles.footerTextContainer]}>
<NunitoSansText size={selectedFont.size} textColor="#000">Don't have an account? </NunitoSansText>
<Pressable onPress={GoToRegister}>
<NunitoSansText size={selectedFont.size} textColor={colorScheme.skyBlue}>Register Here</NunitoSansText>
</Pressable>
</View>
</View>
</KeyboardAwareScrollView>
</View>
); I hope this helps! Best, |
After reading through countless threads and watching a lot of videos. I finally stumbled upon a thread from expo. This uses react-native-reanimated and react-native-keyboard-controller. yarn add react-native-keyboard-controller Wrap your app inside KeyboardProvider (_layout.tsx or App.tsx) import { KeyboardProvider } from "react-native-keyboard-controller";
...
export default function Layout() {
return (
<KeyboardProvider statusBarTranslucent>
...
</KeyboardProvider>
)
} PS: statusBarTranslucent prop can be removed according to needs. Create a new hook file useGradualAnimation.ts import { useKeyboardHandler } from "react-native-keyboard-controller";
import { useSharedValue } from "react-native-reanimated";
export const useGradualAnimation = () => {
const height = useSharedValue(0);
useKeyboardHandler(
{
onMove: (event) => {
"worklet";
height.value = Math.max(event.height, 0);
},
},
[]
);
return { height };
}; Create a new file KeyboardAwareView.tsx import { StyleSheet, View, ViewProps } from "react-native";
import React from "react";
import { useGradualAnimation } from "@/hooks/useGradualAnimation";
import Animated, { useAnimatedStyle } from "react-native-reanimated";
export default function KeyboardAwareView({ children, style }: ViewProps) {
const { height } = useGradualAnimation();
const keyboardSizePaddingStyles = useAnimatedStyle(() => {
return {
height: Math.abs(height.value),
};
}, []);
return (
<View style={[styles.container, style]}>
{children}
<Animated.View style={keyboardSizePaddingStyles} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
}); Now, you can simply use this new component as a standalone replacement for the default KeyboardAwareView. |
the simple way is don't make KeyboardAvoidingView is root of element, instead you make View as root with flex 1 |
No suggestions here have worked for me and I'm surprised so many are able to get a good outcome with a fixed magic number (100) - I'll tell you this is a fluke and by no means a solid or dynamic solution. |
hello, this is my solution 1. create a state for your keyboard:
2. update the state on change: import { useEffect } from "react";
3. render your component (i do recommend rendering the component KeyboardAvoidingView inside of a View component because if like me you are using custom colors for themes, you might notice some flickering when toggling the keyboard at the bottom of your screen if you use KeyboardAvoidingView as root): note: my container has the background color of my theme, therefore the flickering doesn't happen, keyboardContainer has "flex: 1" because in my case I want it to take the rest of the screen. don't worry about "MarkdownTextInput" instead of "TextInput" it behaves the same, the parser prop it's from MarkdownTextInput library, you won't need that if you are not using it.
so, im using a View container to avoid a black (or white, depends on your phone theme) flickering and toggling enable to remove the empty space at the bottom of the screen. hope this helps. |
Even though I haven't checked, I'm quite sure this works for a multiline text input. However, it may not work for a standard text input, as it could add a whitespace when the keyboard hides. Please let me know if it works or not. |
It's ridiculous,but it's WORKING |
[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.
Expected Results
The white space for keyboardVerticalOffset should only exist when the keyboard is toggled.
Snack, code example, screenshot, or link to a repository:
The text was updated successfully, but these errors were encountered: