gorhom / react-native-bottom-sheet

A performant interactive bottom sheet with fully configurable options 🚀
https://gorhom.dev/react-native-bottom-sheet/
MIT License
7.04k stars 768 forks source link

BottomSheet exceeds the maximum height when Keyboard is open on Android #61

Closed padupuy closed 3 years ago

padupuy commented 4 years ago

Bug

I have a TextInput on top of the BottomSheet.
On Android, when the focus is on the TextInput, the keyboard is open and the top of the BottomSheet is no longer visible.
I try to solve the bug by removing the keyboard.height to the max snapPoint but then, the gestures on the BottomSheet are buggy.
When I look at the Map example, i can see in the AndroidManifest.xml android:windowSoftInputMode="adjustPan". In my project I set windowSoftInputMode to adjustResize.
Any idea how can I prevent the BottomSheet to not exceed the maximum height ?

Without focus focus
Screenshot_20201110-125310 Screenshot_20201110-125317

Environment info

Library Version
@gorhom/bottom-sheet 1.4.1
react-native 0.62.2
react-native-reanimated 1.13.1
react-native-gesture-handler 1.8.0

Steps To Reproduce

  1. Focus an input on android inside a BottomSheet
  2. See how the keyboard put the content to the top of the screen

Describe what you expected to happen:

  1. improve the keyboard handling

Reproducible sample code

import * as React from 'react';

import BottomSheet, { BottomSheetOverlay, BottomSheetSectionList } from '@gorhom/bottom-sheet';
import { useFocusEffect } from '@react-navigation/native';
import { StackScreenProps, useHeaderHeight } from '@react-navigation/stack';
import { Dimensions, InteractionManager } from 'react-native';
import { Platform, StatusBar } from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { Easing, Extrapolate, interpolate } from 'react-native-reanimated';
import { useValue } from 'react-native-redash/lib/module/v1';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import styled from 'styled-components/native';

import { MainStackParamList } from 'navigation/MainNavigator';

import BlurredBackground from './BlurredBackground';
import HomeMap from './HomeMap/HomeMap';

const { height: SCREEN_HEIGHT } = Dimensions.get('window');

const STATUS_BAR_HEIGHT = Platform.select({
  android: StatusBar.currentHeight || (Platform.Version < 23 ? 25 : 24),
  default: 0,
});

const Home: React.FC<StackScreenProps<MainStackParamList, 'Home'>> = ({}) => {
  const bottomSheetRef = React.useRef<BottomSheet>(null);
  const { top: topSafeArea, bottom: bottomSafeArea } = useSafeAreaInsets();

  const headerHeight = useHeaderHeight();

  const snapPoints = React.useMemo(() => [bottomSafeArea + 194, SCREEN_HEIGHT / 2, SCREEN_HEIGHT - STATUS_BAR_HEIGHT - headerHeight - topSafeArea], [
    bottomSafeArea,
    headerHeight,
    topSafeArea,
  ]);
  const animatedPosition = useValue<number>(0);
  const animatedPositionIndex = useValue<number>(0);
  const animatedOverlayOpacity = React.useMemo(
    () =>
      interpolate(animatedPosition, {
        inputRange: [snapPoints[1], snapPoints[2]],
        outputRange: [0, 0.25],
        extrapolate: Extrapolate.CLAMP,
      }),
    [animatedPosition, snapPoints],
  );

  const handleSheetChanges = React.useCallback((index: number) => {
    console.log('handleSheetChanges', index);
  }, []);

  const initBottomSheet = React.useCallback(() => {
    const task = InteractionManager.runAfterInteractions(() => {
      bottomSheetRef.current?.snapTo(1);
    });

    return () => task.cancel();
  }, []);

  useFocusEffect(initBottomSheet);

  return (
    <Container>
      <HomeMap />
      <BottomSheetOverlay pointerEvents="none" animatedOpacity={animatedOverlayOpacity} />
      <BottomSheet
        ref={bottomSheetRef}
        snapPoints={snapPoints}
        initialSnapIndex={0}
        topInset={topSafeArea}
        animatedPosition={animatedPosition}
        animatedPositionIndex={animatedPositionIndex}
        animationDuration={500}
        animationEasing={Easing.out(Easing.exp)}
        backgroundComponent={BlurredBackground}
        onChange={handleSheetChanges}>
        <BottomSheetScreen>
          <TextInput />
          <BottomSheetSectionList
            sections={data}
            keyExtractor={(item, index) => item.id + index}
            renderItem={renderItem}
            renderSectionHeader={renderSectionHeader}
            stickySectionHeadersEnabled={false}
            keyboardDismissMode="on-drag"
            keyboardShouldPersistTaps="handled"
          />
        </BottomSheetScreen>
      </BottomSheet>
    </Container>
  );
};
const Container = styled.View`
  position: relative;
  flex: 1;
`;
const BottomSheetScreen = styled.View`
  flex: 1;
`;

export default Home;
padupuy commented 3 years ago

@gorhom do you have any idea to solve this problem ?

gorhom commented 3 years ago

hi @padupuy, could you try to set windowSoftInputMode as the following:

https://github.com/gorhom/react-native-bottom-sheet/blob/dbd6983db84658dd99ad25e3f154fb02fd91898a/example/android/app/src/main/AndroidManifest.xml#L18

padupuy commented 3 years ago

@gorhom this solution works ! But this seems a bit "extreme" no ?

hannojg commented 3 years ago

Having the same issue. adjustPan doesn't really work in our use case as we are using RNN. Also tried settings the input with position: absolute, bottom: 0.

izakfilmalter commented 3 years ago

Ya I am with @hannojg, I need android:windowSoftInputMode="adjustResize" for my app to work well.

Sahejmaharjan1 commented 3 years ago

@izakfilmalter were you able to solve it with android:windowSoftInputMode="adjustResize"?

hotaryuzaki commented 1 year ago

is there any solution? i already tried with windowSoftInputMode="adjustPan" but other issue occur, now half of my footer like sinking to the back of the keyboard i have absolute View in the bottom as a footer that contain buttons but it's only happened for android device with large screen

Screenshot_2022-11-29-20-35-52-213_com brambang apps