• 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/common/container.h"
17 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
18 
19 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
20 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
21 #include "core/components_ng/pattern/navigation/navigation_transition_proxy.h"
22 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
23 #include "core/components_ng/pattern/navrouter/navdestination_context.h"
24 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
25 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
26 #include "core/components_ng/pattern/text/text_layout_property.h"
27 #include "core/components_v2/inspector/inspector_constants.h"
28 #include "core/components_ng/pattern/text/text_pattern.h"
29 
30 namespace OHOS::Ace::NG {
31 constexpr double HALF = 0.5;
32 constexpr float CONTENT_OFFSET_PERCENT = 0.2f;
33 constexpr float TITLE_OFFSET_PERCENT = 0.02f;
34 constexpr float REMOVE_CLIP_SIZE = 10000.0f;
35 constexpr int32_t MAX_RENDER_GROUP_TEXT_NODE_COUNT = 50;
36 constexpr int32_t OPACITY_TITLE_OUT_DELAY = 17;
37 constexpr int32_t OPACITY_TITLE_IN_DELAY = 33;
38 constexpr int32_t OPACITY_TITLE_DURATION = 150;
39 constexpr int32_t OPACITY_BACKBUTTON_IN_DELAY = 150;
40 constexpr int32_t OPACITY_BACKBUTTON_IN_DURATION = 200;
41 constexpr int32_t OPACITY_BACKBUTTON_OUT_DURATION = 67;
42 constexpr float MAX_RENDER_GROUP_TEXT_NODE_HEIGHT = 150.0f;
43 constexpr int32_t INVALID_ANIMATION_ID = -1;
44 constexpr int32_t SYSTEM_ENTER_FADE_TRANSITION_DURATION = 250;
45 constexpr int32_t SYSTEM_EXIT_FADE_TRANSITION_DURATION = 200;
46 constexpr int32_t SYSTEM_ENTER_FADE_TRANSITION_DELAY = 50;
47 constexpr int32_t SYSTEM_EXIT_FADE_TRANSITION_DELAY = 0;
48 constexpr int32_t SYSTEM_EXPLODE_TRANSITION_MASK_DURATION = 300;
49 constexpr int32_t SYSTEM_ENTER_POP_EXPLODE_OPACITY_DURATION = 250;
50 constexpr int32_t SYSTEM_ENTER_POP_EXPLODE_OPACITY_DELAY = 50;
51 constexpr int32_t SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DURATION = 300;
52 constexpr int32_t SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DELAY = 50;
53 constexpr int32_t SYSTEM_EXIT_POP_EXPLODE_OPACITY_DURATION = 150;
54 constexpr int32_t SYSTEM_EXIT_PUSH_EXPLODE_OPACITY_DELAY = 200;
55 constexpr int32_t SYSTEM_SLIDE_TRANSITION_MASK_DURATION = 350;
56 const Color SLIDE_ANIMATION_MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
57 
58 namespace {
BuildAnimationOption(const RefPtr<Curve> & curve,std::function<void ()> && onFinishEvent,int32_t duration=0,int32_t delay=0)59 AnimationOption BuildAnimationOption(const RefPtr<Curve>& curve, std::function<void()>&& onFinishEvent,
60     int32_t duration = 0, int32_t delay = 0)
61 {
62     AnimationOption option(curve, duration);
63     option.SetDelay(delay);
64     option.SetOnFinishEvent(std::move(onFinishEvent));
65     return option;
66 }
67 }
68 
~NavDestinationGroupNode()69 NavDestinationGroupNode::~NavDestinationGroupNode()
70 {
71     if (contentNode_) {
72         contentNode_->Clean();
73     }
74     ReleaseTextNodeList();
75 }
76 
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)77 RefPtr<NavDestinationGroupNode> NavDestinationGroupNode::GetOrCreateGroupNode(
78     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
79 {
80     auto frameNode = GetFrameNode(tag, nodeId);
81     CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavDestinationGroupNode>(frameNode));
82     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
83     auto navDestinationNode = AceType::MakeRefPtr<NavDestinationGroupNode>(tag, nodeId, pattern);
84     navDestinationNode->InitializePatternAndContext();
85     ElementRegister::GetInstance()->AddUINode(navDestinationNode);
86     return navDestinationNode;
87 }
88 
IsNeedContentTransition()89 bool NavDestinationGroupNode::IsNeedContentTransition()
90 {
91     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
92         return true;
93     }
94     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
95 }
96 
TransitionContentInValid()97 bool NavDestinationGroupNode::TransitionContentInValid()
98 {
99     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) == NavigationSystemTransitionType::NONE
100         && mode_ == NavDestinationMode::STANDARD;
101 }
102 
IsNeedTitleTransition()103 bool NavDestinationGroupNode::IsNeedTitleTransition()
104 {
105     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
106         return true;
107     }
108     if (mode_ == NavDestinationMode::STANDARD) {
109         return (systemTransitionType_ & NavigationSystemTransitionType::TITLE) != NavigationSystemTransitionType::NONE;
110     }
111     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
112 }
113 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)114 void NavDestinationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
115 {
116     auto pattern = AceType::DynamicCast<Pattern>(GetPattern());
117     CHECK_NULL_VOID(pattern);
118     auto contentNode = GetContentNode();
119     if (!contentNode) {
120         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
121         ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId);
122         contentNode = FrameNode::GetOrCreateFrameNode(V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId,
123             []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
124         SetContentNode(contentNode);
125         AddChild(contentNode);
126 
127         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
128             auto navdestinationContentNode = AceType::DynamicCast<FrameNode>(contentNode);
129             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
130                 .edges = SAFE_AREA_EDGE_ALL };
131             navdestinationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
132         }
133     }
134     contentNode->AddChild(child, slot);
135 }
136 
DeleteChildFromGroup(int32_t slot)137 void NavDestinationGroupNode::DeleteChildFromGroup(int32_t slot)
138 {
139     auto navDestination = GetContentNode();
140     CHECK_NULL_VOID(navDestination);
141     navDestination->RemoveChildAtIndex(slot);
142 }
143 
OnAttachToMainTree(bool recursive)144 void NavDestinationGroupNode::OnAttachToMainTree(bool recursive)
145 {
146     if (!UseOffscreenProcess()) {
147         ProcessShallowBuilder();
148     }
149     FrameNode::OnAttachToMainTree(recursive);
150 }
151 
OnOffscreenProcess(bool recursive)152 void NavDestinationGroupNode::OnOffscreenProcess(bool recursive)
153 {
154     ProcessShallowBuilder();
155     FrameNode::OnOffscreenProcess(recursive);
156 }
157 
ProcessShallowBuilder()158 void NavDestinationGroupNode::ProcessShallowBuilder()
159 {
160     if (isCacheNode_) {
161         return;
162     }
163 
164     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "render navDestination content");
165     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
166     CHECK_NULL_VOID(navDestinationPattern);
167     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
168     if (shallowBuilder && !shallowBuilder->IsExecuteDeepRenderDone()) {
169         auto eventHub = GetEventHub<NavDestinationEventHub>();
170         if (eventHub) {
171             auto ctx = navDestinationPattern->GetNavDestinationContext();
172             eventHub->FireOnReady(ctx);
173         }
174         shallowBuilder->ExecuteDeepRender();
175         GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
176         AceType::DynamicCast<FrameNode>(contentNode_)
177             ->GetLayoutProperty()
178             ->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
179     }
180 }
181 
GetNavDestinationCustomNode()182 RefPtr<CustomNodeBase> NavDestinationGroupNode::GetNavDestinationCustomNode()
183 {
184     return customNode_.Upgrade();
185 }
186 
SetNavDestinationMode(NavDestinationMode mode)187 void NavDestinationGroupNode::SetNavDestinationMode(NavDestinationMode mode)
188 {
189     mode_ = mode;
190     auto pattern = GetPattern<NavDestinationPattern>();
191     CHECK_NULL_VOID(pattern);
192     auto context = pattern->GetNavDestinationContext();
193     CHECK_NULL_VOID(context);
194     context->SetMode(mode);
195 }
196 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const197 void NavDestinationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
198 {
199     FrameNode::ToJsonValue(json, filter);
200     /* no fixed attr below, just return */
201     if (filter.IsFastFilter()) {
202         return;
203     }
204     auto titleBarNode = DynamicCast<TitleBarNode>(titleBarNode_);
205     if (titleBarNode) {
206         std::string title = NavigationTitleUtil::GetTitleString(titleBarNode, GetPrevTitleIsCustomValue(false));
207         std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
208         json->PutExtAttr("title", title.c_str(), filter);
209         json->PutExtAttr("subtitle", subtitle.c_str(), filter);
210     }
211     json->PutExtAttr("mode", mode_ == NavDestinationMode::DIALOG
212         ? "NavDestinationMode::DIALOG"
213         : "NavDestinationMode::STANDARD", filter);
214 }
215 
InitSystemTransitionPush(bool transitionIn)216 void NavDestinationGroupNode::InitSystemTransitionPush(bool transitionIn)
217 {
218     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
219     float isRTL = GetLanguageDirection();
220     bool needContentAnimation = IsNeedContentTransition();
221     bool needTitleAnimation = IsNeedTitleTransition();
222     if (transitionIn) {
223         SetIsOnAnimation(true);
224         SetTransitionType(PageTransitionType::ENTER_PUSH);
225         auto frameSize = GetGeometryNode()->GetFrameSize();
226         if (needContentAnimation) {
227             if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
228                 GetRenderContext()->ClipWithRRect(
229                     RectF(0.0f, 0.0f, frameSize.Width() * HALF, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
230             } else {
231                 GetRenderContext()->ClipWithRRect(
232                     RectF(frameSize.Width() * HALF, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
233                     RadiusF(EdgeF(0.0f, 0.0f)));
234             }
235             GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
236         }
237         if (titleBarNode && needTitleAnimation) {
238             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
239         }
240         return;
241     }
242     SetTransitionType(PageTransitionType::EXIT_PUSH);
243     SetIsOnAnimation(true);
244     GetRenderContext()->RemoveClipWithRRect();
245     if (needContentAnimation) {
246         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
247     }
248     if (NeedRemoveInPush()) {
249         GetEventHub<EventHub>()->SetEnabledInternal(false);
250     }
251     if (titleBarNode && needTitleAnimation) {
252         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
253     }
254 }
255 
StartSystemTransitionPush(bool transitionIn)256 void NavDestinationGroupNode::StartSystemTransitionPush(bool transitionIn)
257 {
258     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
259     auto frameSize = GetGeometryNode()->GetFrameSize();
260     float isRTL = GetLanguageDirection();
261     bool needContentAnimation = IsNeedContentTransition();
262     bool needTitleAnimation = IsNeedTitleTransition();
263     if (transitionIn) {
264         if (needContentAnimation) {
265             GetRenderContext()->ClipWithRRect(
266                 RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
267             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
268         }
269         if (titleBarNode && needTitleAnimation) {
270             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
271         }
272         return;
273     }
274     if (needContentAnimation) {
275         GetRenderContext()->UpdateTranslateInXY(
276             { -frameSize.Width() * CONTENT_OFFSET_PERCENT * isRTL, 0.0f });
277     }
278     if (titleBarNode && needTitleAnimation) {
279         titleBarNode->GetRenderContext()->UpdateTranslateInXY(
280             { frameSize.Width() * TITLE_OFFSET_PERCENT  * isRTL, 0.0f });
281     }
282 }
283 
SystemTransitionPushCallback(bool transitionIn,const int32_t animationId)284 void NavDestinationGroupNode::SystemTransitionPushCallback(bool transitionIn, const int32_t animationId)
285 {
286     if (animationId != animationId_) {
287         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "push animation invalid,curId: %{public}d, targetId: %{public}d",
288             animationId_, animationId);
289         return;
290     }
291     SetIsOnAnimation(false);
292     if (transitionIn) {
293         if (GetTransitionType() != PageTransitionType::ENTER_PUSH) {
294             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "curNode has another transition");
295             return;
296         }
297         GetRenderContext()->RemoveClipWithRRect();
298         return;
299     }
300     if (IsNeedContentTransition()) {
301         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
302     }
303     GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
304     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
305     auto navigation = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
306     CHECK_NULL_VOID(navigation);
307     bool isInvisible = IsNodeInvisible(navigation);
308     if (GetTransitionType() == PageTransitionType::EXIT_PUSH && isInvisible) {
309         GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
310         SetJSViewActive(false);
311     }
312     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
313     if (titleBarNode && IsNeedTitleTransition()) {
314         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
315     }
316 }
317 
InitSystemTransitionPop(bool isTransitionIn)318 void NavDestinationGroupNode::InitSystemTransitionPop(bool isTransitionIn)
319 {
320     auto frameSize = GetGeometryNode()->GetFrameSize();
321     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
322     float isRTL = GetLanguageDirection();
323     bool needContentAnimation = IsNeedContentTransition();
324     bool needTitleAnimation = IsNeedTitleTransition();
325     if (isTransitionIn) {
326         SetTransitionType(PageTransitionType::ENTER_POP);
327         GetRenderContext()->RemoveClipWithRRect();
328         if (needContentAnimation) {
329             GetRenderContext()->UpdateTranslateInXY({ -frameSize.Width() * CONTENT_OFFSET_PERCENT * isRTL, 0.0f });
330         }
331         if (titleBarNode && needTitleAnimation) {
332             titleBarNode->GetRenderContext()->UpdateTranslateInXY(
333                 { frameSize.Width() * TITLE_OFFSET_PERCENT * isRTL, 0.0f });
334         }
335         return;
336     }
337     SetIsOnAnimation(true);
338     SetTransitionType(PageTransitionType::EXIT_POP);
339     GetEventHub<EventHub>()->SetEnabledInternal(false);
340     if (needContentAnimation) {
341         GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
342             RadiusF(EdgeF(0.0f, 0.0f)));
343         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
344     }
345     if (titleBarNode && needTitleAnimation) {
346         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
347     }
348 }
349 
StartSystemTransitionPop(bool transitionIn)350 void NavDestinationGroupNode::StartSystemTransitionPop(bool transitionIn)
351 {
352     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
353     bool needContentAnimation = IsNeedContentTransition();
354     bool needTitleAnimation = IsNeedTitleTransition();
355     if (transitionIn) {
356         if (needContentAnimation) {
357             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
358         }
359         if (titleBarNode && needTitleAnimation) {
360             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
361         }
362         return;
363     }
364     auto frameSize = GetGeometryNode()->GetFrameSize();
365     float isRTL = GetLanguageDirection();
366     if (needContentAnimation) {
367         if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
368             GetRenderContext()->ClipWithRRect(
369                 RectF(0.0f, 0.0f, frameSize.Width() * HALF, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
370         } else {
371             GetRenderContext()->ClipWithRRect(
372                 RectF(frameSize.Width() * HALF, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
373                 RadiusF(EdgeF(0.0f, 0.0f)));
374         }
375         GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
376     }
377     if (titleBarNode && needTitleAnimation) {
378         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
379     }
380 }
381 
SystemTransitionPopCallback(const int32_t animationId)382 bool NavDestinationGroupNode::SystemTransitionPopCallback(const int32_t animationId)
383 {
384     if (animationId_ != animationId) {
385         TAG_LOGW(AceLogTag::ACE_NAVIGATION,
386             "animation id is invalid, curId: %{public}d, targetId: %{public}d",
387             animationId_, animationId);
388         return false;
389     }
390     SetIsOnAnimation(false);
391     if (GetTransitionType() != PageTransitionType::EXIT_POP) {
392         // has another transition, just return
393         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "preNavDesNode has another transition");
394         return false;
395     }
396     auto preNavDesPattern = GetPattern<NavDestinationPattern>();
397     CHECK_NULL_RETURN(preNavDesPattern, false);
398 
399     // NavRouter will restore the preNavDesNode and needs to set the initial state after the animation ends.
400     auto shallowBuilder = preNavDesPattern->GetShallowBuilder();
401     if (shallowBuilder && !IsCacheNode()) {
402         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
403     }
404     if (!IsCacheNode() && GetContentNode()) {
405         GetContentNode()->Clean();
406     }
407     GetEventHub<EventHub>()->SetEnabledInternal(true);
408     GetRenderContext()->RemoveClipWithRRect();
409     if (IsNeedContentTransition()) {
410         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
411     }
412     auto preTitleNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
413     if (preTitleNode && IsNeedTitleTransition()) {
414         preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
415         preTitleNode->GetRenderContext()->SetOpacity(1.0);
416         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(preTitleNode);
417         CHECK_NULL_RETURN(titleBarNode, true);
418         auto preBackIcon = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
419         if (preBackIcon)  {
420             preBackIcon->GetRenderContext()->SetOpacity(1.0);
421         }
422     }
423     return true;
424 }
425 
InitDialogTransition(bool isZeroY)426 void NavDestinationGroupNode::InitDialogTransition(bool isZeroY)
427 {
428     if (systemTransitionType_ == NavigationSystemTransitionType::NONE
429         || systemTransitionType_ == NavigationSystemTransitionType::TITLE) {
430         return;
431     }
432     auto contentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
433     CHECK_NULL_VOID(contentNode);
434     auto context = contentNode->GetRenderContext();
435     CHECK_NULL_VOID(context);
436     if (isZeroY) {
437         context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
438         return;
439     }
440     context->UpdateTransformTranslate({ 0.0f,
441         contentNode->GetGeometryNode()->GetFrameSize().Height(), 0.0f });
442 }
443 
UpdateTextNodeListAsRenderGroup(bool isPopPage,const RefPtr<NavigationTransitionProxy> & proxy)444 void NavDestinationGroupNode::UpdateTextNodeListAsRenderGroup(
445     bool isPopPage, const RefPtr<NavigationTransitionProxy>& proxy)
446 {
447     if (isPopPage) {
448         CollectTextNodeAsRenderGroup(isPopPage);
449     } else {
450         CHECK_NULL_VOID(proxy);
451         auto pipeline = PipelineContext::GetCurrentContext();
452         CHECK_NULL_VOID(pipeline);
453         pipeline->AddAfterLayoutTask([weakNavDestiniation = WeakClaim(this),
454             weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] () {
455             auto navDestination = weakNavDestiniation.Upgrade();
456             CHECK_NULL_VOID(navDestination);
457             auto proxy = weakProxy.Upgrade();
458             if (proxy && proxy->GetIsFinished()) {
459                 return;
460             }
461             navDestination->CollectTextNodeAsRenderGroup(false);
462         });
463         pipeline->RequestFrame();
464     }
465 }
466 
CollectTextNodeAsRenderGroup(bool isPopPage)467 void NavDestinationGroupNode::CollectTextNodeAsRenderGroup(bool isPopPage)
468 {
469     ReleaseTextNodeList();
470     std::queue<RefPtr<UINode>> childrenLoopQueue;
471     childrenLoopQueue.push(contentNode_);
472 
473     // only the first 50 text nodes will be marked, avoid too much time for traversal
474     // and off-screen drawing at first few frames
475     int32_t remainTextNodeNeedRenderGroup = MAX_RENDER_GROUP_TEXT_NODE_COUNT;
476     while (!childrenLoopQueue.empty() && remainTextNodeNeedRenderGroup > 0) {
477         auto currentNode = childrenLoopQueue.front();
478         childrenLoopQueue.pop();
479         CHECK_NULL_CONTINUE(currentNode);
480         for (auto& child : currentNode->GetChildren()) {
481             if (remainTextNodeNeedRenderGroup <= 0) {
482                 break;
483             }
484             CHECK_NULL_CONTINUE(child);
485             childrenLoopQueue.push(child);
486             auto frameNode = AceType::DynamicCast<FrameNode>(child);
487             if (!frameNode || (frameNode->GetTag() != V2::TEXT_ETS_TAG)) {
488                 continue;
489             }
490             auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
491             if (!layoutProperty ||
492                 (layoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE)) {
493                 continue;
494             }
495             auto& renderContext = frameNode->GetRenderContext();
496             if (!renderContext || renderContext->GetRenderGroupValue(false)) {
497                 continue;
498             }
499             renderContext->SetMarkNodeGroup(isPopPage ||
500                 (renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT));
501             textNodeList_.emplace_back(WeakPtr<UINode>(child));
502             --remainTextNodeNeedRenderGroup;
503             auto pattern = AceType::DynamicCast<TextPattern>(frameNode->GetPattern());
504             CHECK_NULL_CONTINUE(pattern);
505             pattern->RegisterAfterLayoutCallback([weakRenderContext = WeakPtr<RenderContext>(renderContext)]() {
506                 auto renderContext = weakRenderContext.Upgrade();
507                 if (renderContext && !(renderContext->GetRenderGroupValue(false))) {
508                     renderContext->SetMarkNodeGroup(
509                         renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT);
510                 }
511             });
512         }
513     }
514 }
515 
ReleaseTextNodeList()516 void NavDestinationGroupNode::ReleaseTextNodeList()
517 {
518     for (auto& child : textNodeList_) {
519         auto textNode = AceType::DynamicCast<FrameNode>(child.Upgrade());
520         if (!textNode) {
521             continue;
522         }
523         auto pattern = AceType::DynamicCast<TextPattern>(textNode->GetPattern());
524         if (pattern) {
525             pattern->UnRegisterAfterLayoutCallback();
526         }
527         auto renderContext = textNode->GetRenderContext();
528         if (renderContext) {
529             renderContext->SetMarkNodeGroup(renderContext->GetRenderGroupValue(false));
530         }
531     }
532     textNodeList_.clear();
533 }
534 
CleanContent()535 void NavDestinationGroupNode::CleanContent()
536 {
537     // cacheNode is cached for pip info, and is no need to clean when clean content node
538     if (IsCacheNode()) {
539         return;
540     }
541     auto pattern = GetPattern<NavDestinationPattern>();
542     CHECK_NULL_VOID(pattern);
543     auto shallowBuilder = pattern->GetShallowBuilder();
544     if (shallowBuilder) {
545         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
546     }
547     if (GetContentNode()) {
548         GetContentNode()->Clean(false, true);
549     }
550 }
551 
IsNodeInvisible(const RefPtr<FrameNode> & node)552 bool NavDestinationGroupNode::IsNodeInvisible(const RefPtr<FrameNode>& node)
553 {
554     auto navigaiton = DynamicCast<NavigationGroupNode>(node);
555     CHECK_NULL_RETURN(navigaiton, false);
556     int32_t lastStandardIndex = navigaiton->GetLastStandardIndex();
557     bool isInvisible = index_ < lastStandardIndex;
558     return isInvisible;
559 }
560 
TitleOpacityAnimation(bool isTransitionIn)561 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::TitleOpacityAnimation(bool isTransitionIn)
562 {
563     if (!IsNeedTitleTransition()) {
564         return nullptr;
565     }
566     CHECK_NULL_RETURN(GetTitleBarNode(), nullptr);
567     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
568     CHECK_NULL_RETURN(titleNode, nullptr);
569     auto titleRenderContext = titleNode->GetRenderContext();
570     CHECK_NULL_RETURN(titleRenderContext, nullptr);
571     AnimationOption opacityOption;
572     opacityOption.SetCurve(Curves::SHARP);
573     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
574     if (isTransitionIn) {
575         opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
576         titleRenderContext->SetOpacity(0.0f);
577         return AnimationUtils::StartAnimation(opacityOption,
578             [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
579             auto renderContext = weakRender.Upgrade();
580             CHECK_NULL_VOID(renderContext);
581             renderContext->SetOpacity(1.0f);
582         });
583     }
584     // recover after transition animation.
585     opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
586     titleRenderContext->SetOpacity(1.0f);
587     return AnimationUtils::StartAnimation(opacityOption,
588         [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
589         auto renderContext = weakRender.Upgrade();
590         CHECK_NULL_VOID(renderContext);
591         renderContext->SetOpacity(0.0f);
592     });
593 }
594 
BackButtonAnimation(bool isTransitionIn)595 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::BackButtonAnimation(bool isTransitionIn)
596 {
597     if (!IsNeedTitleTransition()) {
598         return nullptr;
599     }
600     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
601     CHECK_NULL_RETURN(titleNode, nullptr);
602     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
603     CHECK_NULL_RETURN(backButtonNode, nullptr);
604     AnimationOption transitionOption;
605     transitionOption.SetCurve(Curves::SHARP);
606     auto backButtonNodeContext = backButtonNode->GetRenderContext();
607     CHECK_NULL_RETURN(backButtonNodeContext, nullptr);
608     if (isTransitionIn) {
609         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
610         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
611         backButtonNodeContext->SetOpacity(0.0f);
612         return AnimationUtils::StartAnimation(transitionOption,
613             [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
614             auto renderContext = weakRender.Upgrade();
615             CHECK_NULL_VOID(renderContext);
616             renderContext->SetOpacity(1.0f);
617         });
618     }
619     transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
620     backButtonNodeContext->SetOpacity(1.0f);
621     return AnimationUtils::StartAnimation(transitionOption,
622         [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
623         auto renderContext = weakRender.Upgrade();
624         CHECK_NULL_VOID(renderContext);
625         renderContext->SetOpacity(0.0f);
626     });
627 }
628 
629 
DoTransition(NavigationOperation operation,bool isEnter)630 int32_t NavDestinationGroupNode::DoTransition(NavigationOperation operation, bool isEnter)
631 {
632     if (navDestinationTransitionDelegate_) {
633         return DoCustomTransition(operation, isEnter);
634     }
635     return DoSystemTransition(operation, isEnter);
636 }
637 
DoSystemTransition(NavigationOperation operation,bool isEnter)638 int32_t NavDestinationGroupNode::DoSystemTransition(NavigationOperation operation, bool isEnter)
639 {
640     auto noneSystemTransition = NavigationSystemTransitionType::NONE;
641     if ((systemTransitionType_ & NavigationSystemTransitionType::FADE) != noneSystemTransition) {
642         return DoSystemFadeTransition(isEnter);
643     }
644     if ((systemTransitionType_ & NavigationSystemTransitionType::SLIDE_RIGHT) != noneSystemTransition ||
645         (systemTransitionType_ & NavigationSystemTransitionType::SLIDE_BOTTOM) != noneSystemTransition) {
646         return DoSystemSlideTransition(operation, isEnter);
647     }
648     if ((systemTransitionType_ & NavigationSystemTransitionType::EXPLODE) != noneSystemTransition) {
649         return isEnter ? DoSystemEnterExplodeTransition(operation) : DoSystemExitExplodeTransition(operation);
650     }
651     return INVALID_ANIMATION_ID;
652 }
653 
DoSystemFadeTransition(bool isEnter)654 int32_t NavDestinationGroupNode::DoSystemFadeTransition(bool isEnter)
655 {
656     auto renderContext = GetRenderContext();
657     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
658     auto eventHub = GetEventHub<EventHub>();
659     if (!canReused_ && eventHub) {
660         eventHub->SetEnabledInternal(false);
661     }
662     animationId_ = MakeUniqueAnimationId();
663     SetIsOnAnimation(true);
664     auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
665         isEnter ? SYSTEM_ENTER_FADE_TRANSITION_DURATION : SYSTEM_EXIT_FADE_TRANSITION_DURATION,
666         isEnter ? SYSTEM_ENTER_FADE_TRANSITION_DELAY : SYSTEM_EXIT_FADE_TRANSITION_DELAY);
667     renderContext->OpacityAnimation(option, isEnter ? 0.0f : 1.0f, isEnter ? 1.0f : 0.0f);
668     return animationId_;
669 }
670 
DoSystemSlideTransition(NavigationOperation operation,bool isEnter)671 int32_t NavDestinationGroupNode::DoSystemSlideTransition(NavigationOperation operation, bool isEnter)
672 {
673     auto eventHub = GetEventHub<EventHub>();
674     if (!canReused_ && eventHub) {
675         eventHub->SetEnabledInternal(false);
676     }
677     animationId_ = MakeUniqueAnimationId();
678     SetIsOnAnimation(true);
679     if ((operation == NavigationOperation::POP) ^ isEnter) {
680         // translate animation
681         bool isRight = (systemTransitionType_ & NavigationSystemTransitionType::SLIDE_RIGHT)
682             != NavigationSystemTransitionType::NONE;
683         std::function<void()> translateEvent = [weak = WeakClaim(this), isEnter, isRight, operation]() {
684             auto navDestination = weak.Upgrade();
685             CHECK_NULL_VOID(navDestination);
686             auto renderContext = navDestination->GetRenderContext();
687             CHECK_NULL_VOID(renderContext);
688             if (!isEnter) {
689                 auto frameSize = navDestination->GetGeometryNode()->GetFrameSize();
690                 renderContext->UpdateTranslateInXY(
691                     { isRight ? frameSize.Width() : 0.0f, isRight ? 0.0f : frameSize.Height() });
692             } else {
693                 renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
694             }
695         };
696         RefPtr<Curve> curve = isRight ? MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f)
697             : MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
698         auto option = BuildAnimationOption(curve, BuildTransitionFinishCallback());
699         if (!isEnter) {
700             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
701         } else {
702             auto frameSize = GetGeometryNode()->GetFrameSize();
703             GetRenderContext()->UpdateTranslateInXY(
704                 { isRight ? frameSize.Width() : 0.0f, isRight ? 0.0f : frameSize.Height() });
705         }
706         AnimationUtils::Animate(option, translateEvent, option.GetOnFinishEvent());
707     } else {
708         // mask animation
709         auto option = BuildAnimationOption(
710             Curves::FRICTION, BuildTransitionFinishCallback(), SYSTEM_SLIDE_TRANSITION_MASK_DURATION);
711         auto beginColor = isEnter ? SLIDE_ANIMATION_MASK_COLOR : Color::TRANSPARENT;
712         auto endColor = !isEnter ? SLIDE_ANIMATION_MASK_COLOR : Color::TRANSPARENT;
713         DoMaskAnimation(option, beginColor, endColor);
714     }
715     return animationId_;
716 }
717 
718 
DoSystemEnterExplodeTransition(NavigationOperation operation)719 int32_t NavDestinationGroupNode::DoSystemEnterExplodeTransition(NavigationOperation operation)
720 {
721     auto renderContext = GetRenderContext();
722     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
723     auto eventHub = GetEventHub<EventHub>();
724     if (!canReused_ && eventHub) {
725         eventHub->SetEnabledInternal(false);
726     }
727     animationId_ = MakeUniqueAnimationId();
728     SetIsOnAnimation(true);
729     if (operation == NavigationOperation::POP) {
730         // mask animation
731         DoMaskAnimation(BuildAnimationOption(Curves::FRICTION, nullptr, SYSTEM_EXPLODE_TRANSITION_MASK_DURATION),
732             SLIDE_ANIMATION_MASK_COLOR, Color::TRANSPARENT);
733         // opacity animation
734         auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
735             SYSTEM_ENTER_POP_EXPLODE_OPACITY_DURATION, SYSTEM_ENTER_POP_EXPLODE_OPACITY_DELAY);
736         renderContext->OpacityAnimation(option, 0.0f, 1.0f);
737         return animationId_;
738     }
739     // opacity animation
740     auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
741         SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DURATION, SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DELAY);
742     renderContext->OpacityAnimation(option, 0.0f, 1.0f);
743     // scale animation for enter-push
744     auto scaleCurve = MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
745     renderContext->ScaleAnimation(
746         BuildAnimationOption(scaleCurve, BuildTransitionFinishCallback()), 0.75f, 1.0f);
747     return animationId_;
748 }
749 
DoSystemExitExplodeTransition(NavigationOperation operation)750 int32_t NavDestinationGroupNode::DoSystemExitExplodeTransition(NavigationOperation operation)
751 {
752     auto renderContext = GetRenderContext();
753     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
754     auto eventHub = GetEventHub<EventHub>();
755     if (!canReused_ && eventHub) {
756         eventHub->SetEnabledInternal(false);
757     }
758     animationId_ = MakeUniqueAnimationId();
759     SetIsOnAnimation(true);
760     if (operation == NavigationOperation::POP) {
761         // opacity animation
762         renderContext->OpacityAnimation(
763             BuildAnimationOption(Curves::SHARP, nullptr, SYSTEM_EXIT_POP_EXPLODE_OPACITY_DURATION), 1.0f, 0.0f);
764         // scale animation
765         auto scaleCurve = MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
766         auto option = BuildAnimationOption(scaleCurve, BuildTransitionFinishCallback());
767         renderContext->ScaleAnimation(option, 1.0f, 0.8f);
768         return animationId_;
769     }
770     // opacity animation
771     renderContext->OpacityAnimation(
772         BuildAnimationOption(Curves::SHARP, nullptr, SYSTEM_EXIT_PUSH_EXPLODE_OPACITY_DELAY), 1.0f, 0.0f);
773     // mask animation
774     auto maskOption = BuildAnimationOption(
775         Curves::FRICTION, BuildTransitionFinishCallback(), SYSTEM_EXPLODE_TRANSITION_MASK_DURATION);
776     DoMaskAnimation(maskOption, Color::TRANSPARENT, SLIDE_ANIMATION_MASK_COLOR);
777     return animationId_;
778 }
779 
DoMaskAnimation(const AnimationOption & option,Color begin,Color end)780 void NavDestinationGroupNode::DoMaskAnimation(const AnimationOption& option, Color begin, Color end)
781 {
782     auto renderContext = GetRenderContext();
783     CHECK_NULL_VOID(renderContext);
784     std::function<void()> maskEvent = [weak = WeakClaim(this), end]() {
785         auto navDestination = weak.Upgrade();
786         CHECK_NULL_VOID(navDestination);
787         auto renderContext = navDestination->GetRenderContext();
788         CHECK_NULL_VOID(renderContext);
789         renderContext->SetActualForegroundColor(end);
790     };
791 
792     // initial property
793     renderContext->SetActualForegroundColor(begin);
794     AnimationUtils::Animate(option, maskEvent, option.GetOnFinishEvent());
795 }
796 
DoCustomTransition(NavigationOperation operation,bool isEnter)797 int32_t NavDestinationGroupNode::DoCustomTransition(NavigationOperation operation, bool isEnter)
798 {
799     auto delegate = navDestinationTransitionDelegate_;
800     if (!delegate) {
801         return INVALID_ANIMATION_ID;
802     }
803     auto eventHub = GetEventHub<EventHub>();
804     if (!canReused_ && eventHub) {
805         eventHub->SetEnabledInternal(false);
806     }
807     auto allTransitions = delegate(operation, isEnter);
808     if (!allTransitions.has_value()) {
809         return INVALID_ANIMATION_ID;
810     }
811     int32_t longestAnimationDuration = INT32_MIN;
812     for (auto transition: allTransitions.value()) {
813         if (transition.duration + transition.delay > longestAnimationDuration) {
814             longestAnimationDuration = transition.duration + transition.delay;
815         }
816     }
817     if (longestAnimationDuration == INT32_MIN) {
818         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navDestination custom transition array is empty!");
819     }
820     auto pipeline = GetContext();
821     CHECK_NULL_RETURN(pipeline, INVALID_ANIMATION_ID);
822     pipeline->FlushBuild();
823     pipeline->FlushUITasks();
824     animationId_ = MakeUniqueAnimationId();
825     bool hasRest = false;
826     for (auto transition: allTransitions.value()) {
827         StartCustomTransitionAnimation(transition, isEnter, hasRest, longestAnimationDuration);
828     }
829     return animationId_;
830 }
831 
StartCustomTransitionAnimation(NavDestinationTransition & transition,bool isEnter,bool & hasResetProperties,int32_t longestAnimationDuration)832 void NavDestinationGroupNode::StartCustomTransitionAnimation(NavDestinationTransition& transition,
833     bool isEnter, bool& hasResetProperties, int32_t longestAnimationDuration)
834 {
835     AnimationOption option;
836     option.SetDuration(transition.duration);
837     option.SetCurve(transition.curve);
838     option.SetDelay(transition.delay);
839 
840     std::function<void()> event =
841         [transitionEvent = std::move(transition.event), weak = WeakClaim(this), isEnter, &hasResetProperties]() {
842             // do necessary system-side tasks
843             auto navDestination = weak.Upgrade();
844             CHECK_NULL_VOID(navDestination);
845             navDestination->SetIsOnAnimation(true);
846             if (!hasResetProperties && isEnter) {
847                 auto pattern = navDestination->GetPattern<NavDestinationPattern>();
848                 CHECK_NULL_VOID(pattern);
849                 auto navigation = AceType::DynamicCast<NavigationGroupNode>(pattern->GetNavigationNode());
850                 if (navigation) {
851                     /*
852                     *  Reset the system animation properties in custom transition
853                     *  animation closure to prevent animation mutation.
854                     */
855                     navigation->ResetSystemAnimationProperties(navDestination);
856                 }
857                 hasResetProperties = true;
858             }
859             // do user-set task
860             transitionEvent();
861             auto pipeline = navDestination->GetContext();
862             CHECK_NULL_VOID(pipeline);
863             pipeline->FlushBuild();
864             pipeline->FlushUITasks();
865         };
866     // only do remove or set visibility in longest custom transition animation's finish callback.
867     std::function<void()> finish = transition.duration + transition.delay == longestAnimationDuration ?
868         BuildTransitionFinishCallback(false, std::move(transition.onTransitionEnd)) :
869         std::move(transition.onTransitionEnd);
870     AnimationUtils::Animate(option, event, finish);
871     auto pattern = GetPattern<NavDestinationPattern>();
872     CHECK_NULL_VOID(pattern);
873     TAG_LOGI(AceLogTag::ACE_NAVIGATION,
874         "%{public}s trigger custom transition, duration: %{public}d, delay: %{public}d, curve: %{public}s",
875         pattern->GetName().c_str(), transition.duration, transition.delay, transition.curve->ToString().c_str());
876 }
877 
MakeUniqueAnimationId()878 int32_t NavDestinationGroupNode::MakeUniqueAnimationId()
879 {
880     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
881     CHECK_NULL_RETURN(navDestinationPattern, INVALID_ANIMATION_ID);
882     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
883     CHECK_NULL_RETURN(navigationNode, INVALID_ANIMATION_ID);
884     return navigationNode->MakeUniqueAnimationId();
885 }
886 
BuildTransitionFinishCallback(bool isSystemTransition,std::function<void ()> && extraOption)887 std::function<void()> NavDestinationGroupNode::BuildTransitionFinishCallback(
888     bool isSystemTransition, std::function<void()>&& extraOption)
889 {
890     std::function<void()> finish = [extraOption = std::move(extraOption), weak = WeakClaim(this),
891         animationId = animationId_, isSystemTransition]() {
892             auto navDestination = weak.Upgrade();
893             CHECK_NULL_VOID(navDestination);
894             auto destinationPattern = navDestination->GetPattern<NavDestinationPattern>();
895             CHECK_NULL_VOID(destinationPattern);
896             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s transition finish", destinationPattern->GetName().c_str());
897             // do extraOption first
898             if (extraOption) {
899                 extraOption();
900             }
901             // do necessary system-side tasks
902             if (animationId != navDestination->GetAnimationId()) {
903                 return;
904             }
905             if (isSystemTransition) {
906                 navDestination->ResetCustomTransitionAnimationProperties();
907             }
908             // only handle current node in latest finish callback.
909             if (!navDestination->GetCanReused()) {
910                 // can't be reused means it is not in navigation stack anymore, so remove it.
911                 navDestination->CleanContent();
912                 auto parent = navDestination->GetParent();
913                 CHECK_NULL_VOID(parent);
914                 parent->RemoveChild(navDestination);
915                 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
916             } else if (navDestination->HasStandardBefore()) {
917                 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
918                 navDestination->SetJSViewActive(false);
919             }
920             navDestination->SetIsOnAnimation(false);
921         };
922     return finish;
923 }
924 
HasStandardBefore() const925 bool NavDestinationGroupNode::HasStandardBefore() const
926 {
927     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
928     CHECK_NULL_RETURN(navDestinationPattern, false);
929     auto navigationNode =
930         AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
931     CHECK_NULL_RETURN(navigationNode, false);
932     return index_ < navigationNode->GetLastStandardIndex();
933 }
934 
ResetCustomTransitionAnimationProperties()935 void NavDestinationGroupNode::ResetCustomTransitionAnimationProperties()
936 {
937     auto renderContext = GetRenderContext();
938     CHECK_NULL_VOID(renderContext);
939     renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
940     renderContext->SetOpacity(userSetOpacity_);
941     renderContext->SetActualForegroundColor(Color::TRANSPARENT);
942 }
943 } // namespace OHOS::Ace::NG
944