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