使用 Expo UI 构建 SwiftUI 应用

了解如何使用 Expo UI 将 SwiftUI 集成到你的 Expo 应用中。

iOS
macOS
tvOS

信息SDK 54 及更高版本 可用。

Expo UI 将 SwiftUI 引入 React Native。你可以使用现代 SwiftUI 基本组件来构建你的应用。

🌐 Expo UI brings SwiftUI to React Native. You can use modern SwiftUI primitives to build your apps.

本指南介绍了使用 Expo UI 将 SwiftUI 集成到 Expo 应用中的基础知识。

🌐 This guide covers the basics of using Expo UI to integrate SwiftUI into your Expo apps.

Expo UI iOS 液态玻璃教程
Expo UI iOS 液态玻璃教程

了解如何在你的 React Native 应用中使用新的 Expo UI 构建真实的 SwiftUI 视图。

特性

🌐 Features

  • SwiftUI 原语:Expo UI 不是另一个 UI 库。它将 SwiftUI 原语引入了 Expo。
  • 一对一映射:Expo UI 中的组件与 SwiftUI 视图存在一对一的映射关系。你可以轻松地在 SwiftUI 生态系统中探索可用的视图,例如 探索 SwiftUILibraried 应用,并找到对应的 Expo UI 组件。
  • 全应用支持:Expo UI 设计为可在整个应用中使用。你可以完全使用 Expo UI 编写应用,同时保持灵活性。集成在组件级别进行。你还可以混合使用 React Native 组件Expo UI 组件DOM 组件 或使用 react-native-skia 自定义的 2D 组件。

安装

🌐 Installation

你需要在你的 Expo 项目中安装 @expo/ui 包。运行以下命令来安装它:

🌐 You'll need to install the @expo/ui package in your Expo project. Run the following command to install it:

Terminal
npx expo install @expo/ui

用法

🌐 Usage

Expo UI 提供了多个可用的 SwiftUI 组件。你可以通过从 @expo/ui/swift-ui 导入它们来在你的应用中使用它们。不过,要从 React Native(UIKit)跨界到 SwiftUI,你需要使用 Host 组件。Host 是 SwiftUI 视图的容器。你可以把它想象成 DOM 中的 <svg>react-native-skia 中的 <Canvas>。在底层,它使用 UIHostingController 在 UIKit 中渲染 SwiftUI 视图。

🌐 Expo UI has several SwiftUI components available. You can use them in your app by importing them from @expo/ui/swift-ui. However, to cross the boundary from React Native (UIKit) to SwiftUI, you need to use the Host component. The Host is the container for SwiftUI views. You can think of it like <svg> in the DOM or <Canvas> in react-native-skia. Under the hood, it uses UIHostingController to render SwiftUI views in UIKit.

Host 的基本用法

🌐 Basic usage with Host

SwiftUI loading view
import { CircularProgress, Host } from '@expo/ui/swift-ui'; import { View, Text } from 'react-native'; export default function LoadingView() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Host matchContents> <CircularProgress /> </Host> <Text>Loading...</Text> </View> ); }

使用 HStackVStack

🌐 Using HStack and VStack

你也可以使用 HStackVStack 组件在 SwiftUI 中构建整个布局。

🌐 You can also use the HStack and VStack components to build the entire layout in SwiftUI.

SwiftUI loading with HStack and VStack
import { CircularProgress, Host, HStack, LinearProgress, VStack } from '@expo/ui/swift-ui'; export default function LoadingView() { return ( <Host style={{ flex: 1, margin: 32 }}> <VStack spacing={32}> <HStack spacing={32}> <CircularProgress /> <CircularProgress color="orange" /> </HStack> <LinearProgress progress={0.5} /> <LinearProgress color="orange" progress={0.7} /> </VStack> </Host> ); }

修饰符

🌐 Modifiers

SwiftUI 修饰符 是自定义 SwiftUI 组件外观和行为的一种强大方式。Expo UI 也为 SwiftUI 组件提供了修饰符。你可以从 @expo/ui/swift-ui/modifiers 导入修饰符,并将它们作为数组传递给 modifiers 属性。在下面的示例中,expo-mesh-gradientglassEffect 修饰符结合使用,以创建液态玻璃文本。

注意glassEffect 修饰符需要 Xcode 26 及以上版本和 iOS 26 及以上版本。

SwiftUI modifiers
import { Host, Text } from '@expo/ui/swift-ui'; import { glassEffect, padding } from '@expo/ui/swift-ui/modifiers'; import { MeshGradientView } from 'expo-mesh-gradient'; import { View } from 'react-native'; export default function Page() { return ( <View style={{ flex: 1 }}> <MeshGradientView style={{ flex: 1 }} columns={3} rows={3} colors={['red', 'purple', 'indigo', 'orange', 'white', 'blue', 'yellow', 'green', 'cyan']} points={[ [0.0, 0.0], [0.5, 0.0], [1.0, 0.0], [0.0, 0.5], [0.5, 0.5], [1.0, 0.5], [0.0, 1.0], [0.5, 1.0], [1.0, 1.0], ]} /> <Host style={{ position: 'absolute', top: 0, right: 0, left: 0, bottom: 0 }}> <Text size={32} modifiers={[ padding({ all: 16, }), glassEffect({ glass: { variant: 'clear', }, }), ]}> Glass effect text </Text> </Host> </View> ); }

iOS 设置应用示例

🌐 iOS Settings app example

结合 Expo UI 组件和修饰符,你可以构建一个类似 iOS 设置应用的 UI。

🌐 Combining the Expo UI components and modifiers, you can build a UI like iOS Settings app.

SwiftUI Form example to build iOS Settings app
import { Button, Form, Host, HStack, Image, Section, Spacer, Toggle, Text, } from '@expo/ui/swift-ui'; import { background, clipShape, frame } from '@expo/ui/swift-ui/modifiers'; import { Link } from 'expo-router'; import { useState } from 'react'; export default function SettingsView() { const [isAirplaneMode, setIsAirplaneMode] = useState(true); return ( <Host style={{ flex: 1 }}> <Form> <Section> <HStack spacing={8}> <Image systemName="airplane" color="white" size={18} modifiers={[ frame({ width: 28, height: 28 }), background('#ffa500'), clipShape('roundedRectangle'), ]} /> <Text>Airplane Mode</Text> <Spacer /> <Toggle isOn={isAirplaneMode} onIsOnChange={setIsAirplaneMode} /> </HStack> <Link href="/wifi" asChild> <Button> <HStack spacing={8}> <Image systemName="wifi" color="white" size={18} modifiers={[ frame({ width: 28, height: 28 }), background('#007aff'), clipShape('roundedRectangle'), ]} /> <Text color="primary">Wi-Fi</Text> <Spacer /> <Image systemName="chevron.right" size={14} color="secondary" /> </HStack> </Button> </Link> </Section> </Form> </Host> ); }

常见问题

🌐 Common questions

我可以在 SwiftUI 组件中使用 flexbox 或其他样式吗?

Flexbox 样式可以直接应用到 Host 组件本身。然而,一旦进入 SwiftUI 上下文,Yoga 就不可用——布局应改用 <HStack><VStack> 来定义。

🌐 Flexbox styles can be applied to the Host component itself. Once you're inside the SwiftUI context, however, Yoga is not available — layouts should be defined using <HStack> and <VStack> instead.

什么是 Host 组件?

Host 是 SwiftUI 视图的容器。你可以把它想象成 DOM 中的 <svg>react-native-skia 中的 <Canvas>。在底层,它使用 UIHostingController 在 UIKit 中渲染 SwiftUI 视图。

Expo UI 与像 react-native-paper 或 react-native-elements 这样的库有何不同?

Expo UI 并不是“又一个”UI库,也不是一个有特定设计风格的设计套件。相反,它是一个原语库。它将本地的 SwiftUI 和 Jetpack Compose 组件直接暴露给 JavaScript,而不是在 JavaScript 中重新实现或模拟 UI。

🌐 Expo UI is not "yet another" UI library and not an opinionated design kit. Instead, it's a primitives library. It exposes native SwiftUI and Jetpack Compose components directly to JavaScript, rather than re-implementing or simulating UI in JavaScript.

我可以在 Android 或网页上使用 @expo/ui/swift-ui 吗?

Expo UI 的第一个里程碑是实现从 SwiftUI 到 Expo UI 的一对一映射。通用支持将在路由图的下一阶段实现。我们的首要任务是首先建立强大的 SwiftUI 支持,然后再扩展到 Android 上的 Jetpack Compose 和 Web 上的 DOM 支持。

🌐 The first milestone for Expo UI is achieving a 1-to-1 mapping from SwiftUI to Expo UI. Universal support will come in the next stage of the roadmap. Our priority is to establish strong SwiftUI support first, and then expand to Jetpack Compose on Android and DOM support on the Web.

我可以在 SwiftUI 组件中使用 React Native 组件吗?

是的,你可以将 React Native 组件作为 JSX 子组件放置在 Expo UI 组件中。Expo UI 会自动为你创建一个 UIViewRepresentable 封装器。 然而,请记住,SwiftUI 布局系统的工作方式与 UIKit 不同,并且存在一些限制。根据苹果的文档:

🌐 Yes, you can place React Native components as JSX children of Expo UI components. Expo UI automatically creates a UIViewRepresentable wrapper for you. However, keep in mind that the SwiftUI layout system works differently from UIKit and has some limitations. According to Apple's documentation:

警告 SwiftUI 完全控制 UIKit 视图的 centerboundsframetransform 属性的布局。不要在你自己的代码中直接设置由 UIViewRepresentable 实例管理的视图的这些布局相关属性,因为这样会与 SwiftUI 产生冲突,并导致未定义的行为。

还要注意,一旦你渲染 React Native 组件,就会离开 SwiftUI 上下文。如果你想再次添加 Expo UI 组件,则需要重新引入一个 Host 封装器。

🌐 Also note that once you render React Native components, you're leaving the SwiftUI context. If you want to add Expo UI components again, you'll need to reintroduce a Host wrapper.

我们建议保持 SwiftUI 布局的自包含性。虽然可以进行互操作,但在边界清晰定义的情况下效果最佳。

🌐 We recommend keeping SwiftUI layouts self-contained. Interop is possible, but it works best when boundaries are clearly defined.

我是一个 SwiftUI 开发者。我为什么要学习 Expo UI?

由于 React 承诺的“学一次,随处编写”,它现在已经扩展到 SwiftUI 和 Jetpack Compose。借助 Expo UI,你可以运用 SwiftUI 的知识来构建在 React Native 生态系统中运行的应用,通过 DOM 组件 扩展到 Web,甚至整合 2D3D 渲染。该系统灵活到足以让应用的不同部分使用不同的方法——在组件级别实现无缝集成。

🌐 Because React's promise of "learn once, write anywhere", it now extends to SwiftUI and Jetpack Compose. With Expo UI, you can apply your SwiftUI knowledge to build apps that run in the React Native ecosystem, extend to the Web through DOM components, and even integrate 2D and 3D rendering. The system is flexible enough that different parts of your app can use different approaches — giving you seamless integration at the component level.

其他资源

🌐 Additional resources

Expo UI 参考

有关 API 组件、方法等的信息,请参阅 Expo UI 参考。

Expo UI 示例

我们最新的 Expo UI 示例

热巧克力应用示例

一个使用 Expo UI 复刻 YVR 热巧克力节应用的示例应用

Expo UI 复制到电视的示例

TVOS 对 Expo UI 的支持