鸿蒙5.0开辟进阶:UI开辟常用组件-自界说渲染 (XComponent) ...

打印 上一主题 下一主题

主题 957|帖子 957|积分 2871

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
概述

XComponent组件作为一种渲染组件,通常用于满意开辟者较为复杂的自界说渲染需求,比方相机预览流的显示和游戏画面的渲染。其可通过指定其type字段来实现不同的功能,主要有两个“surface”和“component”字段可供选择。对于“surface”类型,开辟者可将相关数据传入XComponent单独拥有的“NativeWindow”来渲染画面。对于“component”类型,通常用于在XComponent内部执行非UI逻辑以实现动态加载显示内容的目标。
XComponent设置为“surface“类型时,其可以和其他组件一起进行布局和渲染,同时XComponent又拥有单独的“NativeWindow“,可以为开辟者在native侧提供NativeWindow用来创建EGL/OpenGLES情况,进而使用尺度的OpenGL ES开辟。除此之外,媒体相关应用(视频、相机等)也可以将相关数据写入XComponent所提供的NativeWindow,从而呈现相应画面。
目前XComponent组件在type设置为“surface”时主要有两个应用场景。一个是Native XComponent场景,是在native层获取Native XComponent实例,在native侧注册XComponent的生命周期回调,以及触摸、鼠标、按键等事件回调。另一个是ArkTS XComponent场景,是在ArkTS侧获取SurfaceId,生命周期回调、触摸、鼠标、按键等事件回调等均在ArkTS侧触发。
surface类型

Native XComponent场景

在XComponent组件构造函数的libraryname中界说需要加载的动态库,而后应用就可以在Native层获取Native XComponent实例,其是XComponent组件提供在Native层的实例,可作为ArkTS层和Native层XComponent绑定的桥梁。XComponent所提供的NDK接口都依靠于该实例。接口能力包罗获取NativeWindow实例、获取XComponent的布局/事件信息、注册XComponent的生命周期回调、注册XComponent的触摸、鼠标、按键等事件回调。针对Native XComponent,主要的开辟场景如下:


  • 使用Native XComponent提供的接口注册XComponent的生命周期和事件回调。
  • 在这些回调中进行初始化情况、获取当前状态、相应各类事件的开辟。
  • 使用NativeWindow和EGL接口开辟自界说绘制内容以及申请和提交Buffer到图形队列。
接口说明
接口名形貌OH_NativeXComponent_GetXComponentId(OH_NativeXComponent* component, char* id, uint64_t* size)获取XComponent的id。OH_NativeXComponent_GetXComponentSize(OH_NativeXComponent* component, const void* window, uint64_t* width, uint64_t* height)获取XComponent持有的surface的大小。OH_NativeXComponent_GetXComponentOffset(OH_NativeXComponent* component, const void* window, double* x, double* y)获取XComponent持有的surface相对其父组件左顶点的偏移量。OH_NativeXComponent_GetTouchEvent(OH_NativeXComponent* component, const void* window, OH_NativeXComponent_TouchEvent* touchEvent)获取由XComponent触发的触摸事件。touchEvent内的详细属性值可参考OH_NativeXComponent_TouchEvent。OH_NativeXComponent_GetTouchPointToolType(OH_NativeXComponent* component, uint32_t pointIndex, OH_NativeXComponent_TouchPointToolType* toolType)获取XComponent触摸点的工具类型。OH_NativeXComponent_GetTouchPointTiltX(OH_NativeXComponent* component, uint32_t pointIndex, float* tiltX)获取XComponent触摸点处相对X轴的倾斜角度。OH_NativeXComponent_GetTouchPointTiltY(OH_NativeXComponent* component, uint32_t pointIndex, float* tiltY)获取XComponent触摸点处相对Y轴的倾斜角度。OH_NativeXComponent_GetMouseEvent(OH_NativeXComponent* component, const void* window, OH_NativeXComponent_MouseEvent* mouseEvent)获取由XComponent触发的鼠标事件。OH_NativeXComponent_RegisterCallback(OH_NativeXComponent* component, OH_NativeXComponent_Callback* callback)为此OH_NativeXComponent实例注册生命周期和触摸事件回调。OH_NativeXComponent_RegisterMouseEventCallback(OH_NativeXComponent* component, OH_NativeXComponent_MouseEvent_Callback* callback)为此OH_NativeXComponent实例注册鼠标事件回调。OH_NativeXComponent_RegisterFocusEventCallback(OH_NativeXComponent* component, void (*callback)(OH_NativeXComponent* component, void* window))为此OH_NativeXComponent实例注册获得核心事件回调。OH_NativeXComponent_RegisterKeyEventCallback(OH_NativeXComponent* component, void (*callback)(OH_NativeXComponent* component, void* window))为此OH_NativeXComponent实例注册按键事件回调。OH_NativeXComponent_RegisterBlurEventCallback(OH_NativeXComponent* component, void (*callback)(OH_NativeXComponent* component, void* window))为此OH_NativeXComponent实例注册失去核心事件回调。OH_NativeXComponent_GetKeyEvent(OH_NativeXComponent* component, OH_NativeXComponent_KeyEvent** keyEvent)获取由XComponent触发的按键事件。OH_NativeXComponent_GetKeyEventAction(OH_NativeXComponent_KeyEvent* keyEvent, OH_NativeXComponent_KeyAction* action)获取按键事件的动作。OH_NativeXComponent_GetKeyEventCode(OH_NativeXComponent_KeyEvent* keyEvent, OH_NativeXComponent_KeyCode* code)获取按键事件的键码值。OH_NativeXComponent_GetKeyEventSourceType(OH_NativeXComponent_KeyEvent* keyEvent, OH_NativeXComponent_EventSourceType* sourceType)获取按键事件的输入源类型。OH_NativeXComponent_GetKeyEventDeviceId(OH_NativeXComponent_KeyEvent* keyEvent, int64_t* deviceId)获取按键事件的装备ID。OH_NativeXComponent_GetKeyEventTimestamp(OH_NativeXComponent_KeyEvent* keyEvent, int64_t* timestamp)获取按键事件的时间戳。 说明
   上述接口不支持跨线程访问。
  开辟步骤
以下步骤形貌了如何使用XComponent组件调用Node-API接口来创建EGL/GLES情况,实现在主页面绘制图形,并可以改变图形的颜色。
  ArkTS XComponent场景

与Native XComponent不同,ArkTS XComponent不再需要libraryname参数。通过在ArkTS侧获取SurfaceId,布局信息、生命周期回调、触摸、鼠标、按键等事件回调等均在ArkTS侧触发,按需传递到Native侧进行处理。主要开辟场景如下:


  • 基于ArkTS侧获取的SurfaceId,在Native侧调用OH_NativeWindow_CreateNativeWindowFromSurfaceId接口创建出NativeWindow实例。
  • 使用NativeWindow和EGL接口开辟自界说绘制内容以及申请和提交Buffer到图形队列。
  • ArkTS侧获取生命周期、事件等信息传递到Native侧处理。
接口说明
ArkTS侧的XComponentController
接口名形貌getXComponentSurfaceId(): string获取XComponent对应Surface的ID。onSurfaceCreated(surfaceId: string): void当XComponent持有的Surface创建后进行该回调。onSurfaceChanged(surfaceId: string, rect: SurfaceRect): void当XComponent持有的Surface大小改变后(包罗首次创建时的大小改变)进行该回调。onSurfaceDestroyed(surfaceId: string): void当XComponent持有的Surface烧毁后进行该回调。 Native侧
接口名形貌int32_t OH_NativeWindow_CreateNativeWindowFromSurfaceId (uint64_t surfaceId, OHNativeWindow **window )通过surfaceId创建对应的OHNativeWindow。void OH_NativeWindow_DestroyNativeWindow (OHNativeWindow* window)将OHNativeWindow对象的引用计数减1,当引用计数为0的时候,该OHNativeWindow对象会被析构掉。 开辟步骤
以下步骤形貌了如何使用XComponent组件在ArkTS侧传入Surfaceid,在native侧创建NativeWindow实例,然后创建EGL/GLES情况,实现在主页面绘制图形,并可以改变图形的颜色。

  • 在界面中界说XComponent。
    1. @Entry
    2. @Component
    3. struct Index {
    4.     @State message: string = 'Hello World'
    5.     xComponentContext: object | undefined = undefined;
    6.     xComponentAttrs: XComponentAttrs = {
    7.         id: 'xcomponentId',
    8.         type: XComponentType.SURFACE,
    9.         libraryname: 'nativerender'
    10.     }
    11.     build() {
    12.     Row() {
    13.         // ...
    14.         // 在xxx.ets 中定义 XComponent
    15.         XComponent(this.xComponentAttrs)
    16.             .focusable(true) // 可响应键盘事件
    17.             .onLoad((xComponentContext) => {
    18.             this.xComponentContext = xComponentContext;
    19.             })
    20.             .onDestroy(() => {
    21.             console.log("onDestroy");
    22.             })
    23.         // ...
    24.         }
    25.         .height('100%')
    26.     }
    27. }
    28.    
    29. interface XComponentAttrs {
    30. id: string;
    31.     type: number;
    32.     libraryname: string;
    33. }
    复制代码
  • Node-API模块注册。
    1. // 在napi_init.cpp文件中,Init方法注册接口函数,从而将封装的C++方法传递出来,供ArkTS侧调用
    2. EXTERN_C_START
    3. static napi_value Init(napi_env env, napi_value exports)
    4. {
    5.     // ...
    6.     // 向ArkTS侧暴露接口getContext()
    7.     napi_property_descriptor desc[] = {
    8.         { "getContext", nullptr, PluginManager::GetContext, nullptr, nullptr, nullptr, napi_default, nullptr }
    9.     };
    10.     if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
    11.         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed");
    12.         return nullptr;
    13.     }
    14.     // 方法内检查环境变量是否包含XComponent组件实例,若实例存在注册绘制相关接口
    15.     PluginManager::GetInstance()->Export(env, exports);
    16.     return exports;
    17. }
    18. EXTERN_C_END
    19. // 编写接口的描述信息,根据实际需要可以修改对应参数
    20. static napi_module nativerenderModule = {
    21.     .nm_version = 1,
    22.     .nm_flags = 0,
    23.     .nm_filename = nullptr,
    24.     // 入口函数
    25.     .nm_register_func = Init,// 指定加载对应模块时的回调函数
    26.     // 模块名称
    27.     .nm_modname = "nativerender", // 指定模块名称,对于XComponent相关开发,这个名称必须和ArkTS侧XComponent中libraryname的值保持一致
    28.     .nm_priv = ((void *)0),
    29.     .reserved = { 0 }
    30. };
    31. // __attribute__((constructor))修饰的方法由系统自动调用,使用Node-API接口napi_module_register()传入模块描述信息进行模块注册
    32. extern "C" __attribute__((constructor)) void RegisterModule(void)
    33. {
    34.     napi_module_register(&nativerenderModule);
    35. }
    36. // 使用Node-API中的napi_define_properties方法,向ArkTS侧暴露drawPattern()方法,在ArkTS侧调用drawPattern()来绘制内容。
    37. void PluginRender::Export(napi_env env, napi_value exports)
    38. {
    39.     // ...
    40.     // 将接口函数注册为ArkTS侧接口drawPattern
    41.     napi_property_descriptor desc[] = {
    42.         { "drawPattern", nullptr, PluginRender::NapiDrawPattern, nullptr, nullptr, nullptr, napi_default, nullptr }
    43.     };
    44.     if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
    45.         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: napi_define_properties failed");
    46.     }
    47. }
    复制代码
  • 上述注册的六个函数在native侧详细实现。
    1. // 定义一个函数OnSurfaceCreatedCB(),封装初始化环境与绘制背景
    2. void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
    3. {
    4. // ...
    5. // 获取XComponent的id,即ArkTS侧XComponent组件构造中的id参数
    6. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
    7. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    8. if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NativeXComponent_RESULT_SUCCESS) {
    9. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
    10. "OnSurfaceCreatedCB: Unable to get XComponent id");
    11. return;
    12. }
    13. // 初始化环境与绘制背景
    14. std::string id(idStr);
    15. auto render = PluginRender::GetInstance(id);
    16. uint64_t width;
    17. uint64_t height;
    18. // 获取XComponent拥有的surface的大小
    19. int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
    20. if ((xSize == OH_NativeXComponent_RESULT_SUCCESS) && (render != nullptr)) {
    21. if (render->eglCore_->EglContextInit(window, width, height)) {
    22. render->eglCore_->Background();
    23. }
    24. }
    25. }
    26. // 定义一个函数OnSurfaceChangedCB()
    27. void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window)
    28. {
    29. // ...
    30. // 获取XComponent的id
    31. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
    32. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    33. if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NativeXComponent_RESULT_SUCCESS) {
    34. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
    35. "OnSurfaceChangedCB: Unable to get XComponent id");
    36. return;
    37. }
    38. std::string id(idStr);
    39. auto render = PluginRender::GetInstance(id);
    40. if (render != nullptr) {
    41. // 封装OnSurfaceChanged方法
    42. render->OnSurfaceChanged(component, window);
    43. }
    44. }
    45. // 定义一个函数OnSurfaceDestroyedCB(),将PluginRender类内释放资源的方法Release()封装在其中
    46. void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window)
    47. {
    48. // ...
    49. // 获取XComponent的id
    50. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
    51. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    52. if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NativeXComponent_RESULT_SUCCESS) {
    53. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
    54. "OnSurfaceDestroyedCB: Unable to get XComponent id");
    55. return;
    56. }
    57. std::string id(idStr);
    58. // 释放资源
    59. PluginRender::Release(id);
    60. }
    61. // 定义一个函数DispatchTouchEventCB(),响应触摸事件时触发该回调
    62. void DispatchTouchEventCB(OH_NativeXComponent *component, void *window)
    63. {
    64. // ...
    65. // 获取XComponent的id
    66. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
    67. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    68. if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NativeXComponent_RESULT_SUCCESS) {
    69. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback",
    70. "DispatchTouchEventCB: Unable to get XComponent id");
    71. return;
    72. }
    73. std::string id(idStr);
    74. PluginRender *render = PluginRender::GetInstance(id);
    75. if (render != nullptr) {
    76. // 封装OnTouchEvent方法
    77. render->OnTouchEvent(component, window);
    78. }
    79. }
    80. // 定义一个函数DispatchMouseEventCB(),响应鼠标事件时触发该回调
    81. void DispatchMouseEventCB(OH_NativeXComponent *component, void *window) {
    82. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchMouseEventCB");
    83. int32_t ret;
    84. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
    85. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    86. ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
    87. if (ret != OH_NativeXComponent_RESULT_SUCCESS) {
    88. return;
    89. }
    90. std::string id(idStr);
    91. auto render = PluginRender::GetInstance(id);
    92. if (render) {
    93. // 封装OnMouseEvent方法
    94. render->OnMouseEvent(component, window);
    95. }
    96. }
    97. // 定义一个函数DispatchHoverEventCB(),响应鼠标悬停事件时触发该回调
    98. void DispatchHoverEventCB(OH_NativeXComponent *component, bool isHover) {
    99. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchHoverEventCB");
    100. int32_t ret;
    101. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
    102. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    103. ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
    104. if (ret != OH_NativeXComponent_RESULT_SUCCESS) {
    105. return;
    106. }
    107. std::string id(idStr);
    108. auto render = PluginRender::GetInstance(id);
    109. if (render) {
    110. // 封装OnHoverEvent方法
    111. render->OnHoverEvent(component, isHover);
    112. }
    113. }
    114. // 定义一个函数OnFocusEventCB(),响应获焦事件时触发该回调
    115. void OnFocusEventCB(OH_NativeXComponent *component, void *window) {
    116. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnFocusEventCB");
    117. int32_t ret;
    118. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
    119. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    120. ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
    121. if (ret != OH_NativeXComponent_RESULT_SUCCESS) {
    122. return;
    123. }
    124. std::string id(idStr);
    125. auto render = PluginRender::GetInstance(id);
    126. if (render) {
    127. // 封装OnFocusEvent方法
    128. render->OnFocusEvent(component, window);
    129. }
    130. }
    131. // 定义一个函数OnBlurEventCB(),响应失去焦点事件时触发该回调
    132. void OnBlurEventCB(OH_NativeXComponent *component, void *window) {
    133. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnBlurEventCB");
    134. int32_t ret;
    135. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
    136. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    137. ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
    138. if (ret != OH_NativeXComponent_RESULT_SUCCESS) {
    139. return;
    140. }
    141. std::string id(idStr);
    142. auto render = PluginRender::GetInstance(id);
    143. if (render) {
    144. // 封装OnBlurEvent方法
    145. render->OnBlurEvent(component, window);
    146. }
    147. }
    148. // 定义一个函数OnKeyEventCB(),响应按键事件时触发该回调
    149. void OnKeyEventCB(OH_NativeXComponent *component, void *window) {
    150. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnKeyEventCB");
    151. int32_t ret;
    152. char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
    153. uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    154. ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
    155. if (ret != OH_NativeXComponent_RESULT_SUCCESS) {
    156. return;
    157. }
    158. std::string id(idStr);
    159. auto render = PluginRender::GetInstance(id);
    160. if (render) {
    161. // 封装OnKeyEvent方法
    162. render->OnKeyEvent(component, window);
    163. }
    164. }
    165. // 定义一个OnSurfaceChanged()方法
    166. void PluginRender::OnSurfaceChanged(OH_NativeXComponent* component, void* window)
    167. {
    168. // ...
    169. std::string id(idStr);
    170. PluginRender* render = PluginRender::GetInstance(id);
    171. double offsetX;
    172. double offsetY;
    173. // 获取XComponent持有的surface相对其父组件左顶点的偏移量
    174. OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY);
    175. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OH_NativeXComponent_GetXComponentOffset",
    176. "offsetX = %{public}lf, offsetY = %{public}lf", offsetX, offsetY);
    177. uint64_t width;
    178. uint64_t height;
    179. OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
    180. if (render != nullptr) {
    181. render->eglCore_->UpdateSize(width, height);
    182. }
    183. }
    184. // 定义一个OnTouchEvent()方法
    185. void PluginRender::OnTouchEvent(OH_NativeXComponent* component, void* window)
    186. {
    187. // ...
    188. OH_NativeXComponent_TouchEvent touchEvent;
    189. // 获取由XComponent触发的触摸事件
    190. OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent);
    191. // 获取XComponent触摸点相对于XComponent组件左边缘的坐标x和相对于XComponent组件上边缘的坐标y
    192. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent",
    193. "touch info: x = %{public}lf, y = %{public}lf", touchEvent.x, touchEvent.y);
    194. // 获取XComponent触摸点相对于XComponent所在应用窗口左上角的x坐标和相对于XComponent所在应用窗口左上角的y坐标
    195. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent",
    196. "touch info: screenX = %{public}lf, screenY = %{public}lf", touchEvent.screenX, touchEvent.screenY);
    197. std::string id(idStr);
    198. PluginRender* render = PluginRender::GetInstance(id);
    199. if (render != nullptr && touchEvent.type == OH_NativeXComponent_TouchEventType::OH_NativeXComponent_UP) {
    200. render->eglCore_->ChangeColor();
    201. hasChangeColor_ = 1;
    202. }
    203. float tiltX = 0.0f;
    204. float tiltY = 0.0f;
    205. OH_NativeXComponent_TouchPointToolType toolType =
    206. OH_NativeXComponent_TouchPointToolType::OH_NativeXComponent_TOOL_TYPE_UNKNOWN;
    207. // 获取XComponent触摸点的工具类型
    208. OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType);
    209. // 获取XComponent触摸点处相对X轴的倾斜角度
    210. OH_NativeXComponent_GetTouchPointTiltX(component, 0, &tiltX);
    211. // 获取XComponent触摸点处相对Y轴的倾斜角度
    212. OH_NativeXComponent_GetTouchPointTiltY(component, 0, &tiltY);
    213. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent",
    214. "touch info: toolType = %{public}d, tiltX = %{public}lf, tiltY = %{public}lf", toolType, tiltX, tiltY);
    215. }
    216. // 定义一个OnMouseEvent()方法
    217. void PluginRender::OnMouseEvent(OH_NativeXComponent *component, void *window) {
    218. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "OnMouseEvent");
    219. OH_NativeXComponent_MouseEvent mouseEvent;
    220. // 获取由XComponent触发的鼠标事件
    221. int32_t ret = OH_NativeXComponent_GetMouseEvent(component, window, &mouseEvent);
    222. if (ret == OH_NativeXComponent_RESULT_SUCCESS) {
    223. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "MouseEvent Info: x = %{public}f, y = %{public}f, action = %{public}d, button = %{public}d", mouseEvent.x, mouseEvent.y, mouseEvent.action, mouseEvent.button);
    224. } else {
    225. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "GetMouseEvent error");
    226. }
    227. }
    228. // 定义一个OnMouseEvent()方法
    229. void PluginRender::OnKeyEvent(OH_NativeXComponent *component, void *window) {
    230. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "OnKeyEvent");
    231. OH_NativeXComponent_KeyEvent *keyEvent = nullptr;
    232. // 获取由XComponent触发的按键事件。
    233. if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) {
    234. OH_NativeXComponent_KeyAction action;
    235. // 获取按键事件的动作
    236. OH_NativeXComponent_GetKeyEventAction(keyEvent, &action);
    237. OH_NativeXComponent_KeyCode code;
    238. // 获取按键事件的键码值
    239. OH_NativeXComponent_GetKeyEventCode(keyEvent, &code);
    240. OH_NativeXComponent_EventSourceType sourceType;
    241. // 获取按键事件的输入源类型
    242. OH_NativeXComponent_GetKeyEventSourceType(keyEvent, &sourceType);
    243. int64_t deviceId;
    244. // 获取按键事件的设备ID
    245. OH_NativeXComponent_GetKeyEventDeviceId(keyEvent, &deviceId);
    246. int64_t timeStamp;
    247. // 获取按键事件的时间戳
    248. OH_NativeXComponent_GetKeyEventTimestamp(keyEvent, &timeStamp);
    249. OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "KeyEvent Info: action=%{public}d, code=%{public}d, sourceType=%{public}d, deviceId=%{public}ld, timeStamp=%{public}ld", action, code, sourceType, deviceId, timeStamp);
    250. } else {
    251. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "GetKeyEvent error");
    252. }
    253. }
    复制代码
  • 配置详细的CMakeLists,使用CMake工具链将C++源代码编译成动态链接库文件。
    1. void PluginRender::RegisterCallback(OH_NativeXComponent *NativeXComponent) {
    2. // 设置组件创建事件的回调函数,组件创建时触发相关操作,初始化环境与绘制背景
    3. renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB;
    4. // 设置组件改变事件的回调函数,组件改变时触发相关操作
    5. renderCallback_.OnSurfaceChanged = OnSurfaceChangedCB;
    6. // 设置组件销毁事件的回调函数,组件销毁时触发相关操作,释放申请的资源
    7. renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
    8. // 设置触摸事件的回调函数,在触摸事件触发时调用Node-API接口函数,从而调用原C++方法
    9. renderCallback_.DispatchTouchEvent = DispatchTouchEventCB;
    10. // 将OH_NativeXComponent_Callback注册给NativeXComponent
    11. OH_NativeXComponent_RegisterCallback(NativeXComponent, &renderCallback_);
    12. // 设置鼠标事件的回调函数,在触摸事件触发时调用Node-API接口函数,从而调用原C++方法
    13. mouseCallback_.DispatchMouseEvent = DispatchMouseEventCB;
    14. // 设置鼠标悬停事件的回调函数,在触摸事件触发时调用Node-API接口函数,从而调用原C++方法
    15. mouseCallback_.DispatchHoverEvent = DispatchHoverEventCB;
    16. // 将OH_NativeXComponent_MouseEvent_Callback注册给NativeXComponent
    17. OH_NativeXComponent_RegisterMouseEventCallback(NativeXComponent, &mouseCallback_);
    18. // 将OnFocusEventCB方法注册给NativeXComponent
    19. OH_NativeXComponent_RegisterFocusEventCallback(NativeXComponent, OnFocusEventCB);
    20. // 将OnKeyEventCB方法注册给NativeXComponent
    21. OH_NativeXComponent_RegisterKeyEventCallback(NativeXComponent, OnKeyEventCB);
    22. // 将OnBlurEventCB方法注册给 NativeXComponent
    23. OH_NativeXComponent_RegisterBlurEventCallback(NativeXComponent, OnBlurEventCB);
    24. }
    复制代码
component类型

XComponent设置为component类型时通常用于在XComponent内部执行非UI逻辑以实现动态加载显示内容的目标。
说明
   type为"component"时,XComponent作为容器,子组件沿垂直方向布局:
  

  • 垂直方向上对齐格式:FlexAlign.Start
  • 程度方向上对齐格式:FlexAlign.Center
  不支持所有的事件相应。
  布局方式更改和事件相应均可通过挂载子组件来设置。
  内部所写的非UI逻辑需要封装在一个或多个函数内。
  1. napi_value PluginRender::NapiDrawPattern(napi_env env, napi_callback_info info)
  2. {
  3.     // ...
  4.     // 获取环境变量参数
  5.     napi_value thisArg;
  6.     if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
  7.         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawPattern: napi_get_cb_info fail");
  8.         return nullptr;
  9.     }
  10.    
  11.     // 获取环境变量中XComponent实例
  12.     napi_value exportInstance;
  13.     if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
  14.         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender",
  15.             "NapiDrawPattern: napi_get_named_property fail");
  16.         return nullptr;
  17.     }
  18.    
  19.     // 通过napi_unwrap接口,获取XComponent的实例指针
  20.     OH_NativeXComponent *NativeXComponent = nullptr;
  21.     if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&NativeXComponent)) != napi_ok) {
  22.         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawPattern: napi_unwrap fail");
  23.         return nullptr;
  24.     }
  25.    
  26.     // 获取XComponent实例的id
  27.     char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
  28.     uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
  29.     if (OH_NativeXComponent_GetXComponentId(NativeXComponent, idStr, &idSize) != OH_NativeXComponent_RESULT_SUCCESS) {
  30.         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender",
  31.             "NapiDrawPattern: Unable to get XComponent id");
  32.         return nullptr;
  33.     }
  34.    
  35.     std::string id(idStr);
  36.     PluginRender *render = PluginRender::GetInstance(id);
  37.     if (render) {
  38.         // 调用绘制方法
  39.         render->eglCore_->Draw();
  40.         OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "render->eglCore_->Draw() executed");
  41.     }
  42.     return nullptr;
  43. }
复制代码


生命周期说明

开辟者在ArkTS侧使用如下代码即可用XComponent组件进利用用EGL/OpenGLES渲染的开辟。
  1. void EGLCore::UpdateSize(int width, int height)
  2. {
  3. width_ = width;
  4. height_ = height;
  5. if (width_ > 0) {
  6. // 计算绘制矩形宽度百分比
  7. width_Percent_ = FIFTY_PERCENT * height_ / width_;
  8. }
  9. }
  10. bool EGLCore::EglContextInit(void *window, int width, int height)
  11. {
  12. // ...
  13. UpdateSize(width, height);
  14. eglWindow_ = static_cast<EGLNativeWindowType>(window);
  15. // 初始化display
  16. eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  17. if (eglDisplay_ == EGL_NO_DISPLAY) {
  18. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display");
  19. return false;
  20. }
  21. // 初始化EGL
  22. EGLint majorVersion;
  23. EGLint minorVersion;
  24. if (!eglInitialize(eglDisplay_, &majorVersion, &minorVersion)) {
  25. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore",
  26. "eglInitialize: unable to get initialize EGL display");
  27. return false;
  28. }
  29. // 选择配置
  30. const EGLint maxConfigSize = 1;
  31. EGLint numConfigs;
  32. if (!eglChooseConfig(eglDisplay_, ATTRIB_LIST, &eglConfig_, maxConfigSize, &numConfigs)) {
  33. OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs");
  34. return false;
  35. }
  36. // 创建环境
  37. return CreateEnvironment();
  38. }
复制代码
onLoad事件

触发时刻:XComponent准备好surface后触发。
参数context:其上面挂载了暴露在模块上的Native方法,使用方法雷同于使用 import context from "libnativerender.so" 直接加载模块后获得的context实例。
时序
​ Native XComponent场景:
​ onLoad事件的触发和surface相关,其和Native侧的OnSurfaceCreated的时序如下图:


​ ArkTS XComponent场景:
​ onLoad事件的触发和surface相关,其和ArkTS侧的OnSurfaceCreated的时序如下图:


onDestroy事件

触发时刻:XComponent组件被烧毁时触发,与一般ArkUI的组件烧毁机遇同等。
时序:
​ Native XComponent场景:
​ onDestroy事件的触发和surface相关,其和Native侧的OnSurfaceDestroyed的时序如下图:


​ ArkTS XComponent场景:
​ onDestroy事件的触发和surface相关,其和ArkTS侧的OnSurfaceDestroyed的时序如下图:



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表