【HarmonyOS NEXT】沉浸式页面实现

一、背景

在鸿蒙APP开发过程中,为了让用户有更好的视觉体验,提供了沉浸式页面的实现,主要有两种实现方案,整理了两种方案的用法及使用场景

二、概念

沉浸式页面指页面内容延伸至状态栏 / 底部导航栏区域,同时保证核心内容不被系统栏遮挡的布局形式

官方提供了两种实现方案:

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

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

三、两种方案具体实现

3.1、方案1:窗口全屏 + 手动安全区域管理

核心逻辑:通过设置窗口全屏,手动获取状态栏 / 导航栏高度,再通过布局属性(如padding)避开系统栏区域。

3.1.1、实现步骤

步骤 1:窗口初始化时设置全屏 + 获取安全区域高度

UIAbility的窗口创建阶段,设置窗口全屏,并读取状态栏 / 导航栏的安全区域高度(存入全局存储):

TypeScript 复制代码
  // 窗口创建初始化
  onWindowCreateInit(windowStage: window.WindowStage) {
    windowStage.getMainWindow(async (err: BusinessError, data) => {
      if (err.code) {
        console.error(`Failed to obtain the main window. Cause code: ${err.code}, message: ${err.message}`);
        return;
      }
      let windowClass: window.Window = data
      // 1. 设置窗口全屏(内容延伸到系统栏)
      try {
        await windowClass.setWindowLayoutFullScreen(true)
      } catch (error) {
        console.error('Failed to setting the full screen. Cause: ' + JSON.stringify(err));
      }
      // 2. 获取状态栏/导航栏高度(转成vp单位)
      try {
        let statusBarArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
        let navBarArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
        let uiContext = windowStage.getMainWindowSync().getUIContext();
        //顶部导航栏高度,存入全局存储(供页面调用)
        const statusBarHeight = uiContext.px2vp(statusBarArea.topRect.height)
        AppStorageV2.connect(Number, 'statusBarHeight', () => new Number(statusBarHeight))
        //底部导航栏高度,存入全局存储(供页面调用)
        const navBarHeight = uiContext.px2vp(navBarArea.topRect.height)
        AppStorageV2.connect(Number, 'navigationBarHeight', () => new Number(navBarHeight))
      } catch (exception) {
        console.error(`Failed to obtain the area. Cause code: ${exception.code}, message: ${exception.message}`);
      }

      //在页面显示或隐藏时,设置状态栏内容的颜色
      windowClass.setWindowSystemBarProperties({
        statusBarContentColor: '#ffffff'
      }).catch((err: BusinessError) => {
        console.error('Failed to setting the system bar properties. Cause: ' + JSON.stringify(err));
      });
    })
  }

窗口创建阶段引入窗口创建初始化逻辑

TypeScript 复制代码
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    // 初始化保存窗口数据,沉浸式页面实现,状态栏样式设置
    EntryManager.getInstance().onWindowCreateInit(windowStage)
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }
步骤 2:页面中手动添加安全区域间距

通过工具类读取全局存储的高度,用padding避开状态栏:

TypeScript 复制代码
// Index页面:手动设置顶部padding
@Entry
@Component
struct Index {
  build() {
    Navigation() {
      Button('跳转到login组件')
    }
    // 手动添加状态栏高度的padding,避免内容被遮挡
    .padding({ top: AppStorage.get('statusBarHeight') as number })
    .width('100%').height('100%');
  }
}

3.2、方案2:expandSafeArea自动扩展安全区域

核心逻辑:利用鸿蒙的expandSafeArea属性,将当前组件延伸到状态栏和导航栏,不影响其他组件的布局范围,其他组件仍在安全区域内进行布局

3.2.1、实现步骤

步骤 1:开启窗口全屏(恢复setWindowLayoutFullScreen(true)
TypeScript 复制代码
 onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.getMainWindow(async (err, windowClass) => {
      if (err.code) return;
      // 必须开启窗口全屏,否则内容无法延伸到系统栏
      await windowClass.setWindowLayoutFullScreen(true);
    });
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }
步骤 2:让页面内容触及状态栏(比如把 Text 放在 Column 顶部)

修改myPage的布局,让内容顶在页面最上方,触发 "状态栏遮挡" 场景:

TypeScript 复制代码
@Builder
export function myPageBuilder() {
  myPage();
}

@ComponentV2
export struct myPage {
  build() {
    NavDestination() {
      Column() { // 内容靠顶部对齐
        Text('myPage页面呀')
          .fontColor(Color.White)
          .margin({ top: 0 }) // 顶在Column最上方
      }
      .backgroundColor(Color.Green)
      // 情况1:不加expandSafeArea(内容会被状态栏遮挡)
      // .width('100%').height('100%')

      // 情况2:加expandSafeArea(内容自动避开状态栏)
      .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
      .width('100%').height('100%')
      .border({ width: 2, color: Color.Blue })
    }
    .hideToolBar(true)
    .hideTitleBar(true)
  }
}
相关推荐
小Tomkk2 小时前
我开发的一款鸿蒙游戏《猜数字大师》 应用介绍 和技术架构
游戏·华为·harmonyos
鸿蒙开发工程师—阿辉2 小时前
HarmonyOS 5 数据持久化:状态持久化 (PersistentStorage)
华为·harmonyos
C雨后彩虹3 小时前
字符串拼接
java·数据结构·算法·华为·面试
音浪豆豆_Rachel3 小时前
Flutter鸿蒙化之深入解析Pigeon可空返回与参数设计:nullable_returns.dart全解
flutter·harmonyos
音浪豆豆_Rachel3 小时前
Flutter鸿蒙跨平台测试策略解析:从基础Widget测试到平台集成验证
flutter·harmonyos
音浪豆豆_Rachel4 小时前
Flutter鸿蒙跨平台通信协议解析:Pigeon生成的Dart端桥接艺术
flutter·华为·harmonyos
鸿蒙开发工程师—阿辉4 小时前
HarmonyOS 5 数据持久化:首选项 (Preferences)
华为·harmonyos
m0_685535084 小时前
Zemax系统选项中的高级设置
华为·光学·光学设计·光学工程·镜头设计