当前位置: 首页 > news >正文

鸿蒙刘海屏、水滴屏、瀑布屏适配:用 DisplayUtil 获取不可用区域

文章目录

    • 一、前言
    • 二、工具函数方法
    • 三、方法详解
      • 3.1 `getCutoutRect()` — 获取不可用区域矩形
      • 3.2 `getCutoutHeight()` — 获取挖孔区域高度
    • 四、完整演示代码
      • 4.1 数据加载
      • 4.2 UI 渲染
    • 五、实际应用场景
      • 场景 1:计算顶部安全内边距
      • 场景 2:判断是否全面屏并调整布局
      • 场景 3:获取完整矩形信息用于精确避让
    • 六、注意事项
    • 七、小结

一、前言

近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦

案例demo导航展示

↓↓↓↓↓↓接下来言归正传 ↓↓↓↓

现代手机大多采用异形屏设计:刘海屏、水滴屏、挖孔屏、瀑布屏……这些屏幕在顶部或边角存在不可用区域(即摄像头挖孔区域),如果应用内容出现在这些区域,就会被摄像头遮挡,影响用户体验。

HarmonyOS 提供了display.getCutoutInfo()API 来获取这些不可用区域的坐标信息,DisplayUtil对其进行了二次封装,提供了更简洁的getCutoutRect()getCutoutHeight()方法。


二、工具函数方法

// 获取挖孔/刘海区域的矩形坐标(异步)staticasyncgetCutoutRect():Promise<display.Rect>// 获取挖孔/刘海区域的高度(px,异步)staticasyncgetCutoutHeight():Promise<number>

三、方法详解

3.1getCutoutRect()— 获取不可用区域矩形

源码:

staticasyncgetCutoutRect():Promise<display.Rect>{letcutoutInfo=awaitDisplayUtil.getDefaultDisplaySync().getCutoutInfo();returncutoutInfo.boundingRects[0];}

说明:

  • getCutoutInfo()返回的是完整的CutoutInfo对象,包含boundingRects(不可用区域矩形数组)。
  • DisplayUtil取数组第一个元素(boundingRects[0]),即主挖孔区域。
  • 返回的display.Rect对象包含:
    • left:矩形左边距(px)
    • top:矩形上边距(px)
    • width:矩形宽度(px)
    • height:矩形高度(px)

如果设备没有挖孔(全面屏)boundingRects可能为空,boundingRects[0]返回undefined,Demo 中对此有判断处理。


3.2getCutoutHeight()— 获取挖孔区域高度

源码:

staticasyncgetCutoutHeight():Promise<number>{letrect=awaitDisplayUtil.getCutoutRect();if(rect){returnrect.height;}return0;}

说明:

  • 如果有挖孔区域,返回该区域的高度(px)。
  • 如果没有挖孔区域(全面屏),返回0

这个方法非常实用:在计算顶部布局安全区域时,直接用挖孔高度来做内边距偏移即可。


四、完整演示代码

4.1 数据加载

loadCutoutInfo(){this.cutoutLoading=true;DisplayUtil.getCutoutRect().then((rect)=>{this.cutoutLoading=false;if(rect){this.cutoutRectInfo=`left:${rect.left}, top:${rect.top}, width:${rect.width}, height:${rect.height}`;this.addLog('Cutout',`getCutoutRect() OK -${this.cutoutRectInfo}`,'success');}else{this.cutoutRectInfo='无挖孔/刘海区域(全面屏)';this.addLog('Cutout','getCutoutRect() - 无挖孔区域','info');}}).catch((e:Error)=>{this.cutoutLoading=false;this.cutoutRectInfo=`获取失败:${e.message}`;this.addLog('Cutout',`getCutoutRect() 失败:${e.message}`,'error');});DisplayUtil.getCutoutHeight().then((h)=>{this.cutoutHeightInfo=h>0?`${h}px`:'无';this.addLog('Cutout',`getCutoutHeight() =${h}px`,'info');}).catch((e:Error)=>{this.cutoutHeightInfo=`失败:${e.message}`;});}

4.2 UI 渲染

// ══ 挖孔屏 ════════════════════════════════════════if(this.activeTab===2){Column(){Text('getCutoutRect() - 获取挖孔屏区域').fontSize(13).fontColor('#666').fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:8})Row(){Text('区域信息:').fontSize(12).fontColor('#888')if(this.cutoutLoading){LoadingProgress().width(16).height(16).margin({left:6})Text('加载中...').fontSize(12).fontColor('#888').margin({left:4})}else{Text(this.cutoutRectInfo||'无').fontSize(12).fontFamily('monospace').fontColor('#4080FF').margin({left:6})}}.width('100%').margin({bottom:8})Row(){Text('挖孔高度:').fontSize(12).fontColor('#888')Text(this.cutoutHeightInfo||'--').fontSize(12).fontWeight(FontWeight.Bold).fontColor('#D63384').margin({left:6})}.width('100%').margin({bottom:10})Row(){Text('💡 ').fontSize(12).fontColor('#FF9800')Text('挖孔区域用于规避刘海/水滴/瀑布屏不可用区域,确保内容不被遮挡').fontSize(11).fontColor('#888')}.width('100%').backgroundColor('#FFF7E6').padding(8).borderRadius(6).margin({bottom:10})Button('刷新挖孔信息').fontSize(12).height(34).backgroundColor('#4080FF').fontColor('#FFF').onClick(()=>{this.loadCutoutInfo();})}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)this.buildApiCard('Cutout API',[{name:'getCutoutRect()',desc:'异步获取第一个挖孔/刘海区域 rect(left/top/width/height)'},{name:'getCutoutHeight()',desc:'异步获取挖孔区域高度(px),无挖孔返回 0'},]asApiRow[])}

五、实际应用场景

场景 1:计算顶部安全内边距

// 在页面初始化时获取挖孔高度,用于计算顶部安全区域asyncaboutToAppear(){constcutoutHeight=awaitDisplayUtil.getCutoutHeight();// 加上系统状态栏高度,得到真正的安全顶部内边距this.safeTopPadding=cutoutHeight;}

场景 2:判断是否全面屏并调整布局

asynccheckFullScreen(){constheight=awaitDisplayUtil.getCutoutHeight();if(height===0){// 全面屏,顶部内容可以贴边this.topInset=0;}else{// 异形屏,需要避让挖孔区域this.topInset=height;}}

场景 3:获取完整矩形信息用于精确避让

asyncavoidCutout(){constrect=awaitDisplayUtil.getCutoutRect();if(rect){// 挖孔在顶部中央,宽度为 rect.width,高度为 rect.height// 可以用于计算内容左右边距,确保重要内容不出现在挖孔区域constsafeLeft=rect.left;constsafeRight=DisplayUtil.getWidth()-rect.left-rect.width;console.info(`安全左边距:${safeLeft}px, 安全右边距:${safeRight}px`);}}

六、注意事项

  1. 全面屏处理:无挖孔的全面屏设备,getCutoutRect()返回的数组可能为空,需要判断rect是否为undefined

  2. 单位为物理像素(px):获取的矩形坐标是物理像素,在 ArkUI 中使用时需要转换为 vp(vp = px / densityPixels)。

  3. 异步方法:两个方法都是异步的(Promise),需要在aboutToAppearasync函数中await,或使用.then().catch()

  4. 多个挖孔区域boundingRects是数组,某些设备可能有多个挖孔区域(如顶部+底部)。DisplayUtil只取了[0],若需要处理所有区域,需要直接调用display.getCutoutInfo()


七、小结

方法返回类型说明
getCutoutRect()Promise<display.Rect>挖孔区域矩形(left/top/width/height),全面屏返回 undefined
getCutoutHeight()Promise<number>挖孔区域高度(px),全面屏返回 0

这两个方法是实现全面屏适配的关键。只需一行await DisplayUtil.getCutoutHeight(),就能在所有类型的屏幕上正确规避不可用区域,让你的应用在各种异形屏上都能完美呈现。

http://www.gsyq.cn/news/1410151.html

相关文章:

  • 如何快速上手AdelaiDepth:5分钟实现单目深度估计 [特殊字符]
  • 【ChatGPT婚礼策划辅助实战指南】:20年婚庆技术顾问亲授5大高转化AI协同工作流
  • 10个免费VMware Workstation Pro 17许可证密钥:专业虚拟化快速激活指南
  • HarmonyOS FoldStatus 与 FoldDisplayMode 枚举深度解析:折叠屏开发不再难
  • Java 内存区域(6 大存储位置)超清晰总结
  • 从零构建AI代码助手:RAG架构、智能分块与向量检索实战
  • 2026年口碑好的山东防坠落安全绳/高空作业安全绳厂家推荐与选型指南 - 品牌宣传支持者
  • AI设计工具:让AI帮你设计UI界面
  • 账单不是因为模型贵,而是因为请求长歪了:我怎么排查 token 成本
  • 网络数据传输的过程:一条微信消息的奇妙旅行
  • ESP32-S3 WiFi性能到底如何?我实测了TCP/UDP,结果和官方数据有点不一样
  • Keil MDK 5中解决RL-ARM库路径错误的实践指南
  • E5-small常见问题解答:解决使用过程中的10个典型问题
  • C166中断管道问题解析与解决方案
  • FlashAttention与时间序列预测:让AI预知未来
  • 2026年4月国内诚信的窗帘门店口碑推荐,墙布/智能窗帘/遮阳卷帘/天窗/家装软硬包/商场卷帘/木卷帘,窗帘品牌哪家专业 - 品牌推荐师
  • 2026年 哈尔滨无人机执照培训学校推荐榜:CAAC多旋翼教学,视距内/超视距驾驶员与教员考证,报名及无人机驾驶证专业指导 - 品牌企业推荐师(官方)
  • 面试官问‘加法器有几种?’:从行波进位到前缀加法器的性能演进与面试考点解析
  • 还在靠人肉发版?真正的 DevOps 平台,凌晨3点都能自己干活
  • 微信聊天记录永久保存终极方案:3步搞定WeChatMsg免费备份与智能分析
  • R语言偏相关分析实战:用ppcor包和自定义函数搞定土壤微生物数据
  • 基于Android11 的wifi自动连接流程梳理
  • FlashAttention与信息检索:让AI秒找答案
  • 别再傻傻分不清了!Power BI里COUNT、COUNTA、COUNTBLANK到底啥区别?一个例子讲透
  • 2026世界杯洛杉矶SoFi体育场:50亿造价的天价足球圣殿
  • 从MLM到RTD:一文读懂DeBERTa V3的预训练任务革新与HuggingFace快速上手
  • 202614读书笔记|《中亚:女孩的归宿是证明“清白”,男孩的征途是星辰大海》——“自由”不是所有人都能轻易拥有
  • 手把手教你配置Redis,搞定等保2.0测评里的那些‘坑’(附配置文件详解)
  • 【多无人机集群控制11】鲁棒编队跟踪仿真,滑模与PID对比,MATLAB例程
  • 第6篇_Retain_Will_KeepAlive_工业现场为什么不能只会转发PUBLISH