如何在鸿蒙系统上实现「沉浸式」页面?

兄弟们圣诞快乐 🎉

何谓「沉浸式」体验?

相信 Android or iOS应用开发者对「沉浸式」一词都不陌生。所谓的沉浸式,通常就是指应用将内容区延伸到状态栏和导航栏界面,使得用户使用时更加专注于内容,不被无关元素干扰。

顾名思义,应用使用沉浸式设计能带来以下几点好处:

  • 使页面和避让区域的色调统一,为用户提供更好的视觉体验。
  • 最大程度利用屏幕可视区域,使页面获得更大的布局空间。
  • 提供完全沉浸的体验,让用户沉浸其中,不被其他事物所干扰。

如何实现沉浸式设计?

主流的移动操作系统都提供了相关能力以便开发者实现沉浸式设计,主要包含以下几点能力:

  • 扩展内容的展示区域至状态栏和导航栏部分,将应用的内容区延伸到状态栏和导航栏,充分利用屏幕的可视区域;
  • 处理内容区域(安全区)状态栏以及导航栏(非安全区)内容展示的避让逻辑;
  • 将状态栏和导航条颜色与界面元素颜色相匹配,不出现明显的突兀感。

鸿蒙系统同样也提供了以上能力,我们一起来看一下。

将应用页面延伸到状态栏和导航栏

Harmony OS系统上,想要最大程度利用屏幕可视区域,将应用页面延伸到状态栏和导航栏区域,使页面获得更大的布局空间,有以下两种方法:

  1. 使用 Window.setWindowLayoutFullScreen() 方法设置窗口为全屏模式。

  2. 设置组件的expandSafeArea属性,扩展组件的安全区域到状态栏和导航栏,从而实现沉浸式。

两种方式都能将应用页面展示区域延伸至状态栏和导航栏区域,不同的是expandSafeAreaapi只作用于当前组件,只会将当前组件延伸到状态栏和导航栏,不影响其他组件的布局范围,其他组件仍在安全区域内进行布局;

Window.setWindowLayoutFullScreen()api 会将页面的所有组件布局范围从安全区域扩展为整个窗口(包括状态栏和导航栏),以电商首页为例,两种方式差异性如下图。

避让安全区域

使用expandSafeArea属性无需避让安全区域

使用expandSafeArea属性扩展背景组件安全区域时,只会将当前组件延伸到状态栏和导航栏,不影响其他组件的布局范围,其他组件仍在安全区域内进行布局,所以不需要状态栏以及导航栏进行避让:

arkts 复制代码
Tabs({ barPosition: BarPosition.End }) {
  // ...
}
.backgroundColor('#F1F3F5')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

使用Window.setWindowLayoutFullScreen()需对非安全区域进行避让

使用Window.setWindowLayoutFullScreen()方法设置应用窗口为全屏后,应用的页面将延伸到状态栏和导航栏,我们需要通过Window.getWindowAvoidArea()方法获取状态栏和导航栏高度,并用状态变量avoidArea记录。使用avoidAreaChange事件监听避让区域的变化,变化时更新状态变量avoidArea

arkts 复制代码
@State avoidArea: AvoidArea = { topRectHeight: 0, bottomRectHeight: 0 };

onShown() {
  this.windowClass.setWindowLayoutFullScreen(true);
  this.setAvoidArea()
  this.windowClass.on('avoidAreaChange', this.onAvoidAreaChange)
}

// ...

setAvoidArea() {
  // status bar area
  const statusBarArea = this.windowClass.getWindowAvoidArea(statusBarType);
  this.avoidArea.topRectHeight = statusBarArea.topRect.height;
  // navigation bar area
  const navBarArea = this.windowClass.getWindowAvoidArea(navBarType);
  this.avoidArea.bottomRectHeight = navBarArea.bottomRect.height;
}

onAvoidAreaChange = (data: window.AvoidAreaOptions) => {
  if (data.type === statusBarType) {
    this.avoidArea.topRectHeight = data.area.topRect.height;
  } else if (data.type === navBarType) {
    this.avoidArea.bottomRectHeight = data.area.bottomRect.height;
  }
}

获得状态栏和导航栏的高度后,再对需要进行避让的组件添加上下padding,上下padding分别为状态栏和导航栏的高度,达到内容避让状态栏和导航条的效果:

arkts 复制代码
Tabs({ barPosition: BarPosition.End }) {
  // ...
}
.backgroundColor('#F1F3F5')
.padding({
  top: this.avoidArea.topRectHeight + 'px',
  bottom: this.avoidArea.bottomRectHeight + 'px'
})

隐藏状态栏/导航栏

某些场景下,我们希望全身心沉浸式使用app,eg:全身心沉浸式打王者、追剧看电影、阅读。此时,我们往往会觉得导航栏和状态栏很「碍眼」,想要隐藏状态栏和导航栏,在使用Window.setWindowLayoutFullScreen()方法设置窗口为全屏模式后,我们还需要调用Window.setWindowSystemBarEnable()方法设置状态栏和导航条的显隐:

arkts 复制代码
onShown() {
  this.windowClass.setWindowLayoutFullScreen(true);
  this.windowClass.setWindowSystemBarEnable([]);
}

onHidden() {
  this.windowClass.setWindowLayoutFullScreen(false);
  this.windowClass.setWindowSystemBarEnable(['status', 'navigation']);
}

build() {
  NavDestination() {
    Column() {
      Video({ src: $rawfile('video.mp4') })
        // ...
    }
    .height('100%')
    .width('100%')
  }
  .hideTitleBar(true)
  .onShown(() => this.onShown())
  .onHidden(() => this.onHidden())
}

鸿蒙系统目前对于隐藏状态栏的实现是将状态栏整体布局隐藏,因此状态栏高度也会变为0,这点和Android上的表现也是不一样的。

需要注意的是,目前的鸿蒙设备大多采用挖孔屏幕,我们在隐藏状态栏和导航栏后需要考虑挖孔区域是否对交互会产生影响,决定是否要对挖孔区域进行避让,以保证用户正常的交互体验,获取挖孔区域的宽高和位置可以调用以下api:

arkts 复制代码
// 通过Display.getCutoutInfo()方法获取挖孔区域的宽高和位置信息。
async getCutoutInfo() {
  const displayClass = display.getDefaultDisplaySync();
  const res = await displayClass.getCutoutInfo();
  return res.boundingRects;
}

状态栏颜色适配

在某些将深色背景延伸到状态栏的沉浸式页面中,我们需要根据页面内状态栏区域的背景色选择合适的状态栏颜色 (黑/白),保证易读性。eg:状态栏背景为深色时,需要设置状态栏时间文字、信号图标、电量图标等内容为浅色进行适配,避免状态栏内容不清晰,以此提升用户的视觉体验:

我们可以使用Window.setWindowSystemBarProperties()方法设置状态栏内容的颜色:

arkts 复制代码
onShown() {
  this.windowClass.setWindowSystemBarProperties({
    statusBarContentColor: '#FFFFFF'
  });
}

onHidden() {
  this.windowClass.setWindowSystemBarProperties({
    statusBarContentColor: '#000000'
  });
}

build() {
  NavDestination() {
    // ...
  }
  .hideTitleBar(true)
  .onShown(() => this.onShown())
  .onHidden(() => this.onHidden())
}
相关推荐
键盘鼓手苏苏1 分钟前
Flutter 三方库 p2plib 的鸿蒙化适配指南 - 实现高性能的端到端(P2P)加密通讯、支持分布式节点发现与去中心化数据流传输实战
flutter·harmonyos·鸿蒙·openharmony
加农炮手Jinx1 分钟前
Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南
数据库·flutter·华为·postgresql·restful·harmonyos·鸿蒙
加农炮手Jinx2 分钟前
Flutter 组件 heart 适配鸿蒙 HarmonyOS 实战:分布式心跳监控,构建全场景保活检测与链路哨兵架构
flutter·harmonyos·鸿蒙·openharmony
钛态5 分钟前
Flutter 三方库 http_mock_adapter — 赋能鸿蒙应用开发的高效率网络接口 Mock 与自动化测试注入引擎(适配鸿蒙 HarmonyOS Next ohos)
android·网络协议·flutter·http·华为·中间件·harmonyos
王码码20355 分钟前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos
王码码20356 分钟前
Flutter 三方库 dns_client 的鸿蒙化适配指南 - 告别 DNS 劫持、探索 DNS-over-HTTPS (DoH) 技术、构建安全的鸿蒙网络请求环境
flutter·harmonyos·鸿蒙·openharmony·dns_client
键盘鼓手苏苏6 分钟前
Flutter 组件 highlighter 适配鸿蒙 HarmonyOS 实战:高性能语法高亮,构建大规模代码分析与文本染色架构
flutter·harmonyos·鸿蒙·openharmony
国医中兴8 分钟前
Flutter 三方库 langchain_google 的鸿蒙化适配指南 - 链接 Gemini 智慧中枢、LangChain AI 实战、鸿蒙级智能应用专家
flutter·langchain·harmonyos
发现一只大呆瓜9 分钟前
深入浅出 AST:解密 Vite、Babel编译的底层“黑盒”
前端·面试·vite
左手厨刀右手茼蒿9 分钟前
Flutter for OpenHarmony: Flutter 三方库 shamsi_date 助力鸿蒙应用精准适配波斯历法(中东出海必备)
android·flutter·ui·华为·自动化·harmonyos