鸿蒙新特性实战:@ohos.display — 显示信息诊断、折叠屏检测与多显示器管理
引言
屏幕是用户与数字世界交互的唯一窗口。无论你的应用是短视频播放器、文档阅读器,还是 3D 渲染引擎,它最终都要呈现在一块真实的物理屏幕上。但大多数开发者对"屏幕"的认知止步于 vp2px 和媒体查询——实际上,HarmonyOS NEXT 通过 @ohos.display 模块暴露了一套完整的显示子系统诊断 API,让开发者能够:
- 精确感知屏幕物理属性:分辨率、刷新率、像素密度(DPI / densityPixels / scaledDensity)、方向(含四方向枚举)、屏幕形态(矩形/圆形)
- 深度理解折叠屏行为:设备是否可折叠?当前是展开还是折叠?副屏是否激活?屏幕折痕区域在哪?折叠角度是多少度?
- 检测屏幕开孔与曲面:前置摄像头挖孔/刘海的精确边界矩形、瀑布屏的四边曲面区域
- 识别显示源模式:当前屏幕是主显示器、镜像模式还是扩展模式?(2in1/平板外接显示器场景)
- 监听屏幕录屏/投屏:
isCaptured()检测是否正在被录屏,captureStatusChange实时监听状态变化 - 多显示器管理:枚举所有连接的显示器,每个都有独立的 Display 对象和属性
本文构建一个显示信息诊断中心 Demo,通过同步和事件监听两种方式,全面展示当前设备的显示系统状态,并实时追踪屏幕变化、折叠屏状态变化和录屏状态变化。
读完本文,你将掌握:
- Display 对象:15+ 属性覆盖屏幕的所有物理参数
- 折叠屏 API:
isFoldable()/getFoldStatus()/getFoldDisplayMode()/getCurrentFoldCreaseRegion() - 屏幕开孔检测:
getCutoutInfo()返回 CutoutInfo(含 boundingRects + waterfall 曲面区域) - 显示事件监听:
display.on('change')/on('foldStatusChange')/on('captureStatusChange')/on('foldAngleChange') - 多显示器枚举:
getAllDisplays()返回所有连接的 Display 对象 - API 级别意识:不同 API 的最低版本要求(API 10-23),以及如何做版本兼容处理
环境与权限
@ohos.display 自 API 7 开始提供,属于 @kit.ArkUI。导入方式:
import display from '@ohos.display';
零权限需求:所有读操作(获取 Display 属性、检测折叠状态、监听事件)均不需要任何权限声明。仅 createVirtualScreen() / destroyVirtualScreen() 等写操作需要 ohos.permission.ACCESS_VIRTUAL_SCREEN(系统级权限)。
一、核心数据结构
1.1 Display — 显示器对象
Display 是 @ohos.display 最核心的数据结构,代表一个物理或虚拟显示器的完整属性集合。通过 getDefaultDisplaySync() 同步获取:
interface Display {
id: number; // 显示器唯一 ID
name: string; // 显示器名称
alive: boolean; // 是否存活(未销毁)
state: DisplayState; // 屏幕状态(ON/OFF/DOZE等 7 种)
refreshRate: number; // 当前刷新率(Hz)
rotation: number; // 旋转值(0/1/2/3 对应 0°/90°/180°/270°)
width: number; // 逻辑宽度(px)
height: number; // 逻辑高度(px)
availableWidth: number; // 可用宽度(排除系统栏)(API 12+)
availableHeight: number; // 可用高度(排除系统栏)(API 12+)
densityDPI: number; // 屏幕 DPI
densityPixels: number; // 像素密度缩放系数(1.0 = 低分辨率基准)
scaledDensity: number; // 文本缩放密度
xDPI: number; // X 轴物理 DPI(API 20+ crossplatform)
yDPI: number; // Y 轴物理 DPI(API 20+ crossplatform)
orientation: Orientation; // 显示方向(四向枚举)
screenShape?: ScreenShape; // 屏幕形态(矩形/圆形)(API 18+)
colorSpaces: ColorSpace[]; // 支持的所有色彩空间(API 11+)
hdrFormats: HDRFormat[]; // 支持的所有 HDR 格式(API 11+)
sourceMode?: DisplaySourceMode; // 显示源模式(主/镜像/扩展)(API 19+)
supportedRefreshRates?: number[]; // 支持的所有刷新率(API 20+)
x?: number; // 相对于主屏幕的 X 偏移(API 19+)
y?: number; // 相对于主屏幕的 Y 偏移(API 19+)
// 实例方法
getCutoutInfo(): Promise<CutoutInfo>; // 获取挖孔/刘海信息
getAvailableArea(): Promise<Rect>; // 获取可用区域(API 12+)
getLiveCreaseRegion(): FoldCreaseRegion; // 获取当前折痕区域(API 20+)
getRoundedCorner(): RoundedCorner[]; // 获取圆角信息(API 23+)
getDisplayCapability(): string; // 获取显示能力摘要(API 18+)
}
Display 的设计兼顾了通用性和可扩展性——基础属性自 API 7 就存在,而较新的特性(如 supportedRefreshRates、screenShape、sourceMode)通过可选字段添加,保证向后兼容。
1.2 DisplayState — 屏幕状态(7 种)
enum DisplayState {
STATE_UNKNOWN = 0, // 未知
STATE_OFF = 1, // 息屏
STATE_ON = 2, // 亮屏(正常显示)
STATE_DOZE = 3, // 低功耗常显(AOD)
STATE_DOZE_SUSPEND = 4, // 低功耗暂停更新
STATE_VR = 5, // VR 模式
STATE_ON_SUSPEND = 6 // 亮屏但暂停更新
}
DisplayState 是理解设备屏幕电源管理的关键。STATE_DOZE 对应 Android 的 Ambient Mode(熄屏显示),而 STATE_VR 是 VR 头显的特殊状态。
1.3 Orientation — 四方向枚举
enum Orientation {
PORTRAIT = 0, // 竖屏 0°
LANDSCAPE = 1, // 横屏 90°
PORTRAIT_INVERTED = 2, // 倒竖屏 180°
LANDSCAPE_INVERTED = 3 // 倒横屏 270°
}
Orientation 是跨平台枚举(crossplatform, API 10+),比 rotation 数值更语义化。两者的关系:Orientation 描述的是显示内容的渲染方向,而 rotation 是屏幕硬件旋转的原始值。
1.4 FoldStatus — 折叠状态(11 种,含双折叠)
enum FoldStatus {
FOLD_STATUS_UNKNOWN = 0, // 未知
FOLD_STATUS_EXPANDED = 1, // 展开(单折叠)
FOLD_STATUS_FOLDED = 2, // 折叠(单折叠)
FOLD_STATUS_HALF_FOLDED = 3, // 半折(悬停态,单折叠)
FOLD_STATUS_EXPANDED_WITH_SECOND_EXPANDED = 11, // 双展开(API 15+)
FOLD_STATUS_EXPANDED_WITH_SECOND_HALF_FOLDED = 21, // 第一轴展开第二轴半折
FOLD_STATUS_FOLDED_WITH_SECOND_EXPANDED = 12, // 第一轴折叠第二轴展开
FOLD_STATUS_FOLDED_WITH_SECOND_HALF_FOLDED = 22, // 第一轴折叠第二轴半折
FOLD_STATUS_HALF_FOLDED_WITH_SECOND_EXPANDED = 13, // 第一轴半折第二轴展开
FOLD_STATUS_HALF_FOLDED_WITH_SECOND_HALF_FOLDED = 23 // 双半折
}
HarmonyOS 的 FoldStatus 枚举覆盖了从单折叠手机到双折叠轴设备的全部状态组合。枚举值的编码设计很有技巧:十位数表示第一轴状态(0=未知, 1=展开, 2=折叠, 3=半折),个位数表示第二轴状态。这种编码方式让状态比较可以直接通过数学运算进行。
1.5 FoldDisplayMode — 折叠显示模式
enum FoldDisplayMode {
FOLD_DISPLAY_MODE_UNKNOWN = 0, // 未知
FOLD_DISPLAY_MODE_FULL = 1, // 全屏(完全展开时)
FOLD_DISPLAY_MODE_MAIN = 2, // 主屏(折叠时用户面对的屏幕)
FOLD_DISPLAY_MODE_SUB = 3, // 副屏(折叠时背面的屏幕)
FOLD_DISPLAY_MODE_COORDINATION = 4 // 协同模式(双屏联动)
}
FoldStatus 描述的是硬件物理状态,而 FoldDisplayMode 描述的是软件层面的显示策略——在折叠状态下,App 的内容渲染在哪个屏幕上。
1.6 CutoutInfo — 屏幕开孔与曲面
interface CutoutInfo {
readonly boundingRects: Rect[]; // 挖孔/刘海边界矩形数组
readonly waterfallDisplayAreaRects: WaterfallDisplayAreaRects; // 瀑布屏曲面区域
}
interface WaterfallDisplayAreaRects {
readonly left: Rect; // 左侧曲面区域
readonly right: Rect; // 右侧曲面区域
readonly top: Rect; // 顶部曲面区域
readonly bottom: Rect; // 底部曲面区域
}
interface Rect {
left: number;
top: number;
width: number;
height: number;
}
getCutoutInfo() 是异步方法,返回 Promise<CutoutInfo>。boundingRects 数组中的每个 Rect 描述了一个屏幕开孔(前置摄像头挖孔或刘海)的像素级边界。waterfallDisplayAreaRects 描述曲面屏的弯曲边缘区域——这对于需要在曲面区域放置可交互 UI 元素的应用至关重要。
二、同步 API — 获取显示属性
2.1 getDefaultDisplaySync()
let d: display.Display = display.getDefaultDisplaySync();
同步返回默认的 Display 对象。所有 Display 属性都是快照值(不会自动更新),如果屏幕属性发生了变化(如旋转、折叠状态切换),需要重新调用该方法获取最新值,或通过事件监听器接收通知。
2.2 读取 Display 属性
let width = d.width; // 逻辑宽度
let height = d.height; // 逻辑高度
let density = d.densityDPI; // 屏幕 DPI
let scale = d.densityPixels; // 像素密度系数
let rate = d.refreshRate; // 当前刷新率
let orient = d.orientation; // 方向枚举
// 版本相关属性 — 需要判空
if (d.supportedRefreshRates) {
let rates = d.supportedRefreshRates; // API 20+
}
if (d.screenShape !== undefined) {
let shape = d.screenShape; // API 18+
}
关键注意事项:较高 API 版本的属性(screenShape、sourceMode、supportedRefreshRates、x、y)被定义为可选字段(?),在读取前必须做空值检查,否则在低版本设备上会导致运行时异常。
2.3 getAllDisplays() — 多显示器枚举
display.getAllDisplays().then((displays: display.Display[]) => {
for (let d of displays) {
console.log(`Display #${d.id}: ${d.name} ${d.width}x${d.height}`);
}
});
在 2in1 设备、平板连接外部显示器时,这个方法会返回多个 Display 对象。每个 Display 都有独立的 id、name、分辨率和方向。sourceMode 属性(API 19+)可以区分主显示器(MAIN)、镜像模式(MIRROR)、扩展模式(EXTEND)和独立模式(ALONE)。

三、折叠屏 API — 从检测到监听
HarmonyOS 对折叠屏的支持是全方位的——从"设备是否可折叠"到"当前折叠角度",从"折痕像素区域"到"双显示器模式切换"。这些 API 全部零权限、同步返回。
3.1 isFoldable() — 判断是否折叠设备
let foldable = display.isFoldable(); // true on foldable phones/tablets
这是任何折叠屏适配逻辑的入口。在非折叠设备上,所有后续的折叠相关 API 要么返回默认值,要么抛出异常,因此 isFoldable() 的结果应当作为条件分支的守卫。
3.2 getFoldStatus() — 获取折叠状态
let status = display.getFoldStatus();
switch (status) {
case display.FoldStatus.FOLD_STATUS_EXPANDED:
// 屏幕完全展开 — 全屏体验
break;
case display.FoldStatus.FOLD_STATUS_FOLDED:
// 屏幕完全折叠 — 适配小屏或切换到副屏
break;
case display.FoldStatus.FOLD_STATUS_HALF_FOLDED:
// 半折悬停态 — 可以通过 split-screen 或特殊的悬停 UI
break;
}
折叠状态变化会自然触发应用的界面适配。例如,视频播放器在 FOLDED 状态切换到副屏(FOLD_DISPLAY_MODE_SUB)播放,而主屏显示控制面板。
3.3 getFoldDisplayMode() — 当前显示模式
let mode = display.getFoldDisplayMode();
// FULL: 完全展开,使用整块屏幕
// MAIN: 折叠时用户面对的主屏幕
// SUB: 折叠时背面的副屏幕(如 Galaxy Z Flip 的外屏)
// COORDINATION: 双屏协同模式
getFoldDisplayMode() 回答的是"我的 App 当前渲染在哪个屏幕上"。在折叠状态下,App 可能被系统自动切换到副屏(通常是小尺寸外屏),这时需要对 UI 做大幅度的简化。
3.4 getCurrentFoldCreaseRegion() — 折痕区域
let crease = display.getCurrentFoldCreaseRegion();
// crease.displayId — 折痕所在的屏幕 ID
// crease.creaseRects — 折痕矩形数组
for (let rect of crease.creaseRects) {
console.log(`Crease: ${rect.left},${rect.top} ${rect.width}x${rect.height}`);
}
折痕区域信息让开发者可以主动避开在折痕位置放置关键交互元素(如按钮、滑块),避免用户触摸体验不佳。这在设计折叠屏优化布局时是"最后 1px 的精细调整"。
3.5 折叠角度事件 (API 12+)
display.on('foldAngleChange', (angles: Array<number>) => {
// angles[0] = 第一折叠轴的角度(0° = 完全折叠,180° = 完全展开)
// angles[1] = 第二折叠轴的角度(双折叠设备)
console.log('Fold angle: ' + angles[0] + '°');
});
foldAngleChange 是折叠屏 API 中最细粒度的事件——它不是离散的状态变化通知,而是连续的物理角度值。这让开发者可以实现实时响应用户折叠动作的动画效果(如折叠一半时 UI 布局的渐进式变化)。
四、屏幕开孔与曲面检测
4.1 getCutoutInfo() — 挖孔/刘海/曲面
let d = display.getDefaultDisplaySync();
d.getCutoutInfo().then((info: display.CutoutInfo) => {
// 挖孔/刘海区域
for (let rect of info.boundingRects) {
console.log(`Notch: ${rect.left},${rect.top} ${rect.width}x${rect.height}`);
}
// 瀑布屏曲面区域
let wf = info.waterfallDisplayAreaRects;
if (wf.left) { /* 左侧曲面 */ }
if (wf.right) { /* 右侧曲面 */ }
if (wf.top) { /* 顶部曲面 */ }
if (wf.bottom) { /* 底部曲面 */ }
});
getCutoutInfo() 是异步方法(返回 Promise),需要注意:在调用前确保 Display 对象仍然 alive,否则可能抛出异常。
waterfallDisplayAreaRects 的四个方向曲面是独立检测的——有的设备只有左右曲面(曲面屏手机),有的设备四边都是曲面(环形瀑布屏)。四个字段都是 Rect | null,需要逐个判空。
4.2 getAvailableArea() — 可用区域(API 12+)
d.getAvailableArea().then((rect: display.Rect) => {
// rect 描述了排除挖孔、刘海、系统栏后的可用渲染区域
console.log(`Safe area: ${rect.left},${rect.top} ${rect.width}x${rect.height}`);
});
与 availableWidth/availableHeight 相比,getAvailableArea() 返回的是完整的 Rect(包含起始坐标),适合处理不规则可用区域(如有曲面边缘的设备)。
五、录屏与投屏检测
5.1 isCaptured() — 检测录屏状态
let captured = display.isCaptured();
if (captured) {
// 设备正在被录屏或投屏
// 可以隐藏敏感信息、启用防截屏保护
}
isCaptured() 是 API 12 新增的方法,同步返回当前屏幕的捕获状态。检测范围包括:
- 系统录屏功能
- 第三方录屏应用
- 无线投屏(屏幕镜像)
- 有线视频输出(HDMI/DP 外接显示器)
5.2 captureStatusChange — 监听状态变化
display.on('captureStatusChange', (captured: boolean) => {
if (captured) {
// 开始录屏/投屏 — 启用水印或隐藏敏感数据
} else {
// 录屏结束 — 恢复正常显示
}
});
captureStatusChange 事件让应用可以在录屏开始时即时响应,而不是周期性地轮询 isCaptured()。对于金融类应用、隐私敏感应用,这是一个非常实用的安全防护点。
六、事件监听体系
@ohos.display 提供了完整的事件监听机制,覆盖了所有重要的显示状态变化:
| 事件类型 | 回调参数 | 触发时机 | 最低 API |
|---|---|---|---|
change |
Callback<number> |
显示器增加/移除/属性变更 | API 7 |
foldStatusChange |
Callback<FoldStatus> |
折叠状态变化 | API 10 |
foldDisplayModeChange |
Callback<FoldDisplayMode> |
折叠显示模式变化 | API 10 |
foldAngleChange |
Callback<Array<number>> |
折叠角度变化(连续值) | API 12 |
captureStatusChange |
Callback<boolean> |
录屏/投屏状态变化 | API 12 |
availableAreaChange |
Callback<Rect> |
可用区域变化(Display 实例方法) | API 12 |
brightnessInfoChange |
BrightnessCallback<number, BrightnessInfo> |
亮度信息变化(API 22) | API 22 |
6.1 注册与注销
// 注册监听
let changeCallback = (id: number) => { /* ... */ };
display.on('change', changeCallback);
// 注销监听(必须传递相同的 callback 引用)
display.off('change', changeCallback);
// 注销该事件类型的所有回调(API 20+)
display.off('change');
关键陷阱:off() 的 callback 参数在 API 7-19 是必填的,必须传递与 on() 相同的函数引用才能成功注销。API 20 起 callback 变为可选——不传则移除该事件类型的所有回调。
6.2 onChangeWithAttribute — 精确属性过滤(API 23)
display.onChangeWithAttribute(['refreshRate', 'orientation'], (id: number) => {
// 仅在刷新率或方向变化时触发,避免噪音通知
});
这个 API 让事件监听更精准——只关注你关心的属性变化,减少不必要的事件处理和 UI 刷新。
七、实战 Demo:显示信息诊断中心
页面结构
显示信息诊断中心
├── 标题栏 — "显示信息诊断中心" + @ohos.display
├── 摘要栏 — 分辨率 + 刷新率 + DPI + 刷新按钮
├── 基础显示属性
│ ├── ID / 名称 / 存活状态
│ ├── 分辨率 + 可用区域
│ ├── 刷新率 + 支持的刷新率列表
│ ├── 密度(DPI / densityPixels / scaledDensity / X/Y DPI)
│ ├── 方向 + 旋转值
│ └── 屏幕形态(矩形/圆形)
├── 显示状态
│ ├── 屏幕状态(ON/OFF/DOZE/VR 等)
│ ├── 显示源模式(MAIN/MIRROR/EXTEND/ALONE)
│ ├── 色彩空间数量 + HDR 格式数量
│ └── 录屏状态
├── 折叠屏检测
│ ├── 是否折叠设备
│ ├── 折叠状态 + 折叠显示模式
│ ├── 折痕区域
│ └── 折叠角度(实时更新)
├── 屏幕开孔与曲面
│ ├── 挖孔/刘海区域(边界矩形坐标)
│ └── 曲面屏区域(L/R/T/B)
├── 多显示器(异步加载)
│ └── 每个显示器的 ID/名称/分辨率/方向/状态
├── 实时事件监听(开关控制)
│ └── change / foldStatusChange / foldDisplayModeChange / captureStatusChange / foldAngleChange
├── 四类显示事件对比卡片
└── 核心 API 参考 — 18 个关键 API + 枚举
4 个交互点
- 一键刷新全部属性 — 点击刷新按钮,同步读取 Display 对象的所有属性并更新 UI
- 实时事件监听 — 拨动开关开启所有事件监听器(change / foldStatus / foldDisplayMode / capture / foldAngle),每个事件触发时实时更新 UI 并追加事件日志
- 折叠屏专项诊断 — 独立读取和展示折叠状态、显示模式、折痕区域和折叠角度
- 多显示器浏览 — 异步加载所有连接的显示器,以卡片列表展示每个显示器的独立属性
核心代码实现
Display 对象属性读取
import display from '@ohos.display';
refreshAll(): void {
try {
let d = display.getDefaultDisplaySync();
this.displayId = d.id;
this.displayName = d.name;
this.isAlive = d.alive;
this.scrWidth = d.width;
this.scrHeight = d.height;
this.availWidth = d.availableWidth;
this.availHeight = d.availableHeight;
this.refreshRate = d.refreshRate;
this.densityDPI = d.densityDPI;
this.densityPixels = d.densityPixels;
this.scaledDensity = d.scaledDensity;
this.xDPI = d.xDPI;
this.yDPI = d.yDPI;
this.orientation = orientationLabel(d.orientation);
this.rotation = d.rotation;
this.displayState = stateLabel(d.state);
// 版本相关属性 — 判空
if (d.supportedRefreshRates !== undefined && d.supportedRefreshRates !== null) {
this.supportedRates = d.supportedRefreshRates.map(r => r + 'Hz').join(', ');
}
if (d.screenShape !== undefined && d.screenShape !== null) {
this.screenShape = d.screenShape === 0 ? '矩形' : '圆形';
}
if (d.sourceMode !== undefined && d.sourceMode !== null) {
this.sourceMode = ['NONE', 'MAIN', 'MIRROR', 'EXTEND', 'ALONE'][d.sourceMode];
}
} catch (e) {
// 异常处理
}
}
折叠屏专项检测
refreshFoldable(): void {
try {
this.isFoldable = display.isFoldable();
} catch (e) {
this.isFoldable = false;
}
if (this.isFoldable) {
this.foldStatus = this.foldStatusLabel(display.getFoldStatus());
this.foldDisplayMode = this.foldDisplayModeLabel(display.getFoldDisplayMode());
let crease = display.getCurrentFoldCreaseRegion();
this.creaseInfo = 'displayId: ' + crease.displayId
+ ', 折痕区域: ' + crease.creaseRects.length + ' 个';
}
}
事件监听全套注册
startListeners(): void {
// 显示变化
this.displayCallback = (id: number) => {
this.addLog('显示变化 (id:' + id + ')', '#3B82F6');
this.refreshAll();
};
display.on('change', this.displayCallback);
// 折叠状态变化
this.foldCallback = (status: display.FoldStatus) => {
this.addLog('折叠状态: ' + this.foldStatusLabel(status), '#8B5CF6');
this.foldStatus = this.foldStatusLabel(status);
};
display.on('foldStatusChange', this.foldCallback);
// 录屏状态变化
this.captureCallback = (captured: boolean) => {
this.isCaptured = captured;
this.addLog(captured ? '开始录屏/投屏' : '录屏/投屏已停止',
captured ? '#EF4444' : '#10B981');
};
display.on('captureStatusChange', this.captureCallback);
// 折叠角度变化
this.foldAngleCallback = (angles: Array<number>) => {
this.foldAngle = angles.map(a => a + '°').join(', ');
this.addLog('折叠角度: ' + this.foldAngle, '#8B5CF6');
};
display.on('foldAngleChange', this.foldAngleCallback);
}
注销时必须传递相同的 callback 引用:
stopListeners(): void {
display.off('change', this.displayCallback);
display.off('foldStatusChange', this.foldCallback);
display.off('captureStatusChange', this.captureCallback);
display.off('foldAngleChange', this.foldAngleCallback);
}
预览效果预期
- 摘要栏:显示类似 “1260×2720 @120Hz 450DPI” 的实时屏幕摘要
- 基础属性区:15 行属性值,包括分辨率、密度(4 种)、刷新率、方向等
- 折叠屏区:在折叠设备上显示详细的折叠状态和折痕区域;在普通手机上显示"非折叠设备"
- 挖孔区:显示类似 “1 个: [100,24 120x30]” 或 “无挖孔/刘海”;曲面区显示 “曲面: L,R” 或 “非曲面屏”
- 事件日志:开启监听后,折叠/展开设备、插拔外接显示器时实时收到事件通知
八、与 Android / iOS 的 API 对比
| 能力 | Android (DisplayManager) | iOS (UIScreen) | HarmonyOS (display) |
|---|---|---|---|
| 默认屏幕 | getDefaultDisplay() |
UIScreen.main |
getDefaultDisplaySync() |
| 所有屏幕 | getDisplays() |
UIScreen.screens |
getAllDisplays() |
| 分辨率/密度 | DisplayMetrics | nativeBounds / scale | Display.width/height/densityPixels |
| 刷新率 | Display.Mode.getRefreshRate() | UIScreen.maximumFramesPerSecond |
Display.refreshRate + supportedRefreshRates |
| 折叠检测 | PackageManager.hasSystemFeature() 间接判断 |
无标准 API | isFoldable() 直接 API |
| 折叠状态 | 需监听 Configuration 变化 | 无 | getFoldStatus() + on('foldStatusChange') |
| 折痕位置 | 无标准 API | 无 | getCurrentFoldCreaseRegion() |
| 挖孔/刘海 | WindowInsets.getDisplayCutout() API 28+ |
safeAreaInsets |
getCutoutInfo() |
| 曲面屏 | 无 | 无 | waterfallDisplayAreaRects |
| 录屏检测 | MediaProjection 需权限 |
UIScreen.isCaptured iOS 11+ |
isCaptured() + captureStatusChange |
| 权限需求 | 无(读操作) | 无(读操作) | 无(读操作) |
HarmonyOS 在显示子系统 API 的设计上有一个独特的优势——它将折叠屏能力和曲面屏检测作为一等公民来对待,而不是通过间接方式推断。这意味着折叠设备上的 App 可以获得 Android 生态中需要大量样板代码才能实现(甚至无法实现)的精准屏幕感知能力。
九、常见陷阱与最佳实践
9.1 Display 对象是快照,不是实时引用
let d = display.getDefaultDisplaySync();
// ... 5 秒后用户旋转屏幕 ...
// d.orientation 仍然是旧值!
// 需要重新调用 getDefaultDisplaySync() 或通过事件监听更新
Display 对象获取后不会自动更新。需要定期刷新或通过事件监听获取最新状态。
9.2 版本兼容性——可选字段判空
// 错误 — 在 API 17 设备上 screenShape 为 undefined
let shapeText = d.screenShape === 0 ? '矩形' : '圆形'; // 崩溃!
// 正确
if (d.screenShape !== undefined && d.screenShape !== null) {
let shapeText = d.screenShape === 0 ? '矩形' : '圆形';
}
9.3 off() 的 callback 引用陷阱
// 错误 — off 传递了新的匿名函数,与 on 不是同一引用
display.on('change', (id: number) => { /* A */ });
display.off('change', (id: number) => { /* B */ }); // 不会生效!
// 正确 — 保存 callback 引用
let cb = (id: number) => { /* ... */ };
display.on('change', cb);
display.off('change', cb);
9.4 折叠 API 的条件调用
// 非折叠设备上以下调用可能抛出异常:
// getFoldStatus(), getFoldDisplayMode(), getCurrentFoldCreaseRegion()
if (display.isFoldable()) {
// 安全地调用折叠 API
let status = display.getFoldStatus();
}
十、总结
@ohos.display 是 HarmonyOS NEXT 显示子系统的完整程序化入口。它远不止是"获取屏幕尺寸"那么简单——核心能力包括:
- Display 对象:15+ 属性覆盖了屏幕的物理参数、密度体系、刷新率、方向、色彩和 HDR,以及显示源模式
- 折叠屏全套 API:从
isFoldable()到getFoldStatus()到foldAngleChange,覆盖了折叠设备的所有维度——物理状态、显示策略、折痕区域、连续角度 - 屏幕开孔与曲面:
getCutoutInfo()返回精确的边界矩形坐标,让 UI 可以主动避开障碍区域 - 录屏检测:
isCaptured()和captureStatusChange提供了零权限的录屏/投屏感知能力 - 事件监听体系:6 种事件类型覆盖显示系统所有的重要状态变化
- 多显示器管理:
getAllDisplays()枚举所有连接的屏幕,每个都有独立的完整属性集
结合 @ohos.window(窗口管理)、@ohos.screen(屏幕亮度/省电策略)和 @ohos.mediaquery(媒体查询),HarmonyOS 开发者拥有了从硬件感知到 UI 适配的完整工具链。
更多推荐




所有评论(0)