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

React Navigation Native Stack v6如何修改Modal弹窗高度?

React Navigation Native Stack v6 修改Modal弹窗高度为非全屏样式

我在使用React Navigation Native Stack v6开发时,将弹窗的presentation设置为'modal',当前弹窗为全屏样式(截图:当前全屏弹窗),希望修改为指定的非全屏高度样式(截图:目标非全屏弹窗)。查阅官方文档后未找到修改Modal高度的相关样式配置方法,特此询问是否有可行方案实现该需求。

/* eslint-disable react/no-unstable-nested-components */
import React from 'react';
import { View } from 'react-native';

import PersonalNewSecurity from './screens/PersonalNewSecurity';
import Home from './screens/Home';
import SelectLocation from './screens/SelectLocation';
import CameraScreen from './screens/CameraScreen';
import HomeToCheckOut from './screens/HomeToCheckOut';
import HomeAfterCheckOut from './screens/HomeAfterCheckout';
import ScanQR from './screens/ScanQR';
import DetailCheckIn from './screens/DetailCheckIn';
import DetailCheckOut from './screens/DetailCheckOut';
import UpdateAccount from './screens/UpdateAccount';
import Others from './screens/OthersScreen';

import Icon from 'react-native-vector-icons/MaterialCommunityIcons';

import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();

function TabNavigator() {
  return (
    <Tab.Navigator
      screenOptions={({ route }) => ({
        tabBarIcon: ({ focused, color, size }) => {
          let iconName;

          if (route.name === 'Home') {
            iconName = focused ? 'home' : 'home';
          } else if (route.name === 'Settings') {
            iconName = focused
              ? 'account-circle-outline'
              : 'account-circle-outline';
          } else if (route.name === 'ScanQR') {
            iconName = focused ? 'qrcode-scan' : 'qrcode-scan';
          }

          return (
            <Icon
              name={iconName}
              size={size}
              color={color}
            />
          );
        },
        tabBarActiveTintColor: 'black',
        tabBarInactiveTintColor: 'gray',
        tabBarStyle: { backgroundColor: '#E5E7EB' },
      })}
    >
      <Tab.Screen
        name="Home"
        component={DetailCheckOut}
        options={{ headerShown: false }}
      />
      <Tab.Screen
        name="ScanQR"
        component={StackNavigator}
        options={{ headerShown: false }}
      />
      <Tab.Screen
        name="Settings"
        component={PersonalNewSecurity}
        options={{ headerShown: false }}
      />
    </Tab.Navigator>
  );
}

function StackNavigator() {
  return (
    <Stack.Navigator
      screenOptions={{
        presentation: 'modal', // or formSheet
        cardOverlayEnabled: true,
        gestureEnabled: true,
        animation: 'slide_from_bottom',
      }}
    >
      <Stack.Screen
        name="Select Location"
        component={SelectLocation}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="Other Location"
        component={Others}
        options={{ headerShown: false }}
      />
    </Stack.Navigator>
  );
}

export default function RootStack() {
  return (
    <NavigationContainer>
      <TabNavigator />
    </NavigationContainer>
  );
}

otherscreen.js

import { View, Text, TextInput, TouchableOpacity } from 'react-native';
import React from 'react';

export default function OthersScreen({ navigation }) {
  return (
    <View className={'ml-4 p-3 mr-4 mt-1'}>
      <Text className={'text-3xl font-bold'}>Other Location</Text>
      <Text className={'text-sm mt-4 mb-1'}>Latitude: 19.67</Text>
      <Text className={'text-sm mb-1'}>Longitude: 100.34</Text>
      <Text className={'text-sm mb-1'}>Timestamp: 2022-08-21 12:30 PM</Text>
      <Text className={'text-sm mt-4 font-bold'}>Remarks</Text>
      <TextInput
        className={'mt-1 border rounded-lg p-7'}
        placeholder="Please enter reamarks here"
        placeholderTextColor="#000"
      />
      <View className={'mt-4 items-center flex-row space-x-5 '}>
        <TouchableOpacity
          className={'p-3 w-40 items-center justify-center border rounded-lg'}
          onPress={() => navigation.goBack()}
        >
          <Text className={'text-sm'}>Cancel</Text>
        </TouchableOpacity>
        <TouchableOpacity
          className={
            'bg-gray-400 p-3 w-40 items-center justify-center rounded-lg'
          }
        >
          <Text className={'text-sm text-white'}>Check-In</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

可行实现方案

方案1:自定义Navigation弹窗容器+页面高度

Native Stack的modal默认是全屏布局,我们可以通过修改屏幕的cardStyle让容器靠底部对齐,再给页面设置固定高度:

  1. 修改Stack.Screen的配置,添加cardStyle:
<Stack.Screen
  name="Other Location"
  component={Others}
  options={{
    headerShown: false,
    cardStyle: {
      flex: 1,
      justifyContent: 'flex-end', // 让内容靠底部
      backgroundColor: 'transparent', // 背景透明,显示下层页面
    },
  }}
/>
  1. 修改OthersScreen的最外层View,设置高度和圆角(匹配目标样式):
export default function OthersScreen({ navigation }) {
  return (
    <View style={{ 
      height: '75%', // 自定义高度,比如占屏幕75%
      backgroundColor: 'white',
      borderTopLeftRadius: 20,
      borderTopRightRadius: 20,
      paddingHorizontal: 16,
      paddingTop: 8
    }}>
      {/* 原有内容 */}
      <Text className={'text-3xl font-bold'}>Other Location</Text>
      {/* ... 其余代码保持不变 */}
    </View>
  );
}

方案2:iOS平台用formSheet原生样式(快速实现)

如果是iOS开发,直接把presentation改成'formSheet',这是系统原生的非全屏弹窗样式:

<Stack.Navigator
  screenOptions={{
    presentation: 'formSheet', // 替换modal
    cardOverlayEnabled: true,
    gestureEnabled: true,
    animation: 'slide_from_bottom',
  }}
>

注意:这个样式是iOS专属,高度由系统控制,不能自由定制;Android平台无效。

方案3:用React Native原生Modal完全自定义

如果需要跨平台完全可控的弹窗,直接用RN的Modal组件实现,脱离Navigation的modal限制:

在触发弹窗的页面(比如SelectLocation)中添加:

import { Modal, TouchableOpacity, Text } from 'react-native';
import React, { useState } from 'react';
import OthersScreen from './OthersScreen';

function SelectLocation() {
  const [showModal, setShowModal] = useState(false);

  return (
    <>
      {/* 原有页面内容 */}
      <TouchableOpacity onPress={() => setShowModal(true)}>
        <Text>打开Other Location弹窗</Text>
      </TouchableOpacity>

      <Modal
        animationType="slide"
        transparent={true}
        visible={showModal}
        onRequestClose={() => setShowModal(false)}
      >
        <View style={{ flex: 1, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0.4)' }}>
          {/* 弹窗内容,复用OthersScreen */}
          <OthersScreen navigation={{ goBack: () => setShowModal(false) }} />
        </View>
      </Modal>
    </>
  );
}

然后修改OthersScreen的最外层View样式,设置高度即可,完全自定义弹窗的大小、背景和动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:54:56