使用 SwiftUI 扩展
学习如何创建与 Expo UI 集成的自定义 SwiftUI 组件和修改器。
本指南解释了如何创建自定义 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:
@expo/ui已安装在你的项目中。有关更多信息,请参阅 使用 Expo UI 构建 SwiftUI 应用。- 你的应用的开发版本(Expo UI 在 Expo Go 中不可用)
- 对 Expo Modules API 和 SwiftUI 的基本了解
- npx expo install @expo/ui创建自定义组件
🌐 Creating a custom component
项目设置
🌐 Project setup
1
在你的项目中创建一个本地 Expo 模块:
🌐 Create a local Expo module in your project:
- npx create-expo-module@latest --local my-ui2
在你的模块的 podspec 文件中将 ExpoUI 添加为依赖:
🌐 Add ExpoUI as a dependency in your module's podspec file:
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:
- Props 类:从
ExpoUI扩展UIBaseViewProps以自动支持modifiers属性 - View 结构体:遵循
ExpoSwiftUI.View协议,该协议要求有一个@ObservedObjectprops 属性和一个body
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:
import ExpoModulesCore import ExpoUI public class MyUiModule: Module { public func definition() -> ModuleDefinition { Name("MyUi") ExpoUIView(MyCustomView.self) } }
5
创建一个封装组件,将修饰符与事件处理连接起来。createViewModifierEventListener 工具使基于事件的修饰符如 onTapGesture 和 onAppear 可以在你的自定义视图中使用:
🌐 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:
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:
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
创建一个符合 ViewModifier 和 Record 的修饰符结构体:
🌐 Create a modifier struct that conforms to ViewModifier and Record:
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:
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:
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:
export { MyCustomView, type MyCustomViewProps } from './src/MyCustomView'; export { customBorder } from './src/modifiers';
使用自定义修饰符
🌐 Using custom modifiers
你的自定义修改器适用于任何 ExpoUI 组件:
🌐 Your custom modifier works with any ExpoUI component:
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 包分享给其他人使用