23、鸿蒙Harmony Next开发:屏幕管理(OH_DisplayManager 和Display)

目录

使用OH_DisplayManager实现屏幕基础信息查询和状态监听

基本概念

在CMake脚本中链接动态库

添加头文件 

获取屏幕状态

监听屏幕状态变化

监听折叠设备状态变化

使用Display实现屏幕属性查询及状态监听

获取Display对象

获取屏幕相关属性

监听屏幕状态变化

监听折叠设备状态变化


使用OH_DisplayManager实现屏幕基础信息查询和状态监听

OH_DisplayManagerOH_DisplayManagerOH_DisplayManager屏幕管理模块用于提供屏幕的信息查询、屏幕状态变化监听、折叠设备的折叠状态变化监听等能力,应用可根据对应的屏幕信息、屏幕状态变化、屏幕折叠状态适配不同的UI界面显示。

  • 支持查询的屏幕信息,包括屏幕的分辨率、物理像素密度、逻辑像素密度、刷新率、屏幕尺寸、屏幕旋转方向、屏幕旋转角度等。
  • 支持屏幕状态变化的监听,包括屏幕旋转变化,屏幕分辨率变化、屏幕刷新率变化等。
  • 支持查询当前设备是否为可折叠设备,同时支持折叠状态(展开/折叠)变化的监听。

基本概念

  • 屏幕的物理像素密度(densityDPI):代表每英寸屏幕所拥有的物理像素点数。
  • 屏幕的逻辑像素的密度(densityPixels):代表物理像素与逻辑像素的缩放系数比,计算方法为物理像素密度除以160。

在CMake脚本中链接动态库

target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
target_link_libraries(entry PUBLIC libnative_display_manager.so )

添加头文件 

#include 
#include 
#include 

获取屏幕状态

  1. 可以通过OH_NativeDisplayManager_GetDefaultDisplayRotation获取默认屏幕的旋转角度。
    #include "napi/native_api.h"
    #include 
    #include 
    #include 
    
    static napi_value GetDefaultDisplayRotation(napi_env env, napi_callback_info info)
    {
        NativeDisplayManager_Rotation displayRotation;
        NativeDisplayManager_ErrorCode errCode = OH_NativeDisplayManager_GetDefaultDisplayRotation(&displayRotation);
        if (errCode == NativeDisplayManager_ErrorCode::DISPLAY_MANAGER_OK) {
            napi_value rotation;
            napi_create_int32(env, displayRotation, &rotation);
            return rotation;
        } else {
            napi_value errorCode;
            napi_create_int32(env, errCode, &errorCode);
            return errorCode;  
        }
    }
    
    EXTERN_C_START
    static napi_value Init(napi_env env, napi_value exports) {
        napi_property_descriptor desc[] = {
           {"getDisplayRotation", nullptr, GetDefaultDisplayRotation, nullptr, nullptr, nullptr, napi_default, nullptr},
        };
        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
        return exports;
    }
    EXTERN_C_END
    
  2. 可以通过OH_NativeDisplayManager_CreateDefaultDisplayCutoutInfo获取挖孔屏、刘海屏、瀑布屏等不可用屏幕区域信息。 可通过OH_NativeDisplayManager_DestroyDefaultDisplayCutoutInfo销毁挖孔屏、刘海屏、瀑布屏等不可用屏幕区域信息。 
    #include "napi/native_api.h"
    #include 
    #include 
    #include 
    
    static napi_value CreateDefaultDisplayCutoutInfo(napi_env env, napi_callback_info info)
    {
        NativeDisplayManager_CutoutInfo *cutOutInfo = NULL;
        NativeDisplayManager_ErrorCode errCode = OH_NativeDisplayManager_CreateDefaultDisplayCutoutInfo(&cutOutInfo);
        OH_LOG_INFO(LOG_APP, "GetDefaultCutoutInfo errCode=%{public}d", errCode);
        if (errCode == NativeDisplayManager_ErrorCode::DISPLAY_MANAGER_OK) {
            if (cutOutInfo != NULL && cutOutInfo->boundingRectsLength != 0) {
                OH_LOG_INFO(LOG_APP, "GetDefaultCutoutInfo cutOutInfo length=%{public}d", cutOutInfo->boundingRectsLength);
                for (int i = 0; i < cutOutInfo->boundingRectsLength; i++) {
                    OH_LOG_INFO(LOG_APP, "cutOutInfo[%{public}d]=[%{public}d %{public}d %{public}d %{public}d]",
                        i, cutOutInfo->boundingRects[i].left, cutOutInfo->boundingRects[i].top,
                        cutOutInfo->boundingRects[i].width, cutOutInfo->boundingRects[i].height);
                }
                OH_LOG_INFO(LOG_APP, "cutOutInfo waterfall left rect=[%{public}d %{public}d %{public}d %{public}d]",
                cutOutInfo->waterfallDisplayAreaRects.left.left, cutOutInfo->waterfallDisplayAreaRects.left.top,
                cutOutInfo->waterfallDisplayAreaRects.left.left, cutOutInfo->waterfallDisplayAreaRects.left.left);
                OH_LOG_INFO(LOG_APP, "cutOutInfo waterfall top rect=[%{public}d %{public}d %{public}d %{public}d]",
                cutOutInfo->waterfallDisplayAreaRects.top.left, cutOutInfo->waterfallDisplayAreaRects.top.top,
                cutOutInfo->waterfallDisplayAreaRects.top.left, cutOutInfo->waterfallDisplayAreaRects.top.left);
                OH_LOG_INFO(LOG_APP, "cutOutInfo waterfall right rect=[%{public}d %{public}d %{public}d %{public}d]",
                cutOutInfo->waterfallDisplayAreaRects.right.left, cutOutInfo->waterfallDisplayAreaRects.right.top,
                cutOutInfo->waterfallDisplayAreaRects.right.left, cutOutInfo->waterfallDisplayAreaRects.right.left);
                OH_LOG_INFO(LOG_APP, "cutOutInfo waterfall bottom rect=[%{public}d %{public}d %{public}d %{public}d]",
                cutOutInfo->waterfallDisplayAreaRects.bottom.left, cutOutInfo->waterfallDisplayAreaRects.bottom.top,
                cutOutInfo->waterfallDisplayAreaRects.bottom.left, cutOutInfo->waterfallDisplayAreaRects.bottom.left);            
            }
            napi_value boundingRectsLength;
            napi_create_int32(env, cutOutInfo->boundingRectsLength, &boundingRectsLength);
            OH_NativeDisplayManager_DestroyDefaultDisplayCutoutInfo(cutOutInfo);   
            return boundingRectsLength;
        } else {
            napi_value errorCode;
            napi_create_int32(env, errCode, &errorCode);
            return errorCode;  
        }
    }
    
    EXTERN_C_START
    static napi_value Init(napi_env env, napi_value exports) {
        napi_property_descriptor desc[] = {
            {"getCutoutInfo", nullptr, CreateDefaultDisplayCutoutInfo, nullptr, nullptr, nullptr, napi_default, nullptr},
        };
        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
        return exports;
    }
    EXTERN_C_END
    

监听屏幕状态变化

可以通过OH_NativeDisplayManager_RegisterDisplayChangeListener接口注册屏幕变化的监听,包括屏幕旋转、分辨率变化、刷新率变化、DPI变化等。 通过OH_NativeDisplayManager_UnregisterDisplayChangeListener接口取消屏幕状态变化的监听。

#include "napi/native_api.h"
#include 
#include 
#include 

void DisplayChangeCallback(uint64_t displayId)
{
    OH_LOG_INFO(LOG_APP, "DisplayChangeCallback displayId=%{public}lu.", displayId);
}

static napi_value RegisterDisplayChangeListener(napi_env env, napi_callback_info info)
{
    uint32_t listenerIndex;
    NativeDisplayManager_ErrorCode errCode = OH_NativeDisplayManager_RegisterDisplayChangeListener(
        DisplayChangeCallback, &listenerIndex);
    OH_LOG_INFO(LOG_APP, "RegisterDisplayChangeListener listenerIndex =%{public}d errCode=%{public}d.",
        listenerIndex, errCode);
    if (errCode == NativeDisplayManager_ErrorCode::DISPLAY_MANAGER_OK) {
        napi_value registerIndex;
        napi_create_int32(env, listenerIndex, ®isterIndex);
        return registerIndex;
    } else {
        napi_value errorCode;
        napi_create_int32(env, errCode, &errorCode);
        return errorCode;  
    }
}

static napi_value UnregisterDisplayChangeListener(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = { nullptr };

    uint32_t listenerIndex;
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    napi_get_value_uint32(env, args[0], &listenerIndex);
    OH_LOG_INFO(LOG_APP, "UnregisterDisplayChangeListener listenerIndex =%{public}d.", listenerIndex);
    NativeDisplayManager_ErrorCode errCode = OH_NativeDisplayManager_UnregisterDisplayChangeListener(listenerIndex);
    OH_LOG_INFO(LOG_APP, "UnregisterDisplayChangeListener errCode=%{public}d.", errCode);
    napi_value errorCode;
    napi_create_int32(env, errCode, &errorCode);
    return errorCode;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"registerDisplayChange", nullptr, RegisterDisplayChangeListener, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"unregisterDisplayChange", nullptr, UnregisterDisplayChangeListener, nullptr, nullptr, nullptr,
            napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

监听折叠设备状态变化

  1. 可以通过OH_NativeDisplayManager_IsFoldable接口查询设备是不是折叠设备。
    #include "napi/native_api.h"
    #include 
    #include 
    #include 
    
    static napi_value IsFoldable(napi_env env, napi_callback_info info)
    {
        bool isFoldDevice = OH_NativeDisplayManager_IsFoldable();
        OH_LOG_INFO(LOG_APP, "IsFoldable isFoldDevice =%{public}d.", isFoldDevice);
        napi_value isFold;
        napi_get_boolean(env, isFoldDevice, &isFold);
        return isFold;
    }
    
    EXTERN_C_START
    static napi_value Init(napi_env env, napi_value exports) {
        napi_property_descriptor desc[] = {
            {"checkIsFoldDevice", nullptr, IsFoldable, nullptr, nullptr, nullptr, napi_default, nullptr},
        };
        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
        return exports;
    }
    EXTERN_C_END
    

使用Display实现屏幕属性查询及状态监听

DisplayDisplayDisplay屏幕属性提供管理设备屏幕的一些基础能力,例如获取默认显示设备的相关信息、获取全部显示设备的信息,此外还能对显示设备的插拔行为进行监听。应用可以根据对应的屏幕信息、屏幕状态变化、屏幕折叠状态等适配不同的UI界面显示 。

屏幕属性的常见使用场景有以下几种:

  • 查询屏幕信息:包括屏幕的分辨率、物理像素密度、逻辑像素密度、刷新率、屏幕尺寸、屏幕旋转方向、屏幕旋转角度等,具体可见Display属性。
  • 监听屏幕状态变化,包括屏幕旋转变化,屏幕分辨率变化、屏幕刷新率变化等。
  • 查询当前设备是否为可折叠设备,同时支持折叠状态(展开/折叠)变化的监听。

获取Display对象

Display对象,即屏幕实例,提供屏幕相关属性及监听变化的接口。目前有以下几种不同获取Display的方式,开发者可根据具体场景需要选择使用。

  • 获取当前默认的Display对象:使用getDefaultDisplaySync()接口获取。
  • 获取当前所有Display对象:使用getAllDisplays()获取。
  • 根据屏幕Id获取对应的Display对象:使用getDisplayByIdSync()接口获取。

此处,以使用getDefaultDisplaySync()获取当前默认Display对象为例,示例如下:

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

let displayClass: display.Display | null = null;
displayClass = display.getDefaultDisplaySync();
// 确保获取到Display对象,即displayClass,再进行后续相关屏幕属性信息查询和事件/状态变化监听

获取屏幕相关属性

  1. 确保获取到Display对象之后(具体可见获取Display对象),可以通过相关属性查询屏幕的一些基础信息。
    import { display } from '@kit.ArkUI';
    
    let displayClass: display.Display | null = null;
    displayClass = display.getDefaultDisplaySync();
    
    // 获取屏幕Id
    console.info(`The screen Id is ${displayClass.id}.`);
    // 获取屏幕刷新率
    console.info(`The screen is ${displayClass.refreshRate}.`);
    // 获取屏幕宽度
    console.info(`The screen width is ${displayClass.width}.`);
    // 获取屏幕高度
    console.info(`The screen height is ${displayClass.height}.`);
    // ...
    
  2. 还可以通过getCutoutInfo()获取挖孔屏、刘海屏、瀑布屏等不可用的屏幕区域信息,以在UI布局时更好地规避该区域。也可以通过getAvailableArea()获取当前设备屏幕的可用区域。
    import { BusinessError } from '@kit.BasicServicesKit';
    
    displayClass.getCutoutInfo().then((cutoutInfo: display.CutoutInfo) => {
      console.info('Succeeded in getting cutoutInfo. Data: ' + JSON.stringify(cutoutInfo));
    }).catch((err: BusinessError) => {
      console.error(`Failed to obtain all the display objects. Code: ${err.code}, message: ${err.message}`);
    });
    
    displayClass.getAvailableArea().then((availableArea) => {
      console.info('Succeeded get the available area in this display. data: ' + JSON.stringify(availableArea));
    }).catch((err: BusinessError) => {
      console.error(`Failed to get the available area in this display. Code: ${err.code}, message: ${err.message}`);
    });
    
  3. 此外,还可以通过display.isCaptured()判断当前设备是否正在截屏、投屏或录屏。
    console.info(`The screen is captured or not : ${display.isCaptured()}`);
    

监听屏幕状态变化

  1. 可以通过display.on('add'|'remove'|'change')监听设备屏幕变化,支持监听屏幕设备的增加、移除和改变等,可以通过display.off('add'|'remove'|'change')关闭对应的监听。
    import { display } from '@kit.ArkUI';
    import { Callback } from '@kit.BasicServicesKit';
    
    let callback1: Callback = (data: number) => {
      console.info('Listening enabled. Data: ' + JSON.stringify(data));
    };
    // 此处以监听显示设备的增加为例
    display.on("add", callback1);
    
    // 如果通过on注册多个callback,同时关闭所有callback监听
    display.off("add");
    // 关闭单个callback监听
    display.off('add', callback1);
    
  2. 可以通过display.on('captureStatusChange')开启屏幕截屏、投屏或录屏状态变化的监听;可以通过display.off('captureStatusChange')关闭对应的监听。
    let callback2: Callback = (captureStatus: boolean) => {
        // captureStatus为true表示显示设备开始截屏、投屏或录屏,false表示结束截屏、投屏或录屏
      console.info('Listening capture status: ' + captureStatus);
    };
    // 开启屏幕截屏、投屏、录屏状态变化的监听
    display.on('captureStatusChange', callback2);
    
    display.off('captureStatusChange', callback2);
    

监听折叠设备状态变化

  1. 可以通过display.isFoldable()接口查询当前设备是不是折叠设备。
    import { display } from '@kit.ArkUI';
    
    let ret: boolean = false;
    ret = display.isFoldable();
    
  2. 若当前设备为折叠设备,可以通过display.on('foldStatusChange')开启折叠设备折叠状态变化的监听;可通过display.off('foldStatusChange')关闭对应的监听。
    import { Callback } from '@kit.BasicServicesKit';
    
    /**
     * 注册监听的callback参数要采用对象传递.
     * 若使用匿名函数注册,每次调用会创建一个新的底层对象,引起内存泄漏问题。
    */
    let callback: Callback = (data: display.FoldStatus) => {
      console.info('Listening enabled. Data: ' + JSON.stringify(data));
    };
    display.on('foldStatusChange', callback);
    
    // 如果通过on注册多个callback,同时关闭所有callback监听
    display.off('foldStatusChange');
    // 关闭单个callback监听
    display.off('foldStatusChange', callback);
    

你可能感兴趣的:(HarmonyOS开发,harmonyos,华为,鸿蒙,前端)