This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
底部弹出页
与 @gorhom/bottom-sheet 兼容的底部弹出页。
一个与 @gorhom/bottom-sheet API 兼容的 BottomSheet 组件。它封装了平台特定的 @expo/ui 原语:Android 上使用 Jetpack Compose ModalBottomSheet,iOS 上使用 SwiftUI BottomSheet。在 web 上,它使用 vaul 抽屉。
如果你需要对平台特定的样式、修饰器或布局行为进行更底层的控制,请直接使用原生原语。
安装
- npx expo install @expo/uiIf you are installing this in an existing React Native app, make sure to install expo in your project.
从 @gorhom/bottom-sheet 迁移
-
将导入从以下内容更新:
import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';改为使用
@expo/ui/community/bottom-sheet:import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; -
此实现不需要来自
react-native-gesture-handler的GestureHandlerRootView。如果应用的其他部分需要它,你可以保留不变。 -
不支持诸如
BottomSheetBackdrop、BottomSheetHandle、BottomSheetFooter、BottomSheetDraggableView、BottomSheetVirtualizedList、BottomSheetFlashList、useBottomSheetModal、useBottomSheetSpringConfigs和useBottomSheetTimingConfigs等组件和 hook 导出。为兼容 API,导出了一些相关的 prop 类型。
基本用法
import { useRef } from 'react'; import { Button, Text, View } from 'react-native'; import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function BottomSheetExample() { const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="Open" onPress={() => sheetRef.current?.snapToIndex(0)} /> <BottomSheet ref={sheetRef} snapPoints={['25%', '50%', '90%']} index={-1} onChange={index => { console.log('onChange', index); }} onClose={() => { console.log('closed'); }} enablePanDownToClose> <BottomSheetView style={{ flex: 1, padding: 24, alignItems: 'center' }}> <Text>Sheet 内容</Text> </BottomSheetView> </BottomSheet> </View> ); }
BottomSheetModal
从 @gorhom/bottom-sheet 的 modal API 迁移时,请使用 BottomSheetModal。它默认处于关闭状态,并通过 present() 打开。
import { useRef } from 'react'; import { Button, Text, View } from 'react-native'; import { BottomSheetModal, BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function BottomSheetModalExample() { const modalRef = useRef<BottomSheetModal>(null); return ( <View style={{ flex: 1 }}> <Button title="Present" onPress={() => modalRef.current?.present()} /> <BottomSheetModal ref={modalRef} snapPoints={['50%', '90%']} enablePanDownToClose> <BottomSheetView style={{ padding: 24 }}> <Text>Modal 内容</Text> <Button title="Dismiss" onPress={() => modalRef.current?.dismiss()} /> </BottomSheetView> </BottomSheetModal> </View> ); }
动态尺寸
当未提供 snapPoints 时,底部弹窗默认会根据其内容自动调整大小。请使用 BottomSheetView 作为底部弹窗内容的包装组件。
import { useRef } from 'react'; import { Button, Text, View } from 'react-native'; import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function DynamicBottomSheetExample() { const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="打开" onPress={() => sheetRef.current?.present()} /> <BottomSheet ref={sheetRef} index={-1} enablePanDownToClose> <BottomSheetView style={{ padding: 24 }}> <Text>此底部弹窗会根据其内容自动调整大小。</Text> </BottomSheetView> </BottomSheet> </View> ); }
平台行为
@gorhom/bottom-sheet 会以内联方式渲染在其父视图底部。此组件在 Android 和 iOS 上使用原生模态展示,在 web 上使用抽屉覆盖层。
这种差异是有意为之。@gorhom/bottom-sheet 通过 react-native-gesture-handler 和 react-native-reanimated 自主管理手势和动画层,而 @expo/ui/community/bottom-sheet 则将这些行为委托给 Jetpack Compose、SwiftUI 以及 web 抽屉原语。因此,此组件最适合模态底部弹窗流程,包括使用 BottomSheet API 而不是 BottomSheetModal 的调用场景。
| 功能 | Android | iOS | Web |
|---|---|---|---|
| 展示方式 | Jetpack Compose 模态底部弹窗 | SwiftUI sheet | vaul 抽屉 |
| 吸附点 | 映射为部分展开和完全展开状态 | 支持所提供的吸附点 | 支持所提供的吸附点 |
无 snapPoints | 适配内容 | 适配内容 | 适配内容 |
| 向下拖动关闭 | 同时启用返回按钮和遮罩点击关闭 | 同时启用背景层点击关闭 | 启用抽屉关闭 |
| 持久内联预览 | 不支持 | 不支持 | 不支持 |
支持的导出
| 导出项 | 支持情况 | 备注 |
|---|---|---|
BottomSheet | Android 和 iOS 上为模态框,web 上为抽屉 | |
BottomSheetModal | 初始为关闭状态,并通过 present() 打开 | |
BottomSheetModalProvider | 为了兼容性直接渲染子组件 | |
BottomSheetView | 包裹底部 sheet 内容 | |
BottomSheetScrollView | React Native ScrollView 的重新导出 | |
BottomSheetFlatList | React Native FlatList 的重新导出 | |
BottomSheetSectionList | React Native SectionList 的重新导出 | |
BottomSheetTextInput | React Native TextInput 的重新导出 | |
useBottomSheet | 从上下文返回 sheet ref 方法 | |
BottomSheetBackdrop | 原生 sheet 或 web 抽屉会处理背景遮罩 | |
BottomSheetHandle | 原生 sheet 或 web 抽屉会处理拖拽指示器 | |
BottomSheetFooter | 此实现中没有对应项 |
兼容性说明
- 支持
snapPoints、index、onChange、onClose、onDismiss、enablePanDownToClose和enableDynamicSizing。 handleComponent={null}会隐藏原生或 Web 的拖拽指示器。自定义的 handle 组件不会在原生平台上渲染。backgroundStyle在 Web 上完全生效。在 Android 上,backgroundColor用于原生容器颜色。在 iOS 上,使用系统 sheet 背景。- 动画、过度拖拽、内容拖动、handle 拖动、键盘行为、自定义背景遮罩、自定义背景、自定义页脚、动画值和 detached 属性会为兼容 API 而被接受,但不会改变行为。
API
import BottomSheet from '@expo/ui/community/bottom-sheet';
Components
Type: React.Element<BottomSheetProps>
Bottom sheet component. Defaults to index={0} and opens at the first snap point on mount.
Props for the BottomSheet component. API-compatible with @gorhom/bottom-sheet where native platform behavior allows.
boolean • Default: trueWhether the sheet should automatically size to fit its content.
boolean • Default: falseWhether the sheet can be dismissed by panning down.
Type: React.Element<BottomSheetProps>
Modal variant of BottomSheet. Starts closed and opens with present().
Type: React.Element<{
children: React.ReactNode
}>
Provider for BottomSheetModal. It renders children directly for API compatibility.
Type: React.Element<BottomSheetViewProps>
A wrapper for content inside a BottomSheet.
boolean • Default: trueWhether the sheet should automatically size to fit its content.
boolean • Default: falseWhether the sheet can be dismissed by panning down.
Hooks
Returns the imperative methods for the nearest BottomSheet.
BottomSheetMethodsTypes
Imperative methods exposed by BottomSheet and BottomSheetModal refs.
| Property | Type | Description |
|---|---|---|
| close | () => void | Close the bottom sheet. |
| collapse | () => void | Snap to the minimum snap point. |
| dismiss | () => void | Dismiss the bottom sheet. |
| expand | () => void | Snap to the maximum snap point. |
| forceClose | () => void | Force close the bottom sheet. |
| present | () => void | Present the bottom sheet at the first snap point. |
| snapToIndex | (index: number) => void | Snap to a snap point by index. |
| snapToPosition | (position: string | number) => void | Snap to a pixel value or percentage position. |