HarmonyOS鸿蒙Next中RN OpenHarmony特征&多设备适配最佳实践

发布于 1周前 作者 h691938207 来自 鸿蒙OS

HarmonyOS鸿蒙Next中RN OpenHarmony特征&多设备适配最佳实践

  1. 概述

现有的伙伴应用使用RN框架开发的历史页面多且冗杂。为达到HarmonyOS系统一多体验,所有页面若均使用ArkUI框架重新开发耗时长、成本高,不可行。针对此问题,本文将主要提供一套RN多设备响应式组件及方案:

1)一套基于RN的鸿蒙特征动画组件库,在RN页面实现鸿蒙特征动画UI效果;

2)一套基于RN的一多高阶组件库,在RN页面实现折叠屏悬停避让分栏的UI效果;

首先介绍组件及效果说明,再分别结合组件效果提供对应场景的开发案例,最终提供示例代码指导实际开发。

组件库安装

参考rn_multidevice_layout_scenepkgrn_hmfeatures

  1. 多设备断点

2.1 断点设计原理

RN断点是基于鸿蒙多设备封装的一套断点机制,通过设置断点,让开发者可以结合窗口宽度去实现不同的页面布局效果。

断点以应用窗口宽度为基准,将应用窗口在宽度维度上分成了几个不同的区间即不同的断点,默认提供的断点区间如下所示。

断点名称 取值范围(px)
xs [0, 320)
sm [320, 600)
md [600, 840)
lg [840, 1440)
xl [1440, +∞)

2.2 多设备适配指导

在实际开发过程中,可以使用rn_multidevice_layout_scenepkg的setBreakpoints自定义断点的区间,也可以使用上述默认的断点区间。使用useBreakpointValue时,只需将屏幕断点所对应的参数传入useBreakpointValue,当屏幕断点发生变化时,该hook会根据当前断点的类型返回所对应的数据。

具体示例如下所示:

自定义断点区间

// 自定义断点区间,可选 
useEffect(() => { 
  setBreakpoints({ 
    base: 320, 
    md: 768, 
    lg: 1024, 
  }); 
});

使用断点hook并获取不同断点下的属性值

const color = useBreakpointValue({ 
  base: 'red', 
  xs: 'blue', 
  sm: 'green', 
  md: 'yellow', 
  lg: 'purple', 
  xl: 'orange', 
});

return ( 
  <Text style={{ color }}>Responsive Color Text</Text> 
);
  1. RN 鸿蒙特征动画组件

3.1 组件使用说明

rn_hmfeatures鸿蒙特征动画组件GeometryView,基于ArkUI的geometryTransition接口,实现了鸿蒙特征动画效果,详细介绍可参考:使用geometryTransition共享元素转场

组件导入方式

import GeometryView from 'rn_hmfeatures/src/';

组件API

名称 类型 必填 说明
geometryViewID string 设置转场动效ID
onGeometryViewClick DirectEventHandler 点击回调函数

3.2 场景案例

点击歌单页当前播放音乐控件,跳转音乐播放页,触发一镜到底的转场效果。

33.gif

关键代码片段

1、将歌单页中的当前播放音乐控件设置共享元素ID,监听点击事件并发送消息至ArkUI侧。(SampleTurboModule为自定义TurboModule,执行调用ArkUI侧发送消息方法)

return ( 
        <GeometryView 
            style={styles.container} 
            geometryViewID={'test'}   // 设置共享元素ID 
            onGeometryViewClick={() => { 
                SampleTurboModule.pushStringToHarmony('pages/MusicPlay', 1); 
            }}> 
            <Image source={require('../..../..../asset/cover.png')} style={[styles.albumCover, { marginLeft: itemLeft }]} /> 
            <View style={styles.songInfo}> 
                <Text style={styles.songTitle}>{song.title}</Text> 
                <Text style={styles.songArtist}>{song.artist}</Text> 
            </View> 
            <View style={{ flex: 1 }} /> 
            {controlIcons} 
        </GeometryView> 
    );

2、ArkUI侧监听跳转事件,在animateTo闭包内执行页面跳转逻辑

aboutToAppear() { 
    emitter.on({ eventId: 1 }, () => { 
      animateTo({ duration: 700, curve: Curve.Friction }, () => { 
        this.navPathStack.pushPath({ name: 'MusicPlayPage' }); 
      }); 
    }); 
  }

3、音乐播放页设置与歌单页一致的共享元素ID

@Component 
export default struct MusicPlayPage { 
  private instance: RNInstance = LoadManager.instance; 
  private bundlePath = 'bundle/musicplay.harmony.bundle'; 
  private moduleName = 'MusicPlay'; 
  @StorageLink('isMetroAvailable') isMetroAvailable: boolean = false; 
  @Consume('navPathStack') navPathStack: NavPathStack; 
  aboutToAppear() { 
    emitter.on({ eventId: 2 }, () => { 
      animateTo({ duration: 700, curve: Curve.Friction }, () => { 
        this.navPathStack.pop(); 
      }); 
    }); 
  } 
  aboutToDisappear() { 
    emitter.off(2); 
  } 
  build() { 
    NavDestination() { 
      if (this.isMetroAvailable) { 
        MetroBaseRN({ 
          moduleName: this.moduleName, 
        }) 
          .align(Alignment.Top) 
      } else if (this.instance) { 
        BaseRN({ 
          rnInstance: this.instance, 
          moduleName: this.moduleName, 
          bundlePath: this.bundlePath, 
        }).align(Alignment.Top) 
      } 
    } 
    .geometryTransition('test')  // 设置共享元素ID 
    .hideTitleBar(true) 
  } 
}
  1. RN 折叠屏适配组件

4.1 组件使用说明

RN折叠屏适配组件FoldSplitContainer,包含primary、secondary、extra三个区域,实现折叠屏二分栏、三分栏在展开态、悬停态以及折叠屏悬停状态下折痕区避让,详情参考:rn_multidevice_layout_scenepkg

组件导入方式

import { FoldSplitContainer } from 'rn_multidevice_layout_scenepkg/src';

FoldSplitContainer组件

Name Description Type Platform
primary 主要区域回调函数。 function OpenHarmony
secondary 次要区域回调函数。 function OpenHarmony
extra 扩展区域回调函数,不传入的情况,没有对应区域。 function OpenHarmony
expandedLayoutOptions 展开态布局信息。 ExpandedRegionLayoutOptions OpenHarmony
hoverModeLayoutOptions 悬停态布局信息。 HoverModeRegionLayoutOptions OpenHarmony
foldedLayoutOptions 折叠态布局信息。 FoldedRegionLayoutOptions OpenHarmony
onHoverStatusChange 折叠屏进入或退出悬停模式时触发的回调函数。 onHoverStatusChangeHandler OpenHarmony

ExpandedRegionLayoutOptions

Name Description Type Platform
isExtraRegionPerpendicular 扩展区域是否从上到下贯穿整个组件,当且仅当extra有效时此字段才生效。默认值:true。 boolean OpenHarmony
verticalSplitRatio 主要区域与次要区域之间的高度比例。默认值:PresetSplitRatio.LAYOUT_1V1。 number OpenHarmony
horizontalSplitRatio 主要区域与扩展区域之间的宽度比例,当且仅当extra有效时此字段才生效。默认值:PresetSplitRatio.LAYOUT_3V2。 number OpenHarmony
extraRegionPosition 扩展区域的位置信息,当且仅当isExtraRegionPerpendicular = false有效时此字段才生效。默认值:ExtraRegionPosition.top。 ExtraRegionPosition OpenHarmony

HoverModeRegionLayoutOptions

Name Description Type Platform
showExtraRegion 可折叠屏幕在半折叠状态下是否显示扩展区域。默认值:false。 boolean OpenHarmony
horizontalSplitRatio 主要区域与扩展区域之间的宽度比例,当且仅当extra有效时此字段才生效。默认值:PresetSplitRatio.LAYOUT_3V2。 number OpenHarmony
extraRegionPosition 扩展区域的位置信息,当且仅当showExtraRegion时此字段才生效。默认值:ExtraRegionPosition.top。 ExtraRegionPosition OpenHarmony

FoldedRegionLayoutOptions

Name Description Type Platform
verticalSplitRatio 主要区域与次要区域之间的高度比例。默认值:PresetSplitRatio.LAYOUT_1V1。 number OpenHarmony

onHoverStatusChangeHandler

Name Description Type Platform
callback 折叠屏进入或退出悬停模式时触发的回调函数。 (status: HoverModeStatus) => void OpenHarmony

HoverModeStatus

Name Description Type Platform
foldStatus 设备的折叠状态。 FoldStatus OpenHarmony
isHoverMode app当前是否处于悬停态。 boolean OpenHarmony

ExtraRegionPosition

Name Description Value
top 扩展区域在组件上半区域。 1
bottom 扩展区域在组件下半区域。 2

PresetSplitRatio

Name Description Value
LAYOUT_1V1 1:1比例。 1/1
LAYOUT_3V2 3:2比例。 3/2
LAYOUT_2V3 2:3比例。 2/3

推荐使用方式

const primaryRender = () => ( 
    <View> 
      <Text> 此区域为primary </Text>
    </View> 
  ); 
  const secondRender = () => ( 
    <View> 
      <Text> 此区域为second </Text>
    </View> 
  ); 
  const extraRender = () => ( 
    <View> 
      <Text> 此区域为extra </Text>
    </View> 
  ); 
  
  const expandedLayoutOptions: ExpandedRegionLayoutOptions = { 
    isExtraRegionPerpendicular: true, 
    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
    horizontalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
  }; 
  const foldedRegionLayoutOptions: FoldedRegionLayoutOptions = { 
    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
  }; 
  const hoverModeLayoutOptions: HoverModeRegionLayoutOptions = { 
    horizontalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
    showExtraRegion: true, 
  }; 
   
  <FoldSplitContainer 
    primary={primaryRender()} 
    secondary={secondRender()} 
    extra={extraRender()} 
    expandedLayoutOptions={expandedLayoutOptions} 
    foldedLayoutOptions={foldedRegionLayoutOptions} 
    hoverModeLayoutOptions={hoverModeLayoutOptions} 
  />

4.2 场景案例

实现效果

fold expanded hover

关键代码片段

const secondRender = () => ( 
    <View style={{flex: 1, alignItems: 'center'}}> 
      <View style={styles.message}> 
        <View> 
          <Text style={styles.title}>{title}</Text> 
          <Text style={styles.artist}>{artist}</Text> 
        </View> 
        <Image 
          source={require('../../asset/likes.svg')} 
          style={styles.imageGrey} 
        /> 
      </View> 
      <View style={styles.slider}> 
        <Slider 
          style={{width: '100%'}} 
          minimumValue={0} 
          maximumValue={duration} 
          value={position} 
          minimumTrackTintColor="#e8e1e1" 
          maximumTrackTintColor="#784949" 
          thumbStyle={{opacity: 0}} 
          onValueChange={(val: number) => { 
            seekTo(val); 
          }} 
        /> 
      </View> 
      <View style={styles.controls}> 
        <Text style={styles.text}>{formatTime(position)}</Text> 
        <Text style={styles.text}>{formatTime(duration)}</Text> 
      </View> 
      <View style={styles.container}> 
        <Image 
          source={require('../../asset/repeat.svg')} 
          style={styles.imageGrey} 
        /> 
        <TouchableOpacity onPress={skipToPrevious}> 
          <Image 
            source={require('../../asset/left.svg')} 
            style={styles.image} 
          /> 
        </TouchableOpacity> 
        <TouchableOpacity onPress={togglePlayPause}> 
          <Image 
            source={playState === State.Playing ? require('../../asset/pause.svg') : require('../../asset/play.svg')} 
            style={styles.imagePlay} 
          /> 
        </TouchableOpacity> 
        <TouchableOpacity onPress={skipToNext}> 
          <Image 
            source={require('../../asset/forward_end_fill.svg')} 
            style={styles.image} 
          /> 
        </TouchableOpacity> 
        <Image 
          source={require('../../asset/music_note_list.svg')} 
          style={styles.imageGrey} 
        /> 
      </View> 
      <View style={styles.container}> 
        <Image 
          source={require('../../asset/share_play.svg')} 
          style={styles.imageGrey} 
        /> 
        <Image 
          source={require('../../asset/bell.svg')} 
          style={styles.imageGrey} 
        /> 
        <Image 
          source={require('../../asset/arrow_down_circle.svg')} 
          style={styles.imageGrey} 
        /> 
        <Image 
          source={require('../../asset/dot.svg')} 
          style={styles.imageGrey} 
        /> 
      </View> 
    </View> 
  ); 
  const extraRender = () => ( 
    <View style={styles.extra}> 
      <Text style={{ 
        marginTop: isHover ? 70 : 0, 
        marginRight: isPad ? 200 : 0, 
        fontSize: 23, 
        color: '#ffffff', 
      }}> 
        此歌曲为纯音乐,请您欣赏 
      </Text> 
    </View> 
  ); 
  const expandedLayoutOptions: ExpandedRegionLayoutOptions = { 
    isExtraRegionPerpendicular: true, 
    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
    horizontalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
  }; 
  const foldedRegionLayoutOptions: FoldedRegionLayoutOptions = { 
    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1, 
  }; 
  const hoverModeLayoutOptions: HoverModeRegionLayoutOptions = { 
    horizontalSplitRatio: 0.66, 
    showExtraRegion: true, 
  }; 
  return ( 
    <ImageBackground 
      source={require('../../asset/blur.png')} 
      style={{width: '100%', height: '100%'}}> 
      <View style={{position: 'absolute', width: '100%', alignItems: 'center'}}> 
        <FoldSplitContainer 
          primary={primaryRender()} 
          secondary={secondRender()} 
          extra={extraRender()} 
          expandedLayoutOptions={expandedLayoutOptions} 
          foldedLayoutOptions={foldedRegionLayoutOptions} 
          hoverModeLayoutOptions={hoverModeLayoutOptions} 
        /> 
    </ImageBackground> 
  );

更多关于HarmonyOS鸿蒙Next中RN OpenHarmony特征&多设备适配最佳实践的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS鸿蒙Next中,React Native(RN)与OpenHarmony的结合为开发者提供了跨平台开发的能力,同时支持多设备适配。RN在OpenHarmony中的特征主要包括:

  • 跨平台一致性:RN允许开发者使用JavaScript编写代码,并在多个设备上运行,确保应用在手机、平板、智能手表等设备上的一致性体验。

  • 组件化开发:RN的组件化开发模式与OpenHarmony的组件化架构相匹配,开发者可以通过RN的组件库快速构建应用界面,并与OpenHarmony的底层能力进行无缝集成。

  • 性能优化:RN在OpenHarmony中通过Native Modules和Native Components与底层系统进行高效通信,确保应用的性能接近原生应用。

  • 多设备适配:RN支持响应式布局和自适应UI,能够根据不同设备的屏幕尺寸和分辨率自动调整界面布局,确保应用在不同设备上的显示效果。

  • 生态系统支持:RN与OpenHarmony的生态系统紧密结合,开发者可以利用OpenHarmony的分布式能力,实现跨设备的协同工作和数据共享。

在多设备适配的最佳实践中,开发者应关注以下几点:

  • 统一设计规范:遵循OpenHarmony的设计规范,确保应用在不同设备上的UI一致性。

  • 响应式布局:使用RN的Flexbox布局和Dimensions API,确保应用界面能够自适应不同屏幕尺寸。

  • 设备特性适配:根据设备特性(如触摸屏、传感器等)调整应用功能,充分利用设备的硬件能力。

  • 性能监控:使用RN的性能监控工具,优化应用在不同设备上的运行效率。

通过以上特征和最佳实践,开发者可以在HarmonyOS鸿蒙Next中充分发挥RN与OpenHarmony的优势,构建高效、一致且适配多设备的应用。

更多关于HarmonyOS鸿蒙Next中RN OpenHarmony特征&多设备适配最佳实践的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,RN(React Native)与OpenHarmony的结合主要关注跨平台开发与多设备适配。最佳实践包括:

  • 统一UI组件库:使用鸿蒙提供的UI组件库,确保在不同设备上的一致性。
  • 响应式布局:采用Flexbox布局,适配不同屏幕尺寸和分辨率。
  • 设备能力检测:通过API检测设备特性(如屏幕尺寸、传感器等),动态调整应用行为。
  • 跨平台API封装:封装鸿蒙与RN的API,简化多平台开发。
  • 性能优化:利用鸿蒙的分布式能力,优化跨设备协同性能。

通过这些实践,开发者可以高效构建适配多设备的应用。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!