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.

使用 Jetpack Compose 扩展

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

Android

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

Prerequisites

3 requirements

1.

@expo/ui 已安装

更多信息请参阅 Expo UI 中的 Jetpack Compose 组件。

Terminal
- npx expo install @expo/ui

2.

应用的开发构建版本

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

3.

熟悉 Expo Modules API 和 Jetpack Compose 基础知识

本指南假设你基本了解 Expo Modules API 和 Jetpack Compose。

创建自定义组件

项目设置

1

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

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

2

更新模块的 android/build.gradle,启用 Jetpack Compose 并依赖 expo-ui。以下代码片段中的注释标记了你需要添加到默认脚手架中的行:

modules/my-ui/android/build.gradle
// Pull in the Kotlin Compose compiler plugin classpath. buildscript { repositories { mavenCentral() } dependencies { classpath("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:${kotlinVersion}") } } apply plugin: 'com.android.library' apply plugin: 'expo-module-gradle-plugin' apply plugin: 'org.jetbrains.kotlin.plugin.compose' // 应用 Compose 编译器插件。 // ... group / version android { // ... namespace, defaultConfig // 为此模块开启 Jetpack Compose。 buildFeatures { compose true } } // 依赖 `expo-ui` 以及你使用的 Compose 库。 dependencies { if (findProject(':expo-ui') != null) { implementation project(':expo-ui') } else { implementation 'expo.modules.ui:expo.modules.ui:+' } implementation 'androidx.compose.foundation:foundation-android:1.10.6' implementation 'androidx.compose.ui:ui-android:1.10.6' implementation 'androidx.compose.material3:material3:1.5.0-alpha17' }

创建 Compose 视图

3

创建你的 Compose 视图。它由两部分组成:

  1. Props data class:带有 @OptimizedComposeProps 注解、实现 ComposeProps,并包含一个 modifiers: ModifierList 字段,用于 modifiers 属性。
  2. @Composable 内容函数:扩展自 FunctionalComposableScope,以便调用 ModifierRegistry.applyModifiers(...) 并渲染 Children(...)。
modules/my-ui/android/src/main/java/expo/modules/myui/MyCustomView.kt
package expo.modules.myui import androidx.compose.foundation.layout.Column import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import expo.modules.kotlin.views.ComposeProps import expo.modules.kotlin.views.FunctionalComposableScope import expo.modules.kotlin.views.OptimizedComposeProps import expo.modules.ui.ModifierList import expo.modules.ui.ModifierRegistry import expo.modules.ui.UIComposableScope @OptimizedComposeProps data class MyCustomViewProps( val title: String = "", val modifiers: ModifierList = emptyList() ) : ComposeProps @Composable fun FunctionalComposableScope.MyCustomViewContent(props: MyCustomViewProps) { Column( modifier = ModifierRegistry.applyModifiers( props.modifiers, appContext, composableScope, globalEventDispatcher ) ) { Text(text = props.title, style = MaterialTheme.typography.titleMedium) Children(UIComposableScope()) // 渲染 React 子元素 } }

4

在你的模块中使用 ExpoUIView 注册该视图。这会将你的 @Composable 内容接入 Expo modules 视图系统,并使其可供 JavaScript 使用:

modules/my-ui/android/src/main/java/expo/modules/myui/MyUiModule.kt
package expo.modules.myui import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import expo.modules.ui.ExpoUIView class MyUiModule : Module() { override fun definition() = ModuleDefinition { Name("MyUi") ExpoUIView<MyCustomViewProps>("MyCustomView") { Content { props -> MyCustomViewContent(props) } } } }

5

创建一个包装组件,将修饰符与事件处理连接起来。createViewModifierEventListener 工具可让诸如 clickable 和 onVisibilityChanged 之类的事件型修饰符与自定义视图协同工作:

modules/my-ui/src/MyCustomView.tsx
import { type PrimitiveBaseProps } from '@expo/ui/jetpack-compose'; import { createViewModifierEventListener } from '@expo/ui/jetpack-compose/modifiers'; import { requireNativeView } from 'expo'; export interface MyCustomViewProps extends PrimitiveBaseProps { 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/jetpack-compose'; import { background, clip, paddingAll, } from '@expo/ui/jetpack-compose/modifiers'; import { MyCustomView } from '../../modules/my-ui'; export default function Index() { return ( <Host style={{ flex: 1 }}> <MyCustomView title="Hello World" modifiers={[ paddingAll(16), background('#f0f0f0'), clip({ type: 'roundedCorner', radius: 12 }), ]}> <Text>子内容</Text> </MyCustomView> </Host> ); }

创建自定义修饰符

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

原生修饰符实现

1

将修饰符的参数定义为 @OptimizedRecord 数据类。然后编写一个函数,根据这些参数返回 Modifier:

modules/my-ui/android/src/main/java/expo/modules/myui/CustomBorderModifier.kt
package expo.modules.myui import android.graphics.Color import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.border import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import expo.modules.kotlin.records.Field import expo.modules.kotlin.records.Record import expo.modules.kotlin.types.OptimizedRecord import expo.modules.ui.compose @OptimizedRecord data class CustomBorderParams( @Field val color: Color? = null, @Field val width: Int = 2, @Field val cornerRadius: Int = 0 ) : Record fun customBorderModifier(params: CustomBorderParams): Modifier { return Modifier.border( border = BorderStroke(params.width.dp, params.color.compose), shape = RoundedCornerShape(params.cornerRadius.dp) ) }

compose 是 expo.modules.ui 包中定义的 android.graphics.Color? 的 Kotlin 扩展属性。通过 import expo.modules.ui.compose 导入它后,你就可以调用 params.color.compose,将从 JS 解析得到的 Android Color 转换为 Compose API(如 BorderStroke)所期望的 androidx.compose.ui.graphics.Color。这与 Expo UI 内置修饰符使用的是同一个辅助工具。

2

在模块定义中使用 ModifierRegistry 注册你的修饰符。使用 OnCreate 进行注册,使用 OnDestroy 进行注销,这样工厂就不会在模块重新加载之间泄漏:

modules/my-ui/android/src/main/java/expo/modules/myui/MyUiModule.kt
package expo.modules.myui import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import expo.modules.kotlin.records.recordFromMap import expo.modules.ui.ExpoUIView import expo.modules.ui.ModifierRegistry class MyUiModule : Module() { override fun definition() = ModuleDefinition { Name("MyUi") OnCreate { ModifierRegistry.register("customBorder") { map, _, _, _ -> customBorderModifier(recordFromMap<CustomBorderParams>(map)) } } OnDestroy { ModifierRegistry.unregister("customBorder") } ExpoUIView<MyCustomViewProps>("MyCustomView") { Content { props -> MyCustomViewContent(props) } } } }

register lambda 会接收从 JavaScript 发送来的原始 map、当前的 ComposableScope(用于像 weight 或 align 这类依赖作用域的修饰符)、AppContext 以及事件分发器。大多数修饰符只需要 map,并通过 recordFromMap<T>(map) 将其转换。

JavaScript 修饰符函数

3

创建一个用于构建修饰符配置的 TypeScript 函数:

modules/my-ui/src/modifiers.ts
import { createModifier } from '@expo/ui/jetpack-compose/modifiers'; import { type ColorValue } from 'react-native'; export const customBorder = (params: { color?: ColorValue; 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 { Column, Host, Text } from '@expo/ui/jetpack-compose'; import { paddingAll } from '@expo/ui/jetpack-compose/modifiers'; import { customBorder } from '../../modules/my-ui'; export default function Index() { return ( <Host style={{ flex: 1 }}> <Column modifiers={[ paddingAll(20), customBorder({ color: '#FF6B35', width: 3, cornerRadius: 8, }), ]}> <Text>This has a custom border!</Text> </Column> </Host> ); }

下一步

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

以下是一些下一步可以尝试构建的内容:

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