Reference version

This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

菜单

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

iOS
tvOS
Included in Expo Go
Recommended version:
~56.0.16

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

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

安装

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'; 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('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 按压式触发器</Text> </Pressable> </RNHostView> }> <Button label="项目 1" onPress={() => console.log('Item 1')} /> <Button label="项目 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')

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.