1 /*
2 * Copyright (c) 2024 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/navdestination_pattern_base.h"
17
18 #include "core/components_ng/pattern/navigation/navdestination_node_base.h"
19
20 namespace OHOS::Ace::NG {
21 namespace {
22 constexpr int32_t DEFAULT_ANIMATION_DURATION = 500;
23 } // namespace
24
UpdateLayoutPropertyBeforeAnimation(const RefPtr<NavDestinationNodeBase> & navNodeBase,bool needRunTitleBarAnimation,bool needRunToolBarAnimation,bool hideTitleBar,bool hideToolBar)25 void NavDestinationPatternBase::UpdateLayoutPropertyBeforeAnimation(const RefPtr<NavDestinationNodeBase>& navNodeBase,
26 bool needRunTitleBarAnimation, bool needRunToolBarAnimation, bool hideTitleBar, bool hideToolBar)
27 {
28 CHECK_NULL_VOID(navNodeBase);
29 auto property = navNodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
30 CHECK_NULL_VOID(property);
31 if (needRunTitleBarAnimation && titleBarAnimationCount_ == 0) {
32 property->UpdateTitleBarTranslateState(hideTitleBar ?
33 BarTranslateState::TRANSLATE_ZERO : BarTranslateState::TRANSLATE_HEIGHT);
34 if (!hideTitleBar) {
35 UpdateTitleBarProperty(property, false, navNodeBase);
36 }
37 }
38 if (needRunToolBarAnimation && toolBarAnimationCount_ == 0) {
39 property->UpdateToolBarTranslateState(hideToolBar ?
40 BarTranslateState::TRANSLATE_ZERO : BarTranslateState::TRANSLATE_HEIGHT);
41 if (!hideToolBar) {
42 UpdateToolBarAndDividerProperty(property, false, navNodeBase);
43 }
44 }
45 }
46
HandleTitleBarAndToolBarAnimation(const RefPtr<NavDestinationNodeBase> & navNodeBase,bool needRunTitleBarAnimation,bool needRunToolBarAnimation)47 void NavDestinationPatternBase::HandleTitleBarAndToolBarAnimation(const RefPtr<NavDestinationNodeBase>& navNodeBase,
48 bool needRunTitleBarAnimation, bool needRunToolBarAnimation)
49 {
50 if (!(needRunToolBarAnimation || needRunTitleBarAnimation)) {
51 return;
52 }
53
54 CHECK_NULL_VOID(navNodeBase);
55 auto pipeline = navNodeBase->GetContext();
56 CHECK_NULL_VOID(pipeline);
57 auto property = navNodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
58 CHECK_NULL_VOID(property);
59 bool hideTitleBar = property->GetHideTitleBarValue(false);
60 bool hideToolBar = property->GetHideToolBarValue(false);
61 UpdateLayoutPropertyBeforeAnimation(navNodeBase, needRunTitleBarAnimation,
62 needRunToolBarAnimation, hideTitleBar, hideToolBar);
63
64 auto task = [weakPattern = WeakClaim(this), needRunTitleBarAnimation, needRunToolBarAnimation,
65 hideTitleBar, hideToolBar]() mutable {
66 auto pattern = weakPattern.Upgrade();
67 CHECK_NULL_VOID(pattern);
68 auto node = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
69 CHECK_NULL_VOID(node);
70 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
71 CHECK_NULL_VOID(property);
72 if (pattern->IsNeedHideToolBarForNavWidth()) {
73 property->ResetToolBarTranslateState();
74 needRunToolBarAnimation = false;
75 }
76 if (!(needRunToolBarAnimation || needRunTitleBarAnimation)) {
77 return;
78 }
79
80 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(node->GetTitleBarNode());
81 if (needRunTitleBarAnimation && !hideTitleBar && titleBarNode && pattern->GetTitleBarAnimationCount() == 0) {
82 pattern->UpdateTitleBarTranslateAndOpacity(true, titleBarNode, pattern->GetTitleBarHeight());
83 }
84 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(node->GetToolBarNode());
85 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(node->GetToolBarDividerNode());
86 if (needRunToolBarAnimation && !hideToolBar && toolBarNode && pattern->GetToolBarAnimationCount() == 0) {
87 pattern->UpdateToolBarAndDividerTranslateAndOpacity(true, toolBarNode,
88 pattern->GetToolBarHeight(), toolBarDividerNode, pattern->GetToolBarDividerHeight());
89 }
90
91 pattern->StartAnimation(needRunTitleBarAnimation, hideTitleBar, needRunToolBarAnimation, hideToolBar);
92 };
93 pipeline->AddAfterLayoutTask(std::move(task));
94 }
95
UpdateTitleBarProperty(const RefPtr<LayoutProperty> & navBarLayoutProperty,bool hide,const RefPtr<NavDestinationNodeBase> & hostNode)96 void NavDestinationPatternBase::UpdateTitleBarProperty(const RefPtr<LayoutProperty>& navBarLayoutProperty, bool hide,
97 const RefPtr<NavDestinationNodeBase>& hostNode)
98 {
99 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
100 CHECK_NULL_VOID(titleBarNode);
101 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty();
102 CHECK_NULL_VOID(titleBarLayoutProperty);
103 if (hide) {
104 titleBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
105 titleBarNode->SetJSViewActive(false);
106 } else {
107 titleBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
108 titleBarNode->SetJSViewActive(true);
109 auto&& opts = navBarLayoutProperty->GetSafeAreaExpandOpts();
110 if (opts) {
111 titleBarLayoutProperty->UpdateSafeAreaExpandOpts(*opts);
112 }
113 }
114 }
115
UpdateTitleBarTranslateAndOpacity(bool hide,const RefPtr<TitleBarNode> & titleBarNode,float titleBarHeight)116 void NavDestinationPatternBase::UpdateTitleBarTranslateAndOpacity(
117 bool hide, const RefPtr<TitleBarNode>& titleBarNode, float titleBarHeight)
118 {
119 if (titleBarNode) {
120 auto renderContext = titleBarNode->GetRenderContext();
121 if (renderContext) {
122 auto offset = renderContext->GetTranslateXYProperty();
123 offset.SetY(hide ? -titleBarHeight : 0.0f);
124 renderContext->UpdateTranslateInXY(offset);
125 renderContext->UpdateOpacity(hide ? 0.0f : 1.0f);
126 }
127 }
128 }
129
UpdateToolBarAndDividerProperty(const RefPtr<LayoutProperty> & navBarLayoutProperty,bool hide,const RefPtr<NavDestinationNodeBase> & hostNode)130 void NavDestinationPatternBase::UpdateToolBarAndDividerProperty(const RefPtr<LayoutProperty>& navBarLayoutProperty,
131 bool hide, const RefPtr<NavDestinationNodeBase>& hostNode)
132 {
133 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(hostNode->GetToolBarNode());
134 CHECK_NULL_VOID(toolBarNode);
135 auto toolBarLayoutProperty = toolBarNode->GetLayoutProperty();
136 CHECK_NULL_VOID(toolBarLayoutProperty);
137 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetToolBarDividerNode());
138 RefPtr<LayoutProperty> toolBarDividerLayoutProperty = nullptr;
139 if (toolBarDividerNode) {
140 toolBarDividerLayoutProperty = toolBarDividerNode->GetLayoutProperty();
141 }
142 if (hide || !toolBarNode->HasValidContent()) {
143 toolBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
144 toolBarNode->SetActive(false);
145 if (toolBarDividerLayoutProperty) {
146 toolBarDividerLayoutProperty->UpdateVisibility(VisibleType::GONE);
147 }
148 } else {
149 toolBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
150 toolBarNode->SetActive(true);
151 if (toolBarDividerLayoutProperty) {
152 toolBarDividerLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
153 }
154
155 auto&& opts = navBarLayoutProperty->GetSafeAreaExpandOpts();
156 if (opts) {
157 toolBarLayoutProperty->UpdateSafeAreaExpandOpts(*opts);
158 }
159 }
160 }
161
UpdateToolBarAndDividerTranslateAndOpacity(bool hide,const RefPtr<NavToolbarNode> & toolBarNode,float toolBarHeight,const RefPtr<FrameNode> & toolbarDividerNode,float toolBarDividerHeight)162 void NavDestinationPatternBase::UpdateToolBarAndDividerTranslateAndOpacity(bool hide,
163 const RefPtr<NavToolbarNode>& toolBarNode, float toolBarHeight, const RefPtr<FrameNode>& toolbarDividerNode,
164 float toolBarDividerHeight)
165 {
166 float opacity = hide ? 0.0f : 1.0f;
167 float offsetY = hide ? (toolBarHeight + toolBarDividerHeight) : 0;
168 if (toolBarNode) {
169 auto renderContext = toolBarNode->GetRenderContext();
170 if (renderContext) {
171 renderContext->UpdateTranslateInXY({ 0.0f, offsetY });
172 renderContext->UpdateOpacity(opacity);
173 }
174 }
175 if (toolbarDividerNode) {
176 auto dividerContext = toolbarDividerNode->GetRenderContext();
177 if (dividerContext) {
178 dividerContext->UpdateTranslateInXY({ 0.0f, offsetY });
179 dividerContext->UpdateOpacity(opacity);
180 }
181 }
182 }
183
HideOrShowTitleBarImmediately(const RefPtr<NavDestinationNodeBase> & hostNode,bool hide)184 void NavDestinationPatternBase::HideOrShowTitleBarImmediately(const RefPtr<NavDestinationNodeBase>& hostNode, bool hide)
185 {
186 auto navBarPattern = hostNode->GetPattern<NavDestinationPatternBase>();
187 CHECK_NULL_VOID(navBarPattern);
188 auto navBarLayoutProperty = hostNode->GetLayoutProperty();
189 CHECK_NULL_VOID(navBarLayoutProperty);
190 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
191 CHECK_NULL_VOID(titleBarNode);
192 UpdateTitleBarProperty(navBarLayoutProperty, hide, hostNode);
193 UpdateTitleBarTranslateAndOpacity(hide, titleBarNode, navBarPattern->GetTitleBarHeight());
194 titleBarNode->MarkModifyDone();
195 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
196 }
197
HideOrShowToolBarImmediately(const RefPtr<NavDestinationNodeBase> & hostNode,bool hide)198 void NavDestinationPatternBase::HideOrShowToolBarImmediately(const RefPtr<NavDestinationNodeBase>& hostNode, bool hide)
199 {
200 auto navDestinationPatternBase = hostNode->GetPattern<NavDestinationPatternBase>();
201 CHECK_NULL_VOID(navDestinationPatternBase);
202 auto navBarLayoutProperty = hostNode->GetLayoutProperty();
203 CHECK_NULL_VOID(navBarLayoutProperty);
204 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(hostNode->GetToolBarNode());
205 CHECK_NULL_VOID(toolBarNode);
206 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetToolBarDividerNode());
207 UpdateToolBarAndDividerProperty(navBarLayoutProperty, hide, hostNode);
208 UpdateToolBarAndDividerTranslateAndOpacity(hide, toolBarNode, GetToolBarHeight(),
209 toolBarDividerNode, GetToolBarDividerHeight());
210 toolBarNode->MarkModifyDone();
211 toolBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
212 }
213
BarAnimationPropertyCallback(bool needRunTitleBarAnimation,bool hideTitle,bool needRunToolBarAnimation,bool hideTool)214 void NavDestinationPatternBase::BarAnimationPropertyCallback(
215 bool needRunTitleBarAnimation, bool hideTitle, bool needRunToolBarAnimation, bool hideTool)
216 {
217 auto node = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
218 CHECK_NULL_VOID(node);
219 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
220 CHECK_NULL_VOID(property);
221 auto context = node->GetContext();
222 CHECK_NULL_VOID(context);
223 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(node->GetTitleBarNode());
224 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(node->GetToolBarNode());
225 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(node->GetToolBarDividerNode());
226 if (needRunTitleBarAnimation && titleBarNode) {
227 property->UpdateTitleBarTranslateState(hideTitle ?
228 BarTranslateState::TRANSLATE_HEIGHT : BarTranslateState::TRANSLATE_ZERO);
229 }
230 if (needRunToolBarAnimation && toolBarNode) {
231 property->UpdateToolBarTranslateState(hideTool ?
232 BarTranslateState::TRANSLATE_HEIGHT : BarTranslateState::TRANSLATE_ZERO);
233 }
234 node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
235 context->FlushUITasks();
236 if (needRunTitleBarAnimation && titleBarNode) {
237 UpdateTitleBarTranslateAndOpacity(hideTitle, titleBarNode, GetTitleBarHeight());
238 }
239 if (needRunToolBarAnimation && toolBarNode) {
240 UpdateToolBarAndDividerTranslateAndOpacity(hideTool, toolBarNode, GetToolBarHeight(),
241 toolBarDividerNode, GetToolBarDividerHeight());
242 }
243 }
244
BarAnimationFinishCallback(bool needRunTitleBarAnimation,bool needRunToolBarAnimation,int32_t animationId)245 void NavDestinationPatternBase::BarAnimationFinishCallback(
246 bool needRunTitleBarAnimation, bool needRunToolBarAnimation, int32_t animationId)
247 {
248 if (needRunTitleBarAnimation) {
249 OnTitleBarAnimationFinish();
250 }
251 if (needRunToolBarAnimation) {
252 OnToolBarAnimationFinish();
253 }
254 RemoveAnimation(animationId);
255 }
256
StartAnimation(bool needRunTitleBarAnimation,bool hideTitle,bool needRunToolBarAnimation,bool hideTool)257 void NavDestinationPatternBase::StartAnimation(
258 bool needRunTitleBarAnimation, bool hideTitle, bool needRunToolBarAnimation, bool hideTool)
259 {
260 auto propertyCallback = [needRunTitleBarAnimation, hideTitle, needRunToolBarAnimation, hideTool,
261 weakPattern = AceType::WeakClaim(this)]() {
262 auto pattern = weakPattern.Upgrade();
263 CHECK_NULL_VOID(pattern);
264 pattern->BarAnimationPropertyCallback(needRunTitleBarAnimation, hideTitle, needRunToolBarAnimation, hideTool);
265 };
266 auto finishCallback = [needRunTitleBarAnimation, needRunToolBarAnimation,
267 weakPattern = AceType::WeakClaim(this), animationId = nextBarAnimationId_]() {
268 auto pattern = weakPattern.Upgrade();
269 CHECK_NULL_VOID(pattern);
270 pattern->BarAnimationFinishCallback(needRunTitleBarAnimation, needRunToolBarAnimation, animationId);
271 };
272
273 AnimationOption option;
274 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
275 option.SetDuration(DEFAULT_ANIMATION_DURATION);
276 if (needRunTitleBarAnimation) {
277 OnTitleBarAnimationStart();
278 }
279 if (needRunToolBarAnimation) {
280 OnToolBarAnimationStart();
281 }
282 auto animation = AnimationUtils::StartAnimation(option, propertyCallback, finishCallback);
283 barAnimations_.emplace(nextBarAnimationId_, animation);
284 nextBarAnimationId_++;
285 }
286
OnTitleBarAnimationFinish()287 void NavDestinationPatternBase::OnTitleBarAnimationFinish()
288 {
289 titleBarAnimationCount_--;
290 if (titleBarAnimationCount_ > 0) {
291 return;
292 }
293
294 auto node = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
295 CHECK_NULL_VOID(node);
296 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
297 CHECK_NULL_VOID(property);
298 property->ResetTitleBarTranslateState();
299 HideOrShowTitleBarImmediately(node, property->GetHideTitleBarValue(false));
300 }
301
OnToolBarAnimationFinish()302 void NavDestinationPatternBase::OnToolBarAnimationFinish()
303 {
304 toolBarAnimationCount_--;
305 if (toolBarAnimationCount_ > 0) {
306 return;
307 }
308
309 auto node = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
310 CHECK_NULL_VOID(node);
311 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
312 CHECK_NULL_VOID(property);
313 property->ResetToolBarTranslateState();
314 HideOrShowToolBarImmediately(node, property->GetHideToolBarValue(false));
315 }
316
AbortBarAnimation()317 void NavDestinationPatternBase::AbortBarAnimation()
318 {
319 for (const auto& pair : barAnimations_) {
320 if (pair.second) {
321 AnimationUtils::StopAnimation(pair.second);
322 }
323 }
324 barAnimations_.clear();
325 }
326
RemoveAnimation(int32_t id)327 void NavDestinationPatternBase::RemoveAnimation(int32_t id)
328 {
329 auto it = barAnimations_.find(id);
330 if (it != barAnimations_.end()) {
331 barAnimations_.erase(it);
332 }
333 }
334 } // namespace OHOS::Ace::NG