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 扩展

了解如何创建与 Expo UI 集成的自定义 SwiftUI 组件和修饰符

iOS
tvOS

本指南介绍如何使用 Expo Modules API 创建自定义 SwiftUI 组件和修饰符,并将其集成到 Expo UI 中。

Prerequisites

3 requirements

1.

@expo/ui 已安装

在项目中安装 @expo/ui。有关更多信息,请参阅 Expo UI 中的 SwiftUI 组件。

Terminal
- npx expo install @expo/ui

2.

开发构建

自定义 Expo 模块包含原生代码,Expo Go 无法加载。请为应用创建开发构建。

3.

熟悉 Expo Modules API 和 SwiftUI

本指南假设你对 Expo Modules API 和 SwiftUI 有基本了解。

创建自定义组件

项目设置

1

在项目中创建本地 Expo 模块:

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

2

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

modules/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 视图

3

通过以下两部分创建 SwiftUI 视图:

  1. Props 类:继承自 ExpoUI 中的 UIBaseViewProps,以自动支持 modifiers 属性
  2. View 结构体:遵循 ExpoSwiftUI.View 协议,该协议要求提供一个 @ObservedObject props 属性和一个 body
modules/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 使用:

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

5

创建一个封装组件,将修饰符与事件处理连接起来。createViewModifierEventListener 工具可使 onTapGesture 和 onAppear 等基于事件的修饰符在自定义视图中正常工作:

modules/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} /> ); }

6

从模块的入口点导出组件:

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

使用自定义组件

现在,自定义组件可以使用所有内置的 Expo UI 修饰符:

src/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 Index() { return ( <Host style={{ flex: 1 }}> <MyCustomView title="Hello World" modifiers={[ padding({ all: 16 }), background('#f0f0f0'), cornerRadius(12), ]}> <Text>Child content</Text> </MyCustomView> </Host> ); }

创建自定义修饰符

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

原生修饰符实现

1

创建一个遵循 ViewModifier 和 Record 的修饰符结构体:

modules/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 注册修饰符。为避免与 SwiftUI 渲染线程发生竞态条件,请在 OnCreate 中调用 register,并在 OnDestroy 中调用 unregister:

modules/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 修饰符函数

3

创建一个生成修饰符配置的 TypeScript 函数:

modules/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

从模块中导出修饰符:

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

使用自定义修饰符

自定义修饰符适用于任何 Expo UI 组件:

src/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 Index() { 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> ); }

后续步骤

现在,自定义组件可以使用内置的修饰符系统。接下来,你可以:

  • 使用 Expo UI 附带的内置 SwiftUI 组件
  • 为应用专属的样式模式构建自定义修饰符
  • 封装第三方 SwiftUI 库,以便在 React Native 中使用
  • 将组件作为 npm 软件包分享给其他人使用