使用 SwiftUI 扩展

学习如何创建与 Expo UI 集成的自定义 SwiftUI 组件和修改器。

iOS
tvOS

本指南解释了如何创建自定义 SwiftUI 组件和修改器,并与 Expo UI 无缝集成。

🌐 This guide explains how to create custom SwiftUI components and modifiers that integrate seamlessly with Expo UI.

先决条件

🌐 Prerequisites

在开始之前,请确保你已经拥有:

🌐 Before you begin, make sure you have:

Terminal
npx expo install @expo/ui

创建自定义组件

🌐 Creating a custom component

项目设置

🌐 Project setup

1

在你的项目中创建一个本地 Expo 模块:

🌐 Create a local Expo module in your project:

Terminal
npx create-expo-module@latest --local my-ui

2

在你的模块的 podspec 文件中将 ExpoUI 添加为依赖:

🌐 Add ExpoUI as a dependency in your module's podspec file:

my-ui/ios/MyUi.podspec
Pod::Spec.new do |s| s.name = 'MyUi' s.version = '1.0.0' s.summary = 'Custom UI components extending Expo UI' # ... other config # Add ExpoUI dependency s.dependency 'ExpoUI' # ... other config end

创建一个 SwiftUI 视图

🌐 Creating a SwiftUI view

3

创建一个由两部分组成的 SwiftUI 视图:

🌐 Create your SwiftUI view with two parts:

  1. Props 类:从 ExpoUI 扩展 UIBaseViewProps 以自动支持 modifiers 属性
  2. View 结构体:遵循 ExpoSwiftUI.View 协议,该协议要求有一个 @ObservedObject props 属性和一个 body
my-ui/ios/MyCustomView.swift
import SwiftUI import ExpoModulesCore import ExpoUI final class MyCustomViewProps: UIBaseViewProps { @Field var title: String = "" } struct MyCustomView: ExpoSwiftUI.View { @ObservedObject public var props: MyCustomViewProps var body: some View { VStack { Text(props.title) .font(.headline) Children() // Renders React children } } }

4

使用 ExpoUIView 在你的模块中注册视图。这会将你的 SwiftUI 视图封装为支持修饰符,并使其可供 JavaScript 使用:

🌐 Register the view in your module using ExpoUIView. This wraps your SwiftUI view with modifier support and makes it available to JavaScript:

my-ui/ios/MyUiModule.swift
import ExpoModulesCore import ExpoUI public class MyUiModule: Module { public func definition() -> ModuleDefinition { Name("MyUi") ExpoUIView(MyCustomView.self) } }

5

创建一个封装组件,将修饰符与事件处理连接起来。createViewModifierEventListener 工具使基于事件的修饰符如 onTapGestureonAppear 可以在你的自定义视图中使用:

🌐 Create a wrapper component that connects modifiers with event handling. The createViewModifierEventListener utility enables event-based modifiers like onTapGesture and onAppear to work with your custom view:

my-ui/src/MyCustomView.tsx
import { requireNativeView } from 'expo'; import { type CommonViewModifierProps } from '@expo/ui/swift-ui'; import { createViewModifierEventListener } from '@expo/ui/swift-ui/modifiers'; export interface MyCustomViewProps extends CommonViewModifierProps { title: string; children?: React.ReactNode; } const NativeMyCustomView = requireNativeView<MyCustomViewProps>('MyUi', 'MyCustomView'); export function MyCustomView({ modifiers, ...restProps }: MyCustomViewProps) { return ( <NativeMyCustomView modifiers={modifiers} {...(modifiers ? createViewModifierEventListener(modifiers) : undefined)} {...restProps} /> ); }

使用自定义组件

🌐 Using your custom component

你的自定义组件现在可以与所有 ExpoUI 内置修饰符一起使用:

🌐 Your custom component now works with all ExpoUI built-in modifiers:

app/index.tsx
import { Host, Text } from '@expo/ui/swift-ui'; import { padding, cornerRadius, background } from '@expo/ui/swift-ui/modifiers'; import { MyCustomView } from './modules/my-ui'; export default function App() { return ( <Host style={{ flex: 1 }}> <MyCustomView title="你好,世界" modifiers={[padding({ all: 16 }), cornerRadius(12), background('#f0f0f0')]}> <Text>Child content</Text> </MyCustomView> </Host> ); }

创建自定义修改器

🌐 Creating custom modifiers

你也可以创建适用于任何 Expo UI 组件的自定义修改器。

🌐 You can also create custom modifiers that work with any Expo UI component.

信息 修饰符是 SwiftUI 用于配置视图的方式,可用于样式、布局、行为等。更多信息请参阅苹果的 ViewModifier 文档

本地修饰符实现

🌐 Native modifier implementation

1

创建一个符合 ViewModifierRecord 的修饰符结构体:

🌐 Create a modifier struct that conforms to ViewModifier and Record:

my-ui/ios/CustomBorderModifier.swift
import SwiftUI import ExpoModulesCore import ExpoUI struct CustomBorderModifier: ViewModifier, Record { @Field var color: Color = .red @Field var width: CGFloat = 2 @Field var cornerRadius: CGFloat = 0 func body(content: Content) -> some View { content .overlay( RoundedRectangle(cornerRadius: cornerRadius) .stroke(color, lineWidth: width) ) } }

2

在模块定义中使用 ViewModifierRegistry 注册你的修改器。使用 OnCreate 进行注册,使用 OnDestroy 进行注销,以避免与 SwiftUI 渲染线程的竞争条件:

🌐 Register your modifier with ViewModifierRegistry in your module definition. Use OnCreate to register and OnDestroy to unregister to avoid race conditions with the SwiftUI render thread:

my-ui/ios/MyUiModule.swift
import ExpoModulesCore import ExpoUI public class MyUiModule: Module { public func definition() -> ModuleDefinition { Name("MyUi") OnCreate { ViewModifierRegistry.register("customBorder") { params, appContext, _ in return try CustomBorderModifier(from: params, appContext: appContext) } } OnDestroy { ViewModifierRegistry.unregister("customBorder") } ExpoUIView(MyCustomView.self) } }

JavaScript 修改函数

🌐 JavaScript modifier function

3

创建一个生成修改器配置的 TypeScript 函数:

🌐 Create a TypeScript function that generates the modifier config:

my-ui/src/modifiers.ts
import { createModifier } from '@expo/ui/swift-ui/modifiers'; export const customBorder = (params: { color?: string; width?: number; cornerRadius?: number }) => createModifier('customBorder', params);

4

从你的模块导出修改器:

🌐 Export the modifier from your module:

my-ui/index.ts
export { MyCustomView, type MyCustomViewProps } from './src/MyCustomView'; export { customBorder } from './src/modifiers';

使用自定义修饰符

🌐 Using custom modifiers

你的自定义修改器适用于任何 ExpoUI 组件:

🌐 Your custom modifier works with any ExpoUI component:

app/index.tsx
import { Host, Text, VStack } from '@expo/ui/swift-ui'; import { padding } from '@expo/ui/swift-ui/modifiers'; import { customBorder } from './modules/my-ui'; export default function App() { return ( <Host style={{ flex: 1 }}> <VStack modifiers={[ padding({ all: 20 }), customBorder({ color: '#FF6B35', width: 3, cornerRadius: 8 }), ]}> <Text>This has a custom border!</Text> </VStack> </Host> ); }

下一步

🌐 Next steps

恭喜!你已经学会了如何使用自定义 SwiftUI 组件和修饰符扩展 Expo UI。你的自定义组件现在可以与内置的修饰符系统无缝集成。

🌐 Congratulations! You've learned how to extend Expo UI with custom SwiftUI components and modifiers. Your custom components now integrate seamlessly with the built-in modifier system.

以下是一些下一步可以构建的想法:

🌐 Here are some ideas for what to build next:

  • 使用随 Expo UI 提供的内置 SwiftUI 组件
  • 为应用特定的样式模式构建自定义修饰符
  • 为 React Native 封装第三方 SwiftUI 库
  • 将你的组件作为 npm 包分享给其他人使用