react-native-bottom-sheet icon indicating copy to clipboard operation
react-native-bottom-sheet copied to clipboard

[v4] | [v2] Centering detached modals

Open joeyfigaro opened this issue 1 year ago • 2 comments

Bug

Detached modals still require snap points and default to the bottom of the screen despite the common pattern not being draggable and being centered on screen.

Environment info

Library Version
@gorhom/bottom-sheet 4.4.3
react-native 0.68.2
react-native-reanimated 2.8.0
react-native-gesture-handler 2.2.1

Steps To Reproduce

  1. Follow steps in documentation for using a detached BottomSheetModal
  2. Notice that snapPoints are required and that the modal is not centered

Describe what you expected to happen:

  1. snapPoints would no longer be required (because modals don't need to be expandable)
  2. The modal would automatically be centered on the screen

Reproducible sample code

N/A

joeyfigaro avatar Aug 05 '22 19:08 joeyfigaro

There doesn't appear to be an easy way to vertically center modals via styles

joeyfigaro avatar Aug 05 '22 19:08 joeyfigaro

Waiting for this feature! +1

joseortiz9 avatar Aug 26 '22 13:08 joseortiz9

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] avatar Sep 26 '22 09:09 github-actions[bot]

any update on this? :(

joseortiz9 avatar Sep 26 '22 10:09 joseortiz9

Still nothing?

eleddie avatar Sep 30 '22 13:09 eleddie

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] avatar Oct 31 '22 09:10 github-actions[bot]

Also really wanting this feature!

TNAJanssen avatar Nov 04 '22 10:11 TNAJanssen

Also really wanting this feature!

So do I.

thaisvilarinho avatar Nov 11 '22 18:11 thaisvilarinho

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] avatar Dec 12 '22 09:12 github-actions[bot]

This issue was closed because it has been stalled for 5 days with no activity.

github-actions[bot] avatar Dec 17 '22 09:12 github-actions[bot]

~Could we reopen this issue? Would love to see this supported~

Never mind, I found a workaround. Please see my comment below 🙇

MiguelAraCo avatar Jul 09 '23 11:07 MiguelAraCo

For anyone still looking for a solution, I created the following hook which can be used to center a detached bottom sheet regardless of its height:

const useCenteredDynamicPositioning = () => {
  const { animatedHandleHeight, animatedContentHeight, handleContentLayout } = useBottomSheetDynamicSnapPoints([
    'CONTENT_HEIGHT',
  ]);

  const insets = useSafeAreaInsets();
  const windowHeight = Dimensions.get('window').height;

  const animatedSnapPoints = useDerivedValue(() => {
    const safeHeight = windowHeight - insets.top - insets.bottom;
    const bottomSheetHeight = animatedContentHeight.value + animatedHandleHeight.value;
    const verticalMargin = (safeHeight - bottomSheetHeight) / 2;
    const snapPoint = windowHeight - insets.top - verticalMargin;

    // Values lower than 1 aren't valid snapPoints, so always return at least 1
    return [snapPoint >= 1 ? snapPoint : 1];
  });

  return {
    animatedSnapPoints,
    animatedHandleHeight,
    animatedContentHeight,
    handleContentLayout,
  };
};

Usage example:

const SomeBottomSheet = () => {
  // ...

  const { animatedSnapPoints, animatedHandleHeight, animatedContentHeight, handleContentLayout } =
    useCenteredDynamicPositioning();

  // ...

  return (
    <BottomSheet
      detached={true}
      // Start on the first (and only) snapPoint
      index={0}
      snapPoints={animatedSnapPoints}
      handleHeight={animatedHandleHeight}
      contentHeight={animatedContentHeight}
    >
      {/* I would recommend adding a maxHeight to styles.contentContainer */}
      {/* A normal View can also be used instead of a BottomSheetScrollView */}
      <BottomSheetScrollView onLayout={handleContentLayout} style={styles.contentContainer}>
        {/* ... bottom sheet contents*/}
      </BottomSheetScrollView>
    </BottomSheet>
  );
};

MiguelAraCo avatar Jul 10 '23 00:07 MiguelAraCo

since useBottomSheetDynamicSnapPoints will be removed on next release, this is my updated hook and fixed issue with device which has inset.bottom, thanks to @MiguelAraCo :

import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { useHeaderHeight } from '@react-navigation/elements';
import { Dimensions } from 'react-native';
import { useDerivedValue, useSharedValue } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export const useCenteredDynamicPositioning = () => {
  const tabBarHeight = useBottomTabBarHeight();
  const headerHeight = useHeaderHeight();
  const insets = useSafeAreaInsets();
  const windowHeight = Dimensions.get('window').height;

  const animatedContentHeight = useSharedValue(0);

  const animatedHandleHeight = useSharedValue(-999);

  const animatedSnapPoints = useDerivedValue(() => {
    const safeHeight =
      windowHeight -
      (insets.top + headerHeight) -
      (insets.bottom + tabBarHeight);
    const bottomSheetHeight =
      animatedContentHeight.value + animatedHandleHeight.value;
    const verticalMargin = (safeHeight - bottomSheetHeight) / 2;
    const snapPoint =
      windowHeight - insets.top - verticalMargin - insets.bottom;

    return [snapPoint >= 1 ? snapPoint : 1];
  });

  return {
    animatedSnapPoints,
    animatedHandleHeight,
    animatedContentHeight,
  };
};

NhatDung avatar Nov 14 '23 15:11 NhatDung

since useBottomSheetDynamicSnapPoints will be removed on next release, this is my updated hook and fixed issue with device which has inset.bottom, thanks to @MiguelAraCo :

import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { useHeaderHeight } from '@react-navigation/elements';
import { Dimensions } from 'react-native';
import { useDerivedValue, useSharedValue } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export const useCenteredDynamicPositioning = () => {
  const tabBarHeight = useBottomTabBarHeight();
  const headerHeight = useHeaderHeight();
  const insets = useSafeAreaInsets();
  const windowHeight = Dimensions.get('window').height;

  const animatedContentHeight = useSharedValue(0);

  const animatedHandleHeight = useSharedValue(-999);

  const animatedSnapPoints = useDerivedValue(() => {
    const safeHeight =
      windowHeight -
      (insets.top + headerHeight) -
      (insets.bottom + tabBarHeight);
    const bottomSheetHeight =
      animatedContentHeight.value + animatedHandleHeight.value;
    const verticalMargin = (safeHeight - bottomSheetHeight) / 2;
    const snapPoint =
      windowHeight - insets.top - verticalMargin - insets.bottom;

    return [snapPoint >= 1 ? snapPoint : 1];
  });

  return {
    animatedSnapPoints,
    animatedHandleHeight,
    animatedContentHeight,
  };
};

This is not working. The bottom sheet is always sticky to the bottom of the screen How is the animatedContentHeight calculated? @NhatDung

HenrikZabel avatar Jan 07 '24 21:01 HenrikZabel

How to calculate animatedContentHeight when useCenteredDynamicPositioning is deprecated?

ng-ha avatar Feb 05 '24 04:02 ng-ha