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.

RNHostView

一个允许在 Jetpack Compose 中使用 React Native 视图的组件。

Android
Included in Expo Go

一个组件,当 React Native 视图渲染在 Jetpack Compose 组件内部时,可启用正确的布局行为。它通过更新 shadow node 的大小,将 Jetpack Compose 的布局信息同步回 React Native 的 Yoga 布局系统。

当 React Native 视图放置在诸如 ModalBottomSheet、Card、Row、Column 等 Jetpack Compose 组件内部时,布局系统需要进行通信。RNHostView 负责弥合这一差距:

  • 使用 matchContents:shadow node 的大小会设置为与子 React Native 视图的固有大小一致,从而允许 Jetpack Compose 父组件根据 React Native 内容来确定自身大小。
  • 不使用 matchContents:shadow node 的大小会设置为与父 Jetpack Compose 视图的大小一致,从而允许 React Native 内容填充可用空间(对 flex: 1 布局很有用)。

安装

Terminal
- npx expo install @expo/ui
- yarn expo install @expo/ui
- pnpm expo install @expo/ui
- bun expo install @expo/ui

If you are installing this in an existing React Native app, make sure to install expo in your project.

用法

使用 matchContents 的基本用法

当你希望 Jetpack Compose 父组件根据 React Native 内容来确定自身大小时,请使用 matchContents。

RNHostViewCounterExample.tsx
import { useState } from 'react'; import { Pressable, Text as RNText } from 'react-native'; import { Host, Card, Column, Row, RNHostView, Text, } from '@expo/ui/jetpack-compose'; import { fillMaxWidth, padding, } from '@expo/ui/jetpack-compose/modifiers'; export default function RNHostViewCounterExample() { const [counter, setCounter] = useState(0); return ( <Host matchContents={{ vertical: true }} style={{ width: '100%' }}> <Card modifiers={[fillMaxWidth()]}> <Column verticalArrangement={{ spacedBy: 12 }} modifiers={[padding(16, 16, 16, 16)]}> <Text>Mixing RN Components with Compose</Text> <Row horizontalArrangement={{ spacedBy: 24 }} verticalAlignment="center"> <RNHostView matchContents> <Pressable onPress={() => setCounter(prev => prev - 1)} style={{ height: 50, width: 50, borderRadius: 100, justifyContent: 'center', alignItems: 'center', backgroundColor: '#9B59B6', }}> <RNText style={{ color: 'white', fontSize: 24 }}> - </RNText> </Pressable> </RNHostView> <Text>{counter}</Text> <RNHostView matchContents> <Pressable onPress={() => setCounter(prev => prev + 1)} style={{ height: 50, width: 50, borderRadius: 100, justifyContent: 'center', alignItems: 'center', backgroundColor: '#9B59B6', }}> <RNText style={{ color: 'white', fontSize: 24 }}> + </RNText> </Pressable> </RNHostView> </Row> </Column> </Card> </Host> ); }

不使用 matchContents 时的弹性内容

当你的 React Native 内容中使用 flex: 1 时,请省略 matchContents 属性,这样内容就会填充可用的 Jetpack Compose 空间。

RNHostViewFlexExample.tsx
import { View } from 'react-native'; import { Host, Card, Column, Row, RNHostView, Text, } from '@expo/ui/jetpack-compose'; import { fillMaxWidth, padding, size, } from '@expo/ui/jetpack-compose/modifiers'; export default function RNHostViewFlexExample() { return ( <Host matchContents={{ vertical: true }} style={{ width: '100%' }}> <Card modifiers={[fillMaxWidth()]}> <Column verticalArrangement={{ spacedBy: 12 }} modifiers={[padding(16, 16, 16, 16)]}> <Text>带有 flex: 1 子元素的 RN 组件</Text> <Row horizontalArrangement={{ spacedBy: 20 }} modifiers={[size(100, 100)]}> <RNHostView> <View style={{ flex: 1, backgroundColor: '#9B59B6', borderRadius: 10, }} /> </RNHostView> </Row> </Column> </Card> </Host> ); }

与 ModalBottomSheet 搭配使用

RNHostView 在 ModalBottomSheet 内部同样表现良好,可用于展示可交互的 React Native 内容。

RNHostViewSheetExample.tsx
import { useRef, useState } from 'react'; import { Pressable, Text as RNText, View } from 'react-native'; import { Host, ModalBottomSheet, Button, Column, RNHostView, Text, useMaterialColors, } from '@expo/ui/jetpack-compose'; import type { ModalBottomSheetRef } from '@expo/ui/jetpack-compose'; import { padding } from '@expo/ui/jetpack-compose/modifiers'; export default function RNHostViewSheetExample() { const [visible, setVisible] = useState(false); const sheetRef = useRef<ModalBottomSheetRef>(null); const colors = useMaterialColors(); const hideSheet = async () => { await sheetRef.current?.hide(); setVisible(false); }; return ( <Host matchContents> <Button onClick={() => setVisible(true)}> <Text>打开抽屉</Text> </Button> {visible && ( <ModalBottomSheet ref={sheetRef} onDismissRequest={() => setVisible(false)}> <Column verticalArrangement={{ spacedBy: 16 }} modifiers={[padding(16, 16, 16, 16)]}> <Text>在底部抽屉中混合使用 Compose 和 RN</Text> <RNHostView matchContents> <View> <RNText style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 8, color: colors.onSurface, }}> React Native 内容 </RNText> <Pressable style={{ backgroundColor: '#007AFF', padding: 12, borderRadius: 8, alignItems: 'center', }} onPress={hideSheet}> <RNText style={{ color: 'white', fontWeight: '600' }}> Close </RNText> </Pressable> </View> </RNHostView> </Column> </ModalBottomSheet> )} </Host> ); }

底部抽屉中的弹性 React Native 内容

使用不带 matchContents 的 RNHostView,让 React Native 视图填充抽屉中的剩余空间。结合父 Column 上的 height 修饰符来控制抽屉大小。

RNHostViewFlexSheetExample.tsx
import { useRef, useState } from 'react'; import { Text as RNText, View } from 'react-native'; import { Host, ModalBottomSheet, Button, Column, RNHostView, Text, } from '@expo/ui/jetpack-compose'; import type { ModalBottomSheetRef } from '@expo/ui/jetpack-compose'; import { height, padding, } from '@expo/ui/jetpack-compose/modifiers'; export default function RNHostViewFlexSheetExample() { const [visible, setVisible] = useState(false); const sheetRef = useRef<ModalBottomSheetRef>(null); return ( <Host matchContents> <Button onClick={() => setVisible(true)}> <Text>打开弹性内容抽屉</Text> </Button> {visible && ( <ModalBottomSheet ref={sheetRef} onDismissRequest={() => setVisible(false)} skipPartiallyExpanded> <Column modifiers={[height(400), padding(16, 16, 16, 16)]}> <RNHostView> <View style={{ flex: 1, backgroundColor: '#9B59B6', borderRadius: 10, }}> <RNText style={{ color: 'white', fontSize: 18, fontWeight: 'bold', padding: 16, }}> React Native 内容(flex: 1) </RNText> </View> </RNHostView> </Column> </ModalBottomSheet> )} </Host> ); }

API

import { RNHostView } from '@expo/ui/jetpack-compose';

Component

RNHostView

Android

Type: React.Element<RNHostProps>

RNHostViewProps

children

Android
Type: ReactElement

The RN View to be hosted.

matchContents

Android
Optional • Type: boolean • Default: false

When true, the RNHost will update its size in the Jetpack Compose view tree to match the children's size. When false, the RNHost will use the size of the parent Jetpack Compose View. Can be only set once on mount.

modifiers

Android
Optional • Type: ModifierConfig[]

Modifiers for the component.

onLayout

Android
Optional • Type: (event: LayoutChangeEvent) => void

Called on mount and whenever this view's layout in the React Native view tree changes. With matchContents, the reported size is the one measured from the hosted view.

Inherited props

  • PrimitiveBaseProps