This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
菜单
一个用于显示下拉菜单的 SwiftUI 菜单组件。
Expo UI Menu 与官方 SwiftUI Menu API 保持一致,并支持通过 buttonStyle 修饰符进行样式设置。Menu 通过单击打开。对于长按交互,请改用 ContextMenu。

注意: 在 tvOS 上,Menu 需要 tvOS 17.0 或更高版本。
安装
- npx expo install @expo/uiIf you are installing this in an existing React Native app, make sure to install expo in your project.
用法
简单文本标签
import { Host, Menu, Button } from '@expo/ui/swift-ui'; export default function SimpleMenuExample() { return ( <Host matchContents> <Menu label="选项"> <Button label="选项 1" onPress={() => console.log('选项 1')} /> <Button label="选项 2" onPress={() => console.log('选项 2')} /> <Button label="选项 3" onPress={() => console.log('选项 3')} /> </Menu> </Host> ); }
带 SF Symbol 的文本标签
import { Host, Menu, Button, Divider } from '@expo/ui/swift-ui'; export default function MenuWithIconExample() { return ( <Host matchContents> <Menu label="更多" systemImage="ellipsis.circle"> <Button label="设置" systemImage="gear" onPress={() => console.log('设置')} /> <Button label="个人资料" systemImage="person" onPress={() => console.log('个人资料')} /> <Divider /> <Button label="删除" role="destructive" systemImage="trash" onPress={() => console.log('删除')} /> </Menu> </Host> ); }
自定义标签
你可以将 React 节点作为标签传入,以进行自定义样式设置。
import { Host, Menu, Button, Text } from '@expo/ui/swift-ui'; import { foregroundStyle } from '@expo/ui/swift-ui/modifiers'; export default function CustomLabelMenuExample() { return ( <Host matchContents> <Menu label={<Text modifiers={[foregroundStyle('accentColor')]}>自定义标签</Text>}> <Button label="操作 1" onPress={() => console.log('操作 1')} /> <Button label="操作 2" onPress={() => console.log('操作 2')} /> </Menu> </Host> ); }
将 React Native 组件作为标签
你可以通过将其包装在 RNHostView 中,将 React Native 视图(例如 Pressable)用作菜单标签。
import { Host, Menu, Button, RNHostView } from '@expo/ui/swift-ui'; import { Pressable, Text } from 'react-native'; export default function RNLabelMenuExample() { return ( <Host matchContents> <Menu label={ <RNHostView matchContents> <Pressable onPress={() => console.log('RN trigger pressed')} style={{ alignSelf: 'flex-start', paddingHorizontal: 16, paddingVertical: 10, borderRadius: 8, backgroundColor: '#9B59B6', }}> <Text style={{ color: 'white', fontWeight: '600' }}>RN 可点击触发器</Text> </Pressable> </RNHostView> }> <Button label="项目 1" onPress={() => console.log('项目 1')} /> <Button label="项目 2" onPress={() => console.log('项目 2')} /> </Menu> </Host> ); }
嵌套菜单
菜单可以嵌套以创建子菜单。
import { Host, Menu, Button } from '@expo/ui/swift-ui'; export default function NestedMenuExample() { return ( <Host matchContents> <Menu label="主菜单"> <Button label="项目 1" onPress={() => console.log('项目 1')} /> <Menu label="子菜单"> <Button label="子项目 1" onPress={() => console.log('子项目 1')} /> <Button label="子项目 2" onPress={() => console.log('子项目 2')} /> </Menu> <Button label="项目 2" onPress={() => console.log('项目 2')} /> </Menu> </Host> ); }
带主操作
当提供 onPrimaryAction 时,单击会触发主操作,而长按会显示菜单。
import { Host, Menu, Button } from '@expo/ui/swift-ui'; export default function PrimaryActionMenuExample() { return ( <Host matchContents> <Menu label="Tap or hold" systemImage="play.circle" onPrimaryAction={() => console.log('已触发主操作!')}> <Button label="菜单项 1" onPress={() => console.log('菜单项 1')} /> <Button label="菜单项 2" onPress={() => console.log('菜单项 2')} /> <Button label="菜单项 3" onPress={() => console.log('菜单项 3')} /> </Menu> </Host> ); }
使用修饰器进行样式设置
你可以使用 buttonStyle 修饰器来更改菜单触发器的外观。
import { Host, Menu, Button } from '@expo/ui/swift-ui'; import { buttonStyle } from '@expo/ui/swift-ui/modifiers'; export default function StyledMenuExample() { return ( <Host matchContents> <Menu label="样式化菜单" modifiers={[buttonStyle('borderedProminent')]}> <Button label="样式化操作 1" onPress={() => console.log('样式 1')} /> <Button label="样式化操作 2" onPress={() => console.log('样式 2')} /> </Menu> </Host> ); }
玻璃菜单
要创建具有 iOS Liquid Glass 外观的菜单,请在 Menu 组件上使用 buttonStyle('glass') 或 buttonStyle('glassProminent')。
重要: 不要对 Menu 的标签视图应用
glassEffect()修饰器来实现玻璃效果。这样会导致一个视觉瑕疵:菜单被关闭时,触发器后方会短暂出现一个矩形光晕。请始终使用buttonStyle,它能与 Menu 的关闭动画正确集成。
import { Host, Menu, Button } from '@expo/ui/swift-ui'; import { buttonStyle } from '@expo/ui/swift-ui/modifiers'; export default function GlassMenuExample() { return ( <Host matchContents> <Menu label="玻璃菜单" systemImage="ellipsis.circle" modifiers={[buttonStyle('glass')]}> <Button label="操作 1" onPress={() => console.log('操作 1')} /> <Button label="操作 2" onPress={() => console.log('操作 2')} /> </Menu> </Host> ); }
若要获得更突出的玻璃效果,请使用 glassProminent:
import { Host, Menu, Button } from '@expo/ui/swift-ui'; import { buttonStyle } from '@expo/ui/swift-ui/modifiers'; export default function GlassProminentMenuExample() { return ( <Host matchContents> <Menu label="突出玻璃菜单" systemImage="slider.horizontal.3" modifiers={[buttonStyle('glassProminent')]}> <Button label="设置" systemImage="gear" onPress={() => console.log('设置')} /> <Button label="筛选" systemImage="line.3.horizontal.decrease" onPress={() => console.log('筛选')} /> </Menu> </Host> ); }
使用控制组
在菜单中使用 ControlGroup 来渲染一行水平排列的图标按钮,类似于 Apple Music 或 Safari 菜单中的快速操作行。
import { Host, Menu, ControlGroup, Button, Section, Divider } from '@expo/ui/swift-ui'; export default function MenuWithControlGroupExample() { return ( <Host matchContents> <Menu label="歌曲选项" systemImage="ellipsis.circle"> <ControlGroup> <Button systemImage="plus" label="添加" onPress={() => console.log('添加')} /> <Button systemImage="star" label="收藏" onPress={() => console.log('收藏')} /> <Button systemImage="square.and.arrow.up" label="分享" onPress={() => console.log('分享')} /> </ControlGroup> <Section> <Button systemImage="text.badge.plus" label="Add to a playlist" onPress={() => console.log('Add to playlist')} /> <Button systemImage="antenna.radiowaves.left.and.right" label="Create station" onPress={() => console.log('Create station')} /> </Section> <Divider /> <Button systemImage="hand.thumbsdown" label="Suggest less" onPress={() => console.log('Suggest less')} /> </Menu> </Host> ); }
禁用项
在菜单 Button 上使用 disabled(true) 修饰器,可以将其渲染为灰色且不可交互。该按钮仍会显示在菜单中,但不会触发 onPress。
import { Host, Menu, Button } from '@expo/ui/swift-ui'; import { disabled } from '@expo/ui/swift-ui/modifiers'; export default function DisabledMenuItemExample() { return ( <Host matchContents> <Menu label="选项"> <Button label="可用" onPress={() => console.log('可用')} /> <Button label="已锁定" systemImage="lock" modifiers={[disabled(true)]} onPress={() => console.log('这里永远不会触发')} /> </Menu> </Host> ); }
可选项(勾选标记)
放置在 Menu 中的 SwiftUI Toggle 会自动渲染为一行:当设置了 systemImage 时,前面带有 SF Symbol;当 isOn 为 true 时,后面带有勾选标记。请使用这种模式,而不是自定义一个勾选项。
import { Host, Menu, Button, Toggle } from '@expo/ui/swift-ui'; import { useState } from 'react'; export default function CheckmarkMenuItemExample() { const [showCompleted, setShowCompleted] = useState(true); const [showArchived, setShowArchived] = useState(false); return ( <Host matchContents> <Menu label="筛选" systemImage="line.3.horizontal.decrease.circle"> <Toggle isOn={showCompleted} label="显示已完成" systemImage="checkmark.circle" onIsOnChange={setShowCompleted} /> <Toggle isOn={showArchived} label="显示已归档" systemImage="archivebox" onIsOnChange={setShowArchived} /> <Button label="清除筛选" onPress={() => console.log('清除')} /> </Menu> </Host> ); }
仅图标菜单按钮
使用 labelStyle('iconOnly') 修饰器仅显示图标,而不显示标签文本。出于可访问性考虑,仍应提供 label 属性。
import { Host, Menu, Button } from '@expo/ui/swift-ui'; import { labelStyle } from '@expo/ui/swift-ui/modifiers'; export default function IconOnlyMenuExample() { return ( <Host matchContents> <Menu label="仅图标按钮" systemImage="gear" modifiers={[labelStyle('iconOnly')]}> <Button label="菜单项 1" onPress={() => console.log('菜单项 1')} /> <Button label="菜单项 2" onPress={() => console.log('菜单项 2')} /> <Button label="菜单项 3" onPress={() => console.log('菜单项 3')} /> </Menu> </Host> ); }
API
import { Menu } from '@expo/ui/swift-ui';
Component
Type: React.Element<MenuProps>
Displays a dropdown menu when tapped.
Props for the Menu component.
ReactNodeThe menu's content items, which are shown when the menu is opened.
Can contain Button, Toggle, Picker, Section, Divider or nested Menu components.
ReactNodeThe label for the menu trigger. Can be a string for simple text labels, or a ReactNode for custom label content.
() => voidA callback that is invoked when the user taps the menu label. When provided, a single tap triggers this action, while a long-press shows the menu. When not provided, a single tap shows the menu.
stringAn SF Symbol name to display alongside the label.
Only used when label is a string.