HarmonyOS 鸿蒙Next窗口分合场景适配指导
HarmonyOS 鸿蒙Next窗口分合场景适配指导
1、场景介绍
对于存在Tab页的应用,如华为浏览器,窗口的拖拽分合是关键体验。
图1
2、功能介绍
2.1 隐藏系统标题栏
- 系统标题栏无法实现Tab页签功能,首先通过
setWindowDecorVisible()
接口隐藏系统标题栏,应用实现自定义标题栏。
2.2 禁用系统标题栏默认移动窗口的能力
- 隐藏系统标题栏后,标题栏变为透明,但是标题栏默认移动窗口的能力仍然存在;对于存在Tab页的应用,如华为浏览器,为了实现自定义Tab页签的拖动效果,需通过
setWindowTitleMoveEnabled
接口实现禁止/使能窗口标题栏默认移动窗口和双击最大化的功能。
2.3 窗口分合场景下,实现输入事件转移
- 窗口拽离场景下,需要通过事件转移接口
shiftAppWindowPointerEvent
和shiftAppWindowTouchEvent
,将输入事件从源窗口转移至目标窗口。 - 窗口缝合场景下,仍然需要上述接口实现输入事件从源窗口转移至目标窗口。
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 回复
在HarmonyOS Next中实现Tab页应用的窗口分合功能,需要重点关注以下几个关键点:
- 自定义标题栏处理:
- 使用
setWindowDecorVisible(false)
隐藏系统标题栏 - 通过
setWindowTitleMoveEnabled(false)
禁用系统标题栏的默认移动功能
- 输入事件转移:
- 分合窗口时使用
shiftAppWindowPointerEvent
/shiftAppWindowTouchEvent
转移输入事件 - 确保事件在源窗口和目标窗口间正确传递
- 窗口拖动控制:
startMoving(offsetX, offsetY)
用于精确控制窗口拖动起始位置stopMoving()
可随时终止拖动过程
- 事件监听:
- 通过NDK接口注册鼠标/触摸事件过滤器
- 使用
OH_NativeWindowManager_Register*EventFilter
系列API - 在CMake中链接
libnative_window_manager.so
和libohinput.so
示例代码展示了如何实现事件过滤,包括:
- 过滤特定鼠标事件(如右键点击)
- 拦截触摸移动事件
- 注册/注销事件过滤器
这种实现方式可以确保Tab页应用在窗口分合时保持流畅的用户体验,同时提供完全自定义的交互控制能力。