React Navigation Native Stack v6如何修改Modal弹窗高度?
我在使用React Navigation Native Stack v6开发时,将弹窗的presentation设置为'modal',当前弹窗为全屏样式(截图:当前全屏弹窗),希望修改为指定的非全屏高度样式(截图:目标非全屏弹窗)。查阅官方文档后未找到修改Modal高度的相关样式配置方法,特此询问是否有可行方案实现该需求。
navigation.js
/* 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让容器靠底部对齐,再给页面设置固定高度:
- 修改
Stack.Screen的配置,添加cardStyle:
<Stack.Screen name="Other Location" component={Others} options={{ headerShown: false, cardStyle: { flex: 1, justifyContent: 'flex-end', // 让内容靠底部 backgroundColor: 'transparent', // 背景透明,显示下层页面 }, }} />
- 修改
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
相关产品推荐
相关产品推荐

