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 组件和修饰符。
Recommended version:
~57.0.22
本指南解释了如何使用 Expo Modules API 创建自定义的 Jetpack Compose 组件和修饰符,并与 Expo UI 集成。
🌐 This guide explains how to use the Expo Modules API to create custom Jetpack Compose components and modifiers that integrate with Expo UI.
2.
你的应用的开发版本
自定义的 Expo 模块包含原生代码,Expo Go 无法加载。请为你的应用创建一个开发版本 。
3.
对 Expo 模块 API 和 Jetpack Compose 的基础了解
创建自定义组件
🌐 Creating a custom component
项目设置
🌐 Project setup
1
在你的项目中创建一个本地 Expo 模块:
🌐 Create a local Expo module in your project:
- npx create-expo-module@latest --local my-ui
2
更新你模块的 android/build.gradle 以启用 Jetpack Compose 并依赖 expo-ui。下面代码片段中的注释标出了你在默认脚手架中添加的行:
🌐 Update your module's android/build.gradle to enable Jetpack Compose and depend on expo-ui. Comments in the following snippet mark the lines you add to the default scaffold:
modules/my-ui/android/build.gradle
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'
android {
buildFeatures {
compose true
}
}
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 视图
🌐 Creating a Compose view
3
创建你的 Compose 视图。它有两个部分:
🌐 Create your Compose view. It has two parts:
Props 数据类 :有 @OptimizedComposeProps 注解,实现 ComposeProps,并包含一个 modifiers: ModifierList 字段用于 modifiers prop。
@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 ( ) )
}
}
4
使用 ExpoUIView 在你的模块中注册视图。这会将你的 @Composable 内容连接到 Expo 模块视图系统,并使其可供 JavaScript 使用:
🌐 Register the view in your module using ExpoUIView. This wires your @Composable content into the Expo modules view system and makes it available to 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 可以与你的自定义视图一起使用:
🌐 Create a wrapper component that connects modifiers with event handling. The createViewModifierEventListener utility enables event-based modifiers like clickable and onVisibilityChanged to work with your custom view:
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
从你的模块入口导出组件:
🌐 Export the component from your module's entry point:
export {
MyCustomView,
type MyCustomViewProps ,
} from './src/MyCustomView' ;
使用自定义组件
🌐 Using your custom component
你的自定义组件现在可以使用所有内置的 Expo UI 修饰符了:
🌐 Your custom component now works with all built-in Expo UI modifiers:
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 = " 你好,世界"
modifiers = { [
paddingAll ( 16 ) ,
background ( '#f0f0f0' ) ,
clip ( { type: 'roundedCorner' , radius: 12 } ) ,
] } >
< Text > Child content </ Text >
</ MyCustomView >
</ Host >
) ;
}
创建自定义修改器
🌐 Creating custom modifiers
你也可以创建适用于任何 Expo UI 组件的自定义修改器。
🌐 You can also create custom modifiers that work with any Expo UI component.
信息 修饰符是 Compose 用于配置布局的方式,可用于样式、大小、行为等。更多内容请参见 Android 的 Compose 修饰符文档 。
本地修饰符实现
🌐 Native modifier implementation
1
将你的修饰符参数定义为一个 @OptimizedRecord 数据类。然后写一个函数,从这些参数返回一个 Modifier:
🌐 Define your modifier's parameters as an @OptimizedRecord data class. Then write a function that returns a Modifier from those parameters:
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 取消注册,以防工厂在模块重新加载时泄漏:
🌐 Register your modifier with ModifierRegistry in your module definition. Use OnCreate to register and OnDestroy to unregister so the factory does not leak across module reloads:
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 修改函数
🌐 JavaScript modifier function
3
创建一个 TypeScript 函数来构建修饰符配置:
🌐 Create a TypeScript function that builds the modifier config:
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
从你的模块导出修改器:
🌐 Export the modifier from your module:
export {
MyCustomView,
type MyCustomViewProps ,
} from './src/MyCustomView' ;
export { customBorder } from './src/modifiers' ;
使用自定义修饰符
🌐 Using custom modifiers
你的自定义修饰符可以用于任何 Expo UI 组件:
🌐 Your custom modifier works with any Expo UI component:
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 >
) ;
}
下一步
🌐 Next steps
你自定义的组件现在可以和内置的修改器系统一起使用了。
🌐 Your custom components now work with the built-in modifier system.
以下是一些下一步可以构建的想法:
🌐 Here are some ideas for what to build next:
使用随 Expo UI 提供的 内置 Jetpack Compose 组件 。
为特定应用的样式模式构建自定义修饰符。
将第三方 Compose 库封装以供在 React Native 中使用。
将你的组件作为 npm 包分享给其他人使用。