1# ContentSlot:混合开发 2 3用于渲染并管理Native层使用C-API创建的组件。 4 5支持混合模式开发,当容器是ArkTS组件,子组件在Native侧创建时,推荐使用ContentSlot占位组件。 6 7## 接口 8 9### ContentSlot组件接口 10 11```ts 12ContentSlot(content: Content); // 当前开发者需要使用ArkUI提供的NodeContent作为管理器 13``` 14 15| 参数名 | 类型 | 必填 | 参数描述 | 16| ------- | -------- | ---- | ------------------------------------------------------------ | 17| content | Content | 是 | Content作为ContentSlot的管理器,通过Native侧提供的接口,可以注册并触发ContentSlot的上下树事件回调以及管理ContentSlot的子组件。 | 18 19```ts 20abstract class Content { 21} 22``` 23 24### ContentSlotInterface 25 26(content: Content): ContentSlotAttribute; 27 28当内容添加到占位符组件时调用 29 30**系统能力:** SystemCapability.ArkUI.ArkUI.Full 31 32**参数:** 33 34| 参数名 | 类型 | 必填 | 参数描述 | 35| ------- | -------- | ---- | ------------------------------------------------------------ | 36| content | Content | 是 | Content作为ContentSlot的管理器,通过Native侧提供的接口,可以注册并触发ContentSlot的上下树事件回调以及管理ContentSlot的子组件。 | 37 38### ContentSlotAttribute 39 40定义ContentSlot属性,以防止不正确的递归使用ContentSlot 41 42**系统能力:** SystemCapability.ArkUI.ArkUI.Full 43 44### Native侧接口 45 46| 接口名 | 描述 | 47| -------- | -------- | 48|OH_ArkUI_NodeContent_RegisterCallback(ArkUI_NodeContentHandle content, ArkUI_NodeContentCallback callback)|向管理器Content上注册事件。| 49|OH_ArkUI_NodeContentEvent_GetEventType(ArkUI_NodeContentEvent* event)|获取Content上触发的事件类型。| 50|OH_ArkUI_NodeContent_AddNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node)|在Content上添加子组件。| 51|OH_ArkUI_NodeContent_InsertNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node, int32_t position)|在Content上插入子组件。| 52|OH_ArkUI_NodeContent_RemoveNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node)|在Content上移除子组件。| 53|OH_ArkUI_GetNodeContentFromNapiValue(napi_env env, napi_value value, ArkUI_NodeContentHandle* content)|在Native侧获取ArkTS侧Content指针。| 54|OH_ArkUI_NodeContentEvent_GetNodeContentHandle(ArkUI_NodeContentEvent* event)|获取触发上下树事件的Content对象。| 55|OH_ArkUI_NodeContent_SetUserData(ArkUI_NodeContentHandle content, void* userData)|在Content上设置用户自定义属性。| 56|OH_ArkUI_NodeContent_GetUserData(ArkUI_NodeContentHandle content)|在Content上获取用户自定义属性。| 57|typedef enum {<br> NOTE_CONTENT_EVENT_ON_ATTACH_TO_WINDOW = 0,<br> NOTE_CONTENT_EVENT_ON_DETACH_FROM_WINDOW = 1,<br>} ArkUI_NodeContentEventType|Content上会触发的上树和下树两种事件类型。| 58 59## 开发实现 60 61### ArkTS侧代码实现 62 63```ts 64import { nativeNode } from 'libNativeNode.so' // 开发者自己实现的so 65import { NodeContent } from '@kit.ArkUI' 66 67@Entry 68@Component 69struct Parent { 70 private nodeContent: Content = new NodeContent(); 71 72 aboutToAppear() { 73 // 通过C-API创建节点,并添加到管理器nodeContent上 74 nativeNode.createNativeNode(this.nodeContent); 75 } 76 77 build() { 78 Column() { 79 // 显示nodeContent管理器里存放的Native侧的组件 80 ContentSlot(this.nodeContent) 81 } 82 } 83} 84``` 85 86### Native侧代码实现 87Napi的基础开发知识请查看以下文档:[开发导读](../napi/ndk-development-overview.md)。 88 89本章节仅描述实现ContentSlot相关逻辑代码。创建C侧组件,具体请查看[使用NDK接口构建UI](../ui/ndk-build-ui-overview.md)。 90 91```c++ 92#include "napi/native_api.h" 93#include "arkui/native_type.h" 94#include "arkui/native_node.h" 95#include "arkui/native_node_napi.h" 96#include "arkui/native_interface.h" 97#include "hilog/log.h" 98 99ArkUI_NodeContentHandle nodeContentHandle_ = nullptr; 100ArkUI_NativeNodeAPI_1 *nodeAPI; 101const unsigned int LOG_PRINT_DOMAIN = 0xFF00; 102 103// Manager为应用定义的NativeNode管理类 104napi_value Manager::CreateNativeNode(napi_env env, napi_callback_info info) { 105 // napi相关处理空指针&数据越界等问题 106 if ((env == nullptr) || (info == nullptr)) { 107 return nullptr; 108 } 109 110 size_t argc = 1; 111 napi_value args[1] = { nullptr }; 112 if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) { 113 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Manager", "CreateNativeNode napi_get_cb_info failed"); 114 } 115 116 if (argc != 1) { 117 return nullptr; 118 } 119 120 nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>( 121 OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNode_API_1")); 122 123 // 将nodeContentHandle_指向ArkTS侧传入的nodeContent 124 OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &nodeContentHandle_); 125 126 if (nodeAPI != nullptr) { 127 if (nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) { 128 ArkUI_NodeHandle component; 129 // 创建C侧组件,具体请查看ArkUI api文档的Capi章节 130 component = CreateNodeHandle(); 131 // 将组件添加到nodeContent管理器中 132 OH_ArkUI_NodeContent_AddNode(nodeContentHandle_, component); 133 } 134 } 135} 136``` 137 138#### 注册上下树事件,并通过事件获取对应的Content对象 139 140```c++ 141auto nodeContentEvent = [](ArkUI_NodeContentEvent *event) { 142 ArkUI_NodeContentHandle content = OH_ArkUI_NodeContentEvent_GetNodeContentHandle(event); 143 // 针对不同content需要额外做的逻辑 144 if (OH_ArkUINodeContentEvent_GetEventType(event) = NODE_CONTENT_EVENT_ON_ATTACH_TO_WINDOW) { 145 // ContentSlot上树时需要触发的逻辑 146 } else if (OH_ArkUINodeContentEvent_GetEventType(event) = NODE_CONTENT_EVENT_ON_DETACH_FROM_WINDOW) { 147 // ContentSlot下树时需要触发的逻辑 148 }; 149}; 150// 将该事件注册到nodeContent上 151OH_ArkUI_NodeContent_RegisterCallback(nodeContentHandle_, nodeContentEvent); 152``` 153 154#### 添加子组件 155 156```c++ 157ArkUINodeHandle component; 158component = CreateNodeHandle(); 159// 将组件添加到nodeContent管理器中 160OH_ArkUI_NodeContent_AddNode(nodeContentHandle_, component); 161``` 162 163#### 插入子组件 164 165```c++ 166ArkUINodeHandle component; 167component = CreateNodeHandle(); 168// 将组件插入nodeContent管理器对应位置 169OH_ArkUI_NodeContent_InsertNode(nodeContentHandle_, component, position); 170``` 171 172#### 删除子组件 173 174```c++ 175// 在nodeContent中移除对应组件 176OH_ArkUI_NodeContent_RemoveNode(nodeContentHandle_, component); 177``` 178 179#### 设置自定义属性 180 181```c++ 182// 创建需要定义的自定义数据 183void *userData = CreateUserData(); 184OH_ArkUI_NodeContent_SetUserData(nodeContentHandle_, userData); 185``` 186 187#### 获取自定义属性 188 189``` 190void *userData = OH_ArkUI_NodeContent_GetUserData(nodeContentHandle_); 191``` 192