模态
了解如何在 Expo Router 中使用模态。
Modal 是移动应用中常见的用户界面模式。它们用于在现有屏幕顶部显示内容,并用于不同的目的,例如显示确认警报或独立表单。你可以使用以下方法在你的应用中创建模式:
¥Modals are a common user interface pattern in mobile apps. They are used to present content on top of the existing screen and is used for different purposes, such as displaying confirmation alerts or standalone forms. You can create modals in your app using the following methods:
-
使用 React Native 的
Modal
组件。¥Use React Native's
Modal
component. -
使用 Expo Router 的特殊基于文件的语法在应用的导航系统中创建模态屏幕。
¥Use Expo Router's special file-based syntax to create a modal screen within the app's navigation system.
每种方法都有其特定的用例。了解何时使用每种方法对于创造积极的用户体验很重要。
¥Each approach has its specific use case. Understanding when to use each method is important for creating a positive user experience.
React 服务器功能
¥React Native's Modal component
Modal
组件是 React Native 核心 API 的一部分。常见用例包括:
¥The Modal
component is part of React Native's core API. Common use cases include:
-
独立交互,例如不需要成为导航系统一部分的自包含任务。
¥Standalone interactions, such as self-contained tasks that don't need to be part of the navigation system.
-
临时警报或确认对话框,非常适合快速交互。
¥Temporary alerts or confirmation dialogs that are ideal for quick interactions.
下面是一个自定义 Modal
组件的示例,该组件在不同平台上覆盖当前屏幕:
¥Below is an example of a custom Modal
component that overlays the current screen on different platforms:
对于大多数用例,你可以使用 Modal
组件并根据应用的用户界面要求对其进行自定义。有关如何使用 Modal
组件及其属性的详细信息,请参阅 React Native 文档。
¥For most use cases, you can use the Modal
component and customize it according to your app's user interface requirements. For details on how to use the Modal
component and its props, see the React Native documentation.
使用 Expo Router 的模态屏幕
¥Modal screen using Expo Router
模式屏幕是在应用目录内创建的文件,用作现有堆栈中的路由。它用于需要成为导航系统一部分的复杂交互,例如多步骤表单,你可以在流程完成后链接到特定屏幕。
¥A modal screen is a file created inside the app directory and is used as a route within the existing stack. It is used for complex interactions that need to be part of the navigation system, such as multi-step forms where you can link to a specific screen after the process completes.
下面是一个模态屏幕在不同平台上的工作方式的示例:
¥Below is an example of how a modal screen works on different platforms:
用法
¥Usage
要实现模态路由,请在应用目录中创建一个名为 modal.tsx 的屏幕。这是一个示例文件结构:
¥To implement a modal route, create a screen called modal.tsx inside the app directory. Here's an example file structure:
app
_layout.tsx
index.tsx
modal.tsx
上述文件结构生成一个布局,其中 index
是堆栈中的第一个路由。在根布局文件 (app/_layout.tsx) 中,你可以在堆栈中添加 modal
路由。要将其作为模态显示,请在路由上将 presentation
选项设置为 modal
。
¥The above file structure produces a layout where the index
is the first route in the stack. Inside the root layout file (app/_layout.tsx), you can add the modal
route in the stack. To present it as a modal, set the presentation
option to modal
on the route.
import { Stack } from 'expo-router';
export default function Layout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen
name="modal"
options={{
presentation: 'modal',
}}
/>
</Stack>
);
}
你可以使用 Link
组件从 index.tsx 文件导航到模式屏幕。
¥You can use the Link
component to navigate to the modal screen from the index.tsx file.
import { Link } from 'expo-router';
import { StyleSheet, Text, View } from 'react-native';
export default function Home() {
return (
<View style={styles.container}>
<Text>Home screen</Text>
<Link href="/modal" style={styles.link}>
Open modal
</Link>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
link: {
paddingTop: 20,
fontSize: 20,
},
});
modal.tsx 渲染了模态的内容。
¥The modal.tsx presents the contents of the modal.
import { StyleSheet, Text, View } from 'react-native';
export default function Modal() {
return (
<View style={styles.container}>
<Text>Modal screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
模态渲染和关闭行为
¥Modal presentation and dismiss behavior
当模式是导航器中的当前屏幕并作为独立屏幕渲染时,它将失去其先前的上下文。其渲染和关闭行为在每个平台上都不同:
¥A modal loses its previous context when it is the current screen in the navigator and is presented as a standalone screen. Its presentation and dismissal behavior are different on each platform:
-
在 Android 上,模式在当前屏幕顶部滑动。要关闭它,请使用后退按钮导航回上一个屏幕。
¥On Android, the modal slides on top of the current screen. To dismiss it, use the back button to navigate back to the previous screen.
-
在 iOS 上,模态框从当前屏幕底部滑动。要关闭它,请从顶部向下滑动。
¥On iOS, the modal slides from the bottom of the current screen. To dismiss it, swipe it down from the top.
-
在网络上,模式显示为单独的路由,并且必须使用
router.canGoBack()
手动提供关闭行为。以下是如何关闭模式的示例:¥On web, the modal is presented as a separate route, and the dismiss behavior has to be provided manually using
router.canGoBack()
. Here's an example of how to dismiss the modal:
import { Link, router} from 'expo-router';
import { StyleSheet, Text, View } from 'react-native';
export default function Modal() {
const isPresented = router.canGoBack();
return (
<View style={styles.container}>
<Text>Modal screen</Text>
{isPresented && <Link href="../">Dismiss modal</Link>}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
更改 iOS 上的状态栏外观
¥Change status bar appearance on iOS
在 iOS 上,默认情况下,模式具有深色背景,可隐藏状态栏。要更改状态栏外观,你可以使用 Platform
API 检查当前平台是否为 iOS,然后使用 StatusBar
组件更改 modal.tsx 文件中的外观。
¥By default on iOS, the modal has a dark background which hides the status bar. To change the status bar appearance, you can use the Platform
API to check if the current platform is iOS and then use the StatusBar
component to change the appearance inside the modal.tsx file.
import { StyleSheet, Text, View, Platform } from 'react-native';
import { StatusBar } from 'expo-status-bar';
export default function Modal() {
return (
<View style={styles.container}>
<Text>Modal screen</Text>
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
Web 模式实现
¥Web modals implementation
上面的视频演示了出现在网页主要内容上的模态窗口。背景变暗以将焦点吸引到模式上,其中包含用户信息。这是 Web 模式的典型行为,用户可以与模式交互或关闭它以返回主页。
¥The video above demonstrates a modal window that appears over the main content of the web page. The background dims to draw focus to the modal, which contains information for the user. This is typical behavior for web modals, where users can interact with the modal or close it to return to the main page.
你可以通过使用 transparentModal
演示模式、设置覆盖和模式内容的样式以及利用 react-native-reanimated
为模式的演示设置动画来实现上述 Web 模式行为。
¥You can achieve the above web modal behavior by using the transparentModal
presentation mode, styling the overlay and modal content, and utilizing react-native-reanimated
to animate the modal's presentation.
修改项目的根布局 (app/_layout.tsx) 以将 options
对象添加到模式路由:
¥Modify your project's root layout (app/_layout.tsx) to add an options
object to the modal route:
import { Stack } from 'expo-router';
export const unstable_settings = {
initialRouteName: 'index',
};
export default function Layout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen
name="modal"
options={{
presentation: 'transparentModal',
animation: 'fade',
headerShown: false,
}}
/>
</Stack>
);
}
unstable_settings
目前仅适用于Stack
导航器。
上述示例使用 unstable_settings
将 index
屏幕设置为 initialRouteName
。这可确保透明模式始终渲染在当前屏幕的顶部,即使用户通过直接链接导航到模式屏幕也是如此。
¥The above example sets the index
screen as the initialRouteName
using unstable_settings
. This ensures that the transparent modal is always rendered on top of the current screen, even when users navigate to the modal screen via a direct link.
在 modal.tsx 中设置覆盖和模态内容的样式,如下所示:
¥Style the overlay and modal content in modal.tsx as shown below:
import { Link } from 'expo-router';
import { Pressable, StyleSheet, Text } from 'react-native';
import Animated, { FadeIn, SlideInDown } from 'react-native-reanimated';
export default function Modal() {
return (
<Animated.View
entering={FadeIn}
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#00000040',
}}
>
{/* Dismiss modal when pressing outside */}
<Link href={'/'} asChild>
<Pressable style={StyleSheet.absoluteFill} />
</Link>
<Animated.View
entering={SlideInDown}
style={{
width: '90%',
height: '80%',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
}}
>
<Text style={{ fontWeight: 'bold', marginBottom: 10 }}>Modal Screen</Text>
<Link href="/">
<Text>← Go back</Text>
</Link>
</Animated.View>
</Animated.View>
);
}
请随意自定义模态动画和样式以满足你的喜好。
¥Feel free to customize the modal animations and styles to your liking.
附加信息
¥Additional information
演示选项
¥Presentation options
在 Android 和 iOS 上使用 presentation
选项有不同的选项来渲染模态屏幕。
¥There are different options to present a modal screen using the presentation
option on Android and iOS.
选项 | 描述 |
---|---|
card | 新屏幕将被推送到堆栈上。Android 上的默认动画将根据操作系统版本和主题而有所不同。在 iOS 上,它会从侧面滑动。 |
modal | 新屏幕将以模态方式渲染,允许在屏幕内渲染嵌套堆栈。 |
transparentModal | 新屏幕将以模态方式渲染,前一个屏幕保持可见。如果屏幕具有半透明背景,则下面的内容仍然可见。 |
containedModal | 在 Android 上,回退到 modal 。在 iOS 上,使用 UIModalPresentationCurrentContext 模态框样式。 |
containedTransparentModal | 在 Android 上,回退到 transparentModal 。在 iOS 上,使用 UIModalPresentationOverCurrentContext 模态框样式。 |
fullScreenModal | 在 Android 上,回退到 modal 。在 iOS 上,使用 UIModalPresentationFullScreen 模态框样式。 |
formSheet | 在 Android 上,回退到 modal 。在 iOS 上,使用 UIModalPresentationFormSheet 模态框样式。 |