react-native-bottom-sheet: [v4] | [v2] Keyboard does not automatically resize on the first try. Works after that though.
Bug
The sheet does not auto resize the content height when keyboard is opened for the first time. It works after that but does not work if you clear the app and open the sheet with TextInput (BottomSheetTextInput) as a content in it for the first time. Video attached below:
Environment info
Library | Version |
---|---|
@gorhom/bottom-sheet | “^4.3.0” |
react-native | “^0.63.4” |
react-native-reanimated | “^2.4.1” |
react-native-gesture-handler | “~1.10.2” |
Steps To Reproduce
- Use the below provided BottomSheet as a standalone component.
- Just use a Controlled TextInput as a children.
- Focus the input, the keyboard wont resize the content height when its visible.
Describe what you expected to happen:
- The content height should move up the keyboard height when its visible everytime not only after the first time
Reproducible sample code
BottomSheet.js
component
import React, {useRef} from 'react';
import {BackHandler, useWindowDimensions} from 'react-native';
import {
BottomSheetView,
BottomSheetModal,
BottomSheetBackdrop,
useBottomSheetDynamicSnapPoints,
} from '@gorhom/bottom-sheet';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
const BottomSheet = ({
visible,
setVisible = () => null,
onDismiss = () => null,
children = null,
automaticallyAdjustHeight = false, // Prop 'key' with unique value as string needs to be passed to calculate the layout changes every time.
backdropComponent = null,
enableHandle = true,
panToDismiss = true,
responsive = true,
snapPoints: _snapPoints = ['25%', '50%'],
index = 1,
modalStyle = {},
}) => {
const bottomSheetRef = useRef(null);
const {bottom: safeAreaBottom} = useSafeAreaInsets();
const {window} = useWindowDimensions();
const MAX_WIDTH = 600;
const marginHorizontal =
window.width > MAX_WIDTH ? (window.width - MAX_WIDTH) / 2 : 0;
const snapPoints = automaticallyAdjustHeight
? ['CONTENT_HEIGHT']
: _snapPoints;
const {
animatedHandleHeight,
animatedSnapPoints,
animatedContentHeight,
handleContentLayout,
} = useBottomSheetDynamicSnapPoints(snapPoints);
React.useEffect(() => {
if (visible) {
bottomSheetRef.current?.present();
} else {
bottomSheetRef.current?.dismiss();
}
}, [visible]);
const renderActualChildren = automaticallyAdjustHeight ? (
<BottomSheetViewComponent
handleContentLayout={handleContentLayout}
key="actualChildren">
{children}
</BottomSheetViewComponent>
) : (
children
);
const handleDismiss = React.useCallback(() => {
setVisible(false);
onDismiss?.();
}, [onDismiss, setVisible]);
const backPressed = React.useCallback(() => {
setVisible(false);
return true;
}, [setVisible]);
React.useEffect(() => {
if (visible) {
BackHandler.addEventListener('hardwareBackPress', backPressed);
} else {
BackHandler.removeEventListener('hardwareBackPress', backPressed);
}
return () => {
BackHandler.removeEventListener('hardwareBackPress', backPressed);
};
}, [visible, backPressed]);
return visible ? (
<BottomSheetModal
style={[
{paddingBottom: safeAreaBottom},
responsive ? {marginHorizontal} : {},
modalStyle,
]}
name="bottomsheet"
ref={bottomSheetRef}
enableHandlePanningGesture
onDismiss={handleDismiss}
enableContentPanningGesture={panToDismiss}
keyboardBehavior="interactive"
keyboardBlurBehavior="restore"
backdropComponent={props => <Backdrop {...props} />}
{...(automaticallyAdjustHeight ? {} : {index})}
{...(backdropComponent !== null ? {backdropComponent} : {})}
{...(!enableHandle ? {handleComponent: null} : {})}
{...(automaticallyAdjustHeight
? {
snapPoints: animatedSnapPoints,
handleHeight: animatedHandleHeight,
contentHeight: animatedContentHeight,
key: `Modal${
automaticallyAdjustHeight ? animatedContentHeight.value : ''
}`,
}
: {snapPoints: _snapPoints})}>
{renderActualChildren}
</BottomSheetModal>
) : null;
};
function BottomSheetViewComponent({
handleContentLayout = () => null,
children = null,
}) {
const {bottom: safeAreaBottom} = useSafeAreaInsets();
return (
<BottomSheetView
onLayout={handleContentLayout}
style={{
paddingBottom: safeAreaBottom,
}}>
{children}
</BottomSheetView>
);
}
function Backdrop({...props}) {
return (
<BottomSheetBackdrop
key="backdrop"
{...props}
pressBehavior={'close'}
appearsOnIndex={0}
disappearsOnIndex={-1}
/>
);
}
export default BottomSheet;
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 1
- Comments: 19 (2 by maintainers)
I identified the issue and preparing a fix
So temporary solution I am using is to get the keyboard height when it opens and render a empty view with keybooard height. Its a little bit slow since it needs to render after keyboard is completely opened, but its fine until I find a solution.
So this is the hook that detects the keyboard height. Should work with expo as well.
And inside my sheet children I just add this AdjustmentView that has height of keyboard when opened. This will automatically adjust the sheet when keyboard is opened.
Hope this helps.
EDIT: Adding new prop in v4
android_keyboardInputMode="adjustResize"
fixes this problem.