- OpenHarmony
- 移动开发
- 跨平台
【免费下载链接】ohos_react_native
React Native鸿蒙化仓库
导读
本文基于 React Native 鸿蒙化仓库(ohos_react_native)的官方多屏适配指导整理而成,围绕鸿蒙生态设备上"一套代码、多端运行"的目标,系统讲解Flexbox 弹性布局、设备类型与像素密度(Platform/PixelRatio)、Dimensions API、useWindowDimensions Hook四条核心适配路径,并深入剖析折叠屏与可变化窗口场景下的监听与刷新机制。读完本文,你将掌握如何在 React Native 应用中编写对不同屏幕尺寸、分辨率、形态(手机/平板/TV/折叠屏)自适应的 UI 代码,同时了解这些 API 在鸿蒙侧底层(窗口监听、DisplayMetrics 维护、PlatformConstants TurboModule)的真实实现与测试验证方式。
多屏适配背景与鸿蒙的多端能力
"多屏适配"指移动应用在多个设备上运行时,需要适配不同的屏幕尺寸、分辨率以及交互方式,使工程 UI 与显示在各种形状、尺寸的设备上保持一致,为用户提供统一的视觉与操作体验。
以鸿蒙生态设备为例:手机、平板、TV、折叠屏等设备屏幕尺寸与形状各不相同。若界面渲染时对尺寸设置不够灵活,会导致不同机型上的视觉与操作体验不统一;而针对每种设备分别编写代码,又会显著抬高开发成本。鸿蒙系统为此集成了 React Native 框架的多端 UI 适配与交互事件支持,帮助开发者降低开发与维护成本、提高代码复用率。
在 UI 适配方面,React Native 提供了多种设置组件高度和宽度的方法。本文重点展开以下四种:Flexbox 布局、设备类型 + 像素密度(PixelRatio)、Dimensions API以及useWindowDimensions Hook API。
Flexbox 布局:弹性盒模型实现自适应排列
弹性盒(Flexbox)是一种 CSS 布局模型,旨在为页面提供灵活、自适应的排列方式。它通过定义容器和内部项目的行为,使页面元素能够以可预测的方式在容器中排列和分布。React Native 使用 Flexbox 规则来指定组件的子元素布局,且能在不同屏幕尺寸上提供一致的布局结构。React Native 中的 Flexbox 与 Web 上 CSS 的工作原理基本一致,也存在少量差异。
一般来说,使用flexDirection、alignItems和justifyContent三个样式属性即可满足大多数布局需求。
flexDirection:决定主轴方向
在组件style中指定flexDirection可以决定布局的主轴,即子元素沿哪个方向排列,默认值是竖直轴column方向:
column(默认值):子元素从上到下对齐;启用换行后,下一行从容器顶部第一个项目的右侧开始。row:子元素从左到右对齐;启用换行后,下一行在容器左侧第一个项目的下方开始。column-reverse:子元素从底部向上对齐;启用换行后,下一行从容器底部第一个项目的右侧开始。row-reverse:子元素从右到左对齐;启用换行后,下一行在容器右侧第一个项目的下方开始。
alignItems:决定次轴排列方式
alignItems决定子元素沿次轴(与主轴垂直的轴,例如主轴为row时次轴为column)的排列方式,可用选项如下:
stretch(默认值):将子元素拉伸以匹配容器次轴的高度。flex-start:将子元素对齐到容器次轴的起始位置。flex-end:将子元素对齐到容器次轴的末尾位置。center:将子元素居中对齐于容器次轴。baseline:沿公共基线对齐子元素;可以为各子元素设置参考基线,作为其父级基线。
justifyContent:决定主轴排列方式
justifyContent决定子元素沿主轴的排列方式,可用选项如下:
flex-start(默认值):子元素沿主轴起始位置对齐。flex-end:子元素沿主轴末尾位置对齐。center:子元素在主轴上居中对齐。space-between:沿主轴均匀分布子元素,剩余空间平均分配给子元素之间。space-around:沿主轴均匀分布子元素,剩余空间围绕在每个子元素周围;与space-between相比,第一个和最后一个子元素前后也会被分配空间。space-evenly:沿主轴均匀分布子项,每一对相邻项、主轴起始边缘与第一项、主轴结束边缘与最后一项之间的间距完全相同。
flexDirection、alignItems、justifyContent配合flex、flexWrap、alignSelf、gap等属性,即可在不同屏幕宽度上自动换行、伸缩,从根本上规避写死尺寸带来的机型适配问题。
设备类型与像素密度:Platform API 与 PixelRatio
isPad、isTV:判断设备形态
Platform API提供isPad与isTV两个布尔值属性,用于确定当前设备是否为平板或 TV。
在 ohos_react_native 仓库中,鸿蒙侧的Platform实现在 Platform.harmony.ts:
get isPad() { return this.constants.deviceType === 'tablet'; }, get isTV() { return this.constants.deviceType === 'tv'; },可以看到isPad与isTV的取值来自PlatformConstantsTurboModule 返回的deviceType。该字段在鸿蒙侧由 PlatformConstantsTurboModule.ts 通过@ohos.deviceInfo读取:
getConstants() { return { Model: deviceInfo.productModel, deviceType: deviceInfo.deviceType, osFullName: deviceInfo.osFullName, // ... }; }也就是说,Platform.isPad在鸿蒙上等价于"设备类型为 tablet",Platform.isTV等价于"设备类型为 tv",可直接用于为平板/TV 设备定制布局。
此外,鸿蒙侧Platform还有两个值得关注的能力(同样见 Platform.harmony.ts):
Platform.OS === 'harmony':鸿蒙化 RN 框架将操作系统名设为'harmony'。Platform.select({android, ios, native, harmony, default}):优先返回harmony键对应的值,其次native,最后default,可用于按平台差异化取值。
对应测试见 PlatformConstantsTest.tsx,其中验证了Platform.OS === 'harmony'、Platform.Version符合OpenHarmony-x.y.z.w格式、Platform.select正确返回harmony分支值等行为。
PixelRatio:像素密度与字体缩放
PixelRatio可获取设备的像素密度与字体缩放比,常用的方法如下。
get()返回设备像素密度。典型取值示例:
PixelRatio.get() === 1:mdpi Android 设备。PixelRatio.get() === 1.5:hdpi Android 设备。PixelRatio.get() === 2:iPhone SE、6S、7、8、XR、11,xhdpi Android 设备。PixelRatio.get() === 3:iPhone 6S Plus、7 Plus、8 Plus、X、XS、XS Max、11 Pro、11 Pro Max,Pixel、Pixel 2,xxhdpi Android 设备。PixelRatio.get() === 3.5:Nexus 6、Pixel XL、Pixel 2 XL,xxxhdpi Android 设备。
getPixelSizeForLayoutSize()将布局尺寸(dp)转换为像素尺寸(px),一定返回整数:
static getPixelSizeForLayoutSize(layoutSize: number): number典型用法是"根据像素密度获取指定分辨率的图片":应用运行在高像素密度设备上时,显示的图片也应当分辨率更高。取得缩略图的好规则是将显示尺寸乘以像素密度比:
const image = getImage({ width: PixelRatio.getPixelSizeForLayoutSize(200), height: PixelRatio.getPixelSizeForLayoutSize(100), }); <Image source={image} style={{width: 200, height: 100}} />PixelRatio.getPixelSizeForLayoutSize(200)会根据当前设备 pixelratio 返回对应值:若当前 pixelratio 为 2,则返回200 * 2 = 400,最终生成的参数为{ width: 400, height: 200 }。getImage方法需要开发者自行实现,根据传入的不同宽高参数返回不同分辨率尺寸的图片地址。
PixelRatio还有getFontScale()(字体缩放比)与roundToNearestPixel()(将布局尺寸四舍五入到最近像素)等方法。仓库中的 PixelRatioTest.tsx 对上述能力做了系统性验证,例如:
PixelRatio.get()返回值应大于等于 1 且小于 4;PixelRatio.getPixelSizeForLayoutSize(10)应约等于PixelRatio.get() * 10;PixelRatio.roundToNearestPixel(8.4)应等于Math.round(8.4 * ratio) / ratio。
Dimensions API:获取屏幕与窗口尺寸
Dimensions API用于获取设备屏幕独立像素信息。通过调用Dimensions.get()可取得包含屏幕长宽信息的对象,据此把握当前设备屏幕大小,并可简易推测用户是否处于横屏状态:
import { Dimensions } from 'react-native'; const windowWidth = Dimensions.get('window').width; const windowHeight = Dimensions.get('window').height;Dimensions主要有两个方法:
addEventListener():添加事件监听函数:
static addEventListener( type: 'change', handler: ({ window, screen, }: DimensionsValue) => void, ): EmitterSubscription;目前支持的事件为change:在Dimensions对象内部属性发生变化时触发,事件处理程序参数是一个DimensionsValue类型的对象(含window与screen两个字段)。
get():获取指定维度('window'或'screen')的当前值:
static get(dim: 'window' | 'screen'): ScaledSize;初始尺寸在调用runApplication之前设置,因此在运行任何其他 require 之前就应可用,但可能随后更新。示例:const {height, width} = Dimensions.get('window');
仓库的 DimensionsTest.tsx 展示了完整的监听与清理用法:同时为window和screen注册change监听,在useEffect清理函数中分别调用subscription.remove()注销,并在界面上实时展示窗口与屏幕尺寸变化。
useWindowDimensions Hook:响应式获取窗口尺寸
useWindowDimensions会根据用户状态栏、虚拟菜单栏以及设备是否横置返回相应的屏幕长宽;在此基础上封装多个屏幕断点,可在断点变化时自适应调整界面布局,并在屏幕尺寸变化时自动更新获取到的width和height值。使用方法:
import { useWindowDimensions } from 'react-native'; const windowWidth = useWindowDimensions().width; const windowHeight = useWindowDimensions().height;useWindowDimensions返回四个属性:
fontScale:当前使用的字体比例。useWindowDimensions().fontScale;scale:运行应用的设备的像素比率。useWindowDimensions().scale;height:应用所占用的窗口或屏幕的高度(以像素为单位)。useWindowDimensions().height;width:应用所占用的窗口或屏幕的宽度(以像素为单位)。useWindowDimensions().width;
仓库 UseWindowDimensionsTest.tsx 解构出{height, width, scale, fontScale}四个值,并断言它们都大于 0,验证了该 Hook 在鸿蒙环境下能正确返回窗口信息。
这三个 API(Dimensions、PixelRatio、useWindowDimensions)均由 react-native-harmony 的入口 index.js 从./Libraries/Utilities/下导出,与标准 React Native 保持一致的调用方式。
如何适配折叠屏与其他可变屏幕
可折叠设备或屏幕尺寸可变的设备(如平板分屏、多窗口、旋转)场景下,推荐使用事件监听函数或useWindowDimensions:
第一步:感知屏幕变化。开发者通过注册Dimensions.addEventListener("change")监听来感知屏幕变化,不再需要时调用remove取消监听。
第二步:获取屏幕与窗口参数。通过Dimensions.get('window')或Dimensions.get('screen')获取窗口和屏幕参数,包括width、height、scale和fontScale。完整示例:
import React, {useState, useEffect} from 'react'; import { Dimensions } from 'react-native'; const windowDimensions = Dimensions.get('window'); const screenDimensions = Dimensions.get('screen'); const App = () => { const [dimensions, setDimensions] = useState({ window: windowDimensions, screen: screenDimensions, }); useEffect(() => { const subscription = Dimensions.addEventListener( 'change', ({window, screen}) => { setDimensions({window, screen}); }, ); return () => subscription?.remove(); }); // 根据 dimensions 渲染自适应布局 }鸿蒙底层:窗口尺寸变化如何驱动 Dimensions/useWindowDimensions 更新
要真正用好折叠屏适配,理解鸿蒙侧的事件链路很有帮助。在 ohos_react_native 仓库中,窗口变化从系统一路传递到 JS 层:
系统窗口监听:RNAbility.ets 中通过
this.mainWindow?.on('windowSizeChange', this.onWindowSizeChange)订阅系统窗口尺寸变化,并将事件转发给RNInstancesCoordinator。同时它还订阅了windowRectChange、windowStageEvent以及(API 15 及以上)systemDensityChange,覆盖窗口矩形、生命周期与系统密度变化。显示指标维护:DisplayMetricsManager.ts 统一维护
windowPhysicalPixels与screenPhysicalPixels两套物理像素指标(含width、height、scale、fontScale、densityDpi、xDpi、yDpi、decorHeight等),updateWindowSize/updateWindowRect/updateConfiguration分别处理窗口尺寸、窗口矩形与配置(字体缩放)变化。这些指标正是Dimensions.get('window'/'screen')与PixelRatio的数据来源。事件下发给 JS:RNInstance.ts 定义了
WINDOW_SIZE_CHANGE生命周期事件,窗口变化时通过lifecycleEventEmitter.emit('WINDOW_SIZE_CHANGE', windowSize)通知 JS 侧,进而触发Dimensions的change事件以及useWindowDimensions的状态刷新。因此在鸿蒙设备上,无论是旋转、分屏还是折叠屏展开/折叠,Dimensions.addEventListener('change')与useWindowDimensions都能及时拿到最新尺寸。
鸿蒙侧对折叠屏设备类型的识别
在设备形态层面,NapiBridge.ts 的getDeviceInfo()展示了鸿蒙侧对折叠屏的识别策略:
const originalDeviceType: string = deviceInfo.deviceType; // 'phone' | 'tablet' | 'pc' let deviceType = 'phone'; if (originalDeviceType === 'phone') { try { if (display.isFoldable()) { deviceType = 'isFoldableDevice'; } } catch (e) { // display.isFoldable() 可能因显示服务短暂不可用而抛出异常, // 失败时回退到非折叠屏路径,避免中断 RN 实例创建。 } } else { deviceType = originalDeviceType; }可见鸿蒙侧将"折叠态"识别为独立的isFoldableDevice设备类型,同时把display.isFoldable()的异常做了容错处理。开发者可通过Platform.constants.deviceType等渠道感知设备形态差异,配合Dimensions尺寸变化事件实现折叠屏展开/折叠时的布局切换。
多屏适配实践建议
综合原文档与仓库实现,可归纳如下实践要点:
- 布局优先用 Flexbox:以
flexDirection+alignItems+justifyContent组合弹性伸缩,避免写死宽高,这是跨机型视觉一致性的根基。 - 图片资源按像素密度分级:用
PixelRatio.getPixelSizeForLayoutSize()按设备密度选取合适分辨率图片,兼顾清晰度与内存占用。 - 一次性尺寸用 Dimensions:在启动早期通过
Dimensions.get('window')获取初始尺寸;需要跟随变化时注册change监听并记得在卸载时remove()。 - 响应式布局优先 useWindowDimensions:函数组件中用它替代手动监听,屏幕尺寸变化时自动重渲染,天然适配旋转、分屏与折叠屏。
- 按设备形态差异化:
Platform.isPad/Platform.isTV/Platform.select({harmony: ...})用于平板、TV 等形态的定制;鸿蒙侧deviceType还包含isFoldableDevice折叠屏形态。 - 验证适配效果:仓库的 PixelRatioTest.tsx、DimensionsTest.tsx、UseWindowDimensionsTest.tsx 与 PlatformConstantsTest.tsx 提供了可直接参考的用例,覆盖了像素密度换算、尺寸获取、Hook 返回值与平台判断等关键行为。
通过上述 API 组合,React Native 应用即可在鸿蒙多设备生态中实现"一套代码、多端统一"的 UI 适配,显著降低多设备应用的开发与维护成本。
- OpenHarmony
- 移动开发
- 跨平台
【免费下载链接】ohos_react_native
React Native鸿蒙化仓库
相关推荐
【限时免费】 uni-app-x跨平台应用开发的安装与使用教程
uni app x跨平台应用开发的安装与使用教程 引言 在当今多终端并存的移动互联网时代,跨平台开发技术已成为开发者必备的核心能力。uni app x作为新一代
前端移动开发示例工程创维 MGV2000-CW 变身 5W 级 Linux 小服务器:Armbian 适配完整教程
创维 MGV2000 CW 变身 5W 级 Linux 小服务器:Armbian 适配完整教程 创维 MGV2000 CW 盒子吃灰已久,1GB 内存、8GB
嵌入式开发工具构建工具操作系统Incident-Response-Powershell实战教程:10个关键PowerShell命令快速响应安全事件
Incident Response Powershell实战教程:10个关键PowerShell命令快速响应安全事件 在当今网络安全威胁日益严峻的环境下,快速响
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考