已开启
8分文档:r1_1to3 #163147
liuhuayi_openharmony创建于 18 天前
8分文档:r1_1to3 #163147
已开启
liuhuayi_openharmony创建于 18 天前
10 个文件变更+368-200
@@ -181,7 +181,7 @@ export default class EntryAbility extends UIAbility {
181 181 
182 onWindowStageCreate(windowStage: window.WindowStage): void {182 onWindowStageCreate(windowStage: window.WindowStage): void {
183 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');183 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
184- // 在loadContent前调用时,vp2px会根据屏幕默认像素密度返回计算结果。184+ // 在loadContent前调用,此无UI实例,vp2px会根据屏幕默认像素密度返回计算结果。
185 let pxValue = vp2px(20);185 let pxValue = vp2px(20);
186 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);186 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);
187 windowStage.loadContent('pages/Index', (err) => {187 windowStage.loadContent('pages/Index', (err) => {
@@ -193,9 +193,7 @@ export default class EntryAbility extends UIAbility {
193 let pxValue = vp2px(20);193 let pxValue = vp2px(20);
194 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);194 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);
195 });195 });
196- // loadContent是异步接口,在此处调用不能保证UI实例已经创建成功196+ // loadContent是异步接口,在loadContent之后并不能保证UI实例已经创建并初始化此时调用例如vp2px等依赖UI实例的函数,可能因实例不正确导致结果不符合预期。
197- pxValue = vp2px(20);
198- hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);
199 }197 }
200 198 
201 // ...199 // ...
@@ -228,14 +226,13 @@ export default class EntryAbility extends UIAbility {
228 // 注册主窗的回调。226 // 注册主窗的回调。
229 WindowUIContextUtils.registerWindowCallback(window);227 WindowUIContextUtils.registerWindowCallback(window);
230 // 在loadContent前调用getUIContext时,UI实例未创建,存在异常。228 // 在loadContent前调用getUIContext时,UI实例未创建,存在异常。
229+ // 调用loadContent后,UI实例的创建与初始化为异步进行。因此,UIContext的获取应在loadContent的完成回调中,而不是在调用loadContent之后。
231 windowStage.loadContent('pages/Index', localStorage, (err) => {230 windowStage.loadContent('pages/Index', localStorage, (err) => {
232- // 需要在loadContent完成后获取UIContext。
233 if (err.code) {231 if (err.code) {
234 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));232 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
235 return;233 return;
236 }234 }
237 hilog.info(DOMAIN, 'testTag', `loadContent success.`);235 hilog.info(DOMAIN, 'testTag', `loadContent success.`);
238- // 需要在回调中调用。
239 try {236 try {
240 let uiContext = window.getUIContext();237 let uiContext = window.getUIContext();
241 PixelUtils.setUIContext(uiContext);238 PixelUtils.setUIContext(uiContext);
@@ -250,7 +247,7 @@ export default class EntryAbility extends UIAbility {
250 } catch (e) {247 } catch (e) {
251 hilog.error(DOMAIN, 'testTag', `Can't get UIContext, ${e}`);248 hilog.error(DOMAIN, 'testTag', `Can't get UIContext, ${e}`);
252 }249 }
253- // loadContent是异步接口,在此处调用不能保证UI实例已经创建成功250+ // loadContent是异步接口,在loadContent之后并不能保证UI实例已经创建并初始化此时调用例如vp2px等依赖UI实例的函数,可能因实例不正确导致结果不符合预期。
254 });251 });
255 }252 }
256 253 
@@ -259,7 +256,7 @@ export default class EntryAbility extends UIAbility {
259 onWindowStageDestroy(): void {256 onWindowStageDestroy(): void {
260 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');257 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
261 // 在窗口销毁时需要移除失效的UIContext258 // 在窗口销毁时需要移除失效的UIContext
262- PixelUtil.removeUIContext();259+ PixelUtils.removeUIContext();
263 }260 }
264 261 
265 // ...262 // ...
@@ -303,9 +300,7 @@ export default class EntryAbility extends UIAbility {
303 let pxValue = vp2px(20);300 let pxValue = vp2px(20);
304 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);301 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);
305 });302 });
306- // loadContent是异步接口,在此处调用不能保证UI实例已经创建成功303+ // loadContent是异步接口,在loadContent之后并不能保证UI实例已经创建并初始化此时调用例如vp2px等依赖UI实例的函数,可能因实例不正确导致结果不符合预期。
307- pxValue = vp2px(20);
308- hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);
309 }304 }
310 305 
311 // ...306 // ...
@@ -386,7 +381,7 @@ export default class EntryAbility extends UIAbility {
386 let pxValue = resolvedUIContext.vp2px(20);381 let pxValue = resolvedUIContext.vp2px(20);
387 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);382 hilog.info(DOMAIN, 'testTag', `20vp equals to ${pxValue}px`);
388 });383 });
389- // loadContent是异步接口,在此处调用不能保证UI实例已经创建成功384+ // loadContent是异步接口,在loadContent之后并不能保证UI实例已经创建并初始化此时调用例如vp2px等依赖UI实例的函数,可能因实例不正确导致结果不符合预期。
390 }385 }
391 386 
392 onWindowStageDestroy(): void {387 onWindowStageDestroy(): void {
@@ -582,14 +577,13 @@ export default class EntryAbility extends UIAbility {
582 // 注册主窗的回调。577 // 注册主窗的回调。
583 WindowUIContextUtils.registerWindowCallback(window);578 WindowUIContextUtils.registerWindowCallback(window);
584 // 在loadContent前调用getUIContext时,UI实例未创建,存在异常。579 // 在loadContent前调用getUIContext时,UI实例未创建,存在异常。
580+ // 调用loadContent后,UI实例的创建与初始化为异步进行。因此,UIContext的获取应在loadContent的完成回调中,而不是在调用loadContent之后。
585 windowStage.loadContent('pages/Index', localStorage, (err) => {581 windowStage.loadContent('pages/Index', localStorage, (err) => {
586- // 需要在loadContent完成后获取UIContext。
587 if (err.code) {582 if (err.code) {
588 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));583 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
589 return;584 return;
590 }585 }
591 hilog.info(DOMAIN, 'testTag', `loadContent success.`);586 hilog.info(DOMAIN, 'testTag', `loadContent success.`);
592- // 需要在回调中调用。
593 try {587 try {
594 let uiContext = window.getUIContext();588 let uiContext = window.getUIContext();
595 PixelUtils.setUIContext(uiContext);589 PixelUtils.setUIContext(uiContext);
@@ -604,8 +598,8 @@ export default class EntryAbility extends UIAbility {
604 } catch (e) {598 } catch (e) {
605 hilog.error(DOMAIN, 'testTag', `Can't get UIContext, ${e}`);599 hilog.error(DOMAIN, 'testTag', `Can't get UIContext, ${e}`);
606 }600 }
607- // loadContent是异步接口,在此处调用不能保证UI实例已经创建成功601+ // loadContent是异步接口,在loadContent之后并不能保证UI实例已经创建并初始化此时调用例如vp2px等依赖UI实例的函数,可能因实例不正确导致结果不符合预期。
608- });602+ });
609 }603 }
610 604 
611 // ...605 // ...
@@ -613,7 +607,7 @@ export default class EntryAbility extends UIAbility {
613 onWindowStageDestroy(): void {607 onWindowStageDestroy(): void {
614 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');608 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
615 // 在窗口销毁时需要移除失效的UIContext609 // 在窗口销毁时需要移除失效的UIContext
616- PixelUtil.removeUIContext();610+ PixelUtils.removeUIContext();
617 }611 }
618 612 
619 // ...613 // ...
@@ -699,7 +693,7 @@ export class WindowUIContextUtils {
699 }693 }
700 });694 });
701 } catch (exception) {695 } catch (exception) {
702- console.error(`Failed to unregister callback. Cause: ${exception}`);696+ console.error(`Failed to register callback. Cause: ${exception}`);
703 }697 }
704 }698 }
705 699 
@@ -748,14 +742,13 @@ export default class EntryAbility extends UIAbility {
748 // 注册主窗的回调。742 // 注册主窗的回调。
749 WindowUIContextUtils.registerWindowCallback(window);743 WindowUIContextUtils.registerWindowCallback(window);
750 // 在loadContent前调用getUIContext时,UI实例未创建,存在异常。744 // 在loadContent前调用getUIContext时,UI实例未创建,存在异常。
745+ // 调用loadContent后,UI实例的创建与初始化为异步进行。因此,UIContext的获取应在loadContent的完成回调中,而不是在调用loadContent之后。
751 windowStage.loadContent('pages/Index', localStorage, (err) => {746 windowStage.loadContent('pages/Index', localStorage, (err) => {
752- // 需要在loadContent完成后获取UIContext。
753 if (err.code) {747 if (err.code) {
754 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));748 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
755 return;749 return;
756 }750 }
757 hilog.info(DOMAIN, 'testTag', `loadContent success.`);751 hilog.info(DOMAIN, 'testTag', `loadContent success.`);
758- // 需要在回调中调用。
759 try {752 try {
760 let uiContext = window.getUIContext();753 let uiContext = window.getUIContext();
761 PixelUtils.setUIContext(uiContext);754 PixelUtils.setUIContext(uiContext);
@@ -770,7 +763,7 @@ export default class EntryAbility extends UIAbility {
770 } catch (e) {763 } catch (e) {
771 hilog.error(DOMAIN, 'testTag', `Can't get UIContext, ${e}`);764 hilog.error(DOMAIN, 'testTag', `Can't get UIContext, ${e}`);
772 }765 }
773- // loadContent是异步接口,在此处调用不能保证UI实例已经创建成功766+ // loadContent是异步接口,在loadContent之后并不能保证UI实例已经创建并初始化此时调用例如vp2px等依赖UI实例的函数,可能因实例不正确导致结果不符合预期。
774 });767 });
775 }768 }
776 769 
@@ -944,6 +937,10 @@ export class PixelUtils {
944 PixelUtils.uiContext = uiContext;937 PixelUtils.uiContext = uiContext;
945 }938 }
946 939 
940+ static removeUIContext(): void {
941+ PixelUtils.uiContext = undefined;
942+ }
943+ 
947 static vp2px(vpValue: number, uiContext?: UIContext): number | undefined {944 static vp2px(vpValue: number, uiContext?: UIContext): number | undefined {
948 let _uiContext = uiContext ?? PixelUtils.uiContext;945 let _uiContext = uiContext ?? PixelUtils.uiContext;
949 if (!_uiContext || !_uiContext.isAvailable()) {946 if (!_uiContext || !_uiContext.isAvailable()) {
@@ -1032,6 +1029,9 @@ struct GetContextPage {
1032 1029 
1033``` TypeScript1030``` TypeScript
1034// Common/ContextUtils.ets1031// Common/ContextUtils.ets
1032+import { Context } from '@kit.AbilityKit';
1033+import { UIContext } from '@kit.ArkUI';
1034+ 
1035export class ContextUtils {1035export class ContextUtils {
1036 public static context: Context | undefined;1036 public static context: Context | undefined;
1037 1037 
@@ -1075,6 +1075,7 @@ export default class EntryAbility extends UIAbility {
1075 1075 
1076 onDestroy(): void {1076 onDestroy(): void {
1077 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');1077 hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
1078+ ContextUtils.context = undefined;
1078 }1079 }
1079 // ...1080 // ...
1080}1081}
@@ -1180,7 +1181,6 @@ struct LocalStoragePage {
1180 let storage = uiContext.getSharedLocalStorage();1181 let storage = uiContext.getSharedLocalStorage();
1181 if (storage) {1182 if (storage) {
1182 storage.setOrCreate('message', 'onClick is called.');1183 storage.setOrCreate('message', 'onClick is called.');
1183- this.message = 'LocalStoragePageHelloWorld';
1184 }1184 }
1185 })1185 })
1186 }1186 }
@@ -1213,8 +1213,8 @@ export default class EntryAbility extends UIAbility {
1213 let localStorage = new LocalStorage();1213 let localStorage = new LocalStorage();
1214 localStorage.setOrCreate('message', 'Message from Storage')1214 localStorage.setOrCreate('message', 'Message from Storage')
1215 // ...1215 // ...
1216+ // 调用loadContent后,UI实例的创建与初始化为异步进行。因此,UIContext的获取应在loadContent的完成回调中,而不是在调用loadContent之后。
1216 windowStage.loadContent('pages/Index', localStorage, (err) => {1217 windowStage.loadContent('pages/Index', localStorage, (err) => {
1217- // 需要在loadContent完成后获取UIContext。
1218 if (err.code) {1218 if (err.code) {
1219 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));1219 hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
1220 return;1220 return;
@@ -20,7 +20,7 @@ ArkUI支持在前端使用ArkTS语言创建命令式节点,即[FrameNode](../r
20 20 
21跨语言指的是跨越ArkTS语言和C语言。跨语言配置指的是命令式节点上对于跨语言操作的权限配置。21跨语言指的是跨越ArkTS语言和C语言。跨语言配置指的是命令式节点上对于跨语言操作的权限配置。
22 22 
23-可以通过[setCrossLanguageOptions](../reference/apis-arkui/js-apis-arkui-frameNode.md#setcrosslanguageoptions15)与[OH_ArkUI_NodeUtils_SetCrossLanguageOption](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_setcrosslanguageoption)接口设置当前节点的跨语言配置。如果当前节点无法修改或设置跨语言配置,会抛出异常信息23+可以通过[setCrossLanguageOptions](../reference/apis-arkui/js-apis-arkui-frameNode.md#setcrosslanguageoptions15)与[OH_ArkUI_NodeUtils_SetCrossLanguageOption](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_setcrosslanguageoption)接口设置当前节点的跨语言配置。调用setCrossLanguageOptions时,如果当前节点无法修改或设置跨语言配置,会抛出异常;调用OH_ArkUI_NodeUtils_SetCrossLanguageOption时,可通过接口返回的错误码判断是否设置成功
24 24 
25可以使用[getCrossLanguageOptions](../reference/apis-arkui/js-apis-arkui-frameNode.md#getcrosslanguageoptions15)与[OH_ArkUI_NodeUtils_GetCrossLanguageOption](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getcrosslanguageoption)接口获取当前节点的跨语言配置。25可以使用[getCrossLanguageOptions](../reference/apis-arkui/js-apis-arkui-frameNode.md#getcrosslanguageoptions15)与[OH_ArkUI_NodeUtils_GetCrossLanguageOption](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getcrosslanguageoption)接口获取当前节点的跨语言配置。
26 26 
@@ -168,6 +168,10 @@ struct CrossLanguage {
168 nativeNode.createNativeRoot(this.rootSlot);168 nativeNode.createNativeRoot(this.rootSlot);
169 }169 }
170 170 
171+ aboutToDisappear(): void {
172+ nativeNode.destroyNativeRoot();
173+ }
174+ 
171 build() {175 build() {
172 Scroll() {176 Scroll() {
173 Column({ space: 15 }) {177 Column({ space: 15 }) {
@@ -207,7 +211,7 @@ struct CrossLanguage {
207 ```211 ```
208 212 
2092. 新建`CrossLanguageExample.h`文件,在其中获取到目标节点(该节点在ArkTS侧创建),并设置属性。2132. 新建`CrossLanguageExample.h`文件,在其中获取到目标节点(该节点在ArkTS侧创建),并设置属性。
210- ```c214+ ```cpp
211 // CrossLanguageExample.h215 // CrossLanguageExample.h
212 #ifndef MYAPPLICATION_CROSSLANGUAGEEXAMPLE_H216 #ifndef MYAPPLICATION_CROSSLANGUAGEEXAMPLE_H
213 #define MYAPPLICATION_CROSSLANGUAGEEXAMPLE_H217 #define MYAPPLICATION_CROSSLANGUAGEEXAMPLE_H
@@ -250,7 +254,7 @@ struct CrossLanguage {
250 ArkUI_NumberValue text_height[] = {50};254 ArkUI_NumberValue text_height[] = {50};
251 ArkUI_AttributeItem text_item1 = {text_height, sizeof(text_height) / sizeof(ArkUI_NumberValue)};255 ArkUI_AttributeItem text_item1 = {text_height, sizeof(text_height) / sizeof(ArkUI_NumberValue)};
252 nodeAPI->setAttribute(text0, NODE_HEIGHT, &text_item1);256 nodeAPI->setAttribute(text0, NODE_HEIGHT, &text_item1);
253- ArkUI_AttributeItem text_item = {.string = "C设置TS创建的节点属性"};257+ ArkUI_AttributeItem text_item = {.string = "C设置ArkTS创建的节点属性"};
254 nodeAPI->setAttribute(text0, NODE_TEXT_CONTENT, &text_item);258 nodeAPI->setAttribute(text0, NODE_TEXT_CONTENT, &text_item);
255 ArkUI_NumberValue margin[] = {10};259 ArkUI_NumberValue margin[] = {10};
256 ArkUI_AttributeItem item_margin = {margin, sizeof(margin) / sizeof(ArkUI_NumberValue)};260 ArkUI_AttributeItem item_margin = {margin, sizeof(margin) / sizeof(ArkUI_NumberValue)};
@@ -285,30 +289,39 @@ struct CrossLanguage {
285 289
286 // 注册事件290 // 注册事件
287 auto onClick = [](ArkUI_NodeEvent *event) {291 auto onClick = [](ArkUI_NodeEvent *event) {
288- ArkUI_NodeHandle node = OH_ArkUI_NodeEvent_GetNodeHandle(event);
289 auto nodeAPI = NativeModuleInstance::GetInstance()->GetNativeNodeAPI();292 auto nodeAPI = NativeModuleInstance::GetInstance()->GetNativeNodeAPI();
290 293
291 if (OH_ArkUI_NodeEvent_GetTargetId(event) == 0) { // scrollBarColor294 if (OH_ArkUI_NodeEvent_GetTargetId(event) == 0) { // scrollBarColor
292 ArkUI_NodeHandle node_ptr = nullptr;295 ArkUI_NodeHandle node_ptr = nullptr;
293- OH_ArkUI_NodeUtils_GetAttachedNodeHandleById("scroll", &node_ptr);296+ if (OH_ArkUI_NodeUtils_GetAttachedNodeHandleById("scroll", &node_ptr) !=
294- try {297+ ARKUI_ERROR_CODE_NO_ERROR || node_ptr == nullptr) {
295- ArkUI_NumberValue scroll_color_value[] = {{.u32 = 0xff00ff00}};298+ OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "CrossLanguageExample", "failed to get scroll node");
296- ArkUI_AttributeItem scroll_color_item = {scroll_color_value, sizeof(scroll_color_value) / sizeof(ArkUI_NumberValue)};299+ return;
297- nodeAPI->setAttribute(node_ptr, NODE_SCROLL_BAR_COLOR, &scroll_color_item);300+ }
298- } catch (...) {301+ ArkUI_NumberValue scroll_color_value[] = {{.u32 = 0xff00ff00}};
299- OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "CrossLanguageExample", "crossLanguage setAttribute error");302+ ArkUI_AttributeItem scroll_color_item = {
303+ scroll_color_value, sizeof(scroll_color_value) / sizeof(ArkUI_NumberValue)};
304+ int32_t result = nodeAPI->setAttribute(node_ptr, NODE_SCROLL_BAR_COLOR, &scroll_color_item);
305+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
306+ OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "CrossLanguageExample",
307+ "set scroll bar color failed, error code: %{public}d", result);
300 }308 }
301 }309 }
302 310
303 if (OH_ArkUI_NodeEvent_GetTargetId(event) == 1) { // scrollBarWidth311 if (OH_ArkUI_NodeEvent_GetTargetId(event) == 1) { // scrollBarWidth
304 ArkUI_NodeHandle node_ptr = nullptr;312 ArkUI_NodeHandle node_ptr = nullptr;
305- OH_ArkUI_NodeUtils_GetAttachedNodeHandleById("scroll", &node_ptr);313+ if (OH_ArkUI_NodeUtils_GetAttachedNodeHandleById("scroll", &node_ptr) !=
306- try {314+ ARKUI_ERROR_CODE_NO_ERROR || node_ptr == nullptr) {
307- ArkUI_NumberValue scroll_width_value[] = {{20}};315+ OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "CrossLanguageExample", "failed to get scroll node");
308- ArkUI_AttributeItem scroll_width_item = {scroll_width_value, sizeof(scroll_width_value) / sizeof(ArkUI_NumberValue)};316+ return;
309- nodeAPI->setAttribute(node_ptr, NODE_SCROLL_BAR_WIDTH, &scroll_width_item);317+ }
310- } catch (...) {318+ ArkUI_NumberValue scroll_width_value[] = {{20}};
311- OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "CrossLanguageExample", "crossLanguage setAttribute error");319+ ArkUI_AttributeItem scroll_width_item = {
320+ scroll_width_value, sizeof(scroll_width_value) / sizeof(ArkUI_NumberValue)};
321+ int32_t result = nodeAPI->setAttribute(node_ptr, NODE_SCROLL_BAR_WIDTH, &scroll_width_item);
322+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
323+ OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "CrossLanguageExample",
324+ "set scroll bar width failed, error code: %{public}d", result);
312 }325 }
313 }326 }
314 };327 };
@@ -329,7 +342,7 @@ struct CrossLanguage {
329 ```342 ```
330 343 
3313.`NativeEntry.cpp`中,挂载Native节点。3443.`NativeEntry.cpp`中,挂载Native节点。
332- ```c345+ ```cpp
333 // NativeEntry.cpp346 // NativeEntry.cpp
334 347 
335 348 
@@ -377,8 +390,8 @@ struct CrossLanguage {
377 ```390 ```
378 391 
3794. 修改CMakeLists.txt,添加链接库。3924. 修改CMakeLists.txt,添加链接库。
380- ```c393+ ```cmake
381- // CMakeLists.txt394+ # CMakeLists.txt
382 # the minimum version of CMake.395 # the minimum version of CMake.
383 cmake_minimum_required(VERSION 3.5.0)396 cmake_minimum_required(VERSION 3.5.0)
384 project(CAPI_DEMO)397 project(CAPI_DEMO)
@@ -20,7 +20,7 @@
20 20 
21 实例状态更新的日志格式为:21 实例状态更新的日志格式为:
22 22 
23- `({currentId}:{trackedId}:{trackedReason})][{bundleName}][{moduleName}][{thisInstanceId}]: window {status}`23+ `({currentId}:{trackedId}:{trackedReason})] [{bundleName}][{moduleName}][{thisInstanceId}]: window {status}`
24 24 
25 各字段含义为:25 各字段含义为:
26 26 
@@ -33,8 +33,8 @@
33 |{trackedReason}| 字符串 | singleton | 间接跟踪的原因,开发者可不关注该字段。 |33 |{trackedReason}| 字符串 | singleton | 间接跟踪的原因,开发者可不关注该字段。 |
34 |{bundleName}| 字符串 | com.example.helloworld| 应用的bundleName。 |34 |{bundleName}| 字符串 | com.example.helloworld| 应用的bundleName。 |
35 |{moduleName}| 字符串 | entry| 当前模块的moduleName。 |35 |{moduleName}| 字符串 | entry| 当前模块的moduleName。 |
36- |{thisInstanceId}| 正数 | 100000 | 被通知UI实例的ID。 |36+ |{thisInstanceId}| 正数 | 100000 | 被通知UI实例的ID。 |
37- |{status}| 实例被通知的状态 | focus | 可选值为:<br> - focus:获焦<br> - unfocus:失焦<br> - foreground:前台<br> - background:后台<br> - destroy:销毁 |37+ |{status}| 字符串 | focus | 实例被通知的状态可选值为:<br> - focus:获焦<br> - unfocus:失焦<br> - foreground:前台<br> - background:后台<br> - destroy:销毁 |
38 38 
39 可使用如下正则表达式匹配相关日志:39 可使用如下正则表达式匹配相关日志:
40 40 
@@ -48,9 +48,9 @@
48 48 
49 - 异常日志示例:49 - 异常日志示例:
50 50 
51- `(100000:100000:scoped)] [com.example.helloworld][entry][100001]: window background`51+ `(100000:100000:scope)] [com.example.helloworld][entry][100001]: window background`
52 52 
53- 该异常日志说明存在错误跟踪ID为100000的UI实例53+ 该异常日志说明当前上下文实例ID异常,其值为100000。
54 54 
55 - 若前文出现以下特定格式的日志:55 - 若前文出现以下特定格式的日志:
56 56 
@@ -146,12 +146,12 @@ OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativ
146|——cpp146|——cpp
147| |——types147| |——types
148| | |——libentry148| | |——libentry
149-| | | |——index.d.ts 提供Native和ArkTS侧的桥接方法。149+| | | |——Index.d.ts 提供Native和ArkTS侧的桥接方法。
150-| |——napi_init.cpp 与index.d.ts对应方法对接Native侧义处150+| |——napi_init.cpp 注册Node-API模块,并将Index.d.ts中声明的接口与Native侧实现函数绑定。
151| |——NativeEntry.cpp 桥接方法的Native侧实现。151| |——NativeEntry.cpp 桥接方法的Native侧实现。
152| |——NativeEntry.h 桥接方法的Native侧定义。152| |——NativeEntry.h 桥接方法的Native侧定义。
153| |——NativeModule.h 提供获取ArkUI在Native侧模块的封装接口。153| |——NativeModule.h 提供获取ArkUI在Native侧模块的封装接口。
154-| |——CMakeLists.txt C语言库引用文件。154+| |——CMakeLists.txt CMake构建配置文件,于配置编译源文件和链接库
155| |——ArkUIBaseNode.h 节点封装扩展类。155| |——ArkUIBaseNode.h 节点封装扩展类。
156| |——ArkUINode.h 节点封装扩展类。156| |——ArkUINode.h 节点封装扩展类。
157| |——ArkUIListNode.h 节点封装扩展类。157| |——ArkUIListNode.h 节点封装扩展类。
@@ -161,7 +161,7 @@ OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativ
161| 161|
162|——ets162|——ets
163| |——pages163| |——pages
164-| |——entry.ets 应用启动页,加载承载Native的容器。164+| |——Index.ets 应用启动页,加载承载Native组件的容器。
165|165|
166```166```
167 167 
@@ -262,7 +262,7 @@ OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativ
262 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }262 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
263 ```263 ```
264 264 
265-3. 在NativeEntry.h件中创建Native界面265+3. 在NativeEntry.h中声明桥接函数和Native组生命周期管理类,并在NativeEntry.cpp实现组件的创建、挂载与销毁逻辑
266 266 
267 <!-- @[Cpp_Native](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ButtonList/entry/src/main/cpp/NativeEntry.h) --> 267 <!-- @[Cpp_Native](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ButtonList/entry/src/main/cpp/NativeEntry.h) -->
268 268
@@ -363,7 +363,7 @@ OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativ
363 ```363 ```
364 364
365 365
366- 使用NDK提供的C接口需要在CMakeLists.txt中增加libace_ndk.z.so的引用,如下所示。其中entry为工程导出的动态库名称,如当前示例使用的是默认的名libentry.so。新增cpp文件后,同样需要在CMakeLists.txt中添加相应的cpp文件。若未进行此配置,对应的文件将不会被编译。366+ 使用NDK提供的C接口需要在CMakeLists.txt中增加libace_ndk.z.so的引用,如下所示。其中entry为CMake目标名称,默认生成动态库文件libentry.so。新增cpp文件后,同样需要在CMakeLists.txt中添加相应的cpp文件。若未进行此配置,对应的文件将不会被编译。
367 367
368 ``` c368 ``` c
369 add_library(entry SHARED napi_init.cpp NativeEntry.cpp)369 add_library(entry SHARED napi_init.cpp NativeEntry.cpp)
@@ -11,7 +11,7 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
11 11 
12> **说明:**12> **说明:**
13>13>
14-> - 自定义组件事件注册需要[addNodeCustomEventReceiver](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#addnodecustomeventreceiver)声明监听器注册和[registerNodeCustomEvent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#registernodecustomevent)声明需要的自定义事件类型,监听器只能监听已声明的事件。14+> - 使用自定义组件事件时,需要通过[addNodeCustomEventReceiver](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#addnodecustomeventreceiver)添加事件监听器,并通过[registerNodeCustomEvent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#registernodecustomevent)声明需要监听的自定义事件类型,监听器只能监听已声明的事件。
15> 15>
16> - 需要关注事件的反注册逻辑,如在组件销毁前调用[removeNodeCustomEventReceiver](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#removenodecustomeventreceiver)移除事件监听器,[unregisterNodeCustomEvent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#unregisternodecustomevent)通知ArkUI框架已监听的自定义组件事件不再需要监听。16> - 需要关注事件的反注册逻辑,如在组件销毁前调用[removeNodeCustomEventReceiver](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#removenodecustomeventreceiver)移除事件监听器,[unregisterNodeCustomEvent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#unregisternodecustomevent)通知ArkUI框架已监听的自定义组件事件不再需要监听。
17> 17>
@@ -71,7 +71,7 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
71 void SetPadding(int32_t padding)71 void SetPadding(int32_t padding)
72 {72 {
73 padding_ = padding;73 padding_ = padding;
74- // 自定义属性事件更新需要主动调用标记脏区接口74+ // 自定义布局属性更新后,需要主动标记测算脏区。
75 nativeModule_->markDirty(handle_, NODE_NEED_MEASURE);75 nativeModule_->markDirty(handle_, NODE_NEED_MEASURE);
76 }76 }
77 77
@@ -121,7 +121,7 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
121 maxHeight = size.height;121 maxHeight = size.height;
122 }122 }
123 }123 }
124- // 自定义测算为所有子节点大加固定边距。该自定义节点最终的尺寸以此处设置的值为准。124+ // 自定义测算结果为所有子节点中的最宽度和最大高度分别上两侧固定边距。该自定义节点最终的尺寸以此处设置的值为准。
125 const int paddingMultiplier = 2;125 const int paddingMultiplier = 2;
126 nativeModule_->setMeasuredSize(handle_, maxWidth + paddingMultiplier * padding_,126 nativeModule_->setMeasuredSize(handle_, maxWidth + paddingMultiplier * padding_,
127 maxHeight + paddingMultiplier * padding_);127 maxHeight + paddingMultiplier * padding_);
@@ -537,7 +537,6 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
537 537 
538 // 网格单元配置538 // 网格单元配置
539 struct GridItemConfig {539 struct GridItemConfig {
540- int32_t rowSpan = 1; // 占据的行数
541 int32_t columnSpan = 1; // 占据的列数540 int32_t columnSpan = 1; // 占据的列数
542 };541 };
543 542 
@@ -578,10 +577,9 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
578 }577 }
579 578 
580 // 设置子组件的网格配置579 // 设置子组件的网格配置
581- void SetItemConfig(ArkUI_NodeHandle child, int32_t rowSpan, int32_t columnSpan)580+ void SetItemConfig(ArkUI_NodeHandle child, int32_t columnSpan)
582 {581 {
583 GridItemConfig config;582 GridItemConfig config;
584- config.rowSpan = rowSpan;
585 config.columnSpan = columnSpan;583 config.columnSpan = columnSpan;
586 itemConfigs_[child] = config;584 itemConfigs_[child] = config;
587 nativeModule_->markDirty(handle_, NODE_NEED_MEASURE);585 nativeModule_->markDirty(handle_, NODE_NEED_MEASURE);
@@ -609,7 +607,7 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
609 void MeasureChild(ArkUI_NodeHandle child, int32_t cellWidth,607 void MeasureChild(ArkUI_NodeHandle child, int32_t cellWidth,
610 ArkUI_LayoutConstraint *childConstraint, std::vector<int32_t> &columnHeights)608 ArkUI_LayoutConstraint *childConstraint, std::vector<int32_t> &columnHeights)
611 {609 {
612- GridItemConfig config = {1, 1};610+ GridItemConfig config = {1};
613 auto it = itemConfigs_.find(child);611 auto it = itemConfigs_.find(child);
614 if (it != itemConfigs_.end()) {612 if (it != itemConfigs_.end()) {
615 config = it->second;613 config = it->second;
@@ -838,13 +836,13 @@ ArkUI开发框架在NDK接口提供了自定义UI组件的能力,这些能力
838 const std::vector<uint32_t>& colors)836 const std::vector<uint32_t>& colors)
839 {837 {
840 for (size_t i = 0; i < itemSizes.size(); ++i) {838 for (size_t i = 0; i < itemSizes.size(); ++i) {
841- auto itemNode = nodeAPI->createNode(ARKUI_NODE_STACK);839+ auto itemNode = std::make_shared<ArkUINode>(nodeAPI->createNode(ARKUI_NODE_STACK));
842- SetNodeColorAttribute(nodeAPI, itemNode, colors[i % colors.size()]);840+ SetNodeColorAttribute(nodeAPI, itemNode->GetHandle(), colors[i % colors.size()]);
843- SetNodeBorderRadiusAttribute(nodeAPI, itemNode, GRID_ITEM_RADIUS);841+ SetNodeBorderRadiusAttribute(nodeAPI, itemNode->GetHandle(), GRID_ITEM_RADIUS);
844- SetNodeBorderStyle(nodeAPI, itemNode);842+ SetNodeBorderStyle(nodeAPI, itemNode->GetHandle());
845- SetNodeHeightByRowSpan(nodeAPI, itemNode, itemSizes[i].first);843+ SetNodeHeightByRowSpan(nodeAPI, itemNode->GetHandle(), itemSizes[i].first);
846- gridNode->SetItemConfig(itemNode, itemSizes[i].first, itemSizes[i].second);844+ gridNode->SetItemConfig(itemNode->GetHandle(), itemSizes[i].second);
847- nodeAPI->addChild(gridNode->GetHandle(), itemNode);845+ gridNode->AddChild(itemNode);
848 }846 }
849 }847 }
850 } // namespace848 } // namespace
@@ -88,7 +88,7 @@
88 88 
89## 多线程NDK接口的错误与异常89## 多线程NDK接口的错误与异常
90 90 
91-多线程NDK接口调用规范请参考[多线程NDK接口集合规格](#多线程ndk接口集合规格)。调用多线程NDK接口时必须检查接口返回值如下两种情况接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。91+多线程NDK接口调用规范请参考[多线程NDK接口集合规格](#多线程ndk接口集合规格)。在非UI线程中调用集合中不支持多线程接口,或使用多线程NDK接口操作处于Attached状态的组件时,接口可能返回错误码(如[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode))、空指针、0或默认值,也可能调用不生效,具体行为请参考各接口的多线程规格
92 92 
93- 在非UI线程中调用集合中不支持多线程的接口。93- 在非UI线程中调用集合中不支持多线程的接口。
94 94 
@@ -143,7 +143,7 @@
143| int32_t(\* [insertChildAfter](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#insertchildafter) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) child, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) sibling) | 将child节点挂载到parent节点的子节点列表中,挂载位置在sibling节点之后。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |143| int32_t(\* [insertChildAfter](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#insertchildafter) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) child, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) sibling) | 将child节点挂载到parent节点的子节点列表中,挂载位置在sibling节点之后。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |
144| int32_t(\* [insertChildBefore](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#insertchildbefore) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) child, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) sibling) | 将child节点挂载到parent节点的子节点列表中,挂载位置在sibling节点之前。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |144| int32_t(\* [insertChildBefore](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#insertchildbefore) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) child, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) sibling) | 将child节点挂载到parent节点的子节点列表中,挂载位置在sibling节点之前。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |
145| int32_t(\* [insertChildAt](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#insertchildat) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) child, int32_t position) | 将child节点挂载到parent节点的子节点列表中,挂载位置由position指定。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |145| int32_t(\* [insertChildAt](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#insertchildat) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent, [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) child, int32_t position) | 将child节点挂载到parent节点的子节点列表中,挂载位置由position指定。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |
146-| [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md)(\* [getParent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#getparent) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) node) | 获取node节点的父节点。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |146+| [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md)(\* [getParent](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#getparent) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) node) | 获取node节点的父节点。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回空指针。 |
147| int32_t(\* [removeAllChildren](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#removeallchildren) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent) | 移除parent节点的所有子节点。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |147| int32_t(\* [removeAllChildren](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#removeallchildren) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) parent) | 移除parent节点的所有子节点。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回错误码[ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD](../reference/apis-arkui/capi-arkui-nativemodule-arkui-error-code-h.md#arkui_errorcode)。 |
148| uint32_t(\* [getTotalChildCount](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#gettotalchildcount) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) node) | 获取node节点的子节点个数。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回0。 |148| uint32_t(\* [getTotalChildCount](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#gettotalchildcount) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) node) | 获取node节点的子节点个数。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回0。 |
149| [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md)(\* [getChildAt](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#getchildat) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) node, int32_t position) | 获取node节点的子节点指针,位置由position指定。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回空指针。 |149| [ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md)(\* [getChildAt](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#getchildat) )([ArkUI_NodeHandle](../reference/apis-arkui/capi-arkui-nativemodule-arkui-node8h.md) node, int32_t position) | 获取node节点的子节点指针,位置由position指定。 | 支持 | 在非UI线程调用函数操作Attached节点时,接口返回空指针。 |
@@ -540,7 +540,6 @@ napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info) {
540 result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &g_contextHandle);540 result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &g_contextHandle);
541 if (result != ARKUI_ERROR_CODE_NO_ERROR) {541 if (result != ARKUI_ERROR_CODE_NO_ERROR) {
542 OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result);542 OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result);
543- delete g_contextHandle;
544 g_contextHandle = nullptr;543 g_contextHandle = nullptr;
545 return nullptr;544 return nullptr;
546 }545 }
@@ -71,7 +71,7 @@ ArkUI NDK接口能力主要包括:
71| [构建自定义组件](ndk-build-custom-components.md) | 介绍了如何使用NDK接口能力构建自定义组件,实现差异化UI组件。 |71| [构建自定义组件](ndk-build-custom-components.md) | 介绍了如何使用NDK接口能力构建自定义组件,实现差异化UI组件。 |
72| [嵌入ArkTS组件](ndk-embed-arkts-components.md) | 介绍了如何在Native侧构建带有ArkTS组件的界面。 |72| [嵌入ArkTS组件](ndk-embed-arkts-components.md) | 介绍了如何在Native侧构建带有ArkTS组件的界面。 |
73| [构建渲染节点](ndk-embed-render-components.md) | 介绍了如何在Native侧构建渲染节点。 |73| [构建渲染节点](ndk-embed-render-components.md) | 介绍了如何在Native侧构建渲染节点。 |
74-| [通过自绘制接入无障碍](ndk-accessibility-xcomponent.md) | 介绍了自绘制机制接入的第三方UI框架平台,通过获取AccessibilityProvider如何对接系统无障碍。 |74+| [通过自绘制接入无障碍](ndk-accessibility-xcomponent.md) | 介绍了采用自绘制机制的第三方UI框架如何通过获取AccessibilityProvider对接系统无障碍能力。 |
75| [自定义绘制](arkts-user-defined-draw.md) | 介绍了如何使用自定义绘制能力,实现自定义内容的绘制。 |75| [自定义绘制](arkts-user-defined-draw.md) | 介绍了如何使用自定义绘制能力,实现自定义内容的绘制。 |
76| [查询和操作自定义节点](ndk-node-query-operate.md) | 介绍了如何对自定义节点进行查询和操作。 |76| [查询和操作自定义节点](ndk-node-query-operate.md) | 介绍了如何对自定义节点进行查询和操作。 |
77| [通过EmbeddedComponent拉起EmbeddedUIExtensionAbility](ndk-embedded-component.md) | 介绍了如何在Native侧通过EmbeddedComponent拉起EmbeddedUIExtensionAbility。主要用于有进程隔离需求的模块化开发场景。 |77| [通过EmbeddedComponent拉起EmbeddedUIExtensionAbility](ndk-embedded-component.md) | 介绍了如何在Native侧通过EmbeddedComponent拉起EmbeddedUIExtensionAbility。主要用于有进程隔离需求的模块化开发场景。 |
@@ -82,4 +82,4 @@ ArkUI NDK接口能力主要包括:
82 82 
83## 注意事项83## 注意事项
84 84 
85-使用NDK接口开发UI界面时,需要保证相关UI接口调用在应用主线程调用,避免线程操作导致应用崩溃问题85+使用NDK接口开发UI界面时,应遵循各接口的线程约束;除明确支持多线程调用的接口外,需要在应用主线程调用相关UI接口,避免因违反接口线程约束而导致应用崩溃。
@@ -90,9 +90,9 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
90 // 定义创建函数的返回值,用于ArkTS侧和Native侧的交互。90 // 定义创建函数的返回值,用于ArkTS侧和Native侧的交互。
91 interface MixedModuleResult {91 interface MixedModuleResult {
92 // 定义针对Refresh构建函数的封装对象,用于Native侧转化为ArkUI_NodeHandle对象。92 // 定义针对Refresh构建函数的封装对象,用于Native侧转化为ArkUI_NodeHandle对象。
93- content?: ComponentContent<RefreshAttribute>;93+ content: ComponentContent<RefreshAttribute>;
94 // Refresh作为容器组件,需要使用ContentSlot机制挂载Native侧的子组件。94 // Refresh作为容器组件,需要使用ContentSlot机制挂载Native侧的子组件。
95- childSlot?: NodeContent;95+ childSlot: NodeContent;
96 }96 }
97 97
98 // 提供创建ArkTS组件的入口函数。98 // 提供创建ArkTS组件的入口函数。
@@ -101,19 +101,19 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
101 // 通过AppStorage对象在Ability启动的时候保持UI上下文对象。101 // 通过AppStorage对象在Ability启动的时候保持UI上下文对象。
102 let uiContent = AppStorage.get<UIContext>('context');102 let uiContent = AppStorage.get<UIContext>('context');
103 let modifier = new RefreshModifier();103 let modifier = new RefreshModifier();
104- if (value.width) {104+ if (value.width !== undefined) {
105 modifier.width(value.width);105 modifier.width(value.width);
106 }106 }
107- if (value.height) {107+ if (value.height !== undefined) {
108 modifier.height(value.height);108 modifier.height(value.height);
109 }109 }
110- if (value.backgroundColor) {110+ if (value.backgroundColor !== undefined) {
111 modifier.backgroundColor(value.backgroundColor);111 modifier.backgroundColor(value.backgroundColor);
112 }112 }
113- if (value.pullToRefresh) {113+ if (value.pullToRefresh !== undefined) {
114 modifier.pullToRefresh(value.pullToRefresh);114 modifier.pullToRefresh(value.pullToRefresh);
115 }115 }
116- if (value.refreshOffset) {116+ if (value.refreshOffset !== undefined) {
117 modifier.refreshOffset(value.refreshOffset);117 modifier.refreshOffset(value.refreshOffset);
118 }118 }
119 // 创建NodeContent插槽对象用于Refresh子组件挂载。119 // 创建NodeContent插槽对象用于Refresh子组件挂载。
@@ -132,23 +132,23 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
132 }132 }
133 133
134 // 定义Refresh组件的更新函数,用于Native侧更新。134 // 定义Refresh组件的更新函数,用于Native侧更新。
135- // 在更新场景下,需要将Refresh组件的封装对象及其子组件插槽对象返回,防止组件重新创建。135+ // 在更新场景下,需要将Refresh组件的封装对象及其子组件插槽对象传入更新函数并复用,防止组件重新创建。
136 export function updateMixedRefresh(refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent,136 export function updateMixedRefresh(refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent,
137 value: NativeRefreshAttribute): void {137 value: NativeRefreshAttribute): void {
138 let modifier = new RefreshModifier();138 let modifier = new RefreshModifier();
139- if (value.width) {139+ if (value.width !== undefined) {
140 modifier.width(value.width);140 modifier.width(value.width);
141 }141 }
142- if (value.height) {142+ if (value.height !== undefined) {
143 modifier.height(value.height);143 modifier.height(value.height);
144 }144 }
145- if (value.backgroundColor) {145+ if (value.backgroundColor !== undefined) {
146 modifier.backgroundColor(value.backgroundColor);146 modifier.backgroundColor(value.backgroundColor);
147 }147 }
148- if (value.pullToRefresh) {148+ if (value.pullToRefresh !== undefined) {
149 modifier.pullToRefresh(value.pullToRefresh);149 modifier.pullToRefresh(value.pullToRefresh);
150 }150 }
151- if (value.refreshOffset) {151+ if (value.refreshOffset !== undefined) {
152 modifier.refreshOffset(value.refreshOffset);152 modifier.refreshOffset(value.refreshOffset);
153 }153 }
154 // 调用ComponentContent的update接口进行更新。154 // 调用ComponentContent的update接口进行更新。
@@ -349,7 +349,7 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
349 include_directories(${NATIVERENDER_ROOT_PATH}349 include_directories(${NATIVERENDER_ROOT_PATH}
350 ${NATIVERENDER_ROOT_PATH}/include)350 ${NATIVERENDER_ROOT_PATH}/include)
351 351
352- add_library(entry SHARED NativeEntry.cpp ArkUIMixedRefresh.cpp NapiInit.cpp)352+ add_library(entry SHARED NativeEntry.cpp ArkUIMixedRefresh.cpp NapiInit.cpp UITimer.cpp)
353 # target_link_libraries(entry PUBLIC libace_napi.z.so, libace_ndk.z.so, libhilog_ndk.z.so)353 # target_link_libraries(entry PUBLIC libace_napi.z.so, libace_ndk.z.so, libhilog_ndk.z.so)
354 354
355 find_library(355 find_library(
@@ -445,7 +445,7 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
445 445
446 // 定义Native侧和ArkTS侧的交互数据结构。446 // 定义Native侧和ArkTS侧的交互数据结构。
447 struct NativeRefreshAttribute {447 struct NativeRefreshAttribute {
448- std::optional<bool> isRefreshing;448+ std::optional<bool> isRefreshing = false;
449 std::optional<float> width;449 std::optional<float> width;
450 std::optional<float> height;450 std::optional<float> height;
451 std::optional<uint32_t> backgroundColor;451 std::optional<uint32_t> backgroundColor;
@@ -464,9 +464,15 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
464 napi_ref componentContent, napi_ref nodeContent)464 napi_ref componentContent, napi_ref nodeContent)
465 : ArkUIMixedNode(handle, env, componentContent), contentHandle_(contentHandle), nodeContent_(nodeContent) {}465 : ArkUIMixedNode(handle, env, componentContent), contentHandle_(contentHandle), nodeContent_(nodeContent) {}
466 466
467- ArkUIMixedRefresh() : ArkUIMixedNode(nullptr, nullptr, nullptr) {}467+ ArkUIMixedRefresh()
468+ : ArkUIMixedNode(nullptr, nullptr, nullptr), contentHandle_(nullptr), nodeContent_(nullptr) {}
468 469
469- ~ArkUIMixedRefresh() override { napi_delete_reference(env_, nodeContent_); } // 释放子节点占位组件插槽对象。470+ ~ArkUIMixedRefresh() override
471+ {
472+ if (env_ != nullptr && nodeContent_ != nullptr) {
473+ napi_delete_reference(env_, nodeContent_);
474+ }
475+ } // 释放子节点占位组件插槽对象。
470 476
471 void SetWidth(float width) { attribute_.width = width; }477 void SetWidth(float width) { attribute_.width = width; }
472 478
@@ -569,12 +575,12 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
569 }575 }
570 if (attribute.pullToRefresh) {576 if (attribute.pullToRefresh) {
571 napi_value pullToRefresh;577 napi_value pullToRefresh;
572- napi_create_int32(g_env, attribute.pullToRefresh.value(), &pullToRefresh);578+ napi_get_boolean(g_env, attribute.pullToRefresh.value(), &pullToRefresh);
573 desc[REFRESH_OFFSET_INDEX3].value = pullToRefresh;579 desc[REFRESH_OFFSET_INDEX3].value = pullToRefresh;
574 }580 }
575 if (attribute.isRefreshing) {581 if (attribute.isRefreshing) {
576 napi_value isRefreshing;582 napi_value isRefreshing;
577- napi_create_int32(g_env, attribute.isRefreshing.value(), &isRefreshing);583+ napi_get_boolean(g_env, attribute.isRefreshing.value(), &isRefreshing);
578 desc[REFRESH_OFFSET_INDEX4].value = isRefreshing;584 desc[REFRESH_OFFSET_INDEX4].value = isRefreshing;
579 }585 }
580 if (attribute.refreshOffset) {586 if (attribute.refreshOffset) {
@@ -659,13 +665,21 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
659 // 获取ArkTS的Refresh组件。665 // 获取ArkTS的Refresh组件。
660 napi_value componentContent = nullptr;666 napi_value componentContent = nullptr;
661 napi_get_named_property(g_env, result, "content", &componentContent);667 napi_get_named_property(g_env, result, "content", &componentContent);
662- ArkUI_NodeHandle handle;668+ ArkUI_NodeHandle handle = nullptr;
663- OH_ArkUI_GetNodeHandleFromNapiValue(g_env, componentContent, &handle);669+ auto code = OH_ArkUI_GetNodeHandleFromNapiValue(g_env, componentContent, &handle);
670+ if (code != ARKUI_ERROR_CODE_NO_ERROR) {
671+ napi_close_handle_scope(g_env, scope);
672+ return nullptr;
673+ }
664 // 获取ArkTS的Refresh组件的子组件插槽。674 // 获取ArkTS的Refresh组件的子组件插槽。
665 napi_value nodeContent = nullptr;675 napi_value nodeContent = nullptr;
666 napi_get_named_property(g_env, result, "childSlot", &nodeContent);676 napi_get_named_property(g_env, result, "childSlot", &nodeContent);
667- ArkUI_NodeContentHandle contentHandle;677+ ArkUI_NodeContentHandle contentHandle = nullptr;
668- OH_ArkUI_GetNodeContentFromNapiValue(g_env, nodeContent, &contentHandle);678+ code = OH_ArkUI_GetNodeContentFromNapiValue(g_env, nodeContent, &contentHandle);
679+ if (code != ARKUI_ERROR_CODE_NO_ERROR) {
680+ napi_close_handle_scope(g_env, scope);
681+ return nullptr;
682+ }
669 // 保存ArkTS的ComponentContent用于防止ArkTS侧对象释放以及后续的更新。683 // 保存ArkTS的ComponentContent用于防止ArkTS侧对象释放以及后续的更新。
670 napi_ref componentContentRef;684 napi_ref componentContentRef;
671 napi_create_reference(g_env, componentContent, 1, &componentContentRef);685 napi_create_reference(g_env, componentContent, 1, &componentContentRef);
@@ -742,83 +756,123 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
742 ```756 ```
743 757 
7446. 定时器模块相关简单实现。7586. 定时器模块相关简单实现。
745- <!-- @[ui_timer](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NativeType/NdkEmbedArktsComponents/entry/src/main/cpp/UITimer.h) -->759+ <!-- @[ui_timer](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NativeType/NdkEmbedArktsComponents/entry/src/main/cpp/UITimer.cpp) -->
746 760
747- ``` C761+ ``` C++
748- // UITimer.h762+ // UITimer.cpp
749 // 定时器模块。763 // 定时器模块。
750 764
751- #ifndef MYAPPLICATION_UITIMER_H765+ #include "UITimer.h"
752- #define MYAPPLICATION_UITIMER_H
753 766
754 #include <hilog/log.h>767 #include <hilog/log.h>
755- #include <js_native_api.h>
756- #include <js_native_api_types.h>
757- #include <node_api.h>
758- #include <node_api_types.h>
759 #include <string>768 #include <string>
760 #include <thread>769 #include <thread>
761 #include <uv.h>770 #include <uv.h>
762 771
763 namespace NativeModule {772 namespace NativeModule {
764- 773+ namespace {
765 struct UIData {774 struct UIData {
766- void *userData = nullptr;775+ std::weak_ptr<ArkUIMixedRefresh> refresh;
767 int32_t count = 0;776 int32_t count = 0;
768 int32_t totalCount = 0;777 int32_t totalCount = 0;
769- void (*func)(void *userData, int32_t count) = nullptr;778+ TimerCallback func = nullptr;
779+ napi_threadsafe_function threadSafeFunction = nullptr;
770 };780 };
771 781
772- napi_threadsafe_function threadSafeFunction = nullptr;782+ void DeleteTimerHandle(uv_handle_t *handle)
773-
774- void CreateNativeTimer(napi_env env, void *userData, int32_t totalCount, void (*func)(void *userData, int32_t count))
775 {783 {
776- napi_value name;784+ delete reinterpret_cast<uv_timer_t *>(handle);
777- std::string str = "UICallback";785+ }
778- napi_create_string_utf8(env, str.c_str(), str.size(), &name);786+
779- // UI主线程回调函数。787+ void CloseTimer(uv_timer_t *timer)
780- napi_create_threadsafe_function(788+ {
781- env, nullptr, nullptr, name, 0, 1, nullptr, nullptr, nullptr,789+ uv_timer_stop(timer);
782- [](napi_env env, napi_value value, void *context, void *data) {790+ uv_close(reinterpret_cast<uv_handle_t *>(timer), DeleteTimerHandle);
783- auto userdata = reinterpret_cast<UIData *>(data);791+ }
784- userdata->func(userdata->userData, userdata->count);792+
785- delete userdata;793+ void CallRefreshOnUI(napi_env, napi_value, void *, void *data)
786- },794+ {
787- &threadSafeFunction);795+ auto *callbackData = reinterpret_cast<UIData *>(data);
788- // 启动定时器,模拟数据变化。796+ auto refresh = callbackData->refresh.lock();
789- std::thread timerThread([data = userData, totalCount, func]() {797+ if (refresh != nullptr && callbackData->func != nullptr) {
790- uv_loop_t *loop = uv_loop_new();798+ callbackData->func(refresh, callbackData->count);
791- uv_timer_t *timer = new uv_timer_t();799+ }
792- uv_timer_init(loop, timer);800+ delete callbackData;
793- timer->data = new UIData{data, 0, totalCount, func};801+ }
794- uint64_t timeout = 4000;802+
795- uint64_t repeat = 4000;803+ napi_status CreateTimerThreadSafeFunction(napi_env env, UIData *customData)
796- uv_timer_start(804+ {
797- timer,805+ napi_value name = nullptr;
798- [](uv_timer_t *handle) {806+ const std::string callbackName = "UICallback";
799- OH_LOG_INFO(LOG_APP, "on timeout");807+ auto status = napi_create_string_utf8(env, callbackName.c_str(), callbackName.size(), &name);
800- napi_acquire_threadsafe_function(threadSafeFunction);808+ if (status != napi_ok) {
801- auto *customData = reinterpret_cast<UIData *>(handle->data);809+ return status;
802- // 创建回调数据。810+ }
803- auto *callbackData =811+ return napi_create_threadsafe_function(env, nullptr, nullptr, name, 0, 1, nullptr, nullptr, nullptr,
804- new UIData{customData->userData, customData->count, customData->totalCount, customData->func};812+ CallRefreshOnUI, &customData->threadSafeFunction);
805- napi_call_threadsafe_function(threadSafeFunction, callbackData, napi_tsfn_blocking);813+ }
806- customData->count++;814+
807- if (customData->count > customData->totalCount) {815+ void OnTimer(uv_timer_t *timer)
808- uv_timer_stop(handle);816+ {
809- delete handle;817+ OH_LOG_INFO(LOG_APP, "on timeout");
810- delete customData;818+ auto *customData = reinterpret_cast<UIData *>(timer->data);
811- }819+ auto *callbackData = new UIData(*customData);
812- },820+ if (napi_call_threadsafe_function(customData->threadSafeFunction, callbackData,
813- timeout, repeat);821+ napi_tsfn_blocking) != napi_ok) {
814- uv_run(loop, UV_RUN_DEFAULT);822+ delete callbackData;
823+ }
824+ customData->count++;
825+ if (customData->count <= customData->totalCount) {
826+ return;
827+ }
828+ CloseTimer(timer);
829+ }
830+
831+ void ReleaseTimerData(UIData *customData)
832+ {
833+ napi_release_threadsafe_function(customData->threadSafeFunction, napi_tsfn_release);
834+ delete customData;
835+ }
836+
837+ void RunTimer(UIData *customData)
838+ {
839+ uv_loop_t *loop = uv_loop_new();
840+ if (loop == nullptr) {
841+ ReleaseTimerData(customData);
842+ return;
843+ }
844+ auto *timer = new uv_timer_t();
845+ if (uv_timer_init(loop, timer) != 0) {
846+ delete timer;
847+ ReleaseTimerData(customData);
815 uv_loop_delete(loop);848 uv_loop_delete(loop);
816- });849+ return;
850+ }
851+ timer->data = customData;
852+ constexpr uint64_t timeout = 4000;
853+ constexpr uint64_t repeat = 4000;
854+ if (uv_timer_start(timer, OnTimer, timeout, repeat) != 0) {
855+ CloseTimer(timer);
856+ }
857+ uv_run(loop, UV_RUN_DEFAULT);
858+ ReleaseTimerData(customData);
859+ uv_loop_delete(loop);
860+ }
861+ } // namespace
862+
863+ void CreateNativeTimer(napi_env env, const std::weak_ptr<ArkUIMixedRefresh> &refresh, int32_t totalCount,
864+ TimerCallback func)
865+ {
866+ auto *customData = new UIData {refresh, 0, totalCount, func, nullptr};
867+ if (CreateTimerThreadSafeFunction(env, customData) != napi_ok) {
868+ delete customData;
869+ return;
870+ }
871+ // 启动定时器,模拟数据变化。
872+ std::thread timerThread(RunTimer, customData);
817 timerThread.detach();873 timerThread.detach();
818 }874 }
819 } // namespace NativeModule875 } // namespace NativeModule
820-
821- #endif // MYAPPLICATION_UITIMER_H
822 ```876 ```
823 877 
8247. 使用[接入ArkTS页面](ndk-access-the-arkts-page.md)章节的页面结构,将Refresh组件作为文本列表的父组件。8787. 使用[接入ArkTS页面](ndk-access-the-arkts-page.md)章节的页面结构,将Refresh组件作为文本列表的父组件。
@@ -847,20 +901,26 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
847 NativeRefreshAttribute nativeRefreshAttribute{901 NativeRefreshAttribute nativeRefreshAttribute{
848 .backgroundColor = 0xFF89CFF0, .refreshOffset = 64, .pullToRefresh = true};902 .backgroundColor = 0xFF89CFF0, .refreshOffset = 64, .pullToRefresh = true};
849 auto refresh = ArkUIMixedRefresh::Create(nativeRefreshAttribute);903 auto refresh = ArkUIMixedRefresh::Create(nativeRefreshAttribute);
904+ if (refresh == nullptr) {
905+ return nullptr;
906+ }
850 refresh->AddChild(list);907 refresh->AddChild(list);
851 908
852 // 设置混合模式下的事件。909 // 设置混合模式下的事件。
853 refresh->SetOnOffsetChange(910 refresh->SetOnOffsetChange(
854 [](float offset) { OH_LOG_INFO(LOG_APP, "on refresh offset changed: %{public}f", offset); });911 [](float offset) { OH_LOG_INFO(LOG_APP, "on refresh offset changed: %{public}f", offset); });
855- refresh->SetRefreshCallback([refreshPtr = refresh.get(), env]() {912+ std::weak_ptr<ArkUIMixedRefresh> weakRefresh = refresh;
913+ refresh->SetRefreshCallback([weakRefresh, env]() {
856 OH_LOG_INFO(LOG_APP, "on refreshing");914 OH_LOG_INFO(LOG_APP, "on refreshing");
857- // 启动定时器,模拟数据获取。915+ if (auto refresh = weakRefresh.lock()) {
858- CreateNativeTimer(env, refreshPtr, 1, [](void *userData, int32_t count) {916+ // 启动定时器,模拟数据获取;定时器只保存弱引用,避免访问已销毁的Refresh对象。
859- // 数据获取后关闭刷新。917+ CreateNativeTimer(env, weakRefresh, 1,
860- auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(userData);918+ [](const std::shared_ptr<ArkUIMixedRefresh> &refresh, int32_t count) {
861- refresh->SetRefreshState(false);919+ // 数据获取后关闭刷新。
862- refresh->FlushMixedModeCmd();920+ refresh->SetRefreshState(false);
863- });921+ refresh->FlushMixedModeCmd();
922+ });
923+ }
864 });924 });
865 925
866 // 更新事件到ArkTS侧。926 // 更新事件到ArkTS侧。
@@ -901,12 +961,18 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
901 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);961 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
902 962
903 // 获取NodeContent963 // 获取NodeContent
904- ArkUI_NodeContentHandle contentHandle;964+ ArkUI_NodeContentHandle contentHandle = nullptr;
905- OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);965+ auto code = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
966+ if (code != ARKUI_ERROR_CODE_NO_ERROR) {
967+ return nullptr;
968+ }
906 NativeEntry::GetInstance()->SetContentHandle(contentHandle);969 NativeEntry::GetInstance()->SetContentHandle(contentHandle);
907 970
908 // 创建Refresh文本列表971 // 创建Refresh文本列表
909 auto refresh = CreateMixedRefreshList(env);972 auto refresh = CreateMixedRefreshList(env);
973+ if (refresh == nullptr) {
974+ return nullptr;
975+ }
910 976
911 // 保持Native侧对象到管理类中,维护生命周期。977 // 保持Native侧对象到管理类中,维护生命周期。
912 NativeEntry::GetInstance()->SetRootNode(refresh);978 NativeEntry::GetInstance()->SetRootNode(refresh);
@@ -927,9 +993,38 @@ ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Nati
927 <!-- @[bridge_index](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NativeType/NdkEmbedArktsComponents/entry/src/main/cpp/types/libentry/Index.d.ts) -->993 <!-- @[bridge_index](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NativeType/NdkEmbedArktsComponents/entry/src/main/cpp/types/libentry/Index.d.ts) -->
928 994
929 ``` TypeScript995 ``` TypeScript
930- export const createNativeRoot: (content: Object) => void;996+ import { ComponentContent, NodeContent, RefreshModifier } from '@kit.ArkUI';
997+ 
998+ interface NativeRefreshAttribute {
999+ isRefreshing: boolean;
1000+ width?: number;
1001+ height?: number;
1002+ backgroundColor?: number;
1003+ refreshOffset?: number;
1004+ pullToRefresh?: boolean;
1005+ onRefreshing?: () => void;
1006+ onOffsetChange?: (offset: number) => void;
1007+ }
1008+ 
1009+ interface RefreshAttribute {
1010+ isRefreshing: boolean;
1011+ modifier?: RefreshModifier;
1012+ slot?: NodeContent;
1013+ onRefreshing?: () => void;
1014+ onOffsetChange?: (offset: number) => void;
1015+ }
1016+ 
1017+ interface MixedModuleResult {
1018+ content: ComponentContent<RefreshAttribute>;
1019+ childSlot: NodeContent;
1020+ }
1021+ 
1022+ export const createNativeRoot: (content: NodeContent) => void;
931 export const destroyNativeRoot: () => void;1023 export const destroyNativeRoot: () => void;
932- 1024+ 
933- export const registerCreateMixedRefreshNode: (content: Object) => void;1025+ export const registerCreateMixedRefreshNode: (
934- export const registerUpdateMixedRefreshNode: (content: Object) => void;1026+ callback: (value: NativeRefreshAttribute) => MixedModuleResult) => void;
1027+ export const registerUpdateMixedRefreshNode: (
1028+ callback: (refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent,
1029+ value: NativeRefreshAttribute) => void) => void;
935 ```1030 ```
@@ -43,6 +43,32 @@
43 #include <native_drawing/drawing_path.h>43 #include <native_drawing/drawing_path.h>
44 #include <native_drawing/drawing_pen.h>44 #include <native_drawing/drawing_pen.h>
45 45
46+ // 渲染节点需要在宿主节点销毁后显式释放,避免只销毁FrameNode而泄漏RenderNode。
47+ struct BasicRenderNodeResources {
48+ ArkUI_RenderNodeHandle renderRootNode = nullptr;
49+ ArkUI_RenderNodeHandle firstChildRenderNode = nullptr;
50+ ArkUI_RenderNodeHandle secondChildRenderNode = nullptr;
51+ ArkUI_RenderNodeHandle thirdChildRenderNode = nullptr;
52+ 
53+ ~BasicRenderNodeResources()
54+ {
55+ if (thirdChildRenderNode != nullptr) {
56+ OH_ArkUI_RenderNodeUtils_DisposeNode(thirdChildRenderNode);
57+ }
58+ if (secondChildRenderNode != nullptr) {
59+ OH_ArkUI_RenderNodeUtils_DisposeNode(secondChildRenderNode);
60+ }
61+ if (firstChildRenderNode != nullptr) {
62+ OH_ArkUI_RenderNodeUtils_DisposeNode(firstChildRenderNode);
63+ }
64+ if (renderRootNode != nullptr) {
65+ OH_ArkUI_RenderNodeUtils_DisposeNode(renderRootNode);
66+ }
67+ }
68+ };
69+ 
70+ static BasicRenderNodeResources *g_basicRenderNodeResources = nullptr;
71+ 
46 ArkUI_NodeHandle testRenderNode(ArkUI_NativeNodeAPI_1 *nodeAPI) {72 ArkUI_NodeHandle testRenderNode(ArkUI_NativeNodeAPI_1 *nodeAPI) {
47 // 创建NDK原有容器逻辑。73 // 创建NDK原有容器逻辑。
48 ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL);74 ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL);
@@ -56,7 +82,7 @@
56 nodeAPI->setAttribute(column, NODE_WIDTH, &itemWidth);82 nodeAPI->setAttribute(column, NODE_WIDTH, &itemWidth);
57 nodeAPI->setAttribute(column, NODE_HEIGHT, &itemHeight);83 nodeAPI->setAttribute(column, NODE_HEIGHT, &itemHeight);
58 ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT);84 ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT);
59- ArkUI_AttributeItem content = {.string = "黄色背景是C-API页面"};85+ ArkUI_AttributeItem content = {.string = "是C-API页面"};
60 nodeAPI->setAttribute(text, NODE_TEXT_CONTENT, &content);86 nodeAPI->setAttribute(text, NODE_TEXT_CONTENT, &content);
61 nodeAPI->addChild(column, text);87 nodeAPI->addChild(column, text);
62 88
@@ -73,10 +99,16 @@
73 auto firstChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();99 auto firstChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
74 auto secondChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();100 auto secondChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
75 auto thirdChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();101 auto thirdChildRenderNode = OH_ArkUI_RenderNodeUtils_CreateNode();
102+ 
103+ delete g_basicRenderNodeResources;
104+ g_basicRenderNodeResources = new BasicRenderNodeResources {
105+ renderRootNode, firstChildRenderNode, secondChildRenderNode, thirdChildRenderNode};
76 106
77 auto result = OH_ArkUI_RenderNodeUtils_AddRenderNode(Custom, renderRootNode);107 auto result = OH_ArkUI_RenderNodeUtils_AddRenderNode(Custom, renderRootNode);
78 if (result != ARKUI_ERROR_CODE_NO_ERROR) {108 if (result != ARKUI_ERROR_CODE_NO_ERROR) {
79 // 通过错误码判断根节点是否挂载成功。109 // 通过错误码判断根节点是否挂载成功。
110+ delete g_basicRenderNodeResources;
111+ g_basicRenderNodeResources = nullptr;
80 return scroll;112 return scroll;
81 }113 }
82 114
@@ -149,6 +181,14 @@
149 NativeEntry::GetInstance()->SetRootNode(testNode);181 NativeEntry::GetInstance()->SetRootNode(testNode);
150 return nullptr;182 return nullptr;
151 }183 }
184+ 
185+ napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
186+ // 先销毁宿主节点,再释放其挂载的RenderNode树。
187+ NativeEntry::GetInstance()->DisposeRootNode();
188+ delete g_basicRenderNodeResources;
189+ g_basicRenderNodeResources = nullptr;
190+ return nullptr;
191+ }
152 192
153 ```193 ```
154 194 
@@ -214,15 +254,17 @@
214 254
215 ArkUI_NodeHandle testRenderNode2(ArkUI_NativeNodeAPI_1 *nodeAPI, ArkUI_ContextHandle context) {255 ArkUI_NodeHandle testRenderNode2(ArkUI_NativeNodeAPI_1 *nodeAPI, ArkUI_ContextHandle context) {
216 256
217- ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_COLUMN);257+ ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL);
218 ArkUI_NumberValue valueWidth[] = {400};258 ArkUI_NumberValue valueWidth[] = {400};
219 ArkUI_AttributeItem itemWidth = {valueWidth, sizeof(valueWidth) / sizeof(ArkUI_NumberValue)};259 ArkUI_AttributeItem itemWidth = {valueWidth, sizeof(valueWidth) / sizeof(ArkUI_NumberValue)};
220 nodeAPI->setAttribute(scroll, NODE_WIDTH, &itemWidth);260 nodeAPI->setAttribute(scroll, NODE_WIDTH, &itemWidth);
221 ArkUI_NumberValue valueHeight[] = {600};261 ArkUI_NumberValue valueHeight[] = {600};
222 ArkUI_AttributeItem itemHeight = {valueHeight, sizeof(valueHeight) / sizeof(ArkUI_NumberValue)};262 ArkUI_AttributeItem itemHeight = {valueHeight, sizeof(valueHeight) / sizeof(ArkUI_NumberValue)};
223 nodeAPI->setAttribute(scroll, NODE_HEIGHT, &itemHeight);263 nodeAPI->setAttribute(scroll, NODE_HEIGHT, &itemHeight);
224- valueHeight[0].u32 = 0xff00F100;264+ ArkUI_NumberValue valueBackgroundColor[] = {{.u32 = 0xff00F100}};
225- nodeAPI->setAttribute(scroll, NODE_BACKGROUND_COLOR, &itemHeight);265+ ArkUI_AttributeItem itemBackgroundColor = {
266+ valueBackgroundColor, sizeof(valueBackgroundColor) / sizeof(ArkUI_NumberValue)};
267+ nodeAPI->setAttribute(scroll, NODE_BACKGROUND_COLOR, &itemBackgroundColor);
226 268
227 ArkUI_NodeHandle column = nodeAPI->createNode(ARKUI_NODE_COLUMN);269 ArkUI_NodeHandle column = nodeAPI->createNode(ARKUI_NODE_COLUMN);
228 ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT);270 ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT);
@@ -244,7 +286,7 @@
244 resources->v2 = OH_ArkUI_RenderNodeUtils_CreateVector2AnimatableProperty(1000, 1000);286 resources->v2 = OH_ArkUI_RenderNodeUtils_CreateVector2AnimatableProperty(1000, 1000);
245 resources->color = OH_ArkUI_RenderNodeUtils_CreateColorAnimatableProperty(0xFFFF11FF);287 resources->color = OH_ArkUI_RenderNodeUtils_CreateColorAnimatableProperty(0xFFFF11FF);
246 288
247- // 关联组件和多个modifier。289+ // 将渲染节点与一个modifier关联
248 resources->modifier = OH_ArkUI_RenderNodeUtils_CreateContentModifier();290 resources->modifier = OH_ArkUI_RenderNodeUtils_CreateContentModifier();
249 OH_ArkUI_RenderNodeUtils_AttachContentModifier(resources->renderNode, resources->modifier);291 OH_ArkUI_RenderNodeUtils_AttachContentModifier(resources->renderNode, resources->modifier);
250 // 关联modifier和property。292 // 关联modifier和property。
@@ -392,7 +434,7 @@
392 434 
393节点处于被接纳的附属节点状态下,允许调用[OH_ArkUI_RenderNodeUtils_GetRenderNode](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_getrendernode)获取它对应的RenderNode。435节点处于被接纳的附属节点状态下,允许调用[OH_ArkUI_RenderNodeUtils_GetRenderNode](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_getrendernode)获取它对应的RenderNode。
394 436 
395-调用[ArkUI_NativeNodeAPI_1](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md)的[disposeNode](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#disposenode)接口主动销毁节点时,需要额外调用[OH_ArkUI_RenderNodeUtils_DisposeNode](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_disposenode)释放该渲染节点,否则会发生内存泄漏。437+调用[ArkUI_NativeNodeAPI_1](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md)的[disposeNode](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#disposenode)接口主动销毁该附属节点对应的FrameNode时,需要额外调用[OH_ArkUI_RenderNodeUtils_DisposeNode](../reference/apis-arkui/capi-native-render-h.md#oh_arkui_rendernodeutils_disposenode)释放该渲染节点,否则会发生内存泄漏。
396 438 
397 439 
398### 操作来自附属节点的渲染节点440### 操作来自附属节点的渲染节点
@@ -496,7 +538,6 @@
496 // 定义传递参数的接口538 // 定义传递参数的接口
497 interface ParamsInterface {539 interface ParamsInterface {
498 text: string;540 text: string;
499- func: Function;
500 }541 }
501 class MyNodeController extends NodeController {542 class MyNodeController extends NodeController {
502 private imperativeNode: FrameNode | null = null;543 private imperativeNode: FrameNode | null = null;
@@ -515,27 +556,25 @@
515 let buildNode = new BuilderNode<[ParamsInterface]>(uiContext);556 let buildNode = new BuilderNode<[ParamsInterface]>(uiContext);
516 // 创建节点树557 // 创建节点树
517 buildNode.build(wrapBuilder<[ParamsInterface]>(buildText), {558 buildNode.build(wrapBuilder<[ParamsInterface]>(buildText), {
518- text: message, func: () => {559+ text: message
519- return 'FUNCTION';
520- }
521 }, { nestingBuilderSupported: true });560 }, { nestingBuilderSupported: true });
522 this.buildNode = buildNode.getFrameNode();561 this.buildNode = buildNode.getFrameNode();
523 entry.adopt(buildNode);562 entry.adopt(buildNode);
524 }563 }
525- removeAdoptedNode(uiContext:UIContext):void {564+ removeAdoptedNode(): void {
526 entry.removeAdopt();565 entry.removeAdopt();
527 }566 }
528 }567 }
529 568
530 @Builder569 @Builder
531- function buildTextWithFunc(fun: Function) {570+ function buildTextWithFunc() {
532 Web({ src: 'https://www.example.com', controller: new webview.WebviewController() })571 Web({ src: 'https://www.example.com', controller: new webview.WebviewController() })
533 }572 }
534 573
535 @Builder574 @Builder
536 function buildText(params: ParamsInterface) {575 function buildText(params: ParamsInterface) {
537 Column() {576 Column() {
538- buildTextWithFunc(params.func)577+ buildTextWithFunc()
539 }578 }
540 }579 }
541 580
@@ -585,7 +624,7 @@
585 Button(this.adoptmsg)624 Button(this.adoptmsg)
586 .onClick(() => {625 .onClick(() => {
587 if (this.isAdopt) {626 if (this.isAdopt) {
588- this.myNodeController.removeAdoptedNode(this.getUIContext());627+ this.myNodeController.removeAdoptedNode();
589 this.adoptmsg = 'adopt web component';628 this.adoptmsg = 'adopt web component';
590 } else {629 } else {
591 this.myNodeController.adoptNode(this.getUIContext(),this.message);630 this.myNodeController.adoptNode(this.getUIContext(),this.message);
@@ -613,14 +652,27 @@
613 size_t argc = 1;652 size_t argc = 1;
614 napi_value args[1] = {nullptr};653 napi_value args[1] = {nullptr};
615 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);654 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
616- // 获取ArkTS侧组件挂载点。655+ // 获取ArkTS侧句柄
617 int32_t result = OH_ArkUI_GetNodeHandleFromNapiValue(env, args[0], &nodeHandle_);656 int32_t result = OH_ArkUI_GetNodeHandleFromNapiValue(env, args[0], &nodeHandle_);
618 if (result != ARKUI_ERROR_CODE_NO_ERROR) {657 if (result != ARKUI_ERROR_CODE_NO_ERROR) {
619 return nullptr;658 return nullptr;
620 }659 }
621 result = OH_ArkUI_NativeModule_AdoptChild(custom_->GetHandle(), nodeHandle_);660 result = OH_ArkUI_NativeModule_AdoptChild(custom_->GetHandle(), nodeHandle_);
622- OH_ArkUI_RenderNodeUtils_GetRenderNode(nodeHandle_, &renderHandle_);661+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
623- OH_ArkUI_RenderNodeUtils_AddChild(render_->GetHandle(), renderHandle_);662+ return nullptr;
663+ }
664+ result = OH_ArkUI_RenderNodeUtils_GetRenderNode(nodeHandle_, &renderHandle_);
665+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
666+ OH_ArkUI_NativeModule_RemoveAdoptedChild(custom_->GetHandle(), nodeHandle_);
667+ return nullptr;
668+ }
669+ result = OH_ArkUI_RenderNodeUtils_AddChild(render_->GetHandle(), renderHandle_);
670+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
671+ OH_ArkUI_RenderNodeUtils_DisposeNode(renderHandle_);
672+ renderHandle_ = nullptr;
673+ OH_ArkUI_NativeModule_RemoveAdoptedChild(custom_->GetHandle(), nodeHandle_);
674+ return nullptr;
675+ }
624 return nullptr;676 return nullptr;
625 }677 }
626 ```678 ```
@@ -633,9 +685,15 @@
633 685
634 napi_value RemoveAdopt(napi_env env, napi_callback_info info)686 napi_value RemoveAdopt(napi_env env, napi_callback_info info)
635 {687 {
636- OH_ArkUI_NativeModule_RemoveAdoptedChild(custom_->GetHandle(), nodeHandle_);688+ int32_t result = OH_ArkUI_NativeModule_RemoveAdoptedChild(custom_->GetHandle(), nodeHandle_);
689+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
690+ return nullptr;
691+ }
637 // 解除节点的接纳状态后,需要额外调用OH_ArkUI_RenderNodeUtils_DisposeNode释放对应的渲染节点,否则会导致内存泄漏。692 // 解除节点的接纳状态后,需要额外调用OH_ArkUI_RenderNodeUtils_DisposeNode释放对应的渲染节点,否则会导致内存泄漏。
638- OH_ArkUI_RenderNodeUtils_DisposeNode(renderHandle_);693+ result = OH_ArkUI_RenderNodeUtils_DisposeNode(renderHandle_);
694+ if (result != ARKUI_ERROR_CODE_NO_ERROR) {
695+ return nullptr;
696+ }
639 nodeHandle_ = nullptr;697 nodeHandle_ = nullptr;
640 renderHandle_ = nullptr;698 renderHandle_ = nullptr;
641 return nullptr;699 return nullptr;
@@ -26,10 +26,10 @@ const unsigned int VALUE_3 = 50;
26 {26 {
27 ArkUI_NativeNodeAPI_1* nodeAPI = NativeModuleInstance::GetInstance()->GetNativeNodeAPI();27 ArkUI_NativeNodeAPI_1* nodeAPI = NativeModuleInstance::GetInstance()->GetNativeNodeAPI();
28 ArkUI_NodeHandle testNode = nodeAPI->createNode(ARKUI_NODE_COLUMN);28 ArkUI_NodeHandle testNode = nodeAPI->createNode(ARKUI_NODE_COLUMN);
29- ArkUI_NumberValue value[] = {VALUE_1};29+ ArkUI_NumberValue value[] = {{.f32 = VALUE_1}};
30 ArkUI_AttributeItem item = {value, sizeof(value) / sizeof(ArkUI_NumberValue)};30 ArkUI_AttributeItem item = {value, sizeof(value) / sizeof(ArkUI_NumberValue)};
31- value[0].f32 = VALUE_2;
32 nodeAPI->setAttribute(testNode, NODE_WIDTH, &item);31 nodeAPI->setAttribute(testNode, NODE_WIDTH, &item);
32+ value[0].f32 = VALUE_2;
33 nodeAPI->setAttribute(testNode, NODE_HEIGHT, &item);33 nodeAPI->setAttribute(testNode, NODE_HEIGHT, &item);
34 struct IdList {34 struct IdList {
35 int32_t id = -1;35 int32_t id = -1;
@@ -44,7 +44,7 @@ const unsigned int VALUE_3 = 50;
44 nodeAPI->setAttribute(button, NODE_HEIGHT, &item);44 nodeAPI->setAttribute(button, NODE_HEIGHT, &item);
45 nodeAPI->addChild(testNode, button);45 nodeAPI->addChild(testNode, button);
46 nodeAPI->registerNodeEvent(button, NODE_ON_CLICK, 1, &idl);46 nodeAPI->registerNodeEvent(button, NODE_ON_CLICK, 1, &idl);
47- OH_LOG_Print(LOG_APP, LOG_WARN, LOG_PRINT, "GetNodeUniqueId", "GetNodeHandleByUniqueId success1");47+ OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT, "GetNodeUniqueId", "Node initialized, waiting for button click");
48 nodeAPI->registerNodeEventReceiver([](ArkUI_NodeEvent *event) {48 nodeAPI->registerNodeEventReceiver([](ArkUI_NodeEvent *event) {
49 auto targetId = OH_ArkUI_NodeEvent_GetTargetId(event);49 auto targetId = OH_ArkUI_NodeEvent_GetTargetId(event);
50 if (targetId == 1) {50 if (targetId == 1) {
@@ -56,6 +56,8 @@ const unsigned int VALUE_3 = 50;
56 }56 }
57 }57 }
58 });58 });
59+ return std::make_shared<ArkUINode>(testNode);
60+ }
59```61```
60 62 
61## 通过用户id获取节点信息63## 通过用户id获取节点信息
@@ -96,7 +98,7 @@ const unsigned int VALUE_3 = 50;
96 98 
97 <!-- @[ndknodequeryoperate3_start](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkNodeQueryOperate/entry/src/main/cpp/GetNodeByIdExample.h) -->99 <!-- @[ndknodequeryoperate3_start](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkNodeQueryOperate/entry/src/main/cpp/GetNodeByIdExample.h) -->
98 100
99- ```c101+ ```cpp
100 // GetNodeByIdExample.h102 // GetNodeByIdExample.h
101 #ifndef MYAPPLICATION_GETNODEBYID_H103 #ifndef MYAPPLICATION_GETNODEBYID_H
102 #define MYAPPLICATION_GETNODEBYID_H104 #define MYAPPLICATION_GETNODEBYID_H
@@ -289,11 +291,11 @@ const unsigned int VALUE_3 = 50;
289 }291 }
290 ```292 ```
291 293 
292-2. 新建`MoveTo.h`文件,在其中创建Stack节点,通过OH_ArkUI_NodeUtils_MoveTo接口移动Stack节点。294+2. 新建`MoveToExample.h`文件,在其中创建Stack节点,通过OH_ArkUI_NodeUtils_MoveTo接口移动Stack节点。
293 295 
294 <!-- @[ndknodequeryoperate5_start](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkNodeQueryOperate/entry/src/main/cpp/MoveToExample.h) -->296 <!-- @[ndknodequeryoperate5_start](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkNodeQueryOperate/entry/src/main/cpp/MoveToExample.h) -->
295 297 
296- ```c298+ ```cpp
刘睿
刘睿刘睿10 天前

这个得看同源打标是什么

likedislike
297 // MoveToExample.h299 // MoveToExample.h
298 #ifndef MYAPPLICATION_MOVETO_H300 #ifndef MYAPPLICATION_MOVETO_H
299 #define MYAPPLICATION_MOVETO_H301 #define MYAPPLICATION_MOVETO_H
@@ -312,7 +314,9 @@ const unsigned int VALUE_3 = 50;
312 ArkUI_NodeHandle node;314 ArkUI_NodeHandle node;
313 ArkUI_NodeHandle targetParent;315 ArkUI_NodeHandle targetParent;
314 };316 };
315- A* a = new A;317+ // 本示例只创建一个节点树,使用静态存储保证事件回调数据在节点销毁前仍然有效。
318+ static A eventData{};
319+ A* a = &eventData;
316 320 
317 // 创建根节点Scroll321 // 创建根节点Scroll
318 ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL);322 ArkUI_NodeHandle scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL);
@@ -417,7 +421,6 @@ const unsigned int VALUE_3 = 50;
417 if (a != nullptr) {421 if (a != nullptr) {
418 OH_ArkUI_NodeUtils_MoveTo(a->node, a->targetParent, 2);422 OH_ArkUI_NodeUtils_MoveTo(a->node, a->targetParent, 2);
419 nodeAPI->unregisterNodeEvent(eventNode, NODE_ON_CLICK);423 nodeAPI->unregisterNodeEvent(eventNode, NODE_ON_CLICK);
420- delete a;
421 }424 }
422 }425 }
423 };426 };
@@ -556,7 +559,7 @@ const unsigned int VALUE_3 = 50;
556 559 
557 <!-- @[ndknodequeryoperate7_start](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkNodeQueryOperate/entry/src/main/cpp/Attribute_util.h) -->560 <!-- @[ndknodequeryoperate7_start](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkNodeQueryOperate/entry/src/main/cpp/Attribute_util.h) -->
558 561
559- ```c562+ ```cpp
560 #ifndef MYAPPLICATION_ATTRIBUTE_UTIL_H563 #ifndef MYAPPLICATION_ATTRIBUTE_UTIL_H
561 #define MYAPPLICATION_ATTRIBUTE_UTIL_H564 #define MYAPPLICATION_ATTRIBUTE_UTIL_H
562 565
@@ -696,7 +699,7 @@ const unsigned int VALUE_3 = 50;
696 }699 }
697 ```700 ```
698 701 
699-4. 运行程序,点击按钮切换图片正常展示。702+4. 运行程序,点击按钮切换组件分支,图片正常展示且无闪烁
700 703 
701 ![moveToNativeDemo](figures/OH_ArkUI_NativeModule_InvalidateAttributes_test.png)704 ![moveToNativeDemo](figures/OH_ArkUI_NativeModule_InvalidateAttributes_test.png)
702 705 
@@ -704,7 +707,7 @@ const unsigned int VALUE_3 = 50;
704 707 
705NDK支持通过不同的展开方式获取目标节点下的有效节点信息。例如,在LazyForEach场景下,可以处理存在多个子节点的情况。708NDK支持通过不同的展开方式获取目标节点下的有效节点信息。例如,在LazyForEach场景下,可以处理存在多个子节点的情况。
706 709 
707-从API version 20开始,使用[OH_ArkUI_NodeUtils_GetFirstChildIndexWithoutExpand](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getfirstchildindexwithoutexpand)接口,可以获取目标节点的第一个存在于组件树的节点。使用[OH_ArkUI_NodeUtils_GetLastChildIndexWithoutExpand](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getlastchildindexwithoutexpand)接口,可以获取目标节点的最后一个存在于组件树的节点。[OH_ArkUI_NodeUtils_GetChildWithExpandMode](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getchildwithexpandmode)接口,可以通过不同的节点展开模式获取对应下标的子节点。710+从API version 20开始,使用[OH_ArkUI_NodeUtils_GetFirstChildIndexWithoutExpand](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getfirstchildindexwithoutexpand)接口,可以获取目标节点在不展开节点时的第一个节点下标。使用[OH_ArkUI_NodeUtils_GetLastChildIndexWithoutExpand](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getlastchildindexwithoutexpand)接口,可以获取目标节点在不展开节点时的最后一个节点下标使用[OH_ArkUI_NodeUtils_GetChildWithExpandMode](../reference/apis-arkui/capi-native-node-h.md#oh_arkui_nodeutils_getchildwithexpandmode)接口,可以通过不同的节点展开模式获取对应下标的子节点。
708 711 
709> **说明:**712> **说明:**
710>713>
@@ -850,6 +853,7 @@ NDK支持通过不同的展开方式获取目标节点下的有效节点信息
850 }853 }
851 .cachedCount(5)854 .cachedCount(5)
852 .listDirection(Axis.Horizontal)855 .listDirection(Axis.Horizontal)
856+ .id("LazyForEachList")
853 }857 }
854 858
855 class MyNodeController extends NodeController {859 class MyNodeController extends NodeController {
@@ -980,14 +984,15 @@ NDK支持通过不同的展开方式获取目标节点下的有效节点信息
980 984
981 ```c985 ```c
cc520bf
cc520bfcc520bf17 天前

[🟢低] 代码块语言标记建议修正为 cpp

此代码块标记为 �KE_PH_0�c 改为 ```cpp,保持文件内一致性。

likedislike
982 ArkUI_NodeHandle childNode = nullptr;986 ArkUI_NodeHandle childNode = nullptr;
983- OH_ArkUI_NodeUtils_GetAttachedNodeHandleById("N3", &childNode);987+ // ArkTS侧List已设置.id("LazyForEachList")
988+ OH_ArkUI_NodeUtils_GetAttachedNodeHandleById("LazyForEachList", &childNode);
984 989
985 uint32_t index = 0;990 uint32_t index = 0;
986 OH_ArkUI_NodeUtils_GetFirstChildIndexWithoutExpand(childNode, &index);991 OH_ArkUI_NodeUtils_GetFirstChildIndexWithoutExpand(childNode, &index);
987 uint32_t index1 = 0;992 uint32_t index1 = 0;
988 OH_ArkUI_NodeUtils_GetLastChildIndexWithoutExpand(childNode, &index1);993 OH_ArkUI_NodeUtils_GetLastChildIndexWithoutExpand(childNode, &index1);
989 ArkUI_NodeHandle child = nullptr;994 ArkUI_NodeHandle child = nullptr;
990- auto result = OH_ArkUI_NodeUtils_GetChildWithExpandMode(childNode, 3, &child, 0);995+ auto result = OH_ArkUI_NodeUtils_GetChildWithExpandMode(childNode, 3, &child, ARKUI_LAZY_EXPAND);
991 OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Manager",996 OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Manager",
992 "firstChildIndex - lastChildIndex == %{public}d -- %{public}d, -- getResult = %{public}d",997 "firstChildIndex - lastChildIndex == %{public}d -- %{public}d, -- getResult = %{public}d",
993 index, index1, result);998 index, index1, result);