1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "core/components_ng/manager/drag_drop/utils/drag_animation_helper.h"
16
17 #include "core/animation/animation_pub.h"
18 #include "core/components_ng/base/frame_node.h"
19 #include "core/components_ng/event/drag_event.h"
20 #include "core/components_ng/event/gesture_event_hub.h"
21 #include "core/components_ng/pattern/menu/menu_theme.h"
22 #include "core/components_ng/pattern/overlay/overlay_manager.h"
23 #include "core/components_ng/render/animation_utils.h"
24 #include "core/components_ng/render/render_context.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr int32_t BEFORE_LIFTING_TIME = 650;
31 constexpr int32_t IMAGE_SHOW_TIME = 50;
32 constexpr int32_t PIXELMAP_ANIMATION_DURATION = 300;
33 constexpr int32_t BADGE_ANIMATION_DURATION = 200;
34 constexpr int32_t BADGE_ANIMATION_DELAY = 100;
35 constexpr float DEFAULT_ANIMATION_SCALE = 0.95f;
36 constexpr float GATHER_SPRING_RESPONSE = 0.304f;
37 constexpr float GATHER_SPRING_DAMPING_FRACTION = 0.97f;
38 constexpr float GRID_MOVE_SCALE = 0.2f;
39 constexpr float LIST_MOVE_SCALE = 0.2f;
40 constexpr float EULER_NUMBER = 2.71828f;
41 constexpr float GATHER_OFFSET_RADIUS = 0.1f;
42 constexpr float PIXELMAP_DRAG_SCALE_MULTIPLE = 1.05f;
43 constexpr float BADGE_ANIMATION_SCALE = 1.0f;
44 constexpr Dimension BADGE_RELATIVE_OFFSET = 8.0_vp;
45 constexpr Dimension BADGE_DEFAULT_SIZE = 24.0_vp;
46 constexpr Dimension BADGE_TEXT_FONT_SIZE = 14.0_fp;
47 const Color BADGE_TEXT_FONT_COLOR = Color::FromString("#ffffffff");
48 const Color BADGE_BACKGROUND_COLOR = Color::FromString("#ff007dff");
49 constexpr float DEFAULT_INTERPOLATING_SPRING_VELOCITY = 10.0f;
50 constexpr float DEFAULT_INTERPOLATING_SPRING_MASS = 1.0f;
51 constexpr float DEFAULT_INTERPOLATING_SPRING_STIFFNESS = 410.0f;
52 constexpr float DEFAULT_INTERPOLATING_SPRING_DAMPING = 38.0f;
53 }
54
CalcDistanceBeforeLifting(bool isGrid,CalcResult & calcResult,OffsetF gatherNodeCenter,const std::vector<GatherNodeChildInfo> & gatherNodeChildrenInfo)55 void DragAnimationHelper::CalcDistanceBeforeLifting(bool isGrid, CalcResult& calcResult, OffsetF gatherNodeCenter,
56 const std::vector<GatherNodeChildInfo>& gatherNodeChildrenInfo)
57 {
58 for (const auto& child : gatherNodeChildrenInfo) {
59 auto imageNode = child.imageNode.Upgrade();
60 CHECK_NULL_VOID(imageNode);
61 auto width = child.width;
62 auto height = child.height;
63 OffsetF curPos = {child.offset.GetX() + child.halfWidth, child.offset.GetY() + child.halfHeight};
64 float dis = sqrt(pow(gatherNodeCenter.GetX() - curPos.GetX(), 2) +
65 pow(gatherNodeCenter.GetY() - curPos.GetY(), 2));
66 calcResult.maxDistance = std::max(calcResult.maxDistance, dis);
67 calcResult.minDistance = calcResult.minDistance < 0 ? dis : std::min(calcResult.minDistance, dis);
68 if (isGrid) {
69 calcResult.maxTranslation = calcResult.maxTranslation < 0 ? std::min(width, height) :
70 std::min(calcResult.maxTranslation, std::min(width, height));
71 } else {
72 calcResult.maxTranslation = calcResult.maxTranslation < 0 ? height :
73 std::min(calcResult.maxTranslation, height);
74 }
75 }
76 calcResult.maxTranslation *= isGrid ? GRID_MOVE_SCALE : LIST_MOVE_SCALE;
77 }
78
CalcOffsetToTarget(OffsetF curPos,OffsetF targetPos,CalcResult & calcResult)79 OffsetF DragAnimationHelper::CalcOffsetToTarget(OffsetF curPos, OffsetF targetPos, CalcResult& calcResult)
80 {
81 if (NearZero(calcResult.maxDistance) || NearZero(calcResult.minDistance) || calcResult.maxTranslation < 0) {
82 return { 0.0f, 0.0f };
83 }
84
85 float xDis = targetPos.GetX() - curPos.GetX();
86 float yDis = targetPos.GetY() - curPos.GetY();
87 float dis = sqrt(pow(xDis, 2) + pow(yDis, 2));
88 if (NearZero(dis)) {
89 return { 0.0f, 0.0f };
90 }
91 auto trans = calcResult.maxTranslation * pow(EULER_NUMBER, -(dis - calcResult.minDistance) /
92 calcResult.maxDistance * GATHER_OFFSET_RADIUS);
93 float x = xDis * trans / dis;
94 float y = yDis * trans / dis;
95 return { x, y };
96 }
97
PlayGatherNodeTranslateAnimation(const RefPtr<DragEventActuator> & actuator,const RefPtr<OverlayManager> & overlayManager)98 void DragAnimationHelper::PlayGatherNodeTranslateAnimation(const RefPtr<DragEventActuator>& actuator,
99 const RefPtr<OverlayManager>& overlayManager)
100 {
101 CHECK_NULL_VOID(actuator);
102 AnimationOption option;
103 option.SetDuration(BEFORE_LIFTING_TIME);
104 option.SetCurve(Curves::SHARP);
105 auto frameNode = actuator->GetFrameNode();
106 auto gatherNodeCenter = frameNode->GetPaintRectCenter();
107 auto gatherNodeChildrenInfo = overlayManager->GetGatherNodeChildrenInfo();
108
109 bool isGrid = frameNode->GetTag() == V2::GRID_ITEM_ETS_TAG;
110 CalcResult calcResult = { 0.0f, -1.0f, -1.0f };
111 CalcDistanceBeforeLifting(isGrid, calcResult, gatherNodeCenter, gatherNodeChildrenInfo);
112 AnimationUtils::Animate(
113 option,
114 [gatherNodeCenter, gatherNodeChildrenInfo, calcResult]() mutable {
115 for (const auto& child : gatherNodeChildrenInfo) {
116 auto imageNode = child.imageNode.Upgrade();
117 CHECK_NULL_VOID(imageNode);
118 auto imageContext = imageNode->GetRenderContext();
119 CHECK_NULL_VOID(imageContext);
120 auto curPos = child.offset + OffsetF(child.halfWidth, child.halfHeight);
121 auto offset = CalcOffsetToTarget(curPos, gatherNodeCenter, calcResult);
122 imageContext->UpdatePosition(OffsetT<Dimension>(
123 Dimension(child.offset.GetX() + offset.GetX()),
124 Dimension(child.offset.GetY() + offset.GetY())));
125 }
126 });
127 }
128
PlayGatherNodeOpacityAnimation(const RefPtr<OverlayManager> & overlayManager)129 void DragAnimationHelper::PlayGatherNodeOpacityAnimation(const RefPtr<OverlayManager>& overlayManager)
130 {
131 CHECK_NULL_VOID(overlayManager);
132 auto gatherNodeChildrenInfo = overlayManager->GetGatherNodeChildrenInfo();
133
134 AnimationOption opacityOption;
135 opacityOption.SetDuration(IMAGE_SHOW_TIME);
136 opacityOption.SetCurve(AceType::MakeRefPtr<CubicCurve>(0.0f, 0.0f, 1.0f, 1.0f));
137
138 for (const auto& child : gatherNodeChildrenInfo) {
139 auto imageNode = child.imageNode.Upgrade();
140 CHECK_NULL_VOID(imageNode);
141 auto imageContext = imageNode->GetRenderContext();
142 CHECK_NULL_VOID(imageContext);
143 imageContext->OpacityAnimation(opacityOption, 0.0f, 1.0f);
144 }
145 }
146
PlayGatherAnimationBeforeLifting(const RefPtr<DragEventActuator> & actuator)147 void DragAnimationHelper::PlayGatherAnimationBeforeLifting(const RefPtr<DragEventActuator>& actuator)
148 {
149 TAG_LOGI(AceLogTag::ACE_DRAG, "Play gather animation before lifting");
150 CHECK_NULL_VOID(actuator);
151 if (!actuator->IsNeedGather()) {
152 return;
153 }
154 auto pipeline = PipelineContext::GetCurrentContext();
155 CHECK_NULL_VOID(pipeline);
156 auto manager = pipeline->GetOverlayManager();
157 CHECK_NULL_VOID(manager);
158 auto frameNode = actuator->GetFrameNode();
159 CHECK_NULL_VOID(frameNode);
160 auto gatherNode = actuator->GetGatherNode();
161 CHECK_NULL_VOID(gatherNode);
162 auto imageContext = gatherNode->GetRenderContext();
163 CHECK_NULL_VOID(imageContext);
164 imageContext->UpdatePosition(OffsetT<Dimension>(Dimension(0.0f), Dimension(0.0f)));
165 auto gatherNodeChildrenInfo = actuator->GetGatherNodeChildrenInfo();
166 DragEventActuator::MountGatherNode(manager, frameNode, gatherNode, gatherNodeChildrenInfo);
167 actuator->ClearGatherNodeChildrenInfo();
168 pipeline->FlushSyncGeometryNodeTasks();
169 manager->SetIsGatherWithMenu(false);
170 PlayGatherNodeOpacityAnimation(manager);
171 PlayGatherNodeTranslateAnimation(actuator, manager);
172 }
173
PlayNodeAnimationBeforeLifting(const RefPtr<FrameNode> & frameNode)174 void DragAnimationHelper::PlayNodeAnimationBeforeLifting(const RefPtr<FrameNode>& frameNode)
175 {
176 CHECK_NULL_VOID(frameNode);
177 auto previewOptions = frameNode->GetDragPreviewOption();
178 if (!previewOptions.defaultAnimationBeforeLifting) {
179 return;
180 }
181 AnimationOption option;
182 option.SetDuration(BEFORE_LIFTING_TIME);
183 auto springCurve = AceType::MakeRefPtr<InterpolatingSpring>(DEFAULT_INTERPOLATING_SPRING_VELOCITY,
184 DEFAULT_INTERPOLATING_SPRING_MASS, DEFAULT_INTERPOLATING_SPRING_STIFFNESS,
185 DEFAULT_INTERPOLATING_SPRING_DAMPING);
186 option.SetCurve(springCurve);
187 auto renderContext = frameNode->GetRenderContext();
188 CHECK_NULL_VOID(renderContext);
189 renderContext->UpdateTransformScale({ 1.0f, 1.0f });
190
191 AnimationUtils::Animate(
192 option,
193 [renderContext]() mutable {
194 CHECK_NULL_VOID(renderContext);
195 renderContext->UpdateTransformScale({ DEFAULT_ANIMATION_SCALE, DEFAULT_ANIMATION_SCALE });
196 });
197 }
198
PlayNodeResetAnimation(const RefPtr<DragEventActuator> & actuator)199 void DragAnimationHelper::PlayNodeResetAnimation(const RefPtr<DragEventActuator>& actuator)
200 {
201 CHECK_NULL_VOID(actuator);
202 auto frameNode = actuator->GetFrameNode();
203 CHECK_NULL_VOID(frameNode);
204 bool defaultAnimationBeforeLifting = frameNode->GetDragPreviewOption().defaultAnimationBeforeLifting;
205 if (!defaultAnimationBeforeLifting) {
206 return;
207 }
208 auto frameContext = frameNode->GetRenderContext();
209 CHECK_NULL_VOID(frameContext);
210 auto layoutProperty = frameNode->GetLayoutProperty();
211 if (layoutProperty) {
212 layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
213 }
214 AnimationOption option;
215 option.SetDuration(PIXELMAP_ANIMATION_DURATION);
216 const RefPtr<Curve> curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(0.33f, 0.67f, 1.0f);
217 option.SetCurve(curve);
218 AnimationUtils::Animate(
219 option,
220 [frameContext]() mutable {
221 frameContext->UpdateTransformScale({ 1.0f, 1.0f });
222 },
223 option.GetOnFinishEvent());
224 }
225
PlayGatherAnimation(const RefPtr<FrameNode> & frameNode,const RefPtr<OverlayManager> & overlayManager)226 void DragAnimationHelper::PlayGatherAnimation(const RefPtr<FrameNode>& frameNode,
227 const RefPtr<OverlayManager>& overlayManager)
228 {
229 TAG_LOGI(AceLogTag::ACE_DRAG, "Play gather animation");
230 CHECK_NULL_VOID(frameNode);
231 auto gatherNodeCenter = frameNode->GetPaintRectCenter();
232 CHECK_NULL_VOID(overlayManager);
233 auto gatherNodeChildrenInfo = overlayManager->GetGatherNodeChildrenInfo();
234 BorderRadiusProperty borderRadius;
235 borderRadius.SetRadius(0.0_vp);
236 borderRadius.multiValued = false;
237 for (const auto& child : gatherNodeChildrenInfo) {
238 auto imageNode = child.imageNode.Upgrade();
239 CHECK_NULL_VOID(imageNode);
240 auto imageContext = imageNode->GetRenderContext();
241 CHECK_NULL_VOID(imageContext);
242 imageContext->UpdateBorderRadius(borderRadius);
243 }
244
245 AnimationOption option;
246 option.SetDuration(PIXELMAP_ANIMATION_DURATION);
247 const RefPtr<Curve> curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(GATHER_SPRING_RESPONSE,
248 GATHER_SPRING_DAMPING_FRACTION, 0.0f);
249 option.SetCurve(curve);
250 auto geometryNode = frameNode->GetGeometryNode();
251 CHECK_NULL_VOID(geometryNode);
252 auto frameNodeSize = geometryNode->GetFrameSize();
253 auto renderContext = frameNode->GetRenderContext();
254 CHECK_NULL_VOID(renderContext);
255 GatherAnimationInfo gatherAnimationInfo = { PIXELMAP_DRAG_SCALE_MULTIPLE, frameNodeSize.Width(),
256 frameNodeSize.Height(), gatherNodeCenter, renderContext->GetBorderRadius() };
257 AnimationUtils::Animate(
258 option,
259 [overlayManager, gatherAnimationInfo]() {
260 DragDropManager::UpdateGatherNodeAttr(overlayManager, gatherAnimationInfo);
261 },
262 option.GetOnFinishEvent());
263 }
264
ShowBadgeAnimation(const RefPtr<FrameNode> & textNode)265 void DragAnimationHelper::ShowBadgeAnimation(const RefPtr<FrameNode>& textNode)
266 {
267 auto pipelineContext = PipelineContext::GetCurrentContext();
268 CHECK_NULL_VOID(pipelineContext);
269 auto dragDropManager = pipelineContext->GetDragDropManager();
270 CHECK_NULL_VOID(dragDropManager);
271 if (!dragDropManager->IsShowBadgeAnimation()) {
272 return;
273 }
274 CHECK_NULL_VOID(textNode);
275 auto textNodeContext = textNode->GetRenderContext();
276 CHECK_NULL_VOID(textNodeContext);
277 textNodeContext->UpdateTransformScale({ 0.0f, 0.0f });
278 RefPtr<Curve> interpolatingSpring = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 628.0f, 40.0f);
279 CHECK_NULL_VOID(interpolatingSpring);
280 AnimationOption textOption;
281 textOption.SetDuration(BADGE_ANIMATION_DURATION);
282 textOption.SetCurve(interpolatingSpring);
283 textOption.SetDelay(BADGE_ANIMATION_DELAY);
284 AnimationUtils::Animate(
285 textOption,
286 [textNodeContext]() mutable {
287 textNodeContext->UpdateTransformScale({ BADGE_ANIMATION_SCALE, BADGE_ANIMATION_SCALE });
288 },
289 textOption.GetOnFinishEvent());
290
291 dragDropManager->SetIsShowBadgeAnimation(false);
292 }
293
CalcBadgeTextOffset(const RefPtr<MenuPattern> & menuPattern,const RefPtr<FrameNode> & imageNode,const RefPtr<PipelineBase> & context,int32_t badgeLength)294 OffsetF DragAnimationHelper::CalcBadgeTextOffset(const RefPtr<MenuPattern>& menuPattern,
295 const RefPtr<FrameNode>& imageNode, const RefPtr<PipelineBase>& context, int32_t badgeLength)
296 {
297 CHECK_NULL_RETURN(imageNode, OffsetF());
298 CHECK_NULL_RETURN(menuPattern, OffsetF());
299 auto offset = imageNode->GetPaintRectOffset();
300 auto width = imageNode->GetGeometryNode()->GetFrameSize().Width();
301 auto scaleAfter = menuPattern->GetPreviewAfterAnimationScale();
302 auto menuTheme = context->GetTheme<NG::MenuTheme>();
303 CHECK_NULL_RETURN(menuTheme, OffsetF());
304 auto previewAfterAnimationScale =
305 LessNotEqual(scaleAfter, 0.0) ? menuTheme->GetPreviewAfterAnimationScale() : scaleAfter;
306 double textOffsetX = offset.GetX() + width * previewAfterAnimationScale -
307 BADGE_RELATIVE_OFFSET.ConvertToPx() - (BADGE_RELATIVE_OFFSET.ConvertToPx() * badgeLength);
308 double textOffsetY = offset.GetY() - BADGE_RELATIVE_OFFSET.ConvertToPx();
309 return OffsetF(textOffsetX, textOffsetY);
310 }
311
CalcBadgeTextPosition(const RefPtr<MenuPattern> & menuPattern,const RefPtr<OverlayManager> & manager,const RefPtr<FrameNode> & imageNode,const RefPtr<FrameNode> & textNode)312 void DragAnimationHelper::CalcBadgeTextPosition(const RefPtr<MenuPattern>& menuPattern,
313 const RefPtr<OverlayManager>& manager, const RefPtr<FrameNode>& imageNode, const RefPtr<FrameNode>& textNode)
314 {
315 CHECK_NULL_VOID(manager);
316 CHECK_NULL_VOID(textNode);
317 CHECK_NULL_VOID(menuPattern);
318 auto pipelineContext = PipelineContext::GetCurrentContext();
319 CHECK_NULL_VOID(pipelineContext);
320 auto dragDropManager = pipelineContext->GetDragDropManager();
321 CHECK_NULL_VOID(dragDropManager);
322 auto frameNode = FrameNode::GetFrameNode(menuPattern->GetTargetTag(), menuPattern->GetTargetId());
323 CHECK_NULL_VOID(frameNode);
324 auto badgeNumber = frameNode->GetDragPreviewOption().GetCustomerBadgeNumber();
325 auto childSize = badgeNumber.has_value() ? static_cast<size_t>(badgeNumber.value()) :
326 manager->GetGatherNodeChildrenInfo().size() + 1;
327 TAG_LOGI(AceLogTag::ACE_DRAG, "Badge node number %{public}d, children count %{public}d",
328 badgeNumber.value_or(-1), static_cast<int32_t>(manager->GetGatherNodeChildrenInfo().size()));
329 auto badgeLength = std::to_string(childSize).size();
330 UpdateBadgeLayoutAndRenderContext(textNode, badgeLength, childSize);
331 auto textRenderContext = textNode->GetRenderContext();
332 CHECK_NULL_VOID(textRenderContext);
333 auto pipeline = PipelineBase::GetCurrentContext();
334 CHECK_NULL_VOID(pipeline);
335 auto offset = CalcBadgeTextOffset(menuPattern, imageNode, pipeline, badgeLength);
336 textRenderContext->UpdatePosition(OffsetT<Dimension>(Dimension(offset.GetX()), Dimension(offset.GetY())));
337 textNode->MarkDirtyNode(NG::PROPERTY_UPDATE_MEASURE);
338 textNode->MarkModifyDone();
339 textNode->SetLayoutDirtyMarked(true);
340 textNode->SetActive(true);
341 auto context = textNode->GetContext();
342 if (context) {
343 context->FlushUITaskWithSingleDirtyNode(textNode);
344 }
345 pipeline->FlushSyncGeometryNodeTasks();
346 }
347
UpdateBadgeLayoutAndRenderContext(const RefPtr<FrameNode> & textNode,int32_t badgeLength,int32_t childSize)348 void DragAnimationHelper::UpdateBadgeLayoutAndRenderContext(
349 const RefPtr<FrameNode>& textNode, int32_t badgeLength, int32_t childSize)
350 {
351 if (childSize <= 1) {
352 return;
353 }
354 CHECK_NULL_VOID(textNode);
355 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
356 CHECK_NULL_VOID(textLayoutProperty);
357 textLayoutProperty->UpdateContent(std::to_string(childSize));
358 textLayoutProperty->UpdateMaxLines(1);
359 textLayoutProperty->UpdateFontWeight(FontWeight::MEDIUM);
360 textLayoutProperty->UpdateTextColor(BADGE_TEXT_FONT_COLOR);
361 textLayoutProperty->UpdateFontSize(BADGE_TEXT_FONT_SIZE);
362 textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
363 int64_t textWidth = BADGE_DEFAULT_SIZE.ConvertToPx() + (BADGE_RELATIVE_OFFSET.ConvertToPx() * (badgeLength - 1));
364 auto textSize = CalcSize(NG::CalcLength(textWidth), NG::CalcLength(BADGE_DEFAULT_SIZE.ConvertToPx()));
365 textLayoutProperty->UpdateUserDefinedIdealSize(textSize);
366
367 auto textRenderContext = textNode->GetRenderContext();
368 CHECK_NULL_VOID(textRenderContext);
369 textRenderContext->SetVisible(true);
370 textRenderContext->UpdateBackgroundColor(BADGE_BACKGROUND_COLOR);
371 BorderRadiusProperty borderRadius;
372 borderRadius.SetRadius(BADGE_DEFAULT_SIZE);
373 textRenderContext->UpdateBorderRadius(borderRadius);
374 }
375
UpdateGatherNodeToTop()376 void DragAnimationHelper::UpdateGatherNodeToTop()
377 {
378 auto mainPipeline = PipelineContext::GetMainPipelineContext();
379 CHECK_NULL_VOID(mainPipeline);
380 auto manager = mainPipeline->GetOverlayManager();
381 CHECK_NULL_VOID(manager);
382 manager->UpdateGatherNodeToTop();
383 }
384
ShowGatherAnimationWithMenu(const RefPtr<FrameNode> & menuWrapperNode)385 void DragAnimationHelper::ShowGatherAnimationWithMenu(const RefPtr<FrameNode>& menuWrapperNode)
386 {
387 TAG_LOGI(AceLogTag::ACE_DRAG, "Show gather animation with menu");
388 auto mainPipeline = PipelineContext::GetMainPipelineContext();
389 CHECK_NULL_VOID(mainPipeline);
390 auto manager = mainPipeline->GetOverlayManager();
391 CHECK_NULL_VOID(manager);
392 manager->SetIsGatherWithMenu(true);
393
394 mainPipeline->AddAfterRenderTask([weakWrapperNode = AceType::WeakClaim(AceType::RawPtr(menuWrapperNode)),
395 weakManager = AceType::WeakClaim(AceType::RawPtr(manager))]() {
396 auto menuWrapperNode = weakWrapperNode.Upgrade();
397 CHECK_NULL_VOID(menuWrapperNode);
398 auto menuWrapperPattern = menuWrapperNode->GetPattern<MenuWrapperPattern>();
399 CHECK_NULL_VOID(menuWrapperPattern);
400 auto manager = weakManager.Upgrade();
401 auto textNode = menuWrapperPattern->GetBadgeNode();
402 auto imageNode = menuWrapperPattern->GetPreview();
403 auto menuNode = menuWrapperPattern->GetMenu();
404 CHECK_NULL_VOID(menuNode);
405 auto menuPattern = menuNode->GetPattern<MenuPattern>();
406 DragAnimationHelper::PlayGatherAnimation(imageNode, manager);
407 DragAnimationHelper::CalcBadgeTextPosition(menuPattern, manager, imageNode, textNode);
408 DragAnimationHelper::ShowBadgeAnimation(textNode);
409 });
410 }
411 }