鸿蒙新特性:@ohos.display 屏幕信息实验室实战 —— 分辨率、刷新率、密度与折叠状态监听
引言
屏幕是应用与用户交互的唯一窗口。应用的布局适配、字体缩放、图片资源选择,都依赖对屏幕参数的准确感知。HarmonyOS NEXT 通过 @ohos.display 模块将屏幕元信息统一暴露为同步可读的属性和事件回调——分辨率、刷新率、像素密度、旋转角度、折叠状态、录屏检测等,全部无需权限即可获取。
@ohos.display 属于 @kit.ArkUI,是 UI 框架层的核心模块。与 Android 的 DisplayMetrics / WindowManager 和 iOS 的 UIScreen 不同,@ohos.display 不仅提供基础的分辨率和密度,还内置了对折叠设备(Foldable)的完整支持——isFoldable() 判断、getFoldStatus() 查询、on('foldStatusChange') 实时监听,以及 isCaptured() 录屏检测。这些在 Android 和 iOS 中需要分散在多个 API 中的能力,在鸿蒙中被整合到了一个模块中。
本文将深入讲解 @ohos.display 的屏幕属性读取、密度体系、旋转识别和折叠状态管理四大核心能力,并构建一个"屏幕信息实验室"Demo,在一个页面中完整展示屏幕全部参数。
一、API 架构:同步属性 + 事件监听
1.1 核心设计理念
@ohos.display 的 API 分为两层:同步读取层提供屏幕属性的即时获取,全部以 Sync 后缀或直接属性访问的形式提供;事件监听层通过 on/off 模式提供折叠状态、录屏状态等实时变化的回调通知。
import display from '@ohos.display';
// 同步:瞬间返回完整 Display 对象
const d = display.getDefaultDisplaySync();
// 直接读取属性——全部同步
console.log(d.width + ' × ' + d.height); // 分辨率
console.log(d.refreshRate.toFixed(0) + ' Hz'); // 刷新率
console.log(d.densityDPI.toFixed(0) + ' DPI'); // 像素密度
// 事件监听:折叠状态变化
display.on('foldStatusChange', (fs: display.FoldStatus) => {
if (fs === display.FoldStatus.FOLD_STATUS_EXPANDED) {
// 切换到展开布局
}
});
这种"同步读取 + 事件回调"的分层设计非常实用——屏幕基础属性在应用生命周期内通常不变(分辨率、DPI),同步读取零开销;折叠状态和录屏状态是动态变化的,事件监听模型及时且精确。
1.2 getDefaultDisplaySync —— 默认屏幕对象
getDefaultDisplaySync() 是屏幕信息的核心入口。它同步返回一个 Display 对象,包含当前默认屏幕的全部参数。这个方法无参数、无权限要求,可以在任何地方调用。
const d = display.getDefaultDisplaySync();
返回的 Display 对象是一个属性只读的快照——屏幕参数不会自动更新。如果需要获取最新值(例如屏幕旋转后),需要重新调用 getDefaultDisplaySync()。
Display 接口完整属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| id | number | 屏幕唯一标识符 |
| name | string | 屏幕名称(如 “built-in”) |
| alive | boolean | 屏幕是否活跃 |
| state | DisplayState | 屏幕状态(亮屏/息屏/待机/VR) |
| width | number | 屏幕宽度(像素) |
| height | number | 屏幕高度(像素) |
| refreshRate | number | 屏幕刷新率(Hz) |
| rotation | number | 屏幕旋转角度(0/90/180/270) |
| densityDPI | number | 屏幕物理像素密度(DPI) |
| densityPixels | number | 逻辑像素密度(缩放系数) |
| scaledDensity | number | 字体缩放密度 |
1.3 DisplayState —— 屏幕状态枚举
DisplayState 是屏幕当前的工作状态,有四种取值:
| 枚举值 | 说明 | 典型场景 |
|---|---|---|
| STATE_ON | 亮屏 | 正常使用中 |
| STATE_OFF | 息屏 | 锁屏后、按电源键关闭 |
| STATE_DOZE | 待机(常亮显示) | AOD 息屏显示模式 |
| STATE_VR | VR 模式 | 连接 VR 设备时 |
private stateLabel(state: display.DisplayState): string {
if (state === display.DisplayState.STATE_ON) return '亮屏';
if (state === display.DisplayState.STATE_OFF) return '息屏';
if (state === display.DisplayState.STATE_DOZE) return '待机';
if (state === display.DisplayState.STATE_VR) return 'VR 模式';
return '未知';
}
在实际开发中,state 可用于判断是否需要在息屏或待机状态下暂停动画、降低刷新率以节省电量。
1.4 分辨率与刷新率
width 和 height 返回屏幕的物理像素分辨率。与 Android 的 DisplayMetrics.widthPixels 类似,这两个值代表屏幕的实际像素数。
refreshRate 返回屏幕当前的刷新率(Hz)。大多数手机屏幕为 60Hz,高刷屏为 90Hz 或 120Hz。开发者可以根据刷新率调整动画帧率:
const rr = display.getDefaultDisplaySync().refreshRate;
if (rr >= 90) {
// 高刷屏:使用 90fps 流畅动画
} else {
// 标准屏:使用 60fps 动画即可
}
1.5 rotation —— 屏幕旋转角度
rotation 返回当前屏幕的旋转角度(0°、90°、180°、270°)。这个值反映的是屏幕物理旋转状态,不是应用窗口的朝向。配合 @ohos.window 的 setPreferredOrientation() 使用时,rotation 可以帮助判断用户当前的持握方向。
private rotationLabel(rot: number): string {
if (rot === 0) return '0°(竖屏)';
if (rot === 90) return '90°(横屏)';
if (rot === 180) return '180°(倒置)';
if (rot === 270) return '270°(反向横屏)';
return rot.toString() + '°';
}
二、密度体系:DPI、像素密度与缩放密度
2.1 三层密度模型
@ohos.display 提供了三层密度概念,这是理解鸿蒙 UI 尺寸体系的关键:
| 属性 | 说明 | 典型值(手机) | 用途 |
|---|---|---|---|
| densityDPI | 物理像素密度(每英寸像素数) | 420-560 | 判断屏幕精细度等级 |
| densityPixels | 逻辑像素缩放系数 | 2.75-3.5 | 物理像素与逻辑像素的换算 |
| scaledDensity | 字体缩放密度 | 与 densityPixels 相近 | 字体大小的自动适配 |
densityDPI 是屏幕的物理属性,反映了硬件的像素密度。值越高,屏幕越精细。开发者通常不需要直接使用这个值做布局计算,但可以用它来判断设备的屏幕等级(低清/高清/超清)。
densityPixels 是物理像素与逻辑像素(vp)之间的换算系数。在 ArkUI 中,所有尺寸单位(vp、fp)都是逻辑像素,框架会自动根据 densityPixels 换算为物理像素。只有在需要精确控制物理像素(如 Canvas 绘制、图片解码)时才需要读取这个值。
scaledDensity 是在 densityPixels 基础上叠加用户字体缩放设置后的系数。当用户在系统设置中调整字体大小时,这个值会相应变化。
// 三个密度的关系
const d = display.getDefaultDisplaySync();
const physicalPx = 100 * d.densityPixels; // 100vp → 物理像素
const fontSize = 16 * d.scaledDensity; // 16fp → 物理像素
2.2 密度与资源适配
在 HarmonyOS 的资源管理中,系统会根据 densityDPI 自动选择最合适的资源文件(如 resources/base/media vs resources/xxhdpi/media)。开发者通常不需要手动判断 DPI 等级,但了解当前设备的 DPI 值有助于调试资源加载问题。
三、折叠设备支持
3.1 isFoldable —— 判断设备是否可折叠
isFoldable() 同步返回 boolean,判断当前设备是否为折叠设备(折叠屏手机、平板等)。
const foldable = display.isFoldable();
if (foldable) {
// 初始化折叠适配逻辑
}
这是折叠适配的第一步——先判断设备类型,再决定是否启用折叠相关的 UI 逻辑。
3.2 getFoldStatus —— 当前折叠状态
getFoldStatus() 同步返回当前折叠状态,值来自 FoldStatus 枚举:
| 枚举值 | 说明 | 布局策略 |
|---|---|---|
| FOLD_STATUS_EXPANDED | 展开状态 | 大屏布局,充分利用空间 |
| FOLD_STATUS_FOLDED | 折叠状态 | 小屏布局,优化单手操作 |
| FOLD_STATUS_HALF_FOLDED | 半开状态 | 中间态,通常保持前一个状态布局 |
private foldLabel(status: display.FoldStatus): string {
if (status === display.FoldStatus.FOLD_STATUS_EXPANDED) return '展开';
if (status === display.FoldStatus.FOLD_STATUS_FOLDED) return '折叠';
if (status === display.FoldStatus.FOLD_STATUS_HALF_FOLDED) return '半开';
return '未知';
}
在半开状态下(如 Flex 模式悬停),应用可以选择显示特殊的分屏 UI——例如上半屏播放视频、下半屏显示控制面板。
3.3 折叠状态实时监听
on('foldStatusChange', callback) 和 off('foldStatusChange', callback) 提供折叠状态的实时监听。当用户折叠或展开设备时,回调会被立即触发。
private startFoldListen(): void {
if (!display.isFoldable()) {
return;
}
display.on('foldStatusChange', (fs: display.FoldStatus) => {
this.foldStatus = this.foldLabel(fs);
// 根据新状态调整布局
});
}
// 离开页面时取消监听
private stopFoldListen(): void {
display.off('foldStatusChange');
}
需要注意的是,off() 必须在组件销毁(aboutToDisappear)时调用,否则会造成内存泄漏。Demo 中我们将监听开关绑定到 Toggle 按钮,用户可以手动开启/关闭折叠状态监听。

四、实战 Demo:屏幕信息实验室
4.1 页面设计
"屏幕信息实验室"页面分为六个功能区域:
-
屏幕身份卡片:展示屏幕名称(大字标题)、活跃状态(活跃/未活跃带颜色标签)、屏幕 ID。下方三栏展示屏幕 ID、活跃状态和录屏检测结果。
-
分辨率与刷新率面板:双栏展示物理分辨率(width × height)和刷新率(Hz),右侧展示当前旋转角度(0°竖屏/90°横屏/180°倒置/270°反向横屏)。
-
显示密度面板:三栏展示三层密度——DPI(物理像素密度)、像素密度(逻辑缩放系数)、缩放密度(字体缩放系数)。
-
折叠状态面板:展示是否折叠设备、当前折叠状态(展开/折叠/半开)。提供两个按钮——"刷新折叠状态"重新读取最新值,"监听折叠"Toggle 按钮控制折叠状态监听的开启与关闭。
-
API 能力说明:以灰色文字展示核心 API 的方法签名和功能说明。
-
操作日志:记录所有操作,按时间倒序排列,不同类别(success / error / system)以不同颜色标记。
4.2 核心实现
数据模型:
@State displayName: string = '--';
@State displayId: string = '--';
@State displayAlive: string = '--';
@State displayState: string = '--';
@State resolution: string = '--';
@State refreshRate: string = '--';
@State densityDPI: string = '--';
@State densityPixels: string = '--';
@State scaledDensity: string = '--';
@State rotation: string = '--';
@State isFoldable: boolean = false;
@State foldStatus: string = '--';
@State foldListening: boolean = false;
@State isCaptured: string = '--';
@State logs: LogEntry[] = [];
每个屏幕属性独立一个 @State 变量,确保 UI 能够单独更新每一项。
一次性读取全部属性:
private refreshAll(): void {
try {
const d = display.getDefaultDisplaySync();
this.displayName = d.name;
this.displayId = d.id.toString();
this.displayAlive = d.alive ? '活跃' : '未活跃';
this.displayState = this.stateLabel(d.state);
this.resolution = d.width.toString() + ' × ' + d.height.toString();
this.refreshRate = d.refreshRate.toFixed(0) + ' Hz';
this.densityDPI = d.densityDPI.toFixed(0) + ' DPI';
this.densityPixels = d.densityPixels.toFixed(3);
this.scaledDensity = d.scaledDensity.toFixed(3);
this.rotation = this.rotationLabel(d.rotation);
} catch (e) {
this.addLog('获取屏幕信息失败', 'error');
}
try {
this.isFoldable = display.isFoldable();
if (this.isFoldable) {
const fs = display.getFoldStatus();
this.foldStatus = this.foldLabel(fs);
} else {
this.foldStatus = '非折叠设备';
}
} catch (e) {
this.isFoldable = false;
}
try {
this.isCaptured = display.isCaptured() ? '录屏中' : '正常';
} catch (e) {
this.isCaptured = '--';
}
}
每个独立功能块都使用 try/catch 包裹,确保单个模块的异常不影响其他模块的数据读取。
折叠状态监听 Toggle:
private toggleFoldListen(): void {
if (this.foldListening) {
this.stopFoldListen();
} else {
this.startFoldListen();
}
}
private startFoldListen(): void {
if (!display.isFoldable()) {
this.addLog('当前设备不支持折叠', 'system');
return;
}
display.on('foldStatusChange', (fs: display.FoldStatus) => {
this.foldStatus = this.foldLabel(fs);
this.addLog('折叠状态变化: ' + this.foldLabel(fs), 'system');
});
this.foldListening = true;
this.addLog('已开启折叠状态监听', 'success');
}
private stopFoldListen(): void {
try {
display.off('foldStatusChange');
this.foldListening = false;
this.addLog('已关闭折叠状态监听', 'system');
} catch (e) {
this.addLog('关闭折叠监听失败', 'error');
}
}
4.3 交互方式
Demo 提供四个核心交互点:
-
刷新全部信息:屏幕身份卡片中的隐式刷新——每次进入页面时自动调用
refreshAll()读取所有属性。Demo 中不设显式刷新按钮,因为屏幕基础属性在应用生命周期内通常不变,但折叠状态面板有独立刷新按钮。 -
刷新折叠状态:单击"刷新折叠状态"按钮重新调用
isFoldable()+getFoldStatus(),更新折叠设备信息和当前折叠状态。 -
折叠状态监听 Toggle:单击"监听折叠"按钮开启监听(按钮变为红色"停止监听"),再次单击关闭监听(按钮恢复青色"监听折叠")。开启后折叠设备的状态变化会实时反映在 UI 和操作日志中。
-
操作日志:每次 API 调用和状态变化都以时间戳 + 消息的形式记录到日志区域,方便追踪操作时序。
五、实际应用场景
5.1 折叠屏布局适配
class FoldableLayoutManager {
private isExpanded: boolean = false;
constructor() {
if (display.isFoldable()) {
this.isExpanded = display.getFoldStatus() ===
display.FoldStatus.FOLD_STATUS_EXPANDED;
display.on('foldStatusChange', (fs: display.FoldStatus) => {
this.isExpanded = fs === display.FoldStatus.FOLD_STATUS_EXPANDED;
this.onLayoutChanged();
});
}
}
getLayoutMode(): 'single' | 'dual' {
return this.isExpanded ? 'dual' : 'single';
}
private onLayoutChanged(): void {
// 通知 UI 层重新布局
}
}
5.2 根据屏幕密度选择图片资源
function getImageQuality(): 'low' | 'medium' | 'high' {
const dpi = display.getDefaultDisplaySync().densityDPI;
if (dpi >= 480) return 'high';
if (dpi >= 320) return 'medium';
return 'low';
}
虽然 HarmonyOS 的资源系统会自动匹配 DPI 等级,但在使用网络图片时,可以根据此值请求不同分辨率的图片以优化流量和加载速度。
5.3 高刷屏动画优化
function getAnimationFPS(): number {
const rr = display.getDefaultDisplaySync().refreshRate;
if (rr >= 120) return 120;
if (rr >= 90) return 90;
return 60;
}
5.4 录屏检测
function onSensitiveContent(): void {
if (display.isCaptured()) {
// 检测到录屏:隐藏敏感信息、添加水印
showWatermark();
}
}
isCaptured() 返回当前屏幕是否正在被录制(录屏或投屏),这在金融、社交等涉及隐私保护的场景中非常实用。
六、ArkTS 使用注意事项
6.1 Display 对象是快照
getDefaultDisplaySync() 返回的 Display 对象是调用时刻的快照,不会自动更新。如果屏幕发生了旋转或插入了外接显示器,需要重新调用来获取最新值。这与 Android 的 DisplayMetrics 行为一致。
6.2 事件监听的正确清理
display.on('foldStatusChange', callback) 注册的监听器必须在组件生命周期结束时通过 display.off('foldStatusChange', callback) 移除。在 aboutToDisappear() 中执行取消操作是最佳实践。
6.3 非折叠设备的兼容处理
在非折叠设备上,isFoldable() 返回 false,getFoldStatus() 的行为是未定义的。代码中必须先判断 isFoldable() 的返回值,再决定是否调用折叠相关 API。
6.4 densityPixels 与 scaledDensity 的区别
densityPixels 是物理像素与逻辑像素(vp)的换算系数,scaledDensity 在此基础上叠加了用户的字体缩放设置。在布局计算中使用 densityPixels,在字号计算中使用 scaledDensity。
七、总结
@ohos.display 是 HarmonyOS NEXT 中获取屏幕参数和监听显示状态变化的核心模块。通过本文的学习,你应该已经掌握:
- 同步读取模型:
getDefaultDisplaySync()返回Display对象,包含 id/name/alive/state/refreshRate/rotation/width/height/densityDPI/densityPixels/scaledDensity——全部同步可读 - 三层密度体系:densityDPI(物理硬件密度)、densityPixels(逻辑像素缩放系数)、scaledDensity(字体缩放密度),分别服务于资源匹配、布局换算和字体适配
- 屏幕状态识别:
DisplayState枚举(亮屏/息屏/待机/VR)和rotation角度值(0°/90°/180°/270°),是节电策略和方向适配的依据 - 折叠设备支持:
isFoldable()判断 +getFoldStatus()查询 +on/off('foldStatusChange')实时监听,构成完整的折叠屏适配方案 - 录屏检测:
isCaptured()同步返回当前是否处于录屏/投屏状态,是隐私保护的重要检测点
@ohos.display 的最佳使用模式可以总结为:
应用启动时全量读取 Display 对象建立屏幕画像,折叠设备注册 foldStatusChange 监听驱动布局切换,敏感场景调用 isCaptured 检测录屏状态。所有 API 同步为主、事件为辅——零权限、零延迟。
屏幕信息是 UI 适配的元数据。虽然 @ohos.display 的 API 数量不多,但它覆盖了从基础分辨率到折叠状态的完整屏幕模型。在 HarmonyOS NEXT 的 @kit.ArkUI 体系下,@ohos.display 与 @ohos.window 共同构成 UI 框架的双基石——display 负责"屏幕是什么样的",window 负责"窗口怎么做"。
@ohos.display 属于 @kit.ArkUI,是 HarmonyOS NEXT 屏幕信息查询与显示状态监听的统一入口。它的 API 设计体现了"同步优先、事件补充"的核心理念——基础属性零开销读取,动态变化通过 on/off 回调精确感知。与 Android 的 WindowManager + DisplayMetrics + DisplayListener 碎片化 API 相比,@ohos.display 的一站式设计更加简洁和直观。
更多推荐




所有评论(0)