RN主机视图

一个可以在 SwiftUI 中使用 React Native 视图的组件。

iOS
tvOS
Bundled version:
~55.0.2

一个组件,当 React Native 视图在 SwiftUI 组件内渲染时,可以实现正确的布局行为。它通过更新 shadow 节点的大小,将布局信息从 SwiftUI 同步回 React Native 的 Yoga 布局系统。

🌐 A component that enables proper layout behavior when React Native views are rendered inside SwiftUI components. It syncs layout information from SwiftUI back to React Native's Yoga layout system by updating the shadow node size.

当 React Native 视图被放置在 SwiftUI 组件中,例如 BottomSheetPopoverHStack 等时,布局系统需要进行通信。RNHostView 架起了这道桥梁:

🌐 When React Native views are placed inside SwiftUI components like BottomSheet, Popover or HStack and so on, the layout systems need to communicate. RNHostView bridges this gap:

  • 使用 matchContents:阴影节点的大小设置为匹配子 React Native 视图的固有大小,从而允许 SwiftUI 父视图根据 React Native 内容来调整自身大小。
  • 没有 matchContents:影子节点大小设置为与父 SwiftUI 视图的大小相匹配,使 React Native 内容能够填充可用空间(对于 flex: 1 布局很有用)。

安装

🌐 Installation

Terminal
npx expo install @expo/ui

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

用法

🌐 Usage

matchContents 的基本用法

🌐 Basic usage with matchContents

当你希望 SwiftUI 父视图根据 React Native 内容来调整自身大小时,使用 matchContents

🌐 Use matchContents when you want the SwiftUI parent to size itself based on the React Native content.

RNHostView with matchContents
import { useState } from 'react'; import { Pressable, Text, View } from 'react-native'; import { Host, BottomSheet, Button, RNHostView } from '@expo/ui/swift-ui'; function Example() { const [isPresented, setIsPresented] = useState(false); return ( <Host style={{ flex: 1 }}> <Button label="Open Sheet" onPress={() => setIsPresented(true)} /> <BottomSheet isOpened={isPresented} onIsOpenedChange={setIsPresented}> <RNHostView matchContents> <View style={{ padding: 24 }}> <Text style={{ fontSize: 18, fontWeight: 'bold' }}>React Native Content</Text> <Pressable style={{ backgroundColor: '#007AFF', padding: 12, borderRadius: 8, marginTop: 16 }} onPress={() => setIsPresented(false)}> <Text style={{ color: 'white', textAlign: 'center' }}>Close</Text> </Pressable> </View> </RNHostView> </BottomSheet> </Host> ); }

没有匹配内容的灵活内容

🌐 Flexible content without matchContents

在你的 React Native 内容中使用 flex: 1 时,省略 matchContents 属性,这样内容就会填满可用的 SwiftUI 空间。

🌐 When using flex: 1 in your React Native content, omit the matchContents prop so the content fills the available SwiftUI space.

RNHostView with flex content
import { useState } from 'react'; import { Text, View } from 'react-native'; import { Host, BottomSheet, Button, RNHostView } from '@expo/ui/swift-ui'; function Example() { const [isPresented, setIsPresented] = useState(false); return ( <Host style={{ flex: 1 }}> <Button label="Open Sheet" onPress={() => setIsPresented(true)} /> <BottomSheet isOpened={isPresented} onIsOpenedChange={setIsPresented} presentationDetents={['medium', 'large']}> <RNHostView> <View style={{ flex: 1, backgroundColor: '#007AFF', padding: 24 }}> <Text style={{ color: 'white', fontSize: 18 }}> This content fills the available space </Text> </View> </RNHostView> </BottomSheet> </Host> ); }

与弹出框一起使用

🌐 Usage with Popover

RNHostViewPopover 内部工作良好,可显示互动的 React Native 内容。

RNHostView in Popover
import { useState } from 'react'; import { Pressable, Text, View } from 'react-native'; import { Host, Button, Popover, RNHostView } from '@expo/ui/swift-ui'; function Example() { const [isPresented, setIsPresented] = useState(false); const [counter, setCounter] = useState(0); return ( <Host style={{ flex: 1 }}> <Popover isPresented={isPresented} onIsPresentedChange={setIsPresented}> <Popover.Trigger> <Button onPress={() => setIsPresented(true)} label="Show Popover" /> </Popover.Trigger> <Popover.Content> <RNHostView matchContents> <View style={{ padding: 24 }}> <Text style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 8 }}> React Native Content </Text> <Text style={{ color: '#666', marginBottom: 12 }}>Counter: {counter}</Text> <Pressable style={{ backgroundColor: '#007AFF', padding: 12, borderRadius: 8, alignItems: 'center', }} onPress={() => setCounter(counter + 1)}> <Text style={{ color: 'white', fontWeight: '600' }}>Increment</Text> </Pressable> </View> </RNHostView> </Popover.Content> </Popover> </Host> ); }

应用接口

🌐 API

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

Component

RNHostView

iOS
tvOS

Type: React.Element<RNHostViewProps>

RNHostViewProps

children

iOS
tvOS
Type: React.ReactElement

The RN View to be hosted.

matchContents

iOS
tvOS
Optional • Type: boolean • Default: false

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