• 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*/) -> bool {
270         auto navDestination = navDestinationWeak.Upgrade();
271         CHECK_NULL_RETURN(navDestination, false);
272         auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
273         CHECK_NULL_RETURN(eventHub, false);
274         auto isOverride = eventHub->GetOnBackPressedEvent();
275         auto result = false;
276         if (isOverride) {
277             result = eventHub->FireOnBackPressedEvent();
278         }
279         if (result) {
280             return true;
281         }
282         auto navigation = navigationWeak.Upgrade();
283         CHECK_NULL_RETURN(navigation, false);
284         const auto& children = navigation->GetContentNode()->GetChildren();
285         auto isLastChild = children.size() == 1 ? true : false;
286         if (isOverride) {
287             result = navigation->HandleBack(navDestination, isLastChild, true);
288         } else {
289             result = navigation->HandleBack(navDestination, isLastChild, false);
290         }
291         // when js navigationStack is provided, modifyDone will be called by state manager.
292         auto navigationPattern = navigation->GetPattern<NavigationPattern>();
293         CHECK_NULL_RETURN(navigationPattern, false);
294         if (!navigationPattern->GetNavigationStackProvided()) {
295             navigation->MarkModifyDone();
296             navigation->MarkDirtyNode();
297         }
298 
299         return result;
300     }; // backButton event
301 
302     navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
303     backButtonEventHub->GetOrCreateGestureEventHub()->SetUserOnClick(onBackButtonEvent);
304 }
305 
CheckCanHandleBack()306 bool NavigationGroupNode::CheckCanHandleBack()
307 {
308     auto navigation = AceType::WeakClaim(this).Upgrade();
309     CHECK_NULL_RETURN(navigation, false);
310     if (navigation->isOnAnimation_) {
311         return true;
312     }
313     auto navigationPattern = GetPattern<NavigationPattern>();
314     CHECK_NULL_RETURN(navigationPattern, false);
315     const auto& children = contentNode_->GetChildren();
316     if (children.empty()) {
317         return false;
318     }
319     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(children.back());
320     CHECK_NULL_RETURN(navDestination, false);
321     GestureEvent gestureEvent;
322     return navDestination->GetNavDestinationBackButtonEvent()(gestureEvent);
323 }
324 
HandleBack(const RefPtr<FrameNode> & node,bool isLastChild,bool isOverride)325 bool NavigationGroupNode::HandleBack(const RefPtr<FrameNode>& node, bool isLastChild, bool isOverride)
326 {
327     auto navigationPattern = GetPattern<NavigationPattern>();
328     if (!isOverride && !isLastChild) {
329         navigationPattern->RemoveNavDestination();
330         return true;
331     }
332     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
333     CHECK_NULL_RETURN(navDestination, false);
334 
335     auto mode = navigationPattern->GetNavigationMode();
336     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
337     if (isLastChild && (mode == NavigationMode::SPLIT ||
338                            (mode == NavigationMode::STACK && layoutProperty->GetHideNavBar().value_or(false)))) {
339         return false;
340     }
341 
342     navigationPattern->RemoveNavDestination();
343     return true;
344 }
345 
ExitTransitionWithPop(const RefPtr<FrameNode> & node)346 void NavigationGroupNode::ExitTransitionWithPop(const RefPtr<FrameNode>& node)
347 {
348     CHECK_NULL_VOID(node);
349     AnimationOption option;
350     option.SetCurve(interpolatingSpringCurve);
351     option.SetFillMode(FillMode::FORWARDS);
352     option.SetDuration(DEFAULT_ANIMATION_DURATION);
353     auto size = GetGeometryNode()->GetFrameSize();
354     auto nodeWidth = size.Width();
355     auto nodeHeight = size.Height();
356 
357     RefPtr<TitleBarNode> titleNode;
358     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
359     CHECK_NULL_VOID(navDestination);
360     navDestination->SetTransitionType(PageTransitionType::EXIT_POP);
361     titleNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
362     CHECK_NULL_VOID(titleNode);
363 
364     option.SetOnFinishEvent(
365         [weakNode = WeakPtr<NavDestinationGroupNode>(navDestination), weakTitle = WeakPtr<TitleBarNode>(titleNode),
366             weakNavigation = WeakClaim(this), id = Container::CurrentId(), nodeWidth, nodeHeight] {
367             ContainerScope scope(id);
368             auto context = PipelineContext::GetCurrentContext();
369             CHECK_NULL_VOID_NOLOG(context);
370             auto taskExecutor = context->GetTaskExecutor();
371             CHECK_NULL_VOID_NOLOG(taskExecutor);
372             // animation finish event should be posted to UI thread
373             taskExecutor->PostTask(
374                 [weakNode, weakTitle, weakNavigation, nodeWidth, nodeHeight]() {
375                     LOGI("navigation animation end");
376                     PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
377                     auto navigation = weakNavigation.Upgrade();
378                     if (navigation) {
379                         navigation->isOnAnimation_ = false;
380                     }
381                     auto node = weakNode.Upgrade();
382                     CHECK_NULL_VOID(node);
383                     if (node->GetTransitionType() != PageTransitionType::EXIT_POP) {
384                         // has another transition, just return
385                         return;
386                     }
387                     node->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
388                     auto title = weakTitle.Upgrade();
389                     if (title) {
390                         title->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
391                     }
392                     node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
393                     node->GetRenderContext()->ClipWithRRect(
394                         RectF(0.0f, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
395                     auto navDestinationPattern = node->GetPattern<NavDestinationPattern>();
396                     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
397                     if (shallowBuilder) {
398                         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
399                     }
400                     if (node->GetContentNode()) {
401                         node->GetContentNode()->Clean();
402                     }
403                     auto parent = node->GetParent();
404                     CHECK_NULL_VOID(parent);
405                     parent->RemoveChild(node);
406                     parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
407                     auto context = PipelineContext::GetCurrentContext();
408                     CHECK_NULL_VOID(context);
409                     context->MarkNeedFlushMouseEvent();
410                 },
411                 TaskExecutor::TaskType::UI);
412         });
413 
414     // content
415     node->GetEventHub<EventHub>()->SetEnabledInternal(false);
416     node->GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
417     node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
418     // title
419     titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
420     AnimationUtils::Animate(
421         option,
422         [node, titleNode, nodeWidth, nodeHeight]() {
423             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
424             LOGI("navigation animation start");
425             // content
426             node->GetRenderContext()->ClipWithRRect(
427                 RectF(nodeWidth * HALF, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
428             node->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
429             // title
430             titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
431         },
432         option.GetOnFinishEvent());
433     TitleOpacityAnimationOut(titleNode->GetRenderContext());
434 
435     // backIcon opacity
436     auto backIcon = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
437     if (backIcon) {
438         BackButtonAnimation(backIcon, false);
439     }
440 
441     isOnAnimation_ = true;
442 }
443 
ExitTransitionWithPush(const RefPtr<FrameNode> & node,bool isNavBar)444 void NavigationGroupNode::ExitTransitionWithPush(const RefPtr<FrameNode>& node, bool isNavBar)
445 {
446     CHECK_NULL_VOID(node);
447     AnimationOption option;
448     option.SetCurve(interpolatingSpringCurve);
449     option.SetFillMode(FillMode::FORWARDS);
450     option.SetDuration(DEFAULT_ANIMATION_DURATION);
451     auto size = GetGeometryNode()->GetFrameSize();
452     auto nodeWidth = size.Width();
453 
454     RefPtr<FrameNode> titleNode;
455     if (isNavBar) {
456         auto navBarNode = AceType::DynamicCast<NavBarNode>(node);
457         navBarNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
458         titleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
459     } else {
460         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
461         navDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
462         titleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
463     }
464     CHECK_NULL_VOID(titleNode);
465 
466     option.SetOnFinishEvent([weakNode = WeakPtr<FrameNode>(node), weakTitle = WeakPtr<FrameNode>(titleNode),
467                                 weakNavigation = WeakClaim(this), isNavBar, id = Container::CurrentId()] {
468         ContainerScope scope(id);
469         auto context = PipelineContext::GetCurrentContext();
470         CHECK_NULL_VOID_NOLOG(context);
471         auto taskExecutor = context->GetTaskExecutor();
472         CHECK_NULL_VOID_NOLOG(taskExecutor);
473         // animation finish event should be posted to UI thread
474         taskExecutor->PostTask(
475             [weakNode, weakTitle, weakNavigation, isNavBar]() {
476                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
477                 LOGI("navigation animation end");
478                 auto navigation = weakNavigation.Upgrade();
479                 if (navigation) {
480                     navigation->isOnAnimation_ = false;
481                 }
482                 auto title = weakTitle.Upgrade();
483                 if (title) {
484                     title->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
485                 }
486                 auto node = weakNode.Upgrade();
487                 CHECK_NULL_VOID(node);
488                 bool needSetInvisible = false;
489                 if (isNavBar) {
490                     needSetInvisible =
491                         AceType::DynamicCast<NavBarNode>(node)->GetTransitionType() == PageTransitionType::EXIT_PUSH;
492                     // store this flag for navBar layout only
493                     navigation->SetNeedSetInvisible(needSetInvisible);
494                 } else {
495                     needSetInvisible = AceType::DynamicCast<NavDestinationGroupNode>(node)->GetTransitionType() ==
496                                        PageTransitionType::EXIT_PUSH;
497                 }
498                 // for the case, the navBar form EXIT_PUSH to push during animation
499                 if (needSetInvisible) {
500                     node->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
501                 }
502                 node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
503             },
504             TaskExecutor::TaskType::UI);
505     });
506     node->GetEventHub<EventHub>()->SetEnabledInternal(false);
507     node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
508     titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
509 
510     AnimationUtils::Animate(
511         option,
512         [node, titleNode, nodeWidth]() {
513             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
514             LOGI("navigation animation start");
515             node->GetRenderContext()->UpdateTranslateInXY({ -nodeWidth * PARENT_PAGE_OFFSET, 0.0f });
516             titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * PARENT_TITLE_OFFSET, 0.0f });
517         },
518         option.GetOnFinishEvent());
519     MaskAnimation(node->GetRenderContext());
520     isOnAnimation_ = true;
521 }
522 
EnterTransitionWithPush(const RefPtr<FrameNode> & node,bool isNavBar)523 void NavigationGroupNode::EnterTransitionWithPush(const RefPtr<FrameNode>& node, bool isNavBar)
524 {
525     CHECK_NULL_VOID(node);
526     AnimationOption option;
527     option.SetCurve(interpolatingSpringCurve);
528     option.SetFillMode(FillMode::FORWARDS);
529     option.SetDuration(DEFAULT_ANIMATION_DURATION);
530     auto size = GetGeometryNode()->GetFrameSize();
531     auto nodeWidth = size.Width();
532     auto nodeHeight = size.Height();
533 
534     RefPtr<TitleBarNode> titleNode;
535     if (isNavBar) {
536         auto navBarNode = AceType::DynamicCast<NavBarNode>(node);
537         navBarNode->SetTransitionType(PageTransitionType::ENTER_PUSH);
538         titleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
539     } else {
540         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
541         navDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
542         titleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
543     }
544     CHECK_NULL_VOID(titleNode);
545 
546     option.SetOnFinishEvent([weakNavigation = WeakClaim(this), id = Container::CurrentId()] {
547         ContainerScope scope(id);
548         auto context = PipelineContext::GetCurrentContext();
549         CHECK_NULL_VOID(context);
550         auto taskExecutor = context->GetTaskExecutor();
551         CHECK_NULL_VOID(taskExecutor);
552         // animation finish event should be posted to UI thread.
553         taskExecutor->PostTask(
554             [weakNavigation]() {
555                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
556                 LOGI("navigation animation end");
557                 auto navigation = weakNavigation.Upgrade();
558                 CHECK_NULL_VOID(navigation);
559                 navigation->isOnAnimation_ = false;
560             },
561             TaskExecutor::TaskType::UI);
562     });
563 
564     // content
565     node->GetRenderContext()->ClipWithRRect(
566         RectF(nodeWidth * HALF, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
567     node->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
568     // title
569     titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * HALF, 0.0f });
570     AnimationUtils::Animate(
571         option,
572         [node, titleNode, nodeWidth, nodeHeight]() {
573             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
574             LOGI("navigation animation start");
575             // content
576             node->GetRenderContext()->ClipWithRRect(
577                 RectF(0.0f, 0.0f, nodeWidth, nodeHeight), RadiusF(EdgeF(0.0f, 0.0f)));
578             node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
579             // title
580             titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
581         },
582         option.GetOnFinishEvent());
583     // title opacity
584     AnimationOption opacityOption;
585     opacityOption.SetCurve(Curves::SHARP);
586     opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
587     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
588     opacityOption.SetFillMode(FillMode::FORWARDS);
589     titleNode->GetRenderContext()->OpacityAnimation(opacityOption, 0.0f, 1.0f);
590 
591     // backIcon opacity
592     auto backIcon = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
593     if (backIcon) {
594         BackButtonAnimation(backIcon, true);
595     }
596 
597     isOnAnimation_ = true;
598 }
599 
EnterTransitionWithPop(const RefPtr<FrameNode> & node,bool isNavBar)600 void NavigationGroupNode::EnterTransitionWithPop(const RefPtr<FrameNode>& node, bool isNavBar)
601 {
602     CHECK_NULL_VOID(node);
603     AnimationOption option;
604     option.SetCurve(interpolatingSpringCurve);
605     option.SetFillMode(FillMode::FORWARDS);
606     option.SetDuration(DEFAULT_ANIMATION_DURATION);
607     auto size = GetGeometryNode()->GetFrameSize();
608     auto nodeWidth = size.Width();
609 
610     RefPtr<TitleBarNode> titleNode;
611     if (isNavBar) {
612         auto navBarNode = AceType::DynamicCast<NavBarNode>(node);
613         navBarNode->SetTransitionType(PageTransitionType::ENTER_POP);
614         titleNode = navBarNode ? AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode()) : nullptr;
615     } else {
616         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
617         navDestination->SetTransitionType(PageTransitionType::ENTER_POP);
618         titleNode = navDestination ? AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode()) : nullptr;
619     }
620     CHECK_NULL_VOID(titleNode);
621 
622     option.SetOnFinishEvent([weakNavigation = WeakClaim(this), id = Container::CurrentId(), isNavBar] {
623         ContainerScope scope(id);
624         auto context = PipelineContext::GetCurrentContext();
625         CHECK_NULL_VOID(context);
626         auto taskExecutor = context->GetTaskExecutor();
627         CHECK_NULL_VOID(taskExecutor);
628         // animation finish event should be posted to UI thread.
629         taskExecutor->PostTask(
630             [weakNavigation]() {
631                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, false);
632                 LOGI("navigation animation end");
633                 auto navigation = weakNavigation.Upgrade();
634                 CHECK_NULL_VOID(navigation);
635                 navigation->isOnAnimation_ = false;
636                 navigation->SetNeedSetInvisible(false);
637             },
638             TaskExecutor::TaskType::UI);
639     });
640 
641     // content
642     node->GetRenderContext()->UpdateTranslateInXY({ -nodeWidth * PARENT_PAGE_OFFSET, 0.0f });
643     // title
644     titleNode->GetRenderContext()->UpdateTranslateInXY({ nodeWidth * PARENT_TITLE_OFFSET, 0.0f });
645     AnimationUtils::Animate(
646         option,
647         [node, titleNode]() {
648             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
649             LOGI("navigation animation start");
650             node->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
651             titleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
652         },
653         option.GetOnFinishEvent());
654 
655     AnimationOption maskOption;
656     maskOption.SetCurve(Curves::FRICTION);
657     maskOption.SetDuration(MASK_DURATION);
658     maskOption.SetFillMode(FillMode::FORWARDS);
659     node->GetRenderContext()->SetActualForegroundColor(MASK_COLOR);
660     AnimationUtils::Animate(
661         maskOption, [node]() { node->GetRenderContext()->SetActualForegroundColor(DEFAULT_MASK_COLOR); });
662     isOnAnimation_ = true;
663     // clear this flag for navBar layout only
664     if (isNavBar) {
665         SetNeedSetInvisible(false);
666     }
667 }
668 
BackButtonAnimation(const RefPtr<FrameNode> & backButtonNode,bool isTransitionIn)669 void NavigationGroupNode::BackButtonAnimation(const RefPtr<FrameNode>& backButtonNode, bool isTransitionIn)
670 {
671     AnimationOption transitionOption;
672     transitionOption.SetCurve(Curves::SHARP);
673     transitionOption.SetFillMode(FillMode::FORWARDS);
674     auto backButtonNodeContext = backButtonNode->GetRenderContext();
675     CHECK_NULL_VOID(backButtonNodeContext);
676     if (isTransitionIn) {
677         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
678         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
679         backButtonNodeContext->OpacityAnimation(transitionOption, 0.0, 1.0);
680     } else {
681         transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
682         transitionOption.SetOnFinishEvent(
683             [backButtonNodeContextWK = WeakClaim(RawPtr(backButtonNodeContext)), id = Container::CurrentId()] {
684                 ContainerScope scope(id);
685                 auto context = PipelineContext::GetCurrentContext();
686                 CHECK_NULL_VOID_NOLOG(context);
687                 auto taskExecutor = context->GetTaskExecutor();
688                 CHECK_NULL_VOID_NOLOG(taskExecutor);
689                 // animation finish event should be posted to UI thread.
690                 taskExecutor->PostTask(
691                     [backButtonNodeContextWK, id]() {
692                         auto backButtonNodeContext = backButtonNodeContextWK.Upgrade();
693                         CHECK_NULL_VOID_NOLOG(backButtonNodeContext);
694                         ContainerScope scope(id);
695                         backButtonNodeContext->UpdateOpacity(1.0);
696                     },
697                     TaskExecutor::TaskType::UI);
698             });
699         backButtonNodeContext->OpacityAnimation(transitionOption, 1.0, 0.0);
700     }
701 }
702 
MaskAnimation(const RefPtr<RenderContext> & transitionOutNodeContext)703 void NavigationGroupNode::MaskAnimation(const RefPtr<RenderContext>& transitionOutNodeContext)
704 {
705     AnimationOption maskOption;
706     maskOption.SetCurve(Curves::FRICTION);
707     maskOption.SetDuration(MASK_DURATION);
708     maskOption.SetFillMode(FillMode::FORWARDS);
709     maskOption.SetOnFinishEvent(
710         [transitionOutNodeContextWK = WeakPtr<RenderContext>(transitionOutNodeContext), id = Container::CurrentId()] {
711             ContainerScope scope(id);
712             auto context = PipelineContext::GetCurrentContext();
713             CHECK_NULL_VOID_NOLOG(context);
714             auto taskExecutor = context->GetTaskExecutor();
715             CHECK_NULL_VOID_NOLOG(taskExecutor);
716             taskExecutor->PostTask(
717                 [transitionOutNodeContextWK]() {
718                     auto transitionOutNodeContext = transitionOutNodeContextWK.Upgrade();
719                     if (transitionOutNodeContext) {
720                         transitionOutNodeContext->SetActualForegroundColor(DEFAULT_MASK_COLOR);
721                     }
722                 },
723                 TaskExecutor::TaskType::UI);
724         });
725     transitionOutNodeContext->SetActualForegroundColor(DEFAULT_MASK_COLOR);
726     AnimationUtils::Animate(
727         maskOption, [transitionOutNodeContext]() { transitionOutNodeContext->SetActualForegroundColor(MASK_COLOR); },
728         maskOption.GetOnFinishEvent());
729 }
730 
TitleOpacityAnimationOut(const RefPtr<RenderContext> & transitionOutNodeContext)731 void NavigationGroupNode::TitleOpacityAnimationOut(const RefPtr<RenderContext>& transitionOutNodeContext)
732 {
733     AnimationOption opacityOption;
734     opacityOption.SetCurve(Curves::SHARP);
735     opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
736     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
737     opacityOption.SetFillMode(FillMode::FORWARDS);
738     opacityOption.SetOnFinishEvent(
739         [transitionOutNodeContextWK = WeakPtr<RenderContext>(transitionOutNodeContext), id = Container::CurrentId()] {
740             ContainerScope scope(id);
741             auto context = PipelineContext::GetCurrentContext();
742             CHECK_NULL_VOID(context);
743             auto taskExecutor = context->GetTaskExecutor();
744             CHECK_NULL_VOID(taskExecutor);
745             // animation finish event should be posted to UI thread.
746             taskExecutor->PostTask(
747                 [transitionOutNodeContextWK, id]() {
748                     auto transitionOutNodeContext = transitionOutNodeContextWK.Upgrade();
749                     CHECK_NULL_VOID_NOLOG(transitionOutNodeContext);
750                     transitionOutNodeContext->UpdateOpacity(1.0);
751                 },
752                 TaskExecutor::TaskType::UI);
753         });
754     transitionOutNodeContext->OpacityAnimation(opacityOption, 1.0, 0.0);
755     transitionOutNodeContext->UpdateOpacity(0.0);
756 }
757 } // namespace OHOS::Ace::NG
758