1# 使用动画 2 3 4## 使用属性动画 5 6ArkUI开发框架在NDK接口主要提供属性动画,实现组件出现/消失转场。同时,可以通过Node-API桥接ArkTS侧帧动画能力,实现Native侧的动画效果。 7 8> **说明:** 9> 10> - 需要从ArkTS侧获取[this.getUIContext()](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#getuicontext),传入到Native侧。 11> 12> - 在Native侧通过[OH_ArkUI_GetContextFromNapiValue](../reference/apis-arkui/native__node__napi_8h.md)方法获取context。 13> 14> - 需要执行的动画属性变化必须写在[ArkUI_ContextCallback](../reference/apis-arkui/_ark_u_i___context_callback.md)中callback中。 15> 16> - 需要执行的动画属性,必须在执行动画之前设置过。 17 18提供全局animateTo显式动画接口,来指定由于闭包代码导致的状态变化插入过渡动效。同属性动画,布局类改变宽高的动画,内容都是直接到终点状态。 19 201. 在.ets文件中获取[UIContext](../reference//apis-arkui/js-apis-arkui-UIContext.md#uicontext),把this.getUIContext()当做参数输出到Native方法中。 21 ```ts 22 // createNativeNode是Native侧暴露的方法 23 nativeNode.createNativeNode("xcomponentId", this.getUIContext()); 24 ``` 25 262. 解析UIContext转换C中的context对象。 27 ``` 28 // 获取ets测传入的context 29 ArkUI_ContextHandle context = nullptr; 30 // 通过code 判断是否获取成功 31 auto code = OH_ArkUI_GetContextFromNapiValue(env, args[1], &context); 32 ``` 33 343. 获取ArkUI_NativeAnimateAPI_1 对象。 35 ``` 36 // 获取ArkUI_NativeAnimateAPI接口 37 ArkUI_NativeAnimateAPI_1 *animateApi = nullptr; 38 OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_ANIMATE, ArkUI_NativeAnimateAPI_1, animateApi); 39 ``` 40 414. 设置 ArkUI_AnimateOption参数,通过提供的C方法设置对应的参数。 42 ``` 43 ArkUI_AnimateOption *option = OH_ArkUI_AnimateOption_Create(); 44 OH_ArkUI_AnimateOption_SetDuration(option, 2000); 45 OH_ArkUI_AnimateOption_SetTempo(option, 1.1); 46 OH_ArkUI_AnimateOption_SetCurve(option, ARKUI_CURVE_EASE); 47 OH_ArkUI_AnimateOption_SetDelay(option, 20); 48 OH_ArkUI_AnimateOption_SetIterations(option, 1); 49 OH_ArkUI_AnimateOption_SetPlayMode(option, ARKUI_ANIMATION_PLAY_MODE_REVERSE); 50 ArkUI_ExpectedFrameRateRange *range = new ArkUI_ExpectedFrameRateRange; 51 range->min = 10; 52 range->max = 120; 53 range->expected = 60; 54 OH_ArkUI_AnimateOption_SetExpectedFrameRateRange(option, range); 55 ``` 56 575. 设置回调参数。 58 ``` 59 // 用户自定义参数 60 struct UserData{ 61 int32_t data; 62 }; 63 UserData *onFinishUser = new UserData; 64 onFinishUser->data= 101; 65 // 设置完成的回调 66 ArkUI_AnimateCompleteCallback *completeCallback = new ArkUI_AnimateCompleteCallback; 67 completeCallback->userData = onFinishUser; 68 completeCallback->type = ARKUI_FINISH_CALLBACK_REMOVED; 69 completeCallback->callback = [](void *userData) { 70 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Manager", "CreateNativeNode onFinishCallback %{public}d", 71 reinterpret_cast<AA *>(userData)->a); 72 }; 73 // 用户自定义参数 74 UserData *eventUser = new UserData ; 75 eventUser->data= 201; 76 static bool isback = true; 77 ArkUI_ContextCallback *update = new ArkUI_ContextCallback; 78 update->userData = eventUser; 79 update->callback = [](void *user) { 80 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Manager", "CreateNativeNode animateTo %{public}d", 81 reinterpret_cast<UserData*>(user)->data); 82 // 对应的属性变化 width height 83 if (isback) { 84 ArkUI_NumberValue custom_widthValue[] = {200}; 85 ArkUI_AttributeItem custom_widthItem = {custom_widthValue, 1}; 86 ArkUI_NumberValue custom_heightValue1[] = {80}; 87 ArkUI_AttributeItem custom_heightItem1 = {custom_heightValue1, 1}; 88 nodeAPI->setAttribute(textInput, NODE_WIDTH, &custom_widthItem); 89 nodeAPI->setAttribute(textInput, NODE_HEIGHT, &custom_heightItem1); 90 } else { 91 ArkUI_NumberValue custom_widthValue[] = {100}; 92 ArkUI_AttributeItem custom_widthItem = {custom_widthValue, 1}; 93 ArkUI_NumberValue custom_heightValue1[] = {40}; 94 ArkUI_AttributeItem custom_heightItem1 = {custom_heightValue1, 1}; 95 nodeAPI->setAttribute(textInput, NODE_WIDTH, &custom_widthItem); 96 nodeAPI->setAttribute(textInput, NODE_HEIGHT, &custom_heightItem1); 97 } 98 }; 99 // 执行对应的动画 100 animateApi->animateTo(context, option, update, completeCallback); 101 ``` 102 103  104 105 106 107 108 109## 组件出现/消失转场 110 111组件内转场通过NODE_XX_TRANSITION属性(XX包括:OPACITY、TRANSLATE、SCALE、ROTATE、MOVE)配置转场参数,在组件插入和删除时显示过渡动效(通过NODE_TRANSFORM_CENTER属性设置NODE_SCALE_TRANSITION和NODE_ROTATE_ROTATE动效的中心点坐标)。主要用于容器组件中子组件插入和删除时,提升用户体验。 112 1131. 创建可交互界面,界面中包含Button,点击可以控制转场节点的添加和移除。其中 ArkUI_NodeContentHandle 类型节点的获取与使用可参考[接入ArkTS页面](ndk-access-the-arkts-page.md)。 114 ``` 115 constexpr int32_t BUTTON_CLICK_ID = 1; 116 bool flag = false; 117 ArkUI_NodeHandle parrentNode; 118 ArkUI_NodeHandle childNode; 119 ArkUI_NodeHandle buttonNode; 120 121 void mainViewMethod(ArkUI_NodeContentHandle handle) 122 { 123 ArkUI_NativeNodeAPI_1 *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>( 124 OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); 125 ArkUI_NodeHandle column = nodeAPI->createNode(ARKUI_NODE_COLUMN); 126 ArkUI_NumberValue widthValue[] = {{.f32 = 500}}; 127 ArkUI_AttributeItem widthItem = {.value = widthValue, .size = sizeof(widthValue) / sizeof(ArkUI_NumberValue)}; 128 nodeAPI->setAttribute(column, NODE_WIDTH, &widthItem); 129 ArkUI_NumberValue heightValue[] = {{.f32 = 500}}; 130 ArkUI_AttributeItem heightItem = {.value = heightValue, .size = sizeof(heightValue) / sizeof(ArkUI_NumberValue)}; 131 nodeAPI->setAttribute(column, NODE_HEIGHT, &heightItem); 132 ArkUI_NodeHandle buttonShow = nodeAPI->createNode(ARKUI_NODE_BUTTON); 133 ArkUI_NumberValue buttonWidthValue[] = {{.f32 = 200}}; 134 ArkUI_AttributeItem buttonWidthItem = {.value = buttonWidthValue, 135 .size = sizeof(buttonWidthValue) / sizeof(ArkUI_NumberValue)}; 136 nodeAPI->setAttribute(buttonShow, NODE_WIDTH, &buttonWidthItem); 137 ArkUI_NumberValue buttonHeightValue[] = {{.f32 = 50}}; 138 ArkUI_AttributeItem buttonHeightItem = {.value = buttonHeightValue, 139 .size = sizeof(buttonHeightValue) / sizeof(ArkUI_NumberValue)}; 140 nodeAPI->setAttribute(buttonShow, NODE_HEIGHT, &buttonHeightItem); 141 ArkUI_AttributeItem labelItem = {.string = "show"}; 142 nodeAPI->setAttribute(buttonShow, NODE_BUTTON_LABEL, &labelItem); 143 ArkUI_NumberValue buttonOpenTypeValue[] = {{.i32 = static_cast<int32_t>(ARKUI_BUTTON_TYPE_NORMAL)}}; 144 ArkUI_AttributeItem buttonOpenTypeItem = {.value = buttonOpenTypeValue, 145 .size = sizeof(buttonOpenTypeValue) / sizeof(ArkUI_NumberValue)}; 146 nodeAPI->setAttribute(buttonShow, NODE_BUTTON_TYPE, &buttonOpenTypeItem); 147 ArkUI_NumberValue buttonShowMarginValue[] = {{.f32 = 20}}; 148 ArkUI_AttributeItem buttonShowMarginItem = {.value = buttonShowMarginValue, 149 .size = sizeof(buttonShowMarginValue) / sizeof(ArkUI_NumberValue)}; 150 nodeAPI->setAttribute(buttonShow, NODE_MARGIN, &buttonShowMarginItem); 151 nodeAPI->registerNodeEvent(buttonShow, NODE_ON_CLICK, BUTTON_CLICK_ID, nullptr); 152 nodeAPI->addNodeEventReceiver(buttonShow, OnButtonShowClicked); 153 parrentNode = column; 154 buttonNode = buttonShow; 155 nodeAPI->addChild(column, buttonShow); 156 OH_ArkUI_NodeContent_AddNode(handle, column); 157 } 158 ``` 159 1602. 创建一个设置了Transition属性的节点,当目标节点上下树时会播放转场动画。 161 ``` 162 ArkUI_NodeHandle CreateChildNode() { 163 ArkUI_NativeNodeAPI_1 *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>( 164 OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); 165 ArkUI_NodeHandle image = nodeAPI->createNode(ARKUI_NODE_IMAGE); 166 ArkUI_AttributeItem imageSrcItem = {.string = "/pages/common/scenery.jpg"}; 167 nodeAPI->setAttribute(image, NODE_IMAGE_SRC, &imageSrcItem); 168 ArkUI_NumberValue textWidthValue[] = {{.f32 = 300}}; 169 ArkUI_AttributeItem textWidthItem = {.value = textWidthValue, 170 .size = sizeof(textWidthValue) / sizeof(ArkUI_NumberValue)}; 171 nodeAPI->setAttribute(image, NODE_WIDTH, &textWidthItem); 172 ArkUI_NumberValue textHeightValue[] = {{.f32 = 300}}; 173 ArkUI_AttributeItem textHeightItem = {.value = textHeightValue, 174 .size = sizeof(textWidthValue) / sizeof(ArkUI_NumberValue)}; 175 nodeAPI->setAttribute(image, NODE_HEIGHT, &textHeightItem); 176 ArkUI_NumberValue transformCenterValue[] = {0.0f, 0.0f, 0.0f, 0.5f, 0.5f}; 177 ArkUI_AttributeItem transformCenterItem = {.value = transformCenterValue, 178 .size = sizeof(transformCenterValue) / sizeof(ArkUI_NumberValue)}; 179 nodeAPI->setAttribute(image, NODE_TRANSFORM_CENTER, &transformCenterItem); 180 ArkUI_NumberValue rotateAnimationValue[] = {0.0f, 0.0f, 1.0f, 360.0f, 0.0f, {.i32 = 500}, {.i32 = static_cast<int32_t>(ARKUI_CURVE_SHARP)}}; 181 ArkUI_AttributeItem rotateAnimationItem = {.value = rotateAnimationValue, 182 .size = sizeof(rotateAnimationValue) / sizeof(ArkUI_NumberValue)}; 183 nodeAPI->setAttribute(image, NODE_ROTATE_TRANSITION, &rotateAnimationItem); 184 ArkUI_NumberValue scaleAnimationValue[] = { 185 0.0f, 0.0f, 0.0f, {.i32 = 500}, {.i32 = static_cast<int32_t>(ARKUI_CURVE_SHARP)}}; 186 ArkUI_AttributeItem scaleAnimationItem = {.value = scaleAnimationValue, 187 .size = sizeof(scaleAnimationValue) / sizeof(ArkUI_NumberValue)}; 188 nodeAPI->setAttribute(image, NODE_SCALE_TRANSITION, &scaleAnimationItem); 189 ArkUI_NumberValue translateAnimationValue[] = { 190 200, 200, 0.0f, {.i32 = 500}, {.i32 = static_cast<int32_t>(ARKUI_CURVE_SHARP)}}; 191 ArkUI_AttributeItem translateAnimationItem = {.value = translateAnimationValue, 192 .size = sizeof(translateAnimationValue) / sizeof(ArkUI_NumberValue)}; 193 nodeAPI->setAttribute(image, NODE_TRANSLATE_TRANSITION, &translateAnimationItem); 194 return image; 195 } 196 ``` 197 1983. 在Button的监听回调里添加转场节点上下树逻辑,以此控制转场节点的入场和出场。 199 ``` 200 void OnButtonShowClicked(ArkUI_NodeEvent* event) 201 { 202 if (!event) { 203 return; 204 } 205 if (!childNode) { 206 childNode = CreateChildNode(); 207 } 208 ArkUI_NativeNodeAPI_1 *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>( 209 OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); 210 if (flag) { 211 flag = false; 212 ArkUI_AttributeItem labelItem = {.string = "show"}; 213 nodeAPI->setAttribute(buttonNode, NODE_BUTTON_LABEL, &labelItem); 214 nodeAPI->removeChild(parrentNode, childNode); 215 } else { 216 flag = true; 217 ArkUI_AttributeItem labelItem = {.string = "hide"}; 218 nodeAPI->setAttribute(buttonNode, NODE_BUTTON_LABEL, &labelItem); 219 nodeAPI->addChild(parrentNode, childNode); 220 } 221 } 222 ``` 223 224  225 226 227