在移动应用开发中,“沉浸式体验”几乎已经成为标配。它指的是让应用的内容延伸到系统的状态栏 (Status Bar)导航条 (Navigation Bar) 区域,从而获得更大的视野和更统一的视觉效果。

在鸿蒙 (HarmonyOS Next / ArkUI) 开发中,实现沉浸式主要有三种方案。今天我们就来盘点一下它们的优缺点和使用场景。


方案一:窗口级全屏 + 手动避让

这是最底层、最灵活,也是最经典的实现方式。它的核心思想是:先把窗口设为全屏(内容会跑到状态栏底下),然后手动给内容加 Padding 把它“挤”下来。

1. 核心 API

  • window.setWindowLayoutFullScreen(true): 开启全屏布局。
  • window.getWindowAvoidArea(...): 获取避让区高度(状态栏/导航条高度)。
  • window.setWindowSystemBarProperties(...): 设置状态栏文字颜色(黑/白)。

2. 代码实现

通常我们在 EntryAbility 中全局开启,或者在某个页面的 aboutToAppear 中单独开启。

第一步:开启全屏 (EntryAbility.ets)

import { window } from '@kit.ArkUI';

// 在 onWindowStageCreate 中
onWindowStageCreate(windowStage: window.WindowStage): void {
  windowStage.loadContent('pages/Index', (err) => {
    // ...
  });

  // 1. 获取主窗口
  let windowClass = windowStage.getMainWindowSync();
  
  // 2. 设置全屏 (沉浸式核心)
  windowClass.setWindowLayoutFullScreen(true);

  // 3. 设置状态栏透明 & 文字变白 (可选)
  windowClass.setWindowSystemBarProperties({
    statusBarColor: '#00000000', // 透明背景
    statusBarContentColor: '#FFFFFF' // 白色文字
  });
}

第二步:页面避让 (Index.ets)

因为开启全屏后,顶部的文字会被状态栏遮挡,我们需要获取状态栏高度并设置 paddingTop

import { window } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State topPadding: number = 0;

  aboutToAppear() {
    // 1. 获取当前窗口
    window.getLastWindow(getContext(this)).then(win => {
      // 2. 获取状态栏区域 (System)
      let avoidArea = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
      // 3. 将 px 转换为 vp (非常重要!getWindowAvoidArea 返回的是 px)
      this.topPadding = px2vp(avoidArea.topRect.height);
      
      // 4. (进阶) 监听状态栏高度变化(比如折叠屏展开/收起)
      win.on('avoidAreaChange', (data) => {
        if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
           this.topPadding = px2vp(data.area.topRect.height);
        }
      });
    })
  }

  build() {
    Column() {
      // 顶部标题栏
      Text("我是标题")
        .width('100%')
        .height(50)
        .backgroundColor(Color.Blue)
        .fontColor(Color.White)
    }
    .width('100%')
    .height('100%')
    // 核心:设置 paddingTop 避让状态栏
    .padding({ top: this.topPadding }) 
    .backgroundColor(Color.Pink)
  }
}
  • 优点:控制力最强,可以精确控制每个像素。
  • 缺点:代码量大,需要手动处理 px2vp 和监听变化。

方案二:组件级扩展安全区域 (expandSafeArea)

它的思想是:默认布局是在安全区内的,但我允许某个特定的组件(比如背景图)“溢出”到安全区外。

这种方式不需要写任何 window 相关的代码,也不需要计算高度,非常声明式。

代码实现

@Entry
@Component
struct ExpandSafeAreaDemo {
  build() {
    Stack() {
      // 1. 背景图:我希望它铺满全屏,包括状态栏
      Image($r('app.media.bg_image'))
        .width('100%')
        .height('100%')
        .objectFit(ImageFit.Cover)
        // 核心 API:允许延伸到 顶部(TOP) 和 底部(BOTTOM) 的安全区外
        .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

      // 2. 内容区域:默认依然在安全区内,不会被遮挡
      Column() {
        Text("我是安全区内的内容")
          .fontSize(20)
          .fontColor(Color.White)
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
  }
}
  • 优点:代码极其简洁,无需手动计算高度,自动适配。
  • 缺点:灵活性稍弱,适合“背景沉浸,内容安全”的常见场景。
  • 注意expandSafeArea 默认只能延伸到非交互组件(如 Image)。如果是 List 想要延伸,可能需要配合布局调整。

方案三:全屏背景色混淆

如果你的 App 顶部本来就是纯色的(比如白色或蓝色),你其实不需要真正的沉浸式。你只需要把状态栏的颜色设置成和标题栏一样,视觉上看起来就是一体的。

代码实现

// 在 EntryAbility 中
let windowClass = windowStage.getMainWindowSync();

// 不设置 setWindowLayoutFullScreen(true)
// 而是直接设置状态栏背景色
windowClass.setWindowSystemBarProperties({
  statusBarColor: '#FF0000', // 设置成和你 App 标题栏一样的颜色
  statusBarContentColor: '#FFFFFF'
});

或者直接设置窗口背景色:

windowClass.setWindowBackgroundColor("#FF0000");
  • 优点:最简单,0 副作用,不会遮挡内容。
  • 缺点:无法实现“图片背景延伸到状态栏”的效果,只能做纯色适配。

总结:场景选择

场景

推荐方案

全屏背景图/视频 (如:启动页、个人中心)

方案二 (expandSafeArea)

复杂交互页面 (需精确控制顶部距离)

方案一 (setWindowLayoutFullScreen)

普通纯色标题栏应用

方案三 (改状态栏颜色)

避坑指南:

  1. 单位换算window API 返回的都是 px,而 ArkUI 布局用的是 vp。一定要用 px2vp() 进行转换。
  2. 折叠屏适配:方案一必须监听 avoidAreaChange 事件,因为折叠屏展开/收起时,状态栏高度可能会变。方案二会自动处理,无需担心。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐