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