• 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/pattern/stage/page_pattern.h"
46 #include "core/components_ng/property/measure_property.h"
47 #include "core/components_ng/property/property.h"
48 #include "core/components_ng/render/render_context.h"
49 #include "core/components_v2/inspector/inspector_constants.h"
50 
51 namespace OHOS::Ace::NG {
52 namespace {
53 constexpr double HALF = 0.5;
54 constexpr double PARENT_PAGE_OFFSET = 0.2;
55 constexpr double PARENT_TITLE_OFFSET = 0.02;
56 constexpr float REMOVE_CLIP_SIZE = 10000.0f;
57 constexpr int32_t MASK_DURATION = 350;
58 constexpr int32_t OPACITY_TITLE_OUT_DELAY = 17;
59 constexpr int32_t OPACITY_TITLE_IN_DELAY = 33;
60 constexpr int32_t OPACITY_TITLE_DURATION = 150;
61 constexpr int32_t OPACITY_BACKBUTTON_IN_DELAY = 150;
62 constexpr int32_t OPACITY_BACKBUTTON_IN_DURATION = 200;
63 constexpr int32_t OPACITY_BACKBUTTON_OUT_DURATION = 67;
64 constexpr int32_t DEFAULT_ANIMATION_DURATION = 450;
65 constexpr int32_t DEFAULT_REPLACE_DURATION = 150;
66 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
67 const RefPtr<InterpolatingSpring> springCurve = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f);
68 const RefPtr<CubicCurve> replaceCurve = AceType::MakeRefPtr<CubicCurve>(0.33, 0.0, 0.67, 1.0);
69 } // namespace
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)70 RefPtr<NavigationGroupNode> NavigationGroupNode::GetOrCreateGroupNode(
71     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
72 {
73     auto frameNode = GetFrameNode(tag, nodeId);
74     CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavigationGroupNode>(frameNode));
75     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
76     auto navigationGroupNode = AceType::MakeRefPtr<NavigationGroupNode>(tag, nodeId, pattern);
77     navigationGroupNode->InitializePatternAndContext();
78     ElementRegister::GetInstance()->AddUINode(navigationGroupNode);
79     return navigationGroupNode;
80 }
81 
~NavigationGroupNode()82 NavigationGroupNode::~NavigationGroupNode()
83 {
84     auto context = PipelineContext::GetCurrentContext();
85     CHECK_NULL_VOID(context);
86     auto stageManager = context->GetStageManager();
87     CHECK_NULL_VOID(stageManager);
88     RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
89     CHECK_NULL_VOID(pageNode);
90     auto pagePattern = pageNode->GetPattern<PagePattern>();
91     CHECK_NULL_VOID(pagePattern);
92     CHECK_NULL_VOID(pagePattern->GetPageInfo());
93     int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
94     context->RemoveNavigationStateCallback(pageId, GetId());
95     context->DeleteNavigationNode(curId_);
96 }
97 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)98 void NavigationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
99 {
100     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
101     CHECK_NULL_VOID(pattern);
102     auto navBar = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
103     CHECK_NULL_VOID(navBar);
104     auto contentNode = navBar->GetNavBarContentNode();
105     if (!contentNode) {
106         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
107         contentNode = FrameNode::GetOrCreateFrameNode(
108             V2::NAVBAR_CONTENT_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
109         navBar->SetNavBarContentNode(contentNode);
110         navBar->AddChild(contentNode);
111 
112         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
113             auto navBarContentNode = AceType::DynamicCast<FrameNode>(contentNode);
114             SafeAreaExpandOpts opts = {.type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_ALL};
115             navBarContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
116         }
117     }
118     contentNode->AddChild(child);
119 }
120 
UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode> & remainChild,bool modeChange)121 void NavigationGroupNode::UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode>& remainChild, bool modeChange)
122 {
123     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
124     CHECK_NULL_VOID(pattern);
125     const auto& navDestinationNodes = pattern->GetAllNavDestinationNodes();
126 
127     auto navigationContentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
128     CHECK_NULL_VOID(navigationContentNode);
129     bool hasChanged = false;
130     int32_t slot = 0;
131     UpdateLastStandardIndex();
132     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "last standard page index is %{public}d", lastStandardIndex_);
133     for (uint32_t i = 0; i != navDestinationNodes.size(); ++i) {
134         const auto& childNode = navDestinationNodes[i];
135         const auto& uiNode = childNode.second;
136         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
137         if (navDestination == nullptr) {
138             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get destination node failed");
139             return;
140         }
141         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
142         CHECK_NULL_VOID(navDestinationPattern);
143         navDestinationPattern->SetName(childNode.first);
144         navDestinationPattern->SetCustomNode(uiNode);
145         SetBackButtonEvent(navDestination);
146         navDestination->SetIndex(i);
147         auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
148         CHECK_NULL_VOID(eventHub);
149         if (!eventHub->GetOnStateChange()) {
150             auto onStateChangeMap = pattern->GetOnStateChangeMap();
151             auto iter = onStateChangeMap.find(uiNode->GetId());
152             if (iter != onStateChangeMap.end()) {
153                 eventHub->SetOnStateChange(iter->second);
154                 pattern->DeleteOnStateChangeItem(iter->first);
155             }
156         }
157         int32_t childIndex = navigationContentNode->GetChildIndex(navDestination);
158         if (childIndex < 0) {
159             navigationContentNode->AddChild(navDestination, slot);
160             hasChanged = true;
161         } else if (childIndex != slot) {
162             navDestination->MovePosition(slot);
163             hasChanged = true;
164         }
165         slot++;
166     }
167 
168     for (int32_t i = static_cast<int32_t>(navDestinationNodes.size()) - 1; i >= 0; --i) {
169         const auto& childNode = navDestinationNodes[i];
170         const auto& uiNode = childNode.second;
171         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
172         hasChanged = (UpdateNavDestinationVisibility(navDestination, remainChild, i, navDestinationNodes.size())
173          || hasChanged);
174     }
175 
176     while (static_cast<size_t>(slot) < navigationContentNode->GetChildren().size()) {
177         // delete useless nodes that are not at the top
178         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(navigationContentNode->GetLastChild());
179         if (!navDestination) {
180             navigationContentNode->RemoveChild(navigationContentNode->GetLastChild());
181             hasChanged = true;
182             continue;
183         }
184         auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
185         if (eventHub) {
186             eventHub->FireChangeEvent(false);
187         }
188         auto uiNode = navDestination->GetPattern<NavDestinationPattern>()->GetCustomNode();
189         if (uiNode != remainChild) {
190             if (navDestination->IsOnAnimation()) {
191                 // The NavDestination in the animation needs to be cleaned in the animation onfinish callback.
192                 ++slot;
193                 continue;
194             }
195             // remove content child
196             auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
197             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "remove child: %{public}s", navDestinationPattern->GetName().c_str());
198             if (navDestinationPattern->GetIsOnShow()) {
199                 eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
200                 navDestinationPattern->SetIsOnShow(false);
201                 NavigationPattern::FireNavigationStateChange(navDestination, false);
202             }
203             auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
204             if (shallowBuilder) {
205                 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
206             }
207             if (navDestination->GetContentNode()) {
208                 navDestination->GetContentNode()->Clean();
209             }
210             navigationContentNode->RemoveChild(navDestination, true);
211             navDestinationPattern->SetCustomNode(nullptr);
212             hasChanged = true;
213         } else {
214             // remain the last child for pop animation
215             navDestination->MovePosition(slot);
216             ++slot;
217         }
218     }
219     if (modeChange) {
220         navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
221     } else if (hasChanged) {
222         navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
223     }
224 }
225 
ToJsonValue(std::unique_ptr<JsonValue> & json) const226 void NavigationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json) const
227 {
228     FrameNode::ToJsonValue(json);
229     auto navBarNode = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
230     CHECK_NULL_VOID(navBarNode);
231     navBarNode->ToJsonValue(json);
232 }
233 
GetNavDestinationNode(RefPtr<UINode> uiNode)234 RefPtr<UINode> NavigationGroupNode::GetNavDestinationNode(RefPtr<UINode> uiNode)
235 {
236     if (!uiNode) {
237         return nullptr;
238     }
239     // create NavDestinationNode from uiNode stored in NavigationStack
240     while (uiNode) {
241         if (uiNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
242             // this is a navDestination node
243             return uiNode;
244         }
245         if (AceType::DynamicCast<UINode>(uiNode)) {
246             // this is an UINode, go deep further for navDestination node
247             auto children = uiNode->GetChildren();
248             uiNode = children.front();
249             continue;
250         }
251     }
252     CHECK_NULL_RETURN(uiNode, nullptr);
253     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get navDestination node failed: id: %{public}d, %{public}s",
254         uiNode->GetId(), uiNode->GetTag().c_str());
255     return nullptr;
256 }
257 
SetBackButtonEvent(const RefPtr<NavDestinationGroupNode> & navDestination)258 void NavigationGroupNode::SetBackButtonEvent(const RefPtr<NavDestinationGroupNode>& navDestination)
259 {
260     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
261     CHECK_NULL_VOID(titleBarNode);
262     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
263     CHECK_NULL_VOID(backButtonNode);
264     auto backButtonEventHub = backButtonNode->GetEventHub<EventHub>();
265     CHECK_NULL_VOID(backButtonEventHub);
266     auto onBackButtonEvent = [navDestinationWeak = WeakPtr<NavDestinationGroupNode>(navDestination),
267                                  navigationWeak = WeakClaim(this)](GestureEvent& /*info*/) -> bool {
268         auto navDestination = navDestinationWeak.Upgrade();
269         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "click navigation back button");
270         CHECK_NULL_RETURN(navDestination, false);
271         auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
272         CHECK_NULL_RETURN(eventHub, false);
273         auto isOverride = eventHub->GetOnBackPressedEvent();
274         auto result = false;
275         if (isOverride) {
276             result = eventHub->FireOnBackPressedEvent();
277         }
278         if (result) {
279             return true;
280         }
281         auto navigation = navigationWeak.Upgrade();
282         CHECK_NULL_RETURN(navigation, false);
283         // if set hideNavBar and stack size is one, return false
284         auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(navigation->GetLayoutProperty());
285         auto pattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
286         auto stack = pattern->GetNavigationStack();
287         CHECK_NULL_RETURN(stack, false);
288         if (navigationLayoutProperty->GetHideNavBarValue(false) && stack->Size() <= 1) {
289             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "set hideNavBar and stack size is no more than one");
290             return false;
291         }
292         const auto& children = navigation->GetContentNode()->GetChildren();
293         auto isLastChild = children.size() == 1;
294         if (isOverride) {
295             result = navigation->HandleBack(navDestination, isLastChild, true);
296         } else {
297             result = navigation->HandleBack(navDestination, isLastChild, false);
298         }
299         // when js navigationStack is provided, modifyDone will be called by state manager.
300         auto navigationPattern = navigation->GetPattern<NavigationPattern>();
301         CHECK_NULL_RETURN(navigationPattern, false);
302         if (!navigationPattern->GetNavigationStackProvided()) {
303             navigation->MarkModifyDone();
304             navigation->MarkDirtyNode();
305         }
306 
307         return result;
308     }; // backButton event
309 
310     navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
311     backButtonEventHub->GetOrCreateGestureEventHub()->SetUserOnClick(onBackButtonEvent);
312 }
313 
CheckCanHandleBack()314 bool NavigationGroupNode::CheckCanHandleBack()
315 {
316     auto navigation = AceType::WeakClaim(this).Upgrade();
317     CHECK_NULL_RETURN(navigation, false);
318     auto navigationPattern = GetPattern<NavigationPattern>();
319     CHECK_NULL_RETURN(navigationPattern, false);
320 
321     auto navigationStack = navigationPattern->GetNavigationStack();
322     CHECK_NULL_RETURN(navigationStack, false);
323     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
324         NavigationGroupNode::GetNavDestinationNode(navigationStack->Get()));
325     if (!navDestination) {
326         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find destination node to process back press");
327         return false;
328     }
329     auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
330     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination consume back button event: %{public}s",
331         navDestinationPattern->GetName().c_str());
332     GestureEvent gestureEvent;
333     return navDestination->GetNavDestinationBackButtonEvent()(gestureEvent);
334 }
335 
HandleBack(const RefPtr<FrameNode> & node,bool isLastChild,bool isOverride)336 bool NavigationGroupNode::HandleBack(const RefPtr<FrameNode>& node, bool isLastChild, bool isOverride)
337 {
338     auto navigationPattern = GetPattern<NavigationPattern>();
339     if (!isOverride && !isLastChild) {
340         navigationPattern->RemoveNavDestination();
341         return true;
342     }
343     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
344     CHECK_NULL_RETURN(navDestination, false);
345 
346     auto mode = navigationPattern->GetNavigationMode();
347     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
348     if (isLastChild && (mode == NavigationMode::SPLIT ||
349                            (mode == NavigationMode::STACK && layoutProperty->GetHideNavBar().value_or(false)))) {
350         return false;
351     }
352 
353     navigationPattern->RemoveNavDestination();
354     return true;
355 }
356 
TransitionWithPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)357 void NavigationGroupNode::TransitionWithPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
358     bool isNavBar)
359 {
360     CHECK_NULL_VOID(preNode);
361 
362     auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
363     CHECK_NULL_VOID(preNavDestination);
364     preNavDestination->SetTransitionType(PageTransitionType::EXIT_POP);
365 
366     /* obtain preTitle, preBackIcon and preFrameSize of preNavDestination */
367     auto preTitleNode = AceType::DynamicCast<TitleBarNode>(preNavDestination->GetTitleBarNode());
368     CHECK_NULL_VOID(preTitleNode);
369     auto preBackIcon = AceType::DynamicCast<FrameNode>(preTitleNode->GetBackButton());
370     CHECK_NULL_VOID(preBackIcon);
371 
372     auto preFrameSize = preNode->GetGeometryNode()->GetFrameSize();
373     RefPtr<TitleBarNode> curTitleNode;
374     if (curNode) {
375         if (isNavBar) {
376             auto navBarNode = AceType::DynamicCast<NavBarNode>(curNode);
377             CHECK_NULL_VOID(navBarNode);
378             navBarNode->SetTransitionType(PageTransitionType::ENTER_POP);
379             curTitleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
380         } else {
381             auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
382             CHECK_NULL_VOID(curNavDestination);
383             curNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
384             curTitleNode =
385                 curNavDestination ? AceType::DynamicCast<TitleBarNode>(curNavDestination->GetTitleBarNode()) : nullptr;
386         }
387         CHECK_NULL_VOID(curTitleNode);
388     }
389 
390     /* create animation finish callback */
391     AnimationFinishCallback callback = [weakPreNode = WeakPtr<NavDestinationGroupNode>(preNavDestination),
392         weakPreTitle = WeakPtr<TitleBarNode>(preTitleNode),
393         weakPreBackIcon = WeakPtr<FrameNode>(preBackIcon),
394         weakNavigation = WeakClaim(this)] {
395             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation pop animation end");
396             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
397             auto navigation = weakNavigation.Upgrade();
398             if (navigation) {
399                 navigation->isOnAnimation_ = false;
400                 navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
401             }
402             auto preNavDesNode = weakPreNode.Upgrade();
403             CHECK_NULL_VOID(preNavDesNode);
404             if (preNavDesNode->GetTransitionType() != PageTransitionType::EXIT_POP) {
405                 // has another transition, just return
406                 return;
407             }
408             auto preNavDesPattern = preNavDesNode->GetPattern<NavDestinationPattern>();
409             CHECK_NULL_VOID(preNavDesPattern);
410             // NavRouter will restore the preNavDesNode and needs to set the initial state after the animation ends.
411             auto shallowBuilder = preNavDesPattern->GetShallowBuilder();
412             if (shallowBuilder) {
413                 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
414             }
415             preNavDesNode->SetIsOnAnimation(false);
416             preNavDesNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
417             preNavDesNode->GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, REMOVE_CLIP_SIZE, REMOVE_CLIP_SIZE),
418                 RadiusF(EdgeF(0.0f, 0.0f)));
419             preNavDesNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
420             auto preTitleNode = weakPreTitle.Upgrade();
421             if (preTitleNode) {
422                 preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
423             }
424 
425             if (!preNavDesNode->IsCacheNode() && preNavDesNode->GetContentNode()) {
426                 preNavDesNode->GetContentNode()->Clean();
427             }
428 
429             auto parent = preNavDesNode->GetParent();
430             CHECK_NULL_VOID(parent);
431             parent->RemoveChild(preNavDesNode);
432             preNavDesPattern->SetCustomNode(nullptr);
433             parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
434             auto context = PipelineContext::GetCurrentContext();
435             CHECK_NULL_VOID(context);
436             context->MarkNeedFlushMouseEvent();
437         };
438 
439     /* set initial status of animation */
440     preNode->GetEventHub<EventHub>()->SetEnabledInternal(false);
441     preNode->GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, preFrameSize.Width(), REMOVE_CLIP_SIZE),
442         RadiusF(EdgeF(0.0f, 0.0f)));
443     preNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
444     preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
445     preNavDestination->SetIsOnAnimation(true);
446 
447     if (curNode) {
448         auto curFrameSize = curNode->GetGeometryNode()->GetFrameSize();
449         curNode->GetRenderContext()->ClipWithRRect(
450             RectF(0.0f, 0.0f, REMOVE_CLIP_SIZE, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
451         curNode->GetRenderContext()->UpdateTranslateInXY({ -curFrameSize.Width() * PARENT_PAGE_OFFSET, 0.0f });
452         curTitleNode->GetRenderContext()->UpdateTranslateInXY({ curFrameSize.Width() * PARENT_TITLE_OFFSET, 0.0f });
453     }
454 
455     /* start transition animation */
456     AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
457         callback);
458     AnimationUtils::Animate(option, [preNode, preTitleNode, preFrameSize, curNode, curTitleNode]() {
459         PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
460         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation pop animation start");
461         /* preNode */
462         preNode->GetRenderContext()->ClipWithRRect(
463             RectF(preFrameSize.Width() * HALF, 0.0f, preFrameSize.Width(), REMOVE_CLIP_SIZE),
464             RadiusF(EdgeF(0.0f, 0.0f)));
465         preNode->GetRenderContext()->UpdateTranslateInXY({ preFrameSize.Width() * HALF, 0.0f });
466         preTitleNode->GetRenderContext()->UpdateTranslateInXY({ preFrameSize.Width() * HALF, 0.0f });
467 
468         /* curNode */
469         if (curNode) {
470             curNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
471             curTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
472         }
473     }, option.GetOnFinishEvent());
474 
475     /* opacity for title and backIcon */
476     TitleOpacityAnimation(preTitleNode, true);
477     BackButtonAnimation(preBackIcon, false);
478 
479     /* mask animation */
480     if (curNode) {
481         AnimationOption maskOption = CreateAnimationOption(Curves::FRICTION, FillMode::FORWARDS, MASK_DURATION,
482             nullptr);
483         curNode->GetRenderContext()->SetActualForegroundColor(MASK_COLOR);
484         AnimationUtils::Animate(
485             maskOption, [curNode]() { curNode->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT); });
486     }
487 
488     // clear this flag for navBar layout only
489     if (isNavBar) {
490         SetNeedSetInvisible(false);
491     }
492     isOnAnimation_ = true;
493 }
494 
TransitionWithPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)495 void NavigationGroupNode::TransitionWithPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
496     bool isNavBar)
497 {
498     CHECK_NULL_VOID(preNode);
499     CHECK_NULL_VOID(curNode);
500 
501     RefPtr<FrameNode> preTitleNode;
502     if (isNavBar) {
503         auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
504         navBarNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
505         preTitleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
506     } else {
507         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
508         navDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
509         preTitleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
510     }
511     CHECK_NULL_VOID(preTitleNode);
512 
513     auto mode = GetNavigationMode();
514     auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
515     CHECK_NULL_VOID(curNavDestination);
516     curNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
517     auto curTitleNode = AceType::DynamicCast<TitleBarNode>(curNavDestination->GetTitleBarNode());
518     CHECK_NULL_VOID(curTitleNode);
519 
520     auto preFrameSize = preNode->GetGeometryNode()->GetFrameSize();
521     auto curFrameSize = curNode->GetGeometryNode()->GetFrameSize();
522 
523     /* Create animation callback */
524     AnimationFinishCallback callback = [weakPreNode = WeakPtr<FrameNode>(preNode),
525         weakPreTitle = WeakPtr<FrameNode>(preTitleNode),
526         weakNavigation = WeakClaim(this),
527         weakCurNode = WeakPtr<FrameNode>(curNode),
528         isNavBar] {
529             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
530             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation end");
531             auto navigation = weakNavigation.Upgrade();
532             CHECK_NULL_VOID(navigation);
533             auto preNode = weakPreNode.Upgrade();
534             CHECK_NULL_VOID(preNode);
535             auto preTitle = weakPreTitle.Upgrade();
536             if (preTitle) {
537                 preTitle->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
538             }
539             preNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
540             preNode->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
541             bool needSetInvisible = false;
542             if (isNavBar) {
543                 needSetInvisible = AceType::DynamicCast<NavBarNode>(preNode)->GetTransitionType() ==
544                     PageTransitionType::EXIT_PUSH;
545                 // store this flag for navBar layout only
546                 navigation->SetNeedSetInvisible(needSetInvisible);
547             } else {
548                 needSetInvisible = AceType::DynamicCast<NavDestinationGroupNode>(preNode)->GetTransitionType() ==
549                                     PageTransitionType::EXIT_PUSH;
550             }
551             // for the case, the navBar form EXIT_PUSH to push during animation
552             if (needSetInvisible) {
553                 if (!isNavBar) {
554                     preNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
555                     preNode->SetJSViewActive(false);
556                 } else {
557                     // navigation mode could be transformed to split mode in the process of animation and
558                     // navBar will be invisible only under the stack mode
559                     if (navigation->GetNavigationMode() == NavigationMode::STACK) {
560                         preNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
561                         preNode->SetJSViewActive(false);
562                         navigation->NotifyPageHide();
563                     }
564                 }
565             }
566 
567             navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
568             auto curNode = weakCurNode.Upgrade();
569             CHECK_NULL_VOID(curNode);
570             if (AceType::DynamicCast<NavDestinationGroupNode>(curNode)->GetTransitionType() !=
571                 PageTransitionType::ENTER_PUSH) {
572                 return;
573             }
574             navigation->isOnAnimation_ = false;
575             curNode->GetRenderContext()->ClipWithRRect(
576                 RectF(0.0f, 0.0f, REMOVE_CLIP_SIZE, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
577         };
578 
579     /* set initial status of animation */
580     /* preNode */
581     preNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
582     preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
583     /* curNode */
584     curNode->GetRenderContext()->ClipWithRRect(
585         RectF(curFrameSize.Width() * HALF, 0.0f, curFrameSize.Width(), REMOVE_CLIP_SIZE),
586         RadiusF(EdgeF(0.0f, 0.0f)));
587     curNode->GetRenderContext()->UpdateTranslateInXY({ curFrameSize.Width() * HALF, 0.0f });
588     curTitleNode->GetRenderContext()->UpdateTranslateInXY({ curFrameSize.Width() * HALF, 0.0f });
589 
590     /* start transition animation */
591     AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
592         callback);
593     AnimationUtils::Animate(option, [preNode, preTitleNode, curNode, curTitleNode, preFrameSize, curFrameSize,
594         mode]() {
595         PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
596         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation start");
597         // preNode
598         preNode->GetRenderContext()->UpdateTranslateInXY({ -preFrameSize.Width() * PARENT_PAGE_OFFSET, 0.0f });
599         preTitleNode->GetRenderContext()->UpdateTranslateInXY({ preFrameSize.Width() * PARENT_TITLE_OFFSET, 0.0f });
600         // curNode
601         curNode->GetRenderContext()->ClipWithRRect(
602             RectF(0.0f, 0.0f, curFrameSize.Width(), REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
603         curNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
604         curTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
605     }, option.GetOnFinishEvent());
606     MaskAnimation(preNode->GetRenderContext());
607 
608     // title opacity
609     TitleOpacityAnimation(curTitleNode, false);
610     // backIcon opacity
611     auto backIcon = AceType::DynamicCast<FrameNode>(curTitleNode->GetBackButton());
612     BackButtonAnimation(backIcon, true);
613     isOnAnimation_ = true;
614 }
615 
BackButtonAnimation(const RefPtr<FrameNode> & backButtonNode,bool isTransitionIn)616 void NavigationGroupNode::BackButtonAnimation(const RefPtr<FrameNode>& backButtonNode, bool isTransitionIn)
617 {
618     CHECK_NULL_VOID(backButtonNode);
619     AnimationOption transitionOption;
620     transitionOption.SetCurve(Curves::SHARP);
621     auto backButtonNodeContext = backButtonNode->GetRenderContext();
622     CHECK_NULL_VOID(backButtonNodeContext);
623     if (isTransitionIn) {
624         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
625         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
626         backButtonNodeContext->OpacityAnimation(transitionOption, 0.0, 1.0);
627     } else {
628         transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
629         // recover after transition animation.
630         transitionOption.SetOnFinishEvent([backButtonNodeContext]() {
631             backButtonNodeContext->UpdateOpacity(1.0);
632             backButtonNodeContext->SetOpacity(1.0f);
633         });
634         backButtonNodeContext->OpacityAnimation(transitionOption, 1.0, 0.0);
635     }
636 }
637 
MaskAnimation(const RefPtr<RenderContext> & transitionOutNodeContext)638 void NavigationGroupNode::MaskAnimation(const RefPtr<RenderContext>& transitionOutNodeContext)
639 {
640     AnimationOption maskOption;
641     maskOption.SetCurve(Curves::FRICTION);
642     maskOption.SetDuration(MASK_DURATION);
643     maskOption.SetFillMode(FillMode::FORWARDS);
644     transitionOutNodeContext->SetActualForegroundColor(Color::TRANSPARENT);
645     AnimationUtils::Animate(
646         maskOption, [transitionOutNodeContext]() { transitionOutNodeContext->SetActualForegroundColor(MASK_COLOR); },
647         maskOption.GetOnFinishEvent());
648 }
649 
TitleOpacityAnimation(const RefPtr<FrameNode> & node,bool isTransitionOut)650 void NavigationGroupNode::TitleOpacityAnimation(const RefPtr<FrameNode>& node, bool isTransitionOut)
651 {
652     auto titleNode = AceType::DynamicCast<TitleBarNode>(node);
653     CHECK_NULL_VOID(titleNode);
654     auto titleRenderContext = titleNode->GetRenderContext();
655     CHECK_NULL_VOID(titleRenderContext);
656     AnimationOption opacityOption;
657     opacityOption.SetCurve(Curves::SHARP);
658     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
659     if (isTransitionOut) {
660         opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
661         // recover after transition animation.
662         opacityOption.SetOnFinishEvent([titleRenderContext]() {
663             titleRenderContext->UpdateOpacity(1.0);
664             titleRenderContext->SetOpacity(1.0f);
665         });
666         titleRenderContext->OpacityAnimation(opacityOption, 1.0, 0.0);
667     } else {
668         opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
669         titleRenderContext->OpacityAnimation(opacityOption, 0.0, 1.0);
670     }
671 }
672 
TransitionWithReplace(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)673 void NavigationGroupNode::TransitionWithReplace(
674     const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode, bool isNavBar)
675 {
676     CHECK_NULL_VOID(preNode);
677     CHECK_NULL_VOID(curNode);
678     AnimationOption option;
679     option.SetCurve(replaceCurve);
680     option.SetFillMode(FillMode::FORWARDS);
681     option.SetDuration(DEFAULT_REPLACE_DURATION);
682     option.SetOnFinishEvent([weakPreNode = WeakPtr<FrameNode>(preNode), weakNavigation = WeakClaim(this),
683                                 isNavBar]() {
684         PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
685         auto preNode = weakPreNode.Upgrade();
686         CHECK_NULL_VOID(preNode);
687         auto navigationNode = weakNavigation.Upgrade();
688         CHECK_NULL_VOID(navigationNode);
689         navigationNode->isOnAnimation_ = false;
690         navigationNode->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
691         navigationNode->DealNavigationExit(preNode, isNavBar);
692         auto context = PipelineContext::GetCurrentContext();
693         CHECK_NULL_VOID(context);
694         context->MarkNeedFlushMouseEvent();
695     });
696     preNode->GetEventHub<EventHub>()->SetEnabledInternal(false);
697     curNode->GetRenderContext()->UpdateOpacity(0.0f);
698     if (!isNavBar) {
699         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
700         if (navDestination) {
701             navDestination->SetIsOnAnimation(true);
702         }
703     }
704     AnimationUtils::Animate(
705         option,
706         [curNode]() {
707             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
708             curNode->GetRenderContext()->UpdateOpacity(1.0f);
709         },
710         option.GetOnFinishEvent());
711     isOnAnimation_ = true;
712 }
713 
OnInspectorIdUpdate(const std::string & id)714 void NavigationGroupNode::OnInspectorIdUpdate(const std::string& id)
715 {
716     auto context = PipelineContext::GetCurrentContext();
717     CHECK_NULL_VOID(context);
718     context->AddOrReplaceNavigationNode(id, WeakClaim(this));
719     curId_ = id;
720 }
721 
DealNavigationExit(const RefPtr<FrameNode> & preNode,bool isNavBar,bool isAnimated)722 void NavigationGroupNode::DealNavigationExit(const RefPtr<FrameNode>& preNode, bool isNavBar, bool isAnimated)
723 {
724     CHECK_NULL_VOID(preNode);
725     if (preNode->GetEventHub<EventHub>()) {
726         preNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
727     }
728     if (isNavBar && isAnimated) {
729         SetNeedSetInvisible(true);
730         return;
731     }
732     auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
733     CHECK_NULL_VOID(navDestinationNode);
734     navDestinationNode->SetIsOnAnimation(false);
735     auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
736     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
737     if (shallowBuilder) {
738         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
739     }
740     // remove old navdestination node
741     if (navDestinationNode->GetContentNode()) {
742         navDestinationNode->GetContentNode()->Clean();
743     }
744     auto parent = AceType::DynamicCast<FrameNode>(preNode->GetParent());
745     CHECK_NULL_VOID(parent);
746     parent->RemoveChild(preNode);
747     navDestinationPattern->SetCustomNode(nullptr);
748     parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
749 }
750 
NotifyPageHide()751 void NavigationGroupNode::NotifyPageHide()
752 {
753     auto context = PipelineContext::GetCurrentContext();
754     CHECK_NULL_VOID(context);
755     auto stageManager = context->GetStageManager();
756     CHECK_NULL_VOID(stageManager);
757     auto container = Container::Current();
758     CHECK_NULL_VOID(container);
759     auto pageUrlChecker = container->GetPageUrlChecker();
760     CHECK_NULL_VOID(pageUrlChecker);
761     RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
762     CHECK_NULL_VOID(pageNode);
763     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
764     CHECK_NULL_VOID(pagePattern);
765     auto pageInfo = pagePattern->GetPageInfo();
766     CHECK_NULL_VOID(pageInfo);
767     pageUrlChecker->NotifyPageHide(pageInfo->GetPageUrl());
768 }
769 
UpdateLastStandardIndex()770 void NavigationGroupNode::UpdateLastStandardIndex()
771 {
772     // remove the impact of last standard index
773     lastStandardIndex_ = -1;
774     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
775     CHECK_NULL_VOID(navigationPattern);
776     auto navigationStack = navigationPattern->GetNavigationStack();
777     CHECK_NULL_VOID(navigationStack);
778     const auto& navDestinationNodes = navigationStack->GetAllNavDestinationNodes();
779     if (navDestinationNodes.size() == 0) {
780         return;
781     }
782     for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1; index >= 0; index--) {
783         const auto& curPath = navDestinationNodes[index];
784         const auto& uiNode = curPath.second;
785         if (!uiNode) {
786             continue;
787         }
788         auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
789         if (navDestinationNode && navDestinationNode->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
790             lastStandardIndex_ = index;
791             return;
792         }
793     }
794 }
795 
UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode> & navDestination,const RefPtr<UINode> & remainChild,int32_t index,size_t destinationSize)796 bool NavigationGroupNode::UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode>& navDestination,
797     const RefPtr<UINode>& remainChild, int32_t index, size_t destinationSize)
798 {
799     auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
800     CHECK_NULL_RETURN(eventHub, false);
801     if (index == static_cast<int32_t>(destinationSize) - 1) {
802         // process shallow builder
803         navDestination->ProcessShallowBuilder();
804         navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE, true);
805         navDestination->SetJSViewActive(true);
806         navDestination->GetEventHub<EventHub>()->SetEnabledInternal(true);
807         // for the navDestination at the top, FireChangeEvent
808         eventHub->FireChangeEvent(true);
809         bool hasChanged = CheckNeedMeasure(navDestination->GetLayoutProperty()->GetPropertyChangeFlag());
810         if (!hasChanged && NavigationLayoutAlgorithm::IsAutoHeight(GetLayoutProperty<NavigationLayoutProperty>())) {
811             hasChanged = true;
812         }
813         return hasChanged;
814     }
815     if (index < lastStandardIndex_) {
816         auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
817         if (!navDestination->IsOnAnimation()) {
818             if (pattern && pattern->GetIsOnShow()) {
819                 // fire hidden event
820                 eventHub->FireOnHiddenEvent(pattern->GetName());
821                 eventHub->FireChangeEvent(false);
822                 pattern->SetIsOnShow(false);
823                 NavigationPattern::FireNavigationStateChange(navDestination, false);
824             }
825             if (navDestination->GetPattern<NavDestinationPattern>()->GetCustomNode() != remainChild) {
826                 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
827                 navDestination->SetJSViewActive(false);
828             }
829         }
830         return false;
831     }
832     auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
833     if (navDestination->GetPattern<NavDestinationPattern>()->GetCustomNode() != remainChild &&
834         !navDestination->IsOnAnimation()) {
835         navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
836         navDestination->SetJSViewActive(true);
837     }
838     return false;
839 }
840 
CreateAnimationOption(const RefPtr<Curve> & curve,FillMode mode,int32_t duration,const AnimationFinishCallback & callback)841 AnimationOption NavigationGroupNode::CreateAnimationOption(const RefPtr<Curve>& curve, FillMode mode,
842     int32_t duration, const AnimationFinishCallback& callback)
843 {
844     AnimationOption option;
845     option.SetCurve(curve);
846     option.SetFillMode(mode);
847     option.SetDuration(duration);
848     if (callback != nullptr) {
849         option.SetOnFinishEvent(callback);
850     }
851     return option;
852 }
853 
GetNavigationMode()854 NavigationMode NavigationGroupNode::GetNavigationMode()
855 {
856     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
857     CHECK_NULL_RETURN(navigationPattern, NavigationMode::AUTO);
858     return navigationPattern->GetNavigationMode();
859 }
860 
OnDetachFromMainTree(bool recursive)861 void NavigationGroupNode::OnDetachFromMainTree(bool recursive)
862 {
863     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
864     if (pattern) {
865         pattern->DetachNavigationStackFromParent();
866     }
867 
868     GroupNode::OnDetachFromMainTree(recursive);
869 }
870 
OnAttachToMainTree(bool recursive)871 void NavigationGroupNode::OnAttachToMainTree(bool recursive)
872 {
873     GroupNode::OnAttachToMainTree(recursive);
874 
875     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
876     if (pattern) {
877         pattern->AttachNavigationStackToParent();
878     }
879 }
880 } // namespace OHOS::Ace::NG
881