• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 
16 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/memory/referenced.h"
20 #include "base/perfmonitor/perf_constants.h"
21 #include "base/perfmonitor/perf_monitor.h"
22 #include "base/utils/utils.h"
23 #include "core/animation/page_transition_common.h"
24 #include "core/common/container.h"
25 #include "core/components/common/layout/constants.h"
26 #include "core/components/theme/app_theme.h"
27 #include "core/components_ng/base/view_stack_processor.h"
28 #include "core/components_ng/event/focus_hub.h"
29 #include "core/components_ng/pattern/button/button_layout_property.h"
30 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
31 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
32 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
33 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
34 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
35 #include "core/components_ng/pattern/navigation/title_bar_node.h"
36 #include "core/components_ng/pattern/navrouter/navdestination_event_hub.h"
37 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
38 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
39 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
40 #include "core/components_ng/pattern/navrouter/navrouter_event_hub.h"
41 #include "core/components_ng/pattern/navrouter/navrouter_group_node.h"
42 #include "core/components_ng/pattern/stack/stack_layout_property.h"
43 #include "core/components_ng/pattern/stack/stack_model_ng.h"
44 #include "core/components_ng/pattern/stack/stack_pattern.h"
45 #include "core/components_ng/property/measure_property.h"
46 #include "core/components_ng/property/property.h"
47 #include "core/components_ng/render/render_context.h"
48 #include "core/components_v2/inspector/inspector_constants.h"
49 
50 namespace OHOS::Ace::NG {
51 namespace {
52 constexpr double HALF = 0.5;
53 constexpr double PARENT_PAGE_OFFSET = 0.2;
54 constexpr double PARENT_TITLE_OFFSET = 0.02;
55 constexpr int32_t MASK_DURATION = 350;
56 constexpr int32_t OPACITY_TITLE_OUT_DELAY = 17;
57 constexpr int32_t OPACITY_TITLE_IN_DELAY = 33;
58 constexpr int32_t OPACITY_TITLE_DURATION = 150;
59 constexpr int32_t OPACITY_BACKBUTTON_IN_DELAY = 150;
60 constexpr int32_t OPACITY_BACKBUTTON_IN_DURATION = 200;
61 constexpr int32_t OPACITY_BACKBUTTON_OUT_DURATION = 67;
62 constexpr int32_t DEFAULT_ANIMATION_DURATION = 400;
63 const RefPtr<InterpolatingSpring> interpolatingSpringCurve =
64     AceType::MakeRefPtr<InterpolatingSpring>(18.0f, 1.0f, 324.0f, 36.0f);
65 } // namespace
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)66 RefPtr<NavigationGroupNode> NavigationGroupNode::GetOrCreateGroupNode(
67     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
68 {
69     auto frameNode = GetFrameNode(tag, nodeId);
70     CHECK_NULL_RETURN_NOLOG(!frameNode, AceType::DynamicCast<NavigationGroupNode>(frameNode));
71     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
72     auto navigationGroupNode = AceType::MakeRefPtr<NavigationGroupNode>(tag, nodeId, pattern);
73     navigationGroupNode->InitializePatternAndContext();
74     ElementRegister::GetInstance()->AddUINode(navigationGroupNode);
75     return navigationGroupNode;
76 }
77 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)78 void NavigationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
79 {
80     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
81     CHECK_NULL_VOID(pattern);
82     auto navBar = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
83     CHECK_NULL_VOID(navBar);
84     auto contentNode = navBar->GetNavBarContentNode();
85     if (!contentNode) {
86         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
87         contentNode = FrameNode::GetOrCreateFrameNode(
88             V2::NAVBAR_CONTENT_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
89         navBar->SetNavBarContentNode(contentNode);
90         auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
91         CHECK_NULL_VOID(layoutProperty);
92         navBar->AddChild(contentNode);
93     }
94     contentNode->AddChild(child);
95 }
96 
UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode> & remainChild)97 void NavigationGroupNode::UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode>& remainChild)
98 {
99     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
100     CHECK_NULL_VOID(pattern);
101     const auto& navDestinationNodes = pattern->GetAllNavDestinationNodes();
102 
103     auto navigationContentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
104     CHECK_NULL_VOID(navigationContentNode);
105     bool hasChanged = false;
106     int32_t slot = 0;
107     for (size_t i = 0; i != navDestinationNodes.size(); ++i) {
108         const auto& childNode = navDestinationNodes[i];
109         const auto& uiNode = childNode.second;
110         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
111         CHECK_NULL_VOID(navDestination);
112         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
113         CHECK_NULL_VOID(navDestinationPattern);
114         navDestinationPattern->SetName(childNode.first);
115         navDestinationPattern->SetNavDestinationNode(uiNode);
116         SetBackButtonEvent(navDestination);
117         auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
118         CHECK_NULL_VOID(eventHub);
119         if (i == navDestinationNodes.size() - 1) {
120             // process shallow builder
121             navDestination->ProcessShallowBuilder();
122             navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
123             navDestination->GetEventHub<EventHub>()->SetEnabledInternal(true);
124             // for the navDestination at the top, FireChangeEvent
125             eventHub->FireChangeEvent(true);
126             hasChanged = CheckNeedMeasure(navDestination->GetLayoutProperty()->GetPropertyChangeFlag());
127             if (!hasChanged && NavigationLayoutAlgorithm::IsAutoHeight(GetLayoutProperty<NavigationLayoutProperty>())) {
128                 hasChanged = true;
129             }
130         } else {
131             eventHub->FireChangeEvent(false);
132             // split mode and node is not animation node in stack mode need to hide
133             if (pattern->GetNavigationMode() == NavigationMode::SPLIT ||
134                 navDestination->GetPattern<NavDestinationPattern>()->GetNavDestinationNode() != remainChild) {
135                 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
136             }
137         }
138         int32_t childIndex = navigationContentNode->GetChildIndex(navDestination);
139         if (childIndex < 0) {
140             navigationContentNode->AddChild(navDestination, slot);
141             hasChanged = true;
142         } else if (childIndex != slot) {
143             navDestination->MovePosition(slot);
144             hasChanged = true;
145         }
146         slot++;
147     }
148 
149     while (static_cast<size_t>(slot) < navigationContentNode->GetChildren().size()) {
150         // delete useless nodes that are not at the top
151         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(navigationContentNode->GetLastChild());
152         if (!navDestination) {
153             navigationContentNode->RemoveChild(navigationContentNode->GetLastChild());
154             hasChanged = true;
155             continue;
156         }
157         auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
158         if (eventHub) {
159             eventHub->FireChangeEvent(false);
160         }
161         auto uiNode = navDestination->GetPattern<NavDestinationPattern>()->GetNavDestinationNode();
162         if (uiNode != remainChild) {
163             // remove content child
164             auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
165             auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
166             if (shallowBuilder) {
167                 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
168             }
169             if (navDestination->GetContentNode()) {
170                 navDestination->GetContentNode()->Clean();
171             }
172             navigationContentNode->RemoveChild(navDestination, true);
173             hasChanged = true;
174         } else {
175             // remain the last child for pop animation
176             navDestination->MovePosition(slot);
177             ++slot;
178         }
179     }
180     if (hasChanged) {
181         navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
182     }
183 }
184 
ToJsonValue(std::unique_ptr<JsonValue> & json) const185 void NavigationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json) const
186 {
187     FrameNode::ToJsonValue(json);
188     auto navBarNode = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
189     CHECK_NULL_VOID(navBarNode);
190     navBarNode->ToJsonValue(json);
191 }
192 
GetNavDestinationNode(RefPtr<UINode> uiNode)193 RefPtr<UINode> NavigationGroupNode::GetNavDestinationNode(RefPtr<UINode> uiNode)
194 {
195     if (!uiNode) {
196         return nullptr;
197     }
198     // create NavDestinationNode from uiNode stored in NavigationStack
199     while (uiNode) {
200         if (uiNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
201             // this is a navDestination node
202             return uiNode;
203         }
204         if (AceType::DynamicCast<UINode>(uiNode)) {
205             // this is an UINode, go deep further for navDestination node
206             auto children = uiNode->GetChildren();
207             uiNode = children.front();
208             continue;
209         }
210     }
211     return nullptr;
212 }
213 
AddBackButtonIconToNavDestination(const RefPtr<UINode> & navDestinationNode)214 void NavigationGroupNode::AddBackButtonIconToNavDestination(const RefPtr<UINode>& navDestinationNode)
215 {
216     auto navigationNode = AceType::WeakClaim(this).Upgrade();
217     auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
218     CHECK_NULL_VOID(navigationLayoutProperty);
219     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(navDestinationNode);
220     auto navDestinationLayoutProperty = navDestination->GetLayoutProperty<NavDestinationLayoutProperty>();
221     CHECK_NULL_VOID(navDestinationLayoutProperty);
222 
223     // back button icon
224     if (navigationLayoutProperty->HasNoPixMap()) {
225         if (navigationLayoutProperty->HasImageSource()) {
226             navDestinationLayoutProperty->UpdateImageSource(navigationLayoutProperty->GetImageSourceValue());
227         }
228         if (navigationLayoutProperty->HasPixelMap()) {
229             navDestinationLayoutProperty->UpdatePixelMap(navigationLayoutProperty->GetPixelMapValue());
230         }
231         navDestinationLayoutProperty->UpdateNoPixMap(navigationLayoutProperty->GetNoPixMapValue());
232         navDestination->MarkModifyDone();
233     }
234 }
235 
SetBackButtonVisible(const RefPtr<UINode> & navDestinationNode,bool isVisible)236 void NavigationGroupNode::SetBackButtonVisible(const RefPtr<UINode>& navDestinationNode, bool isVisible)
237 {
238     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(navDestinationNode);
239     CHECK_NULL_VOID(navDestination);
240     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
241     CHECK_NULL_VOID(titleBarNode);
242     auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
243     CHECK_NULL_VOID(titleBarLayoutProperty);
244     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
245     CHECK_NULL_VOID(backButtonNode);
246     auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty<LayoutProperty>();
247     CHECK_NULL_VOID(backButtonLayoutProperty);
248     if (isVisible) {
249         backButtonLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
250     } else {
251         backButtonLayoutProperty->UpdateVisibility(VisibleType::GONE);
252     }
253     backButtonNode->MarkModifyDone();
254     navDestination->UpdateTitleFontSize(isVisible);
255 }
256 
SetBackButtonEvent(const RefPtr<NavDestinationGroupNode> & navDestination,const RefPtr<NavRouterPattern> & navRouterPattern)257 void NavigationGroupNode::SetBackButtonEvent(
258     const RefPtr<NavDestinationGroupNode>& navDestination, const RefPtr<NavRouterPattern>& navRouterPattern)
259 {
260     AddBackButtonIconToNavDestination(navDestination);
261     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
262     CHECK_NULL_VOID(titleBarNode);
263     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
264     CHECK_NULL_VOID(backButtonNode);
265     auto backButtonEventHub = backButtonNode->GetEventHub<EventHub>();
266     CHECK_NULL_VOID(backButtonEventHub);
267     auto onBackButtonEvent =
268         [navDestinationWeak = WeakPtr<NavDestinationGroupNode>(navDestination), navigationWeak = WeakClaim(this),
269             navRouterPatternWeak = WeakPtr<NavRouterPattern>(navRouterPattern)](GestureEvent& /*info*/) {
270             // the one before navDestination in the stack
271             auto navDestination = navDestinationWeak.Upgrade();
272             CHECK_NULL_VOID(navDestination);
273             auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
274             CHECK_NULL_VOID(eventHub);
275             auto onBackPressed = eventHub->GetOnBackPressedEvent();
276             bool isOverride = false;
277             if (onBackPressed != nullptr) {
278                 isOverride = eventHub->FireOnBackPressedEvent();
279             }
280             if (isOverride) {
281                 LOGI("this onBackButtonPressed event returns false");
282                 return;
283             }
284             auto navigation = navigationWeak.Upgrade();
285             CHECK_NULL_VOID(navigation);
286             if (navigation->isOnAnimation_) {
287                 LOGI("animation is ongoing");
288                 return;
289             }
290             auto navigationPattern = navigation->GetPattern<NavigationPattern>();
291             CHECK_NULL_VOID(navigationPattern);
292             auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
293             auto preNavDestinationNode =
294                 navigationPattern->GetPreNavDestination(navDestinationPattern->GetName(), navDestination);
295             auto preNavDestination =
296                 AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(preNavDestinationNode));
297 
298             navigationPattern->RemoveNavDestination();
299             // when js navigationStack is provided, modifyDone will be called by state manager.
300             if (!navigationPattern->GetNavigationStackProvided()) {
301                 navigation->MarkModifyDone();
302                 navigation->MarkDirtyNode();
303             }
304         }; // backButton event
305 
306     navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
307     backButtonEventHub->GetOrCreateGestureEventHub()->SetUserOnClick(onBackButtonEvent);
308 }
309 
GetNavDestinationNodeToHandleBack()310 RefPtr<FrameNode> NavigationGroupNode::GetNavDestinationNodeToHandleBack()
311 {
312     auto pattern = GetPattern<NavigationPattern>();
313     CHECK_NULL_RETURN(pattern, nullptr);
314     const auto& children = contentNode_->GetChildren();
315     if (children.empty()) {
316         return nullptr;
317     }
318     auto mode = pattern->GetNavigationMode();
319     if (mode == NavigationMode::SPLIT) {
320         if (children.size() == 1) {
321             return nullptr;
322         }
323         return AceType::DynamicCast<NavDestinationGroupNode>(children.back());
324     }
325     return AceType::DynamicCast<NavDestinationGroupNode>(children.back());
326 }
327 
ExitTransitionWithPop(const RefPtr<FrameNode> & node)328 void NavigationGroupNode::ExitTransitionWithPop(const RefPtr<FrameNode>& node)
329 {
330     CHECK_NULL_VOID(node);
331     AnimationOption option;
332     option.SetCurve(interpolatingSpringCurve);
333     option.SetFillMode(FillMode::FORWARDS);
334     option.SetDuration(DEFAULT_ANIMATION_DURATION);
335     auto size = GetGeometryNode()->GetFrameSize();
336     auto nodeWidth = size.Width();
337     auto nodeHeight = size.Height();
338 
339     RefPtr<TitleBarNode> titleNode;
340     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
341     CHECK_NULL_VOID(navDestination);
342     navDestination->SetTransitionType(PageTransitionType::EXIT_POP);
343     titleNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
344     CHECK_NULL_VOID(titleNode);
345 
346     option.SetOnFinishEvent(
347         [weakNode = WeakPtr<NavDestinationGroupNode>(navDestination), weakTitle = WeakPtr<TitleBarNode>(titleNode),
348             weakNavigation = WeakClaim(this), id = Container::CurrentId(), nodeWidth, nodeHeight] {
349             ContainerScope scope(id);
350             auto context = PipelineContext::GetCurrentContext();
351             CHECK_NULL_VOID_NOLOG(context);
352             auto taskExecutor = context->GetTaskExecutor();
353             CHECK_NULL_VOID_NOLOG(taskExecutor);
354             // animation finish event should be posted to UI thread
355             taskExecutor->PostTask(
356                 [weakNode, weakTitle, weakNavigation, nodeWidth, nodeHeight]() {
357                     LOGI("navigation animation end");
358                     PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
359                     auto navigation = weakNavigation.Upgrade();
360                     if (navigation) {
361                         navigation->isOnAnimation_ = false;
362                     }
363                     auto node = weakNode.Upgrade();
364                     CHECK_NULL_VOID(node);
365                     if (node->GetTransitionType() != PageTransitionType::EXIT_POP) {
366                         // has another transition, just return
367                         return;
368                     }
369                     node->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
370                     auto title = weakTitle.Upgrade();
371                     if (title) {
372                         title->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
373                     }
374                     node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
375                     node->GetRenderContext()->ClipWithRRect(
376                         RectF(0.0f, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
377                     auto navDestinationPattern = node->GetPattern<NavDestinationPattern>();
378                     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
379                     if (shallowBuilder) {
380                         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
381                     }
382                     if (node->GetContentNode()) {
383                         node->GetContentNode()->Clean();
384                     }
385                     auto parent = node->GetParent();
386                     CHECK_NULL_VOID(parent);
387                     parent->RemoveChild(node);
388                     parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
389                     auto context = PipelineContext::GetCurrentContext();
390                     CHECK_NULL_VOID(context);
391                     context->MarkNeedFlushMouseEvent();
392                 },
393                 TaskExecutor::TaskType::UI);
394         });
395 
396     // content
397     node->GetEventHub<EventHub>()->SetEnabledInternal(false);
398     node->GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
399     node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
400     // title
401     titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
402     AnimationUtils::Animate(
403         option,
404         [node, titleNode, nodeWidth, nodeHeight]() {
405             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
406             LOGI("navigation animation start");
407             // content
408             node->GetRenderContext()->ClipWithRRect(
409                 RectF(nodeWidth * HALF, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
410             node->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
411             // title
412             titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
413         },
414         option.GetOnFinishEvent());
415     TitleOpacityAnimationOut(titleNode->GetRenderContext());
416 
417     // backIcon opacity
418     auto backIcon = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
419     if (backIcon) {
420         BackButtonAnimation(backIcon, false);
421     }
422 
423     isOnAnimation_ = true;
424 }
425 
ExitTransitionWithPush(const RefPtr<FrameNode> & node,bool isNavBar)426 void NavigationGroupNode::ExitTransitionWithPush(const RefPtr<FrameNode>& node, bool isNavBar)
427 {
428     CHECK_NULL_VOID(node);
429     AnimationOption option;
430     option.SetCurve(interpolatingSpringCurve);
431     option.SetFillMode(FillMode::FORWARDS);
432     option.SetDuration(DEFAULT_ANIMATION_DURATION);
433     auto size = GetGeometryNode()->GetFrameSize();
434     auto nodeWidth = size.Width();
435 
436     RefPtr<FrameNode> titleNode;
437     if (isNavBar) {
438         auto navBarNode = AceType::DynamicCast<NavBarNode>(node);
439         navBarNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
440         titleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
441     } else {
442         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
443         navDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
444         titleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
445     }
446     CHECK_NULL_VOID(titleNode);
447 
448     option.SetOnFinishEvent([weakNode = WeakPtr<FrameNode>(node), weakTitle = WeakPtr<FrameNode>(titleNode),
449                                 weakNavigation = WeakClaim(this), isNavBar, id = Container::CurrentId()] {
450         ContainerScope scope(id);
451         auto context = PipelineContext::GetCurrentContext();
452         CHECK_NULL_VOID_NOLOG(context);
453         auto taskExecutor = context->GetTaskExecutor();
454         CHECK_NULL_VOID_NOLOG(taskExecutor);
455         // animation finish event should be posted to UI thread
456         taskExecutor->PostTask(
457             [weakNode, weakTitle, weakNavigation, isNavBar]() {
458                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
459                 LOGI("navigation animation end");
460                 auto navigation = weakNavigation.Upgrade();
461                 if (navigation) {
462                     navigation->isOnAnimation_ = false;
463                 }
464                 auto title = weakTitle.Upgrade();
465                 if (title) {
466                     title->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
467                 }
468                 auto node = weakNode.Upgrade();
469                 CHECK_NULL_VOID(node);
470                 bool needSetInVisible = false;
471                 if (isNavBar) {
472                     needSetInVisible =
473                         AceType::DynamicCast<NavBarNode>(node)->GetTransitionType() == PageTransitionType::EXIT_PUSH;
474                 } else {
475                     needSetInVisible = AceType::DynamicCast<NavDestinationGroupNode>(node)->GetTransitionType() ==
476                                        PageTransitionType::EXIT_PUSH;
477                 }
478                 // for the case, the navBar form EXIT_PUSH to push  during animation
479                 if (needSetInVisible) {
480                     node->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
481                 }
482                 node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
483             },
484             TaskExecutor::TaskType::UI);
485     });
486     node->GetEventHub<EventHub>()->SetEnabledInternal(false);
487     node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
488     titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
489 
490     AnimationUtils::Animate(
491         option,
492         [node, titleNode, nodeWidth]() {
493             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
494             LOGI("navigation animation start");
495             node->GetRenderContext()->UpdateTranslateInXY({ -nodeWidth * PARENT_PAGE_OFFSET, 0.0f });
496             titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * PARENT_TITLE_OFFSET, 0.0f });
497         },
498         option.GetOnFinishEvent());
499     MaskAnimation(node->GetRenderContext());
500     isOnAnimation_ = true;
501 }
502 
EnterTransitionWithPush(const RefPtr<FrameNode> & node,bool isNavBar)503 void NavigationGroupNode::EnterTransitionWithPush(const RefPtr<FrameNode>& node, bool isNavBar)
504 {
505     CHECK_NULL_VOID(node);
506     AnimationOption option;
507     option.SetCurve(interpolatingSpringCurve);
508     option.SetFillMode(FillMode::FORWARDS);
509     option.SetDuration(DEFAULT_ANIMATION_DURATION);
510     auto size = GetGeometryNode()->GetFrameSize();
511     auto nodeWidth = size.Width();
512     auto nodeHeight = size.Height();
513 
514     RefPtr<TitleBarNode> titleNode;
515     if (isNavBar) {
516         auto navBarNode = AceType::DynamicCast<NavBarNode>(node);
517         navBarNode->SetTransitionType(PageTransitionType::ENTER_PUSH);
518         titleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
519     } else {
520         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
521         navDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
522         titleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
523     }
524     CHECK_NULL_VOID(titleNode);
525 
526     option.SetOnFinishEvent([weakNavigation = WeakClaim(this), id = Container::CurrentId()] {
527         ContainerScope scope(id);
528         auto context = PipelineContext::GetCurrentContext();
529         CHECK_NULL_VOID(context);
530         auto taskExecutor = context->GetTaskExecutor();
531         CHECK_NULL_VOID(taskExecutor);
532         // animation finish event should be posted to UI thread.
533         taskExecutor->PostTask(
534             [weakNavigation]() {
535                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
536                 LOGI("navigation animation end");
537                 auto navigation = weakNavigation.Upgrade();
538                 CHECK_NULL_VOID(navigation);
539                 navigation->isOnAnimation_ = false;
540             },
541             TaskExecutor::TaskType::UI);
542     });
543 
544     // content
545     node->GetRenderContext()->ClipWithRRect(
546         RectF(nodeWidth * HALF, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
547     node->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
548     // title
549     titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
550     AnimationUtils::Animate(
551         option,
552         [node, titleNode, nodeWidth, nodeHeight]() {
553             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
554             LOGI("navigation animation start");
555             // content
556             node->GetRenderContext()->ClipWithRRect(
557                 RectF(0.0f, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
558             node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
559             // title
560             titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
561         },
562         option.GetOnFinishEvent());
563     // title opacity
564     AnimationOption opacityOption;
565     opacityOption.SetCurve(Curves::SHARP);
566     opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
567     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
568     opacityOption.SetFillMode(FillMode::FORWARDS);
569     titleNode->GetRenderContext()->OpacityAnimation(opacityOption, 0.0f, 1.0f);
570 
571     // backIcon opacity
572     auto backIcon = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
573     if (backIcon) {
574         BackButtonAnimation(backIcon, true);
575     }
576 
577     isOnAnimation_ = true;
578 }
579 
EnterTransitionWithPop(const RefPtr<FrameNode> & node,bool isNavBar)580 void NavigationGroupNode::EnterTransitionWithPop(const RefPtr<FrameNode>& node, bool isNavBar)
581 {
582     CHECK_NULL_VOID(node);
583     AnimationOption option;
584     option.SetCurve(interpolatingSpringCurve);
585     option.SetFillMode(FillMode::FORWARDS);
586     option.SetDuration(DEFAULT_ANIMATION_DURATION);
587     auto size = GetGeometryNode()->GetFrameSize();
588     auto nodeWidth = size.Width();
589 
590     RefPtr<TitleBarNode> titleNode;
591     if (isNavBar) {
592         auto navBarNode = AceType::DynamicCast<NavBarNode>(node);
593         navBarNode->SetTransitionType(PageTransitionType::ENTER_POP);
594         titleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
595     } else {
596         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
597         navDestination->SetTransitionType(PageTransitionType::ENTER_POP);
598         titleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
599     }
600     CHECK_NULL_VOID(titleNode);
601 
602     option.SetOnFinishEvent([weakNavigation = WeakClaim(this), id = Container::CurrentId()] {
603         ContainerScope scope(id);
604         auto context = PipelineContext::GetCurrentContext();
605         CHECK_NULL_VOID(context);
606         auto taskExecutor = context->GetTaskExecutor();
607         CHECK_NULL_VOID(taskExecutor);
608         // animation finish event should be posted to UI thread.
609         taskExecutor->PostTask(
610             [weakNavigation]() {
611                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
612                 LOGI("navigation animation end");
613                 auto navigation = weakNavigation.Upgrade();
614                 CHECK_NULL_VOID(navigation);
615                 navigation->isOnAnimation_ = false;
616             },
617             TaskExecutor::TaskType::UI);
618     });
619 
620     // content
621     node->GetRenderContext()->UpdateTranslateInXY({ -nodeWidth * PARENT_PAGE_OFFSET, 0.0f });
622     // title
623     titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * PARENT_TITLE_OFFSET, 0.0f });
624     AnimationUtils::Animate(
625         option,
626         [node, titleNode]() {
627             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
628             LOGI("navigation animation start");
629             node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
630             titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
631         },
632         option.GetOnFinishEvent());
633 
634     AnimationOption maskOption;
635     maskOption.SetCurve(Curves::FRICTION);
636     maskOption.SetDuration(MASK_DURATION);
637     maskOption.SetFillMode(FillMode::FORWARDS);
638     node->GetRenderContext()->SetActualForegroundColor(MASK_COLOR);
639     AnimationUtils::Animate(
640         maskOption, [node]() { node->GetRenderContext()->SetActualForegroundColor(DEFAULT_MASK_COLOR); });
641     isOnAnimation_ = true;
642 }
643 
BackButtonAnimation(const RefPtr<FrameNode> & backButtonNode,bool isTransitionIn)644 void NavigationGroupNode::BackButtonAnimation(const RefPtr<FrameNode>& backButtonNode, bool isTransitionIn)
645 {
646     AnimationOption transitionOption;
647     transitionOption.SetCurve(Curves::SHARP);
648     transitionOption.SetFillMode(FillMode::FORWARDS);
649     auto backButtonNodeContext = backButtonNode->GetRenderContext();
650     CHECK_NULL_VOID(backButtonNodeContext);
651     if (isTransitionIn) {
652         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
653         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
654         backButtonNodeContext->OpacityAnimation(transitionOption, 0.0, 1.0);
655     } else {
656         transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
657         transitionOption.SetOnFinishEvent(
658             [backButtonNodeContextWK = WeakClaim(RawPtr(backButtonNodeContext)), id = Container::CurrentId()] {
659                 ContainerScope scope(id);
660                 auto context = PipelineContext::GetCurrentContext();
661                 CHECK_NULL_VOID_NOLOG(context);
662                 auto taskExecutor = context->GetTaskExecutor();
663                 CHECK_NULL_VOID_NOLOG(taskExecutor);
664                 // animation finish event should be posted to UI thread.
665                 taskExecutor->PostTask(
666                     [backButtonNodeContextWK, id]() {
667                         auto backButtonNodeContext = backButtonNodeContextWK.Upgrade();
668                         CHECK_NULL_VOID_NOLOG(backButtonNodeContext);
669                         ContainerScope scope(id);
670                         backButtonNodeContext->UpdateOpacity(1.0);
671                     },
672                     TaskExecutor::TaskType::UI);
673             });
674         backButtonNodeContext->OpacityAnimation(transitionOption, 1.0, 0.0);
675     }
676 }
677 
MaskAnimation(const RefPtr<RenderContext> & transitionOutNodeContext)678 void NavigationGroupNode::MaskAnimation(const RefPtr<RenderContext>& transitionOutNodeContext)
679 {
680     AnimationOption maskOption;
681     maskOption.SetCurve(Curves::FRICTION);
682     maskOption.SetDuration(MASK_DURATION);
683     maskOption.SetFillMode(FillMode::FORWARDS);
684     maskOption.SetOnFinishEvent(
685         [transitionOutNodeContextWK = WeakPtr<RenderContext>(transitionOutNodeContext), id = Container::CurrentId()] {
686             ContainerScope scope(id);
687             auto context = PipelineContext::GetCurrentContext();
688             CHECK_NULL_VOID_NOLOG(context);
689             auto taskExecutor = context->GetTaskExecutor();
690             CHECK_NULL_VOID_NOLOG(taskExecutor);
691             taskExecutor->PostTask(
692                 [transitionOutNodeContextWK]() {
693                     auto transitionOutNodeContext = transitionOutNodeContextWK.Upgrade();
694                     if (transitionOutNodeContext) {
695                         transitionOutNodeContext->SetActualForegroundColor(DEFAULT_MASK_COLOR);
696                     }
697                 },
698                 TaskExecutor::TaskType::UI);
699         });
700     transitionOutNodeContext->SetActualForegroundColor(DEFAULT_MASK_COLOR);
701     AnimationUtils::Animate(
702         maskOption, [transitionOutNodeContext]() { transitionOutNodeContext->SetActualForegroundColor(MASK_COLOR); },
703         maskOption.GetOnFinishEvent());
704 }
705 
TitleOpacityAnimationOut(const RefPtr<RenderContext> & transitionOutNodeContext)706 void NavigationGroupNode::TitleOpacityAnimationOut(const RefPtr<RenderContext>& transitionOutNodeContext)
707 {
708     AnimationOption opacityOption;
709     opacityOption.SetCurve(Curves::SHARP);
710     opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
711     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
712     opacityOption.SetFillMode(FillMode::FORWARDS);
713     opacityOption.SetOnFinishEvent(
714         [transitionOutNodeContextWK = WeakPtr<RenderContext>(transitionOutNodeContext), id = Container::CurrentId()] {
715             ContainerScope scope(id);
716             auto context = PipelineContext::GetCurrentContext();
717             CHECK_NULL_VOID(context);
718             auto taskExecutor = context->GetTaskExecutor();
719             CHECK_NULL_VOID(taskExecutor);
720             // animation finish event should be posted to UI thread.
721             taskExecutor->PostTask(
722                 [transitionOutNodeContextWK, id]() {
723                     auto transitionOutNodeContext = transitionOutNodeContextWK.Upgrade();
724                     CHECK_NULL_VOID_NOLOG(transitionOutNodeContext);
725                     transitionOutNodeContext->UpdateOpacity(1.0);
726                 },
727                 TaskExecutor::TaskType::UI);
728         });
729     transitionOutNodeContext->OpacityAnimation(opacityOption, 1.0, 0.0);
730     transitionOutNodeContext->UpdateOpacity(0.0);
731 }
732 } // namespace OHOS::Ace::NG
733