You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中基于Gorhom BottomSheet实现内容自适应底部弹窗

实现Gorhom BottomSheet根据内容自动调整高度

要让Gorhom BottomSheet根据内部内容自动适配高度,核心是利用库内置的CONTENT_HEIGHT常量作为停靠点,同时移除固定的size参数及相关计算,以下是具体改造步骤和完整代码:

关键改造点

  • 移除固定size依赖:删除组件props中的size参数及相关高度计算逻辑
  • 使用内容高度作为停靠点:导入CONTENT_HEIGHT,将snapPoints设置为该值,让弹窗自动适配内容高度
  • 调整弹窗状态逻辑:修改弹窗状态变化的回调逻辑,适配新的停靠点配置
  • 动态内容适配:如果内容是异步加载的,需主动触发高度重新计算

改造后的完整代码

import BottomSheet, { BottomSheetBackdrop, BottomSheetScrollView, CONTENT_HEIGHT } from '@gorhom/bottom-sheet';
import { Portal } from '@gorhom/portal';
import React, { FC, useCallback, useRef, useEffect } from 'react';
import { Platform } from 'react-native';
import { heightPixel } from '../../styles';
import { customBottomSheetStyles } from './style';
import { CustomBottomSheetPropsType } from './types';
import { useSafeAreaInsets } from 'react-native-safe-area-context'; // 推荐用这个处理安全区域

const CustomBottomSheet: FC<Omit<CustomBottomSheetPropsType, 'size'>> = ({ children, onClose }) => {
  const insets = useSafeAreaInsets();
  // 更可靠的安全区域内边距计算
  const bottomInset = insets.bottom;
  
  const bottomSheetRef = useRef<BottomSheet>(null);

  // 内容更新时重新计算弹窗高度(针对动态加载的内容)
  useEffect(() => {
    bottomSheetRef.current?.recalculateSnapPoints();
  }, [children]);

  const handleSheetChanges = useCallback(
    (index: number) => {
      // 当弹窗完全关闭(index为-1)时触发关闭回调
      if (index === -1) {
        onClose();
      }
    },
    [onClose]
  );

  return (
    <Portal>
      <BottomSheet
        ref={bottomSheetRef}
        index={0} // 初始停靠在内容高度位置
        onClose={onClose}
        snapPoints={[CONTENT_HEIGHT]} // 自动适配内容高度作为唯一停靠点
        onChange={handleSheetChanges}
        enablePanDownToClose
        style={customBottomSheetStyles.bottomSheetContainer}
        bottomInset={bottomInset}
        backdropComponent={(props) => (
          <BottomSheetBackdrop
            style={customBottomSheetStyles.backdropContainer}
            {...props}
            opacity={0.2}
            appearsOnIndex={0}
            disappearsOnIndex={-1}
          />
        )}
      >
        <BottomSheetScrollView 
          showsVerticalScrollIndicator={false} 
          nestedScrollEnabled={true}
          // 可选:仅当内容高度超过弹窗可用高度时允许滚动
          scrollEnabled={true}
        >
          {children}
        </BottomSheetScrollView>
      </BottomSheet>
    </Portal>
  );
};

export { CustomBottomSheet };

额外优化建议

  • 限制最大高度:如果担心内容过长导致弹窗占满屏幕,可以给snapPoints添加一个最大高度限制,例如:snapPoints={[CONTENT_HEIGHT, '90%']},当内容高度超过屏幕90%时,弹窗会停在90%高度并允许内部滚动
  • 安全区域处理:推荐使用react-native-safe-area-context库来获取安全区域内边距,比直接调用NativeModules.StatusBarManager更稳定且兼容更多场景
  • 动态内容适配:如果内容是通过网络请求等异步方式加载的,确保在内容渲染完成后调用recalculateSnapPoints(),保证弹窗高度准确

内容的提问来源于stack exchange,提问作者Alliyan Waheed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 06:22:48