在这里插入图片描述

你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌 关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀

前言

在 HarmonyOS 应用开发中,当开启沉浸式窗口或全屏显示时,顶部的系统状态栏(包含时间、电量、信号图标)与底部的导航条(或导航按键)会叠加在应用页面内容之上。如果未对这部分区域做处理,页面顶部的标题栏、返回按钮或底部的操作栏就会被系统 UI 遮挡,影响用户交互。

HarmonyOS 提供了 window.getWindowAvoidArea 接口用于获取系统的避让区域。本文将聚焦于系统基础避让类型 TYPE_SYSTEM,通过解析 topRect(顶部避让区域)与 bottomRect(底部避让区域),结合 ArkUI 的 padding 布局机制,实现简洁高效的页面避让适配。

一、核心机制:TYPE_SYSTEM 与避让矩形

在 HarmonyOS 的窗口子系统中,window.AvoidAreaType.TYPE_SYSTEM 表示系统的基础避让区域,主要涵盖顶部系统状态栏和底部导航条等占用屏幕空间的系统 UI 元素。

调用 getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM) 会返回一个 AvoidArea 对象,其中包含四个方向的矩形区域(topRect、bottomRect、leftRect、rightRect)。在绝大多数常规竖屏场景下,我们需要重点处理的是以下两个属性:

  1. topRect:顶部系统避让矩形,其 height 对应系统状态栏所占用的物理高度。
  2. bottomRect:底部系统避让矩形,其 height 对应系统导航条所占用的物理高度。

关键注意事项:AvoidArea 中返回的矩形尺寸(如 topRect.height 和 bottomRect.height)单位均为物理像素(px)。而在 ArkUI 的组件布局中,默认采用的长度单位是 虚拟像素(vp)。因此,获取到数值后,必须通过全局函数 px2vp() 进行单位转换,才能正确作用于组件的布局属性。

二、最小实践:获取避让区域并应用 Padding

通过 padding(内边距)避让机制,我们可以在保持根容器全屏延伸(实现沉浸式背景)的同时,将页面实际内容限制在安全区域内。

下面是在 ArkTS 页面中获取 TYPE_SYSTEM 避让区域并使用 padding 进行避让的最小完整代码示例:

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

@Entry
@Component
struct AvoidAreaPracticePage {
  // 顶部避让高度(单位:vp)
  @State topAvoidPadding: number = 0;
  // 底部避让高度(单位:vp)
  @State bottomAvoidPadding: number = 0;

  aboutToAppear(): void {
    // 获取当前应用的主窗口实例
    window.getLastWindow(getContext(this)).then((windowClass: window.Window) => {
      // 1. 主动查询当前系统避让区域(TYPE_SYSTEM)
      let avoidArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
      this.updatePadding(avoidArea);

      // 2. 注册避让区域变化监听,确保系统状态栏/导航条状态变化时布局可动态更新
      windowClass.on('avoidAreaChange', (data: window.AvoidAreaOptions) => {
        if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
          this.updatePadding(data.area);
        }
      });
    }).catch((err: Error) => {
      // 窗口获取失败的异常处理
    });
  }

  // 更新内边距数值
  private updatePadding(avoidArea: window.AvoidArea): void {
    // 将物理像素 px 转化为 ArkUI 布局所需的 vp
    this.topAvoidPadding = px2vp(avoidArea.topRect.height);
    this.bottomAvoidPadding = px2vp(avoidArea.bottomRect.height);
  }

  build() {
    // 根容器占满全屏
    Column() {
      // 页头标题区域
      Row() {
        Text('页面标题')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
      .height(56)
      .justifyContent(FlexAlign.Center)
      .backgroundColor('#FFFFFF')

      // 主体内容区域
      Column() {
        Text('内容区域:已被正确避让,不会被状态栏或导航条挡住。')
          .fontSize(14)
          .fontColor('#666666')
      }
      .width('100%')
      .layoutWeight(1)
      .justifyContent(FlexAlign.Center)

      // 页脚操作区域
      Button('提交操作')
        .width('90%')
        .height(40)
        .margin({ bottom: 12 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
    // 关键点:将 px2vp 转换后的 topRect 与 bottomRect 高度设置到根组件的 padding 上
    .padding({
      top: this.topAvoidPadding,
      bottom: this.bottomAvoidPadding
    })
  }
}

三、关键细节拆解

1. px2vp 单位转换的必要性

系统 API getWindowAvoidArea 获取到的 topRect.height 与 bottomRect.height 是屏幕真实分辨率下的物理像素(px)。例如在某高分屏设备上,顶部状态栏的高度可能为 108px。如果直接将 108 赋值给组件的 padding({ top: 108 }),ArkUI 会将其识别为 108vp,导致顶部留白异常偏大。使用 px2vp() 函数转换后,数值会根据设备 PPI 正确缩放为适宜的 vp 值。

2. 为什么选择 padding 避让策略

在沉浸式布局场景中,页面通常有两种避让方案:

  • margin 外边距或绝对偏移:将组件整体向下/向上平移。这种做法容易导致页面背景出现断层或白边。
  • padding 内边距避让:在根容器(如 Column 或 RelativeContainer)上设置 padding。此时,根容器的背景色或背景图依然可以延伸至屏幕最顶端和最底端(实现沉浸式视觉效果),而容器内部的子节点则被挤压回安全的可用区域内,保证内容可读且可交互。

【建议插图1:在 DevEco Studio 预览器中开启/未开启 padding 避让的效果对比图】

3. avoidAreaChange 事件监听

系统避让区域并非完全静止不变。例如,导航栏在特定手势下隐去、或者系统 UI 模式切换时,避让区域的大小可能发生改变。通过调用 windowClass.on('avoidAreaChange', ...),并在回调中判断 data.type === window.AvoidAreaType.TYPE_SYSTEM,能够保证页面布局随系统状态变化实时调整。

四、排查与防错清单

如果在实践中发现内容依然被遮挡或布局异常,可顺着以下顺序排查:

  1. 检查是否漏写了 px2vp():
    观察 padding 留白是否过大。若顶部留白远超状态栏实际高度,大概率是直接使用了 px 数值。
  2. 检查获取避让区域的时机:
    确认 getWindowAvoidArea 是否在窗口加载完成后(如 aboutToAppear 生命周期中获取到 windowClass 后)执行。
  3. 检查 padding 设置的位置:
    padding 应当设置在包裹整体页面内容的根容器上。如果设置在内部子组件(如仅设置在某个 Text 组件)上,可能无法完全遮盖整页的交互安全区。
  4. 检查 AvoidAreaType 枚举类型:
    确认传入的类型为 window.AvoidAreaType.TYPE_SYSTEM,避免错选其他非系统 UI 的避让类型。

五、总结

处理系统状态栏与导航条遮挡问题的核心思路可以总结为三步:

  1. 取值:调用 windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM) 读取 topRect 与 bottomRect;
  2. 换算:使用 px2vp() 将像素单位转换为 ArkUI 布局单位 vp;
  3. 应用:将换算后的高度作用于页面根容器的 padding.top 与 padding.bottom,并绑定 avoidAreaChange 监听实现动态响应。

参考资料

  1. 《@ohos.window (窗口) API 参考》 华为开发者联盟
    链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-window-0000001820880785

  2. 《ArkUI 沉浸式窗口开发指南》 华为开发者联盟
    链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/window-developer-guide-0000001820879685

❤️ 如果本文帮到了你…

  • 请点个赞,让我知道你还在坚持阅读技术长文!
  • 请收藏本文,因为你以后一定还会用上!
  • 如果你在学习过程中遇到bug,请留言,我帮你踩坑!
Logo

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

更多推荐