首页 / 资讯中心 / 文章详情

Expo Router 中实现原生 Form Sheet:配置、底部操作栏与交互深度指南

Expo Router 中实现原生 Form Sheet:配置、底部操作栏与交互深度指南 ★ FEATURED ARTICLE
AI 技能AI 插件人工智能【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600 agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills点击查看免费下载在 iOS 与 Android 原生应用中Form Sheet表单面板是一种从屏幕底部滑出、以卡片形态呈现的模态展示方式非常适合快速确认、设置面板、登录注册等轻量交互场景。本篇技术指南以 building-native-ui 技能 中的 Form Sheet 章节为核心结合仓库内配套的 SKILL.md、route-structure.md 以及 expo-animation 的屏幕转场配方 等源码级材料系统讲解基于 Expo Router Stack 导航器 react-native-screens 实现原生 Form Sheet 的完整配置、底部栏定位、后台内容交互以及跨平台差异。读完你将能够直接在自己的 Expo 应用中落地一套可运行、符合平台交互规范的 Form Sheet 方案。一、什么是 Form Sheet为什么优先选择它Form Sheet 是 iOS 系统级的模态呈现方式面板从屏幕底部向上滑入顶部带可拖拽的抓取条grabber支持通过多个卡点detent停靠在不同高度。它适合快速操作与确认如删除确认、操作选择设置面板登录 / 注册流程带自定义内容的 Action Sheet仓库中 react-native-skills/rules/ui-native-modals.md 明确给出了一条高影响规则优先使用原生 Modal / 原生 Form Sheet而不是 JS 实现的底部面板库。原因在于原生模态自带内置手势下滑关闭、键盘避让、无障碍支持与更好的性能。该规则同时给出了反面示例基于 JS 的 BottomSheet 组件库与正面示例React Navigation v7 原生 form sheet说明在导航器中用presentation: formSheet即可获得真正的平台级组件无需引入第三方依赖。在 Expo Router 中实现 Form Sheet 的唯一前置要求是使用 Stack 导航器Expo Router Stack navigator这一点由 form-sheet.md 明确列出。Stack 导航器由 react-native-screens 提供原生能力支持因此面板的呈现、手势与动画全部在原生侧完成。二、基础用法带底部操作栏的 Form Sheet2.1 在布局中配置 Stack.Screen要启用 Form Sheet需要在_layout.tsx中对目标屏幕设置presentation: formSheet并配合透明背景与面板选项// app/_layout.tsx import { Stack } from expo-router; export default function Layout() { return ( Stack Stack.Screen nameindex / Stack.Screen nameabout options{{ presentation: formSheet, sheetAllowedDetents: [0.25], headerTransparent: true, contentStyle: { backgroundColor: transparent }, sheetGrabberVisible: true, }} Stack.Header style{{ backgroundColor: transparent }}/Stack.Header /Stack.Screen /Stack ); }几个关键点的设计意图presentation: formSheet让该路由以系统原生 Form Sheet 呈现而不是普通 push 页面。仓库 SKILL.md 的 Sheet 小节 指出配合contentStyle: { backgroundColor: transparent }时在 iOS 26 上面板背景会自动呈现 Liquid Glass 液态玻璃效果。headerTransparent: true与Stack.Header style{{ backgroundColor: transparent }}保证标题栏透明使面板内容不会被白色标题栏遮挡视觉上与卡片融为一体。sheetAllowedDetents: [0.25]将面板高度限制在屏幕 25%适合紧凑型操作。2.2 面板屏幕内容用 flex: 1 支撑底部操作栏面板内容页使用flex: 1让内容填满可用空间从而将底部操作栏钉在面板底部// app/about.tsx import { View, Text, StyleSheet } from react-native; export default function AboutSheet() { return ( View style{styles.container} {/* Main content */} View style{styles.content} TextSheet Content/Text /View {/* Footer - stays at bottom */} View style{styles.footer} TextFooter Content/Text /View /View ); } const styles StyleSheet.create({ container: { flex: 1, }, content: { flex: 1, padding: 16, }, footer: { padding: 16, }, });该用法要求Expo SDK 55 或更高版本文档原注Requires Expo SDK 55 or later。这里container和content均使用flex: 1footer不参与弹性伸缩因此无论面板高度如何变化底部操作栏都稳定停留在面板底部。这与仓库 SKILL.md 的响应式规则 中使用 flexbox 而非 Dimensions API的建议一致也是排查内容未填满面板问题时的关键点见后文故障排查。三、让面板背后的内容保持可交互sheetLargestUndimmedDetentIndex默认情况下Form Sheet 出现后其背后屏幕会被系统变暗dimmed。若希望在面板保持打开时仍能操作背后的内容例如在面板下方拖动地图可以使用sheetLargestUndimmedDetentIndex// app/_layout.tsx import { Stack } from expo-router; export default function Layout() { return ( Stack screenOptions{{ headerShown: false }} Stack.Screen nameindex / Stack.Screen nameinfo-sheet options{{ presentation: formSheet, sheetAllowedDetents: [0.2, 0.5, 1.0], sheetLargestUndimmedDetentIndex: 1, /* other options */ }} / /Stack ) }该选项是从 0 开始的索引zero-indexed它指定最大不遮挡背后内容的卡点位置sheetAllowedDetents: [0.2, 0.5, 1.0]定义了三个卡点20%、50%、100%。sheetLargestUndimmedDetentIndex: 1表示在**前两个卡点索引 0 和 1即 20% 与 50%**时背后内容保持可交互、不显示遮罩当面板被拖到第三个卡点索引 2100%时系统会对背后内容施加变暗遮罩。这一设计在需要面板 底层地图/列表协同操作的场景中非常实用也是原生 UISheetPresentationController 提供的标准能力。四、核心选项速查表OptionTypeDescriptionpresentationstring设为formSheet以启用面板呈现sheetGrabberVisibleboolean是否在面板顶部显示拖拽抓取条sheetAllowedDetentsnumber[]卡点高度数组取值 0–1 范围如[0.25]表示 25% 高度headerTransparentboolean让导航栏背景透明contentStyleobject屏幕内容容器的样式对象titlestring屏幕标题设为可隐藏标题补充说明sheetAllowedDetents除了数值数组外还支持字符串fitToContents自适应内容高度expo-animation/RECIPES.md 中即使用了该取值但要注意fitToContents要求内容具有明确的固有高度若根视图是flex: 1则没有可贴合的内在高度卡点会失效——此时应给内容显式设定尺寸。五、常用卡点取值与选择策略[0.25]— 四分之一面板适合紧凑操作如确认框、快速动作[0.5]— 半屏面板适合中等体量内容如设置面板[0.75]— 四分之三面板适合需要更多空间的详细表单[0.25, 0.5, 1]— 多卡点可展开面板用户可自由在三个高度间拖拽在仓库 expo-animation 的屏幕转场配方 中还给出了导航方式的选择建议可作为何时使用 Form Sheet 的决策依据导航场景推荐方式深入层级animation: default平台原生 push可随时放弃的独立任务presentation: modal短时打断选择器、筛选、分享presentation: formSheet 卡点标签页切换animation: none减少动态效果辅助功能animation: fade六、完整可运行示例确认面板下面是一个开箱即用的完整示例包含透明布局配置与带取消 / 确认按钮的面板内容页。6.1 布局配置_layout.tsx// _layout.tsx import { Stack } from expo-router; export default function Layout() { return ( Stack Stack.Screen nameindex options{{ title: Home }} / Stack.Screen nameconfirm options{{ contentStyle: { backgroundColor: transparent }, presentation: formSheet, title: , sheetGrabberVisible: true, sheetAllowedDetents: [0.25], headerTransparent: true, }} Stack.Header style{{ backgroundColor: transparent }} Stack.Header.Right / /Stack.Header /Stack.Screen /Stack ); }title: 用于清除默认标题文本Stack.Header.Right /提供右侧空占位保持布局对称。6.2 面板内容页app/confirm.tsx// app/confirm.tsx import { View, Text, Pressable, StyleSheet } from react-native; import { router } from expo-router; export default function ConfirmSheet() { return ( View style{styles.container} View style{styles.content} Text style{styles.title}Confirm Action/Text Text style{styles.description} Are you sure you want to proceed? /Text /View View style{styles.footer} Pressable style{styles.cancelButton} onPress{() router.back()} Text style{styles.cancelText}Cancel/Text /Pressable Pressable style{styles.confirmButton} onPress{() router.back()} Text style{styles.confirmText}Confirm/Text /Pressable /View /View ); } const styles StyleSheet.create({ container: { flex: 1, }, content: { flex: 1, padding: 20, alignItems: center, justifyContent: center, }, title: { fontSize: 18, fontWeight: 600, marginBottom: 8, }, description: { fontSize: 14, color: #666, textAlign: center, }, footer: { flexDirection: row, padding: 16, gap: 12, }, cancelButton: { flex: 1, padding: 14, borderRadius: 10, backgroundColor: #f0f0f0, alignItems: center, }, cancelText: { fontSize: 16, fontWeight: 500, }, confirmButton: { flex: 1, padding: 14, borderRadius: 10, backgroundColor: #007AFF, alignItems: center, }, confirmText: { fontSize: 16, fontWeight: 500, color: white, }, });要点解读两个按钮均通过router.back()关闭面板即调用返回导航。若需要带结果返回可在back前通过路由参数或状态传递数据。底部操作栏footer使用flexDirection: rowgap: 12实现双按钮并排布局。这与 SKILL.md 样式规则 中优先使用 flex gap 而非 margin/padding 组合的建议一致。flex: 1让取消 / 确认两个按钮等宽铺满底部视觉上更符合 iOS 操作栏习惯。七、跨平台差异iOS 与 Android 的行为边界Form Sheet 在 iOS 与 Android 上均为原生实现但两者能力并不完全等价。expo-animation/RECIPES.md 中对此有明确警告属于在落地时必须注意的硬约束Android 卡点上限为三个。更长的sheetAllowedDetents数组在 iOS 上正常工作但在 Android 上会被静默截断——请按最多三个卡点来设计不要依赖第五、第六个卡点。sheetGrabberVisible仅 iOS 生效。Android 不显示抓取条因此不要把抓取条作为此面板可拖动的唯一视觉提示在 Android 上应额外提供显式的拖动或关闭入口。Android 的 Form Sheet 无法承载原生标题栏或嵌套 Stack。若面板内部还需要自己的导航层级请改用presentation: modal面板内容应保持为单一屏幕。fitToContents需要显式尺寸的内容。flex: 1的根视图没有内在高度可拟合需要为内容设定具体尺寸否则卡点计算会出错。仓库 react-native-skills/rules/ui-native-modals.md 从另一个角度强化了这一原则原生模态自带滑动关闭手势、键盘避让与无障碍支持而 JS 实现的面板库在这些方面天然处于劣势。因此在能力允许的范围内应始终优先选择平台原生的 Form Sheet。八、与路由结构的配合Form Sheet 是 Stack 导航器的一个屏幕因此它遵循 Expo Router 的路由约定详见 route-structure.md路由文件放在app目录下每个文件默认导出一个组件面板屏幕就是其中普通的一个.tsx文件。使用_layout.tsx定义 Stack并在其中通过Stack.Screen的name与文件路径对应。不要在app目录内放置组件、类型或工具函数属于反模式面板内容所需的子组件应放在components/等独立目录。若面板需要接收参数可用useLocalSearchParams读取路由参数。例如在标签页应用中可将确认面板放在共享的分组路由(index,settings)/之下使多个标签页都能 push 到同一个 Form Sheet 屏幕。九、故障排查9.1 内容没有填满面板确保根View使用了flex: 1View style{{ flex: 1 }}{/* content */}/View如果根视图没有弹性拉伸面板高度与内容高度不匹配底部操作栏就无法被推到面板底部。9.2 面板背景透出背景显示异常在options中设置contentStyle: { backgroundColor: transparent }并改由你自己的内容容器设置期望的背景色Stack.Screen namesheet options{{ presentation: formSheet, contentStyle: { backgroundColor: transparent }, }} /这样既能让面板呈现半透明/液态玻璃效果iOS 26也能在自定义背景色时避免出现双层背景叠加的视觉问题。9.3 其他常见坑忘记设置headerTransparent: true导致标题栏白色背景盖住面板顶部内容。在 Android 上依赖抓取条提示可拖动性Android 不渲染抓取条。使用超过三个卡点且没有在 Android 上验证导致卡点静默失效。使用fitToContents但根视图是flex: 1卡点高度计算错误。十、延伸阅读Form Sheet 参考文档本文核心来源building-native-ui 技能主页导航与 Sheet 章节Expo Router 路由结构约定屏幕转场与 Form Sheet 跨平台差异配方原生模态优于 JS 底部面板的规则说明掌握以上配置与约束后你便可以在 Expo Router 应用中稳定地落地符合平台规范的原生 Form Sheet既能实现带底部操作栏的确认面板也能实现多卡点可交互的浮动面板同时规避 iOS 与 Android 之间的行为差异陷阱。赞分享AI 技能AI 插件人工智能【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600 agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills点击查看免费下载相关推荐使用 Expo Router 实现 Form Sheets原生底部表单卡片的完整配置指南使用 Expo Router 实现 Form Sheets原生底部表单卡片的完整配置指南 本指南以 autoskills 仓库 building native在 Expo Router 中实现原生 iOS 工具栏与导航头Stack.Toolbar 完整实战指南在 Expo Router 中实现原生 iOS 工具栏与导航头Stack.Toolbar 完整实战指南 本文基于当前仓库 autoskills 技能注册表中的Buzz 离线语音转文字完整指南3 步跑通首次转录批量导出 SRT 字幕Buzz 离线语音转文字完整指南3 步跑通首次转录批量导出 SRT 字幕 你刚结束一场 2 小时的访谈需要一份可搜索的文字稿但录音绝不能上传到任何服务器语音AI 应用本地部署桌面应用上一篇headlessui与Vue 3组合式API构建高效组件的方法下一篇so-vits-svc人声增强技术NSF-HIFIGAN与浅度扩散联合使用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站