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

React Navigation中NavigationContainer如何实现动态高度

react-native-bottom-sheet 适配 react-navigation v6 动态高度方案

直接按以下步骤实现即可,不需要在每个页面单独绑定onLayout:

  • 问题核心原因:react-navigation v6 默认会对非活跃页面做视图缓存、原生端视图拆分,页面切换时不会重新触发子组件的onLayout事件,直接给页面绑定布局监听拿不到切换后的高度是正常表现。

具体实现

  1. 外层统一测量容器高度
    不要直接把NavigationContainer作为BottomSheet的子组件,先套一层可获取ref的View作为测量锚点,监听导航索引变化主动测量高度:
import { useRef, useState, useEffect } from 'react';
import { View } from 'react-native';
import BottomSheet from '@gorhom/bottom-sheet';
import { NavigationContainer, useNavigationState } from '@react-navigation/native';

const DynamicHeightBottomSheetNav = () => {
  const bottomSheetRef = useRef(null);
  const navWrapRef = useRef(null);
  const [sheetHeight, setSheetHeight] = useState(320); // 初始默认高度

  // 监听当前活跃页面索引
  const activeIndex = useNavigationState(state => state.index);

  // 统一测量更新高度方法
  const updateSheetHeight = () => {
    requestAnimationFrame(() => {
      navWrapRef.current?.measure((_, __, ___, height) => {
        if (height > 0 && height !== sheetHeight) {
          setSheetHeight(height);
          bottomSheetRef.current?.snapToPosition(height);
        }
      });
    });
  };

  // 页面切换时触发测量
  useEffect(() => {
    updateSheetHeight();
  }, [activeIndex]);

  return (
    <BottomSheet
      ref={bottomSheetRef}
      snapPoints={[sheetHeight]}
      enableDynamicSizing={false}
    >
      <View 
        ref={navWrapRef} 
        collapsable={false}
        style={{ flexShrink: 1 }}
        onLayout={updateSheetHeight}
      >
        <NavigationContainer independent={true}>
          {/* 内嵌你的Stack/Tab导航器 */}
        </NavigationContainer>
      </View>
    </BottomSheet>
  );
};
  1. 适配页面内动态内容场景
    如果单个页面内部有展开收起、异步加载内容导致高度变化的情况,通过路由参数触发外层重新测量即可,不需要在页面单独写高度监听:
// 业务页面内,内容变化时触发
import { useNavigation } from '@react-navigation/native';
const PageA = () => {
  const navigation = useNavigation();
  const handleLoadContent = () => {
    // 内容加载/展开完成后触发重测
    setTimeout(() => {
      navigation.setParams({ remeasureTs: Date.now() });
    }, 0);
  };
  // 页面业务逻辑
};

// 外层导航组件内增加参数监听
const activeRouteParams = useNavigationState(state => state.routes[state.index]?.params);
useEffect(() => {
  if (activeRouteParams?.remeasureTs) updateSheetHeight();
}, [activeRouteParams?.remeasureTs]);
  1. 必要配置避坑
  • 如果使用@react-navigation/native-stack,给导航器设置detachInactiveScreens={false},避免非活跃页面被原生端拆分导致测量值不准
  • 内层导航器、页面根容器不要写flex:1样式,会强制撑满父容器导致测量拿到固定最大值,改用flexShrink:1适配内容高度
  • 安卓端记得给测量用的外层View加collapsable={false},防止原生布局优化把节点合并导致测量失败

实测这个方案的高度更新延迟在1-2帧,用户感知不到高度跳变,不需要侵入修改每个业务页面的布局逻辑。

内容的提问来源于stack exchange,提问作者Eden Eliel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 05:27:21