HarmonyOS 鸿蒙Next窗口分合场景适配指导

HarmonyOS 鸿蒙Next窗口分合场景适配指导

1、场景介绍

对于存在Tab页的应用,如华为浏览器,窗口的拖拽分合是关键体验。

图1

2、功能介绍

2.1 隐藏系统标题栏

  • 系统标题栏无法实现Tab页签功能,首先通过setWindowDecorVisible()接口隐藏系统标题栏,应用实现自定义标题栏。

2.2 禁用系统标题栏默认移动窗口的能力

  • 隐藏系统标题栏后,标题栏变为透明,但是标题栏默认移动窗口的能力仍然存在;对于存在Tab页的应用,如华为浏览器,为了实现自定义Tab页签的拖动效果,需通过setWindowTitleMoveEnabled接口实现禁止/使能窗口标题栏默认移动窗口和双击最大化的功能。

2.3 窗口分合场景下,实现输入事件转移

  • 窗口拽离场景下,需要通过事件转移接口shiftAppWindowPointerEventshiftAppWindowTouchEvent,将输入事件从源窗口转移至目标窗口。
  • 窗口缝合场景下,仍然需要上述接口实现输入事件从源窗口转移至目标窗口。

2.4 使用startMoving()实现窗口拖动

在同应用内窗口分合后,且鼠标保持按下状态直接移动新窗口,如果此时鼠标快速移动,窗口移动时鼠标可能会在窗口外。可以使用startMoving(offsetX: number, offsetY: number)接口指定窗口移动时鼠标在窗口内的位置,先移动窗口到鼠标位置,再开始移动窗口。

2.5 通过NDK接口实现输入事件监听

开发者可以NativeWindowEventFilter模块提供的能力去监听和拦截输入事件,让输入事件不往应用内部组件分发。当使用startMoving()实现窗口拖动时,输入事件将被系统接管,应用无法通过应用内部组件监听输入事件,因此系统提供了以下NDK接口实现对输入事件的监听和拦截。

名称 typedef关键字 描述
typedef bool (*OH_NativeWindowManager_MouseEventFilter)(Input_MouseEvent* mouseEvent) OH_NativeWindowManager_MouseEventFilter 定义多模鼠标事件的过滤函数。
WindowManager_ErrorCode OH_NativeWindowManager_RegisterMouseEventFilter(int32_t windowId,OH_NativeWindowManager_MouseEventFilter mouseEventFilter) - 注册鼠标事件的过滤函数。
WindowManager_ErrorCode OH_NativeWindowManager_UnregisterMouseEventFilter(int32_t windowId) - 取消注册窗口的鼠标事件过滤函数。
typedef bool (*OH_NativeWindowManager_TouchEventFilter)(Input_TouchEvent* touchEvent) OH_NativeWindowManager_TouchEventFilter 定义多模触摸事件的过滤函数。
WindowManager_ErrorCode OH_NativeWindowManager_RegisterTouchEventFilter(int32_t windowId,OH_NativeWindowManager_TouchEventFilter touchEventFilter) - 注册触摸事件的过滤函数。
WindowManager_ErrorCode OH_NativeWindowManager_UnregisterTouchEventFilter(int32_t windowId) - 取消注册窗口的触摸事件过滤函数

2.6 使用stopMoving()实现终止窗口拖动

在窗口拖动过程中,应用可以通过stopMoving()终止窗口拖动,如在ESC按键回调中调用stopMoving(),即可实现ESC按键终止窗口拖动的功能。

3、适配指导

  • 使用NativeWindowEventFilter模块提供的能力去监听和拦截输入事件。
  • CMake脚本中链接动态库
target_link_libraries(entry PUBLIC libnative_window_manager.so libohinput.so)
  • 添加头文件
#include "window_manager/oh_window_comm.h"
#include "window_manager/oh_window_event_filter.h"
#include "multimodalinput/oh_input_manager.h"
  • 接口使用说明

    • 应用窗口创建后,通过窗口ID去绑定窗口的鼠标事件/触摸事件过滤函数。
    • 应用窗口需要收到鼠标事件/触摸事件时,窗口才可触发鼠标事件/触摸事件的拦截。
    • 当回调函数返回值为true表示拦截,为false不拦截。
    • 同一个窗口ID注册的回调函数只允许一个,最后注册的回调函数会覆盖之前注册过的回调函数。
  • 示例代码

#include "napi/native_api.h" 
#include "window_manager/oh_window_comm.h" 
#include "window_manager/oh_window_event_filter.h" 
#include "multimodalinput/oh_input_manager.h" 
//设置鼠标事件过滤函数 
static bool filterMouseEvent(Input_MouseEvent* mouseEvent) { 
    int32_t action = OH_Input_GetMouseEventAction(mouseEvent); 
    int32_t displayX = OH_Input_GetMouseEventDisplayX(mouseEvent); 
    int32_t displayY = OH_Input_GetMouseEventDisplayY(mouseEvent); 
    int32_t mouseButton = OH_Input_GetMouseEventButton(mouseEvent); 
    int64_t actionTime = OH_Input_GetMouseEventActionTime(mouseEvent); 
    // 过滤鼠标右键按下 
    return (action == Input_MouseEventAction::MOUSE_ACTION_BUTTON_DOWN 
        && mouseButton == Input_MouseEventButton::MOUSE_BUTTON_RIGHT); 
}
//设置触摸事件过滤函数 
static bool filterTouchEvent(Input_TouchEvent* touchEvent) { 
    int32_t action = OH_Input_GetTouchEventAction(touchEvent); 
    int32_t id = OH_Input_GetTouchEventFingerId(touchEvent); 
    int32_t displayX = OH_Input_GetTouchEventDisplayX(touchEvent); 
    int32_t displayY = OH_Input_GetTouchEventDisplayY(touchEvent); 
    int64_t actionTime = OH_Input_GetTouchEventActionTime(touchEvent); 
    //过滤触摸移动事件 
    return action == Input_TouchEventAction::TOUCH_ACTION_MOVE; 
}
static napi_value registerMouseFilter(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value args[1] = {nullptr}; 
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 
    int32_t windowId; 
    napi_get_value_int32(env, args[0], &windowId); 
    auto result = OH_NativeWindowManager_RegisterMouseEventFilter(windowId, filterMouseEvent); 
    napi_value errCode; 
    napi_create_int32(env, result, &errCode); 
    return errCode; 
}
static napi_value clearMouseFilter(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value args[1] = {nullptr}; 
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 
    int32_t windowId; 
    napi_get_value_int32(env, args[0], &windowId); 
    auto result = OH_NativeWindowManager_UnregisterMouseEventFilter(windowId); 
    napi_value errCode; 
    napi_create_int32(env, result, &errCode); 
    return errCode; 
}
static napi_value registerTouchFilter(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value args[1] = {nullptr}; 
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 
    int32_t windowId; 
    napi_get_value_int32(env, args[0], &windowId); 
    auto result = OH_NativeWindowManager_RegisterTouchEventFilter(windowId, filterTouchEvent); 
    napi_value errCode; 
    napi_create_int32(env, result, &errCode); 
    return errCode; 
}
static napi_value clearTouchFilter(napi_env env, napi_callback_info info) { 
    size_t argc = 1; 
    napi_value args[1] = {nullptr}; 
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 
    int32_t windowId; 
    napi_get_value_int32(env, args[0], &windowId); 
    auto result = OH_NativeWindowManager_UnregisterTouchEventFilter(windowId); 
    napi_value errCode; 
    napi_create_int32(env, result, &errCode); 
    return errCode; 
}
EXTERN_C_START 
static napi_value Init(napi_env env, napi_value exports) { 
    napi_property_descriptor desc[] = { 
        {"registerMouseFilter", nullptr, registerMouseFilter, nullptr, nullptr, nullptr, napi_default, nullptr}, 
        {"clearMouseFilter", nullptr, clearMouseFilter, nullptr, nullptr, nullptr, napi_default, nullptr}, 
        {"registerTouchFilter", nullptr, registerTouchFilter, nullptr, nullptr, nullptr, napi_default, nullptr}, 
        {"clearTouchFilter", nullptr, clearTouchFilter, nullptr, nullptr, nullptr, napi_default, nullptr}, 
    }; 
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 
    return exports; 
} 
EXTERN_C_END

更多关于HarmonyOS 鸿蒙Next窗口分合场景适配指导的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

鸿蒙Next窗口分合场景适配主要涉及以下要点:

  1. 使用WindowStage组件管理窗口生命周期
  2. 通过displayArea属性处理分屏场景布局
  3. 实现onWindowStageCreate/onWindowStageDestroy回调
  4. 使用WindowType枚举定义窗口类型
  5. 调用setWindowAttributes设置窗口属性

适配分合场景时需重点关注:

  • 窗口状态变化时的UI重绘
  • 分屏比例变化时的布局调整
  • 多窗口间数据同步机制
  • 窗口焦点管理

窗口分合事件通过WindowStageEventType监听,包括:

  • DISPLAY_MOVE
  • DISPLAY_SIZE_CHANGED
  • WINDOW_FOCUS

更多关于HarmonyOS 鸿蒙Next窗口分合场景适配指导的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中实现Tab页应用的窗口分合功能,需要重点关注以下几个关键点:

  1. 自定义标题栏处理:
  • 使用setWindowDecorVisible(false)隐藏系统标题栏
  • 通过setWindowTitleMoveEnabled(false)禁用系统标题栏的默认移动功能
  1. 输入事件转移:
  • 分合窗口时使用shiftAppWindowPointerEvent/shiftAppWindowTouchEvent转移输入事件
  • 确保事件在源窗口和目标窗口间正确传递
  1. 窗口拖动控制:
  • startMoving(offsetX, offsetY)用于精确控制窗口拖动起始位置
  • stopMoving()可随时终止拖动过程
  1. 事件监听:
  • 通过NDK接口注册鼠标/触摸事件过滤器
  • 使用OH_NativeWindowManager_Register*EventFilter系列API
  • 在CMake中链接libnative_window_manager.solibohinput.so

示例代码展示了如何实现事件过滤,包括:

  • 过滤特定鼠标事件(如右键点击)
  • 拦截触摸移动事件
  • 注册/注销事件过滤器

这种实现方式可以确保Tab页应用在窗口分合时保持流畅的用户体验,同时提供完全自定义的交互控制能力。

回到顶部