react-native-bottom-sheet: [v4] BottomSheet close (while dismissing keyboard) snaps to intermediate position [Android only]

Bug

Currently on Android, when programmatically closing an open BottomSheet at the same time the Keyboard is open (not using a swipe down gesture or dragging), the closing animations start but the BottomSheet closes to where the Keyboard edge was when open, not the bottom of the screen. This happens when you have a TextInput inside the BottomSheet that opens the Keyboard and you have a close button that closes both.

I’ve tried with close, forceClose, snapToIndex(-1) or snapToPosition(0) functions when using Keyboard.dismiss(). It works as expected on IOS but for Android calling the close command will not move the sheet all the way to the true screen bottom.

Environment info

Library Version
@gorhom/bottom-sheet ^4
react-native 0.69.4
react-native-reanimated 2.9.1
react-native-gesture-handler 2.5.0

Steps To Reproduce

  1. Open the BottomSheet
  2. Click on TextInput, wait for keyboard to pop up
  3. Click on close button inside bottomsheet
  4. The sheet will not fully close, instead stop partially down close to where the keyboard was open.

It seems the calculation for closing the BottomSheet on Android is using the screen height based on where the keyboard top edge ends and not the bottom edge of the screen. I need the close position to be the screen bottom end.

Describe what you expected to happen:

  1. I expect the bottomSheet to go completely to position 0, so the edge of the screen.

Reproducible sample code

const App = () => {
  // refs
  const bottomSheetRef = useRef(null);

  // variables
  const snapPoints = useMemo(() => ['100%'], []);

  // callbacks
  const handleExpandPress = useCallback(() => {
    bottomSheetRef.current?.expand();
  }, []);
  const handleCollapsePress = useCallback(() => {
    bottomSheetRef.current?.collapse();
  }, []);
  const handleClosePress = useCallback(() => {
    bottomSheetRef.current?.close();
    Keyboard.dismiss();
  }, []);

  return (
    <View style={styles.container}>
      <Button onPress={handleExpandPress} title="Expand" />
      <Button onPress={handleCollapsePress} title="Collapse" />
      <BottomSheet
        ref={bottomSheetRef}
        snapPoints={snapPoints}>
          <BottomSheetScrollView
            alwaysBounceVertical={false}
            keyboardShouldPersistTaps="handled">
            <View>
              <Button onPress={handleClosePress} title="Close" />
            </View>
            <List type="FlatList" />
            <BottomSheetTextInput />
          </BottomSheetScrollView>
      </BottomSheet>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingVertical: 64,
    justifyContent: 'flex-start',
    backgroundColor: '#222',
  },
});

export default App;

Couldn’t get the repo to work though.

image

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 16

Most upvoted comments

This is also affecting ios

Here is my workaround, not elegant, but seems to be working. Make sure you use adjustPan or adjustResize for the screen otherwise the Keyboard event won’t fire. Also, for some reason, just subscribing for the didHide even in place didn’t work for me.

https://github.com/rainbow-me/rainbow/pull/4055/files#diff-c12279017bcb91d44b49db027b1dee6a128d3993182f2c174a06fbf08d56aba2R126-R135

For any interested, I have a patch here while the PR is reviewed: https://github.com/gorhom/react-native-bottom-sheet/pull/1164#issuecomment-1298269878

Please let me know if you run into any issue 😄

Facing this issue for 2.x. Here’s the solution that worked for me (Android) -

const BottomSheetWrapper = () => {
  const [isVisible, setIsVisible] = useState(true);

  useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
      setIsVisible(false);
    });

    const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
      setIsVisible(true);
    });

    return () => {
      keyboardDidShowListener.remove();
      keyboardDidHideListener.remove();
    };

  }, []);

  if (!isVisible) {
    return null;
  }

  return (
    <BottomSheet />
  )
}

Hope this helps.