Reference version

菜单

一个用于显示下拉菜单的 SwiftUI Menu 组件。

iOS
tvOS
Included in Expo Go
Bundled version:
~56.0.6

For the complete documentation index, see llms.txt. Use this file to discover all available pages.

Expo UI Menu 与官方 SwiftUI Menu API 保持一致,并支持通过 buttonStyle 修饰符进行样式设置。Menu 会在单击时打开。对于长按交互,请改用 ContextMenu

打开菜单,显示“设置”、“个人资料”和一个带有破坏性操作的“删除”项

注意: 在 tvOS 上,Menu 需要 tvOS 17.0 或更高版本。

安装

Terminal
npx expo install @expo/ui

If you are installing this in an existing React Native app, make sure to install expo in your project.

用法

简单文本标签

SimpleMenuExample.tsx
import { Host, Menu, Button } from '@expo/ui/swift-ui'; export default function SimpleMenuExample() { return ( <Host matchContents> <Menu label="选项"> <Button label="选项 1" onPress={() => console.log('Option 1')} /> <Button label="选项 2" onPress={() => console.log('Option 2')} /> <Button label="选项 3" onPress={() => console.log('Option 3')} /> </Menu> </Host> ); }

带 SF Symbol 的文本标签

MenuWithIconExample.tsx
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('Settings')} /> <Button label="个人资料" systemImage="person" onPress={() => console.log('Profile')} /> <Divider /> <Button label="删除" role="destructive" systemImage="trash" onPress={() => console.log('Delete')} /> </Menu> </Host> ); }

自定义标签

你可以将 React 节点作为标签传入,以便进行自定义样式设置。

CustomLabelMenuExample.tsx
import { Host, Menu, Button, Text } from '@expo/ui/swift-ui'; export default function CustomLabelMenuExample() { return ( <Host matchContents> <Menu label={<Text color="accentColor">自定义标签</Text>}> <Button label="操作 1" onPress={() => console.log('Action 1')} /> <Button label="操作 2" onPress={() => console.log('Action 2')} /> </Menu> </Host> ); }

React Native 组件作为标签

你可以通过将 React Native 视图(例如 Pressable)包裹在 RNHostView 中,将其用作菜单的标签。

RNLabelMenuExample.tsx
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 Pressable 触发器</Text> </Pressable> </RNHostView> }> <Button label="Item 1" onPress={() => console.log('Item 1')} /> <Button label="Item 2" onPress={() => console.log('Item 2')} /> </Menu> </Host> ); }

嵌套菜单

菜单可以嵌套以创建子菜单。

NestedMenuExample.tsx
import { Host, Menu, Button } from '@expo/ui/swift-ui'; export default function NestedMenuExample() { return ( <Host matchContents> <Menu label="主菜单"> <Button label="项目 1" onPress={() => console.log('Item 1')} /> <Menu label="子菜单"> <Button label="子项目 1" onPress={() => console.log('Sub Item 1')} /> <Button label="子项目 2" onPress={() => console.log('Sub Item 2')} /> </Menu> <Button label="项目 2" onPress={() => console.log('Item 2')} /> </Menu> </Host> ); }

带主操作

当提供 onPrimaryAction 时,单击会触发主操作,而长按会显示菜单。

PrimaryActionMenuExample.tsx
import { Host, Menu, Button } from '@expo/ui/swift-ui'; export default function PrimaryActionMenuExample() { return ( <Host matchContents> <Menu label="点击或按住" systemImage="play.circle" onPrimaryAction={() => console.log('Primary action triggered!')}> <Button label="菜单项 1" onPress={() => console.log('Menu Item 1')} /> <Button label="菜单项 2" onPress={() => console.log('Menu Item 2')} /> <Button label="菜单项 3" onPress={() => console.log('Menu Item 3')} /> </Menu> </Host> ); }

使用修饰符进行样式设置

你可以使用 buttonStyle 修饰符来更改菜单触发器的外观。

StyledMenuExample.tsx
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('Styled 1')} /> <Button label="样式化操作 2" onPress={() => console.log('Styled 2')} /> </Menu> </Host> ); }

玻璃菜单

要创建具有 iOS Liquid Glass 外观的菜单,请在 Menu 组件上使用 buttonStyle('glass')buttonStyle('glassProminent')

重要: 不要将 glassEffect() 修饰符应用到 Menu 的标签视图上来实现玻璃效果。这会导致一个视觉瑕疵:菜单被关闭时,触发器后面会短暂出现一个矩形光晕。请始终改用 buttonStyle,因为它能与 Menu 的关闭动画正确集成。

GlassMenuExample.tsx
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('Action 1')} /> <Button label="操作 2" onPress={() => console.log('Action 2')} /> </Menu> </Host> ); }

若要获得更醒目的玻璃效果,请使用 glassProminent

GlassProminentMenuExample.tsx
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('Settings')} /> <Button label="筛选" systemImage="line.3.horizontal.decrease" onPress={() => console.log('Filter')} /> </Menu> </Host> ); }

带控制组

在菜单中使用 ControlGroup 可渲染一行横向排列的图标按钮,类似 Apple Music 或 Safari 菜单中的快速操作行。

MenuWithControlGroupExample.tsx
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('Add')} /> <Button systemImage="star" label="收藏" onPress={() => console.log('Favorite')} /> <Button systemImage="square.and.arrow.up" label="分享" onPress={() => console.log('Share')} /> </ControlGroup> <Section> <Button systemImage="text.badge.plus" label="添加到播放列表" onPress={() => console.log('Add to Playlist')} /> <Button systemImage="antenna.radiowaves.left.and.right" label="创建电台" onPress={() => console.log('Create Station')} /> </Section> <Divider /> <Button systemImage="hand.thumbsdown" label="减少推荐" onPress={() => console.log('Suggest Less')} /> </Menu> </Host> ); }

仅图标菜单按钮

使用 labelStyle('iconOnly') 修饰符仅显示图标,不显示标签文本。label 属性仍应提供,以满足可访问性需求。

IconOnlyMenuExample.tsx
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('Menu Item 1')} /> <Button label="菜单项 2" onPress={() => console.log('Menu Item 2')} /> <Button label="菜单项 3" onPress={() => console.log('Menu Item 3')} /> </Menu> </Host> ); }

API

import { Menu } from '@expo/ui/swift-ui';

Component

iOS
tvOS

Type: React.Element<MenuProps>

Displays a dropdown menu when tapped.

Props for the Menu component.

MenuProps

children

iOS
tvOS
Type: ReactNode

The menu's content items, which are shown when the menu is opened. Can contain Button, Toggle, Picker, Section, Divider or nested Menu components.

label

iOS
tvOS
Literal type: union

The label for the menu trigger. Can be a string for simple text labels, or a ReactNode for custom label content.

Acceptable values are: string | ReactNode

onPrimaryAction

iOS
tvOS
Optional • Type: () => void

A 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.

systemImage

iOS
tvOS
Optional • Type: string

An SF Symbol name to display alongside the label. Only used when label is a string.