HarmonyOS 鸿蒙Next功能交互挂件

HarmonyOS 鸿蒙Next功能交互挂件

一、场景概述

在移动应用开发中,不同设备的屏幕形态各异,如刘海屏、全面屏、折叠屏等,其UI差异较大,且各自存在避让区。为了确保不同设备下功能交互挂件UI位置以及尺寸展示的正确性,h5提供了一系列的适配和避让机制。本文将详细介绍功能交互挂件的实现原理以及适配指导。

1.1 使用场景

功能交互挂件的使用场景比较多,典型应用比如视频播放应用的暂停按钮、返回按钮等,这些挂件在不同设备以及设备的展示状态(横竖屏)下,显示的位置以及避让区域需要有所调整。本示例和设备无强相关的关系,因此下面给出根据断点分类的展示效果图。

横向断点 sm md lg xl
展示逻辑 组件大小根据断点展示 组件大小根据断点展示 组件大小根据断点展示 组件大小根据断点展示
展示布局 图片 图片 图片 图片

1.2 常见问题

  1. 图文页左上角返回箭头紧贴顶部状态栏显示,导致部分点击无法选中
  2. 双屏、三屏态视频播放页播放按钮显示过大
  3. 三屏态连麦直播间按钮错位

1.3 多设备适配

  • 适配点1:沉浸式切换(顶部状态栏的显隐)

图片

图片

  • 适配点2:功能导航挂件尺寸多设备自适应适配

功能导航挂件尺寸支持在不同屏幕尺寸上自适应放大或缩小(如下图播放按钮、返回按钮)

图片

图片

  • 适配点3:功能导航挂件软键盘适配

软键盘由底部呼出时,底部挂件横屏状态下可被软键盘遮挡;屏幕其他位置挂件进行自适应调整,避免被遮挡

图片

图片

图片

图片

二、开发指导

2.1 H5开发

2.1.1 关键能力

功能交互挂件的核心处理之一就是区域避让,这部分功能主要通过原生提供的能力进行实现,包含以下几个核心api。

avoidAreaListener(): 该方法主要用于避让区域事件的监听,通过监听"avoidAreaChange"事件,当状态栏、键盘等涉及避让区域的位置发生变化时,该事件就会被触发,执行对应的回调函数,之后将需要处理的数据通过**runJavaScript()**方法传递到h5页面。

async avoidAreaListener(): Promise<void> {
  Logger.warn('Trying to add listener...')
  const windowClass = await this.webClassProxy.getMainWindow();
  try {
    windowClass.off('avoidAreaChange')
    windowClass.on('avoidAreaChange', (data) => {
      this.webController.runJavaScript(`
window.dispatchEvent(new CustomEvent('statusBarChange',{ detail: ${JSON.stringify(data)} }));
`);
      this.webController.runJavaScript(`
window.dispatchEvent(new CustomEvent('avoidAreaChange',{ detail: ${JSON.stringify(data)} }));
`);
      Logger.warn('Succeeded in enabling the listener for system avoid area changes. type:' +
      JSON.stringify(data.type) + ', area: ' + JSON.stringify(data.area));
    });
  } catch (exception) {
    Logger.error(`Failed to enable the listener for system avoid area changes. Cause code: ${exception.code}, message: ${exception.message}`);
  }
}

通过Web组件的src属性引入H5页面,并使用**registerJavaScriptProxy()**原生侧方法,将JavaScript对象注入到window对象中,从而在window对象中调用该对象的方法,实现H5页面调用原生方法。

Web({ src: 'http://0.0.0.0', controller: this.webController })
  .onControllerAttached(() => {
    this.webController.registerJavaScriptProxy(this, 'webClass', ['pushToPage', 'clearPage', 'getLastPage']);
    this.webController.refresh();
  })

2.1.2 指导案例

以功能交互挂件为例,在vue开发框架下给出具体的开发指导。

说明: 功能交互挂件场景是以视频播放页面为例,页面进入默认沉浸式状态,变化主要围绕顶部状态栏的显示和挂件的UI位置、显示等。

  • 沉浸式切换(控制顶部状态栏的显隐)
  1. 调用原生方法setFullScreen()进入沉浸式,监听当前组件挂载的父层容器的宽高,便于计算各挂件的展示位置。
const handleResize = () => {
  containerHeight.value = document.getElementById('container')?.clientHeight;
};
onMounted(async () => {
  await window.webClass.setWindowBackgroundColor('#000000');
  await window.webClass.setWindowSystemBarProperties();
  await window.webClass.setFullScreen();
  await window.webClass.setWindowSystemBarEnable();
  bottomMargin.value = avoidAreaStore.innerBottomMargin;
  topMargin.value = avoidAreaStore.innerTopMargin;
  containerHeight.value = document.getElementById('container')?.clientHeight || 0;
  window.addEventListener('resize', handleResize);
})
  1. 调用setWindowSystemBarEnable()、disableWindowSystemBarEnable()方法控制顶部状态栏的显隐。
const toggle = async () => {
  if(flag.value) {
    await window.webClass.setWindowSystemBarEnable();
  } else {
    await window.webClass.disableWindowSystemBarEnable();
  }
  flag.value = !flag.value;
}
  • 挂件尺寸多设备自适应
  1. 根据不同设备宽高,自定义设备断点store,用于判断当前窗口所处断点区间。
const DEFAULT_BREAKPOINT_SETTINGS: BreakpointSettings = {
  xs: 0,
  sm: 320,
  md: 600,
  lg: 840,
  xl: 1440,
}
export const useBreakpointStore = defineStore('breakpoint', () => {
  const curBreakpoint = ref<Breakpoints>();
  const breakpointSettings = ref({...DEFAULT_BREAKPOINT_SETTINGS});
  const windowWidth = ref(0);

  const updateBreakpoint = () => {
    windowWidth.value = window.innerWidth;
    for (const [breakpointName, upperLimit] of Object.entries(breakpointSettings.value)) {
      if (windowWidth.value >= upperLimit) {
        curBreakpoint.value = breakpointName as Breakpoints;
      }
    }
  }
  updateBreakpoint();
  window.addEventListener('resize', updateBreakpoint);

  return {
    curBreakpoint,
    breakpointSettings,
    windowWidth,
  }
})
  1. 以播放按钮为例,使用断点控制不同设备下的大小。
const playButtonHeight = computed(() => {
  switch (breakpointStore.curBreakpoint) {
    case 'xs':
    case 'sm':
      return '50px';
    case 'md':
      return '60px';
    case 'lg':
      return '70px';
    case 'xl':
      return '80px';
    default:
      return '50px';
  }
});
img.play {
  height: v-bind(playButtonHeight);
  aspect-ratio: 1;
  position: absolute;
  left: calc((100% - v-bind(playButtonHeight)) / 2);
}
  • 软键盘弹出适配
  1. 页面横竖屏判断,便于控制全屏按钮是否展示。
const isLandScape = computed(() => {
  return appStatusStore.appOrientation === 1 || appStatusStore.appOrientation === 3;
})
  1. 使用原生传入方法控制状态栏是否显示,用于区分功能交互挂件场景整体状态。
const toggle = async () => {
  if(flag.value) {
    await window.webClass.setWindowSystemBarEnable();
  } else {
    await window.webClass.disableWindowSystemBarEnable();
  }
  flag.value = !flag.value;
}
  1. 挂件区域避让、键盘避让

这里以输入栏底部避让为例(需要考虑的因素相对较多:竖屏下键盘弹起需避让输入栏,全屏按钮显示;横屏下键盘弹起需避让输入栏,全屏按钮不显示)。

const inputBottom = computed(() => {
  return (isLandScape.value && avoidAreaStore.isShowKeyboard) ?
    avoidAreaStore.keyboardHeight + 'px' : avoidAreaStore.isShowKeyboard?
    40 + avoidAreaStore.keyboardHeight + 'px' : avoidAreaStore.innerBottomMargin === 0 ?
    bottomMargin.value + 40 + 'px' : avoidAreaStore.innerBottomMargin + 40 + 'px';
})

2.1.3 示例代码

场景Sample示例代码地址:H5三方框架赋能指导配套代码


更多关于HarmonyOS 鸿蒙Next功能交互挂件的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

mark

更多关于HarmonyOS 鸿蒙Next功能交互挂件的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next的功能交互挂件是桌面组件,支持动态信息展示和快捷操作。用户可直接在桌面查看应用关键信息并执行常用功能,无需打开应用。挂件基于ArkTS开发,通过方舟编译器优化性能,实现高效渲染和低功耗运行。

这篇帖子详细介绍了在HarmonyOS Next环境下,针对H5页面中功能交互挂件(如视频播放按钮、返回按钮)的多设备适配方案,核心在于处理不同屏幕形态(刘海屏、折叠屏等)和状态(横竖屏、键盘弹出)下的布局避让与自适应。

帖子中提到的关键技术点非常准确:

  1. 避让区域监听:通过原生的 avoidAreaChange 事件监听状态栏、键盘等系统避让区域的变化,并将变化数据实时同步到H5页面,这是实现动态避让的基础。
  2. 原生与H5通信:使用 registerJavaScriptProxy 方法将原生能力注入到H5的 window 对象,使得H5能够直接调用如 setWindowSystemBarEnable 等原生方法,控制状态栏显隐,实现沉浸式切换。
  3. 响应式断点设计:在H5侧自定义断点(xs, sm, md, lg, xl),根据窗口宽度动态调整挂件尺寸(例如播放按钮在不同断点下设置不同高度),这是实现多设备自适应布局的关键策略。
  4. 综合布局计算:挂件的最终位置(如帖子中 inputBottom 的计算)需要综合考量多个动态因素:横竖屏状态、键盘是否弹出及其高度、以及当前的系统避让区安全边距。这种计算逻辑确保了在各种复杂交互场景下UI元素的正确展示。

总体而言,该方案提供了一套完整的混合开发适配范式,即由原生侧提供动态环境信息与系统能力,由H5侧进行灵活的响应式UI计算与渲染,能有效解决帖子开头提到的挂件紧贴状态栏、尺寸过大、位置错位等常见问题。示例代码仓库为开发者提供了宝贵的参考实现。

回到顶部