1# 监听组件事件 2 3 4NDK接口针对UI组件的事件,提供了监听函数的方式。首先,可使用[addNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodeeventreceiver)函数添加组件事件的监听器,该监听器会监听该组件上发生的所有事件,例如:点击事件、焦点事件。然后,可使用[registerNodeEvent](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodeevent)函数声明组件的哪些事件需要监听,NDK接口支持的事件范围通过[ArkUI_NodeEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeeventtype)枚举值定义。 5 6 7> **说明:** 8> - 事件注册需要声明[addNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodeeventreceiver)监听器注册和[registerNodeEvent](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodeevent)事件类型,监听器只能监听已声明的事件。 9> 10> - 需要关注事件的反注册逻辑,如在组件销毁前调用[removeNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#removenodeeventreceiver)移除事件监听器,[unregisterNodeEvent](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#unregisternodeevent)通知ArkUI框架已监听的事件不再需要监听。 11> 12> - [addNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodeeventreceiver)可以添加多个函数指针,每个函数指针都会在对应事件触发时触发,对应的[removeNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#removenodeeventreceiver)需要传递对应的函数指针用于移除监听。 13> 14> - [registerNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodeeventreceiver)是全局监听函数,不同于[addNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addnodeeventreceiver),[registerNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodeeventreceiver)能够监听所有Native组件的事件触发,但只能传递一个函数指针,多次调用使用最后一次的函数指针进行回调,释放时使用[ungisterNodeEventReceiver](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#unregisternodeeventreceiver)进行释放。 15 16 17以下示例基于[接入ArkTS页面](ndk-access-the-arkts-page.md)章节,补充相关事件监听。 18 19 20- 事件注册和事件解注册 21 22 通过addNodeEventReceiver对节点绑定事件处理函数,接着通过调用registerNodeEvent注册对应的事件。 23 24 > 说明: 25 > 26 > 事件监听函数的入参ArkUI_NodeEvent* event的生命周期只在函数回调周期内生效,不推荐对该指针进行缓存或者进行异步处理。 27 28 ``` 29 ArkUI_NativeNodeAPI_1 *nodeAPI = nullptr; 30 OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); 31 void NodeEventReceiver(ArkUI_NodeEvent *event) { 32 // 设置对应的事件类型触发时进行的操作,如NODE_ON_CLICK 33 }; 34 auto button = nodeAPI->createNode(ARKUI_NODE_BUTTON); 35 nodeAPI->addNodeEventReceiver(button, NodeEventReceiver); 36 nodeAPI->registerNodeEvent(button, NODE_ON_CLICK, 0, nullptr); 37 ``` 38 详细的事件类型请参考[ArkUI_NodeEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeeventtype)。 39 40 通过unregisterNodeEvent解注册对应的事件类型,再通过removeNodeEventReceiver卸载事件处理函数。 41 42 ``` 43 nodeAPI->unregisterNodeEvent(button, NODE_ON_CLICK); 44 nodeAPI->removeNodeEventReceiver(button, NodeEventReceiver); 45 ``` 46 47- 全局事件监听 48 49 使用registerNodeEventReceiver注册全局的事件处理函数,对事件进行统一的处理,结束后可使用ungisterNodeEventReceiver进行释放。 50 51 ``` 52 nodeAPI->registerNodeEventReceiver([](ArkUI_NodeEvent *event){ 53 auto *inputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); 54 auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); 55 case NODE_ON_CLICK: { 56 // 触发点击事件所进行的操作 57 } 58 default: { 59 break; 60 } 61 }) 62 nodeAPI->unregisterNodeEventReceiver(); 63 ``` 64 65**完整示例:** 66 671. 在ArkUINode基类对象中实现通用事件注册逻辑。 68 69 ```c 70 // ArkUINode.h 71 // 提供通用属性和事件的封装。 72 73 #ifndef MYAPPLICATION_ARKUINODE_H 74 #define MYAPPLICATION_ARKUINODE_H 75 76 #include "ArkUIBaseNode.h" 77 #include "NativeModule.h" 78 79 #include <arkui/native_node.h> 80 #include <arkui/native_type.h> 81 82 namespace NativeModule { 83 84 class ArkUINode : public ArkUIBaseNode { 85 public: 86 explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) { 87 nativeModule_ = NativeModuleInstance::GetInstance()->GetNativeNodeAPI(); 88 // 事件触发时需要通过函数获取对应的事件对象,这边通过设置节点自定义数据将封装类指针保持在组件上,方便后续事件分发。 89 nativeModule_->setUserData(handle_, this); 90 // 注册节点监听事件接受器。 91 nativeModule_->addNodeEventReceiver(handle_, ArkUINode::NodeEventReceiver); 92 } 93 94 ~ArkUINode() override { 95 if (onClick_) { 96 nativeModule_->unregisterNodeEvent(handle_, NODE_ON_CLICK); 97 } 98 if (onTouch_) { 99 nativeModule_->unregisterNodeEvent(handle_, NODE_TOUCH_EVENT); 100 } 101 if (onDisappear_) { 102 nativeModule_->unregisterNodeEvent(handle_, NODE_EVENT_ON_DISAPPEAR); 103 } 104 if (onAppear_) { 105 nativeModule_->unregisterNodeEvent(handle_, NODE_EVENT_ON_APPEAR); 106 } 107 nativeModule_->removeNodeEventReceiver(handle_, ArkUINode::NodeEventReceiver); 108 } 109 110 void SetWidth(float width) { 111 assert(handle_); 112 ArkUI_NumberValue value[] = {{.f32 = width}}; 113 ArkUI_AttributeItem item = {value, 1}; 114 nativeModule_->setAttribute(handle_, NODE_WIDTH, &item); 115 } 116 void SetPercentWidth(float percent) { 117 assert(handle_); 118 ArkUI_NumberValue value[] = {{.f32 = percent}}; 119 ArkUI_AttributeItem item = {value, 1}; 120 nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item); 121 } 122 void SetHeight(float height) { 123 assert(handle_); 124 ArkUI_NumberValue value[] = {{.f32 = height}}; 125 ArkUI_AttributeItem item = {value, 1}; 126 nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item); 127 } 128 void SetPercentHeight(float percent) { 129 assert(handle_); 130 ArkUI_NumberValue value[] = {{.f32 = percent}}; 131 ArkUI_AttributeItem item = {value, 1}; 132 nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item); 133 } 134 void SetBackgroundColor(uint32_t color) { 135 assert(handle_); 136 ArkUI_NumberValue value[] = {{.u32 = color}}; 137 ArkUI_AttributeItem item = {value, 1}; 138 nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item); 139 } 140 // 处理通用事件。 141 void RegisterOnClick(const std::function<void()> &onClick) { 142 assert(handle_); 143 onClick_ = onClick; 144 // 注册点击事件。 145 nativeModule_->registerNodeEvent(handle_, NODE_ON_CLICK, 0, nullptr); 146 } 147 148 void RegisterOnTouch(const std::function<void(int32_t type, float x, float y)> &onTouch) { 149 assert(handle_); 150 onTouch_ = onTouch; 151 // 注册触碰事件。 152 nativeModule_->registerNodeEvent(handle_, NODE_TOUCH_EVENT, 0, nullptr); 153 } 154 155 void RegisterOnDisappear(const std::function<void()> &onDisappear) { 156 assert(handle_); 157 onDisappear_ = onDisappear; 158 // 注册卸载事件。 159 nativeModule_->registerNodeEvent(handle_, NODE_EVENT_ON_DISAPPEAR, 0, nullptr); 160 } 161 162 void RegisterOnAppear(const std::function<void()> &onAppear) { 163 assert(handle_); 164 onAppear_ = onAppear; 165 // 注册挂载事件。 166 nativeModule_->registerNodeEvent(handle_, NODE_EVENT_ON_APPEAR, 0, nullptr); 167 } 168 169 protected: 170 // 事件监听器函数指针。 171 static void NodeEventReceiver(ArkUI_NodeEvent *event) { 172 // 获取事件发生的UI组件对象。 173 auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); 174 // 获取保持在UI组件对象中的自定义数据,返回封装类指针。 175 auto *node = reinterpret_cast<ArkUINode *>( 176 NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->getUserData(nodeHandle)); 177 // 基于封装类实例对象处理事件。 178 node->ProcessNodeEvent(event); 179 } 180 void ProcessNodeEvent(ArkUI_NodeEvent *event) { 181 auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); 182 switch (eventType) { 183 case NODE_ON_CLICK: { 184 if (onClick_) { 185 onClick_(); 186 } 187 break; 188 } 189 case NODE_TOUCH_EVENT: { 190 if (onTouch_) { 191 auto *uiInputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); 192 float x = OH_ArkUI_PointerEvent_GetX(uiInputEvent); 193 float y = OH_ArkUI_PointerEvent_GetY(uiInputEvent); 194 auto type = OH_ArkUI_UIInputEvent_GetAction(uiInputEvent); 195 onTouch_(type, x, y); 196 } 197 } 198 case NODE_EVENT_ON_DISAPPEAR: { 199 if (onDisappear_) { 200 onDisappear_(); 201 } 202 break; 203 } 204 case NODE_EVENT_ON_APPEAR: { 205 if (onAppear_) { 206 onAppear_(); 207 } 208 break; 209 } 210 default: { 211 // 组件特有事件交给子类处理 212 OnNodeEvent(event); 213 } 214 } 215 } 216 217 virtual void OnNodeEvent(ArkUI_NodeEvent *event) {} 218 219 void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 220 nativeModule_->addChild(handle_, child->GetHandle()); 221 } 222 223 void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override { 224 nativeModule_->removeChild(handle_, child->GetHandle()); 225 } 226 227 void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override { 228 nativeModule_->insertChildAt(handle_, child->GetHandle(), index); 229 } 230 231 private: 232 std::function<void()> onClick_; 233 std::function<void()> onDisappear_; 234 std::function<void()> onAppear_; 235 std::function<void(int32_t type, float x, float y)> onTouch_; 236 }; 237 } // namespace NativeModule 238 239 #endif // MYAPPLICATION_ARKUINODE_H 240 241 ``` 242 2432. 在ArkUIListNode对象中实现列表事件注册逻辑。 244 ```c 245 // ArkUIListNode.h 246 // 列表封装类对象 247 248 #ifndef MYAPPLICATION_ARKUILISTNODE_H 249 #define MYAPPLICATION_ARKUILISTNODE_H 250 251 #include "ArkUINode.h" 252 #include <hilog/log.h> 253 254 namespace NativeModule { 255 class ArkUIListNode : public ArkUINode { 256 public: 257 ArkUIListNode() 258 : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} 259 260 ~ArkUIListNode() override { nativeModule_->unregisterNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX); } 261 262 void SetScrollBarState(bool isShow) { 263 assert(handle_); 264 ArkUI_ScrollBarDisplayMode displayMode = 265 isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF; 266 ArkUI_NumberValue value[] = {{.i32 = displayMode}}; 267 ArkUI_AttributeItem item = {value, 1}; 268 nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item); 269 } 270 271 // 注册列表相关事件。 272 void RegisterOnScrollIndex(const std::function<void(int32_t index)> &onScrollIndex) { 273 assert(handle_); 274 onScrollIndex_ = onScrollIndex; 275 nativeModule_->registerNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX, 0, nullptr); 276 } 277 278 protected: 279 // 处理List相关事件。 280 void OnNodeEvent(ArkUI_NodeEvent *event) override { 281 auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); 282 switch (eventType) { 283 case NODE_LIST_ON_SCROLL_INDEX: { 284 auto index = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event)->data[0]; 285 if (onScrollIndex_) { 286 onScrollIndex_(index.i32); 287 } 288 } 289 default: { 290 } 291 } 292 } 293 294 private: 295 std::function<void(int32_t index)> onScrollIndex_; 296 }; 297 } // namespace NativeModule 298 299 #endif // MYAPPLICATION_ARKUILISTNODE_H 300 ``` 301 3023. 添加相关事件。 303 ```c 304 // TextListExample.h 305 // 文本列表示例。 306 307 #ifndef MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H 308 #define MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H 309 310 #include "ArkUIBaseNode.h" 311 #include "ArkUIListItemNode.h" 312 #include "ArkUIListNode.h" 313 #include "ArkUITextNode.h" 314 #include <hilog/log.h> 315 316 namespace NativeModule { 317 318 std::shared_ptr<ArkUIBaseNode> CreateTextListExample() { 319 // 创建组件并挂载 320 // 1:创建List组件。 321 auto list = std::make_shared<ArkUIListNode>(); 322 list->SetPercentWidth(1); 323 list->SetPercentHeight(1); 324 // 2:创建ListItem子组件并挂载到List上。 325 for (int32_t i = 0; i < 30; ++i) { 326 auto listItem = std::make_shared<ArkUIListItemNode>(); 327 auto textNode = std::make_shared<ArkUITextNode>(); 328 textNode->SetTextContent(std::to_string(i)); 329 textNode->SetFontSize(16); 330 textNode->SetPercentWidth(1); 331 textNode->SetHeight(100); 332 textNode->SetBackgroundColor(0xFFfffacd); 333 textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); 334 listItem->AddChild(textNode); 335 // 列表项注册点击事件。 336 listItem->RegisterOnClick([i]() { OH_LOG_INFO(LOG_APP, "on %{public}d list item click", i); }); 337 list->AddChild(listItem); 338 } 339 // 3:注册List相关监听事件. 340 list->RegisterOnScrollIndex([](int32_t index) { OH_LOG_INFO(LOG_APP, "on list scroll index: %{public}d", index); }); 341 // 4: 注册挂载事件。 342 list->RegisterOnAppear([]() { OH_LOG_INFO(LOG_APP, "on list mount to tree"); }); 343 // 4: 注册卸载事件。 344 list->RegisterOnDisappear([]() { OH_LOG_INFO(LOG_APP, "on list unmount from tree"); }); 345 return list; 346 } 347 } // namespace NativeModule 348 349 #endif // MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H 350 351 ``` 352