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 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
20
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr int32_t DEFAULT_ANIMATION_DURATION = 500;
24 } // namespace
25
SetTitleBarStyle(const std::optional<BarStyle> & barStyle)26 void NavDestinationPatternBase::SetTitleBarStyle(const std::optional<BarStyle>& barStyle)
27 {
28 if (titleBarStyle_ != barStyle) {
29 // Mark need update safeAreaPadding when it is enabled or disabled.
30 if (barStyle.value_or(BarStyle::STANDARD) == BarStyle::SAFE_AREA_PADDING ||
31 titleBarStyle_.value_or(BarStyle::STANDARD) == BarStyle::SAFE_AREA_PADDING) {
32 safeAreaPaddingChanged_ = true;
33 }
34 titleBarStyle_ = barStyle;
35 auto host = GetHost();
36 CHECK_NULL_VOID(host);
37 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
38 }
39 }
40
SetToolBarStyle(const std::optional<BarStyle> & barStyle)41 void NavDestinationPatternBase::SetToolBarStyle(const std::optional<BarStyle>& barStyle)
42 {
43 if (toolBarStyle_ != barStyle) {
44 // Mark need update safeAreaPadding when it is enabled or disabled.
45 if (barStyle.value_or(BarStyle::STANDARD) == BarStyle::SAFE_AREA_PADDING ||
46 toolBarStyle_.value_or(BarStyle::STANDARD) == BarStyle::SAFE_AREA_PADDING) {
47 safeAreaPaddingChanged_ = true;
48 }
49 toolBarStyle_ = barStyle;
50 auto host = GetHost();
51 CHECK_NULL_VOID(host);
52 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
53 }
54 }
55
UpdateLayoutPropertyBeforeAnimation(const RefPtr<NavDestinationNodeBase> & navNodeBase,bool needRunTitleBarAnimation,bool needRunToolBarAnimation,bool hideTitleBar,bool hideToolBar)56 void NavDestinationPatternBase::UpdateLayoutPropertyBeforeAnimation(const RefPtr<NavDestinationNodeBase>& navNodeBase,
57 bool needRunTitleBarAnimation, bool needRunToolBarAnimation, bool hideTitleBar, bool hideToolBar)
58 {
59 CHECK_NULL_VOID(navNodeBase);
60 auto property = navNodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
61 CHECK_NULL_VOID(property);
62 if (needRunTitleBarAnimation && titleBarAnimationCount_ == 0) {
63 property->UpdateTitleBarTranslateState(hideTitleBar ?
64 BarTranslateState::TRANSLATE_ZERO : BarTranslateState::TRANSLATE_HEIGHT);
65 if (!hideTitleBar) {
66 UpdateTitleBarProperty(property, false, navNodeBase);
67 }
68 }
69 if (needRunToolBarAnimation && toolBarAnimationCount_ == 0) {
70 property->UpdateToolBarTranslateState(hideToolBar ?
71 BarTranslateState::TRANSLATE_ZERO : BarTranslateState::TRANSLATE_HEIGHT);
72 if (!hideToolBar) {
73 UpdateToolBarAndDividerProperty(property, false, navNodeBase);
74 }
75 }
76 }
77
HandleTitleBarAndToolBarAnimation(const RefPtr<NavDestinationNodeBase> & navNodeBase,bool needRunTitleBarAnimation,bool needRunToolBarAnimation)78 void NavDestinationPatternBase::HandleTitleBarAndToolBarAnimation(const RefPtr<NavDestinationNodeBase>& navNodeBase,
79 bool needRunTitleBarAnimation, bool needRunToolBarAnimation)
80 {
81 if (!(needRunToolBarAnimation || needRunTitleBarAnimation)) {
82 return;
83 }
84
85 CHECK_NULL_VOID(navNodeBase);
86 auto pipeline = navNodeBase->GetContext();
87 CHECK_NULL_VOID(pipeline);
88 auto property = navNodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
89 CHECK_NULL_VOID(property);
90 bool hideTitleBar = property->GetHideTitleBarValue(false);
91 bool hideToolBar = property->GetHideToolBarValue(false);
92 UpdateLayoutPropertyBeforeAnimation(navNodeBase, needRunTitleBarAnimation,
93 needRunToolBarAnimation, hideTitleBar, hideToolBar);
94
95 auto task = [weakPattern = WeakClaim(this), needRunTitleBarAnimation, needRunToolBarAnimation,
96 hideTitleBar, hideToolBar]() mutable {
97 auto pattern = weakPattern.Upgrade();
98 CHECK_NULL_VOID(pattern);
99 auto node = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
100 CHECK_NULL_VOID(node);
101 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
102 CHECK_NULL_VOID(property);
103 if (pattern->IsNeedHideToolBarForNavWidth()) {
104 property->ResetToolBarTranslateState();
105 needRunToolBarAnimation = false;
106 }
107 if (!(needRunToolBarAnimation || needRunTitleBarAnimation)) {
108 return;
109 }
110
111 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(node->GetTitleBarNode());
112 if (needRunTitleBarAnimation && !hideTitleBar && titleBarNode && pattern->GetTitleBarAnimationCount() == 0) {
113 pattern->UpdateTitleBarTranslateAndOpacity(true, titleBarNode, pattern->GetTitleBarHeight());
114 }
115 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(node->GetToolBarNode());
116 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(node->GetToolBarDividerNode());
117 if (needRunToolBarAnimation && !hideToolBar && toolBarNode && pattern->GetToolBarAnimationCount() == 0) {
118 pattern->UpdateToolBarAndDividerTranslateAndOpacity(true, toolBarNode,
119 pattern->GetToolBarHeight(), toolBarDividerNode, pattern->GetToolBarDividerHeight());
120 }
121
122 pattern->StartAnimation(needRunTitleBarAnimation, hideTitleBar, needRunToolBarAnimation, hideToolBar);
123 };
124 pipeline->AddAfterLayoutTask(std::move(task));
125 }
126
UpdateTitleBarProperty(const RefPtr<LayoutProperty> & navBarLayoutProperty,bool hide,const RefPtr<NavDestinationNodeBase> & hostNode)127 void NavDestinationPatternBase::UpdateTitleBarProperty(const RefPtr<LayoutProperty>& navBarLayoutProperty, bool hide,
128 const RefPtr<NavDestinationNodeBase>& hostNode)
129 {
130 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
131 CHECK_NULL_VOID(titleBarNode);
132 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty();
133 CHECK_NULL_VOID(titleBarLayoutProperty);
134 if (hide) {
135 titleBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
136 titleBarNode->SetJSViewActive(false);
137 } else {
138 titleBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
139 titleBarNode->SetJSViewActive(true);
140 auto&& opts = navBarLayoutProperty->GetSafeAreaExpandOpts();
141 if (opts) {
142 titleBarLayoutProperty->UpdateSafeAreaExpandOpts(*opts);
143 }
144 }
145 }
146
UpdateTitleBarTranslateAndOpacity(bool hide,const RefPtr<TitleBarNode> & titleBarNode,float titleBarHeight)147 void NavDestinationPatternBase::UpdateTitleBarTranslateAndOpacity(
148 bool hide, const RefPtr<TitleBarNode>& titleBarNode, float titleBarHeight)
149 {
150 if (titleBarNode) {
151 auto renderContext = titleBarNode->GetRenderContext();
152 if (renderContext) {
153 auto offset = renderContext->GetTranslateXYProperty();
154 offset.SetY(hide ? -titleBarHeight : 0.0f);
155 renderContext->UpdateTranslateInXY(offset);
156 renderContext->UpdateOpacity(hide ? 0.0f : 1.0f);
157 }
158 }
159 }
160
UpdateToolBarAndDividerProperty(const RefPtr<LayoutProperty> & navBarLayoutProperty,bool hide,const RefPtr<NavDestinationNodeBase> & hostNode)161 void NavDestinationPatternBase::UpdateToolBarAndDividerProperty(const RefPtr<LayoutProperty>& navBarLayoutProperty,
162 bool hide, const RefPtr<NavDestinationNodeBase>& hostNode)
163 {
164 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(hostNode->GetToolBarNode());
165 CHECK_NULL_VOID(toolBarNode);
166 auto toolBarLayoutProperty = toolBarNode->GetLayoutProperty();
167 CHECK_NULL_VOID(toolBarLayoutProperty);
168 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetToolBarDividerNode());
169 RefPtr<LayoutProperty> toolBarDividerLayoutProperty = nullptr;
170 if (toolBarDividerNode) {
171 toolBarDividerLayoutProperty = toolBarDividerNode->GetLayoutProperty();
172 }
173 if (hide || !toolBarNode->HasValidContent()) {
174 toolBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
175 toolBarNode->SetActive(false);
176 if (toolBarDividerLayoutProperty) {
177 toolBarDividerLayoutProperty->UpdateVisibility(VisibleType::GONE);
178 }
179 } else {
180 toolBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
181 toolBarNode->SetActive(true);
182 if (toolBarDividerLayoutProperty) {
183 toolBarDividerLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
184 }
185
186 auto&& opts = navBarLayoutProperty->GetSafeAreaExpandOpts();
187 if (opts) {
188 toolBarLayoutProperty->UpdateSafeAreaExpandOpts(*opts);
189 }
190 }
191 }
192
UpdateToolBarAndDividerTranslateAndOpacity(bool hide,const RefPtr<NavToolbarNode> & toolBarNode,float toolBarHeight,const RefPtr<FrameNode> & toolbarDividerNode,float toolBarDividerHeight)193 void NavDestinationPatternBase::UpdateToolBarAndDividerTranslateAndOpacity(bool hide,
194 const RefPtr<NavToolbarNode>& toolBarNode, float toolBarHeight, const RefPtr<FrameNode>& toolbarDividerNode,
195 float toolBarDividerHeight)
196 {
197 float opacity = hide ? 0.0f : 1.0f;
198 float offsetY = hide ? (toolBarHeight + toolBarDividerHeight) : 0;
199 if (toolBarNode) {
200 auto renderContext = toolBarNode->GetRenderContext();
201 if (renderContext) {
202 renderContext->UpdateTranslateInXY({ 0.0f, offsetY });
203 renderContext->UpdateOpacity(opacity);
204 }
205 }
206 if (toolbarDividerNode) {
207 auto dividerContext = toolbarDividerNode->GetRenderContext();
208 if (dividerContext) {
209 dividerContext->UpdateTranslateInXY({ 0.0f, offsetY });
210 dividerContext->UpdateOpacity(opacity);
211 }
212 }
213 }
214
HideOrShowTitleBarImmediately(const RefPtr<NavDestinationNodeBase> & hostNode,bool hide)215 void NavDestinationPatternBase::HideOrShowTitleBarImmediately(const RefPtr<NavDestinationNodeBase>& hostNode, bool hide)
216 {
217 auto navBarPattern = hostNode->GetPattern<NavDestinationPatternBase>();
218 CHECK_NULL_VOID(navBarPattern);
219 auto navBarLayoutProperty = hostNode->GetLayoutProperty();
220 CHECK_NULL_VOID(navBarLayoutProperty);
221 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
222 CHECK_NULL_VOID(titleBarNode);
223 UpdateTitleBarProperty(navBarLayoutProperty, hide, hostNode);
224 UpdateTitleBarTranslateAndOpacity(hide, titleBarNode, navBarPattern->GetTitleBarHeight());
225 titleBarNode->MarkModifyDone();
226 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
227 }
228
HideOrShowToolBarImmediately(const RefPtr<NavDestinationNodeBase> & hostNode,bool hide)229 void NavDestinationPatternBase::HideOrShowToolBarImmediately(const RefPtr<NavDestinationNodeBase>& hostNode, bool hide)
230 {
231 auto navDestinationPatternBase = hostNode->GetPattern<NavDestinationPatternBase>();
232 CHECK_NULL_VOID(navDestinationPatternBase);
233 auto navBarLayoutProperty = hostNode->GetLayoutProperty();
234 CHECK_NULL_VOID(navBarLayoutProperty);
235 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(hostNode->GetToolBarNode());
236 CHECK_NULL_VOID(toolBarNode);
237 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetToolBarDividerNode());
238 UpdateToolBarAndDividerProperty(navBarLayoutProperty, hide, hostNode);
239 UpdateToolBarAndDividerTranslateAndOpacity(hide, toolBarNode, GetToolBarHeight(),
240 toolBarDividerNode, GetToolBarDividerHeight());
241 toolBarNode->MarkModifyDone();
242 toolBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
243 }
244
BarAnimationPropertyCallback(bool needRunTitleBarAnimation,bool hideTitle,bool needRunToolBarAnimation,bool hideTool)245 void NavDestinationPatternBase::BarAnimationPropertyCallback(
246 bool needRunTitleBarAnimation, bool hideTitle, bool needRunToolBarAnimation, bool hideTool)
247 {
248 auto node = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
249 CHECK_NULL_VOID(node);
250 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
251 CHECK_NULL_VOID(property);
252 auto context = node->GetContext();
253 CHECK_NULL_VOID(context);
254 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(node->GetTitleBarNode());
255 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(node->GetToolBarNode());
256 auto toolBarDividerNode = AceType::DynamicCast<FrameNode>(node->GetToolBarDividerNode());
257 if (needRunTitleBarAnimation && titleBarNode) {
258 property->UpdateTitleBarTranslateState(hideTitle ?
259 BarTranslateState::TRANSLATE_HEIGHT : BarTranslateState::TRANSLATE_ZERO);
260 }
261 if (needRunToolBarAnimation && toolBarNode) {
262 property->UpdateToolBarTranslateState(hideTool ?
263 BarTranslateState::TRANSLATE_HEIGHT : BarTranslateState::TRANSLATE_ZERO);
264 }
265 node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
266 context->FlushUITasks();
267 if (needRunTitleBarAnimation && titleBarNode) {
268 UpdateTitleBarTranslateAndOpacity(hideTitle, titleBarNode, GetTitleBarHeight());
269 }
270 if (needRunToolBarAnimation && toolBarNode) {
271 UpdateToolBarAndDividerTranslateAndOpacity(hideTool, toolBarNode, GetToolBarHeight(),
272 toolBarDividerNode, GetToolBarDividerHeight());
273 }
274 }
275
BarAnimationFinishCallback(bool needRunTitleBarAnimation,bool needRunToolBarAnimation,int32_t animationId)276 void NavDestinationPatternBase::BarAnimationFinishCallback(
277 bool needRunTitleBarAnimation, bool needRunToolBarAnimation, int32_t animationId)
278 {
279 if (needRunTitleBarAnimation) {
280 OnTitleBarAnimationFinish();
281 }
282 if (needRunToolBarAnimation) {
283 OnToolBarAnimationFinish();
284 }
285 RemoveAnimation(animationId);
286 }
287
StartAnimation(bool needRunTitleBarAnimation,bool hideTitle,bool needRunToolBarAnimation,bool hideTool)288 void NavDestinationPatternBase::StartAnimation(
289 bool needRunTitleBarAnimation, bool hideTitle, bool needRunToolBarAnimation, bool hideTool)
290 {
291 auto propertyCallback = [needRunTitleBarAnimation, hideTitle, needRunToolBarAnimation, hideTool,
292 weakPattern = AceType::WeakClaim(this)]() {
293 auto pattern = weakPattern.Upgrade();
294 CHECK_NULL_VOID(pattern);
295 pattern->BarAnimationPropertyCallback(needRunTitleBarAnimation, hideTitle, needRunToolBarAnimation, hideTool);
296 };
297 auto finishCallback = [needRunTitleBarAnimation, needRunToolBarAnimation,
298 weakPattern = AceType::WeakClaim(this), animationId = nextBarAnimationId_]() {
299 auto pattern = weakPattern.Upgrade();
300 CHECK_NULL_VOID(pattern);
301 pattern->BarAnimationFinishCallback(needRunTitleBarAnimation, needRunToolBarAnimation, animationId);
302 };
303
304 AnimationOption option;
305 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
306 option.SetDuration(DEFAULT_ANIMATION_DURATION);
307 if (needRunTitleBarAnimation) {
308 OnTitleBarAnimationStart();
309 }
310 if (needRunToolBarAnimation) {
311 OnToolBarAnimationStart();
312 }
313 auto animation = AnimationUtils::StartAnimation(option, propertyCallback, finishCallback);
314 barAnimations_.emplace(nextBarAnimationId_, animation);
315 nextBarAnimationId_++;
316 }
317
OnTitleBarAnimationFinish()318 void NavDestinationPatternBase::OnTitleBarAnimationFinish()
319 {
320 titleBarAnimationCount_--;
321 if (titleBarAnimationCount_ > 0) {
322 return;
323 }
324
325 auto node = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
326 CHECK_NULL_VOID(node);
327 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
328 CHECK_NULL_VOID(property);
329 property->ResetTitleBarTranslateState();
330 HideOrShowTitleBarImmediately(node, property->GetHideTitleBarValue(false));
331 }
332
OnToolBarAnimationFinish()333 void NavDestinationPatternBase::OnToolBarAnimationFinish()
334 {
335 toolBarAnimationCount_--;
336 if (toolBarAnimationCount_ > 0) {
337 return;
338 }
339
340 auto node = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
341 CHECK_NULL_VOID(node);
342 auto property = node->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
343 CHECK_NULL_VOID(property);
344 property->ResetToolBarTranslateState();
345 HideOrShowToolBarImmediately(node, property->GetHideToolBarValue(false));
346 }
347
AbortBarAnimation()348 void NavDestinationPatternBase::AbortBarAnimation()
349 {
350 for (const auto& pair : barAnimations_) {
351 if (pair.second) {
352 AnimationUtils::StopAnimation(pair.second);
353 }
354 }
355 barAnimations_.clear();
356 }
357
RemoveAnimation(int32_t id)358 void NavDestinationPatternBase::RemoveAnimation(int32_t id)
359 {
360 auto it = barAnimations_.find(id);
361 if (it != barAnimations_.end()) {
362 barAnimations_.erase(it);
363 }
364 }
365
UpdateHideBarProperty()366 void NavDestinationPatternBase::UpdateHideBarProperty()
367 {
368 auto hostNode = GetHost();
369 CHECK_NULL_VOID(hostNode);
370 auto layoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
371 CHECK_NULL_VOID(layoutProperty);
372 /**
373 * Mark need update safeAreaPadding when usr-set visibility of safe-area-padding-mode titleBar changed.
374 * The same goes for toolBar.
375 */
376 if ((titleBarStyle_.value_or(BarStyle::STANDARD) == BarStyle::SAFE_AREA_PADDING &&
377 isHideTitlebar_ != layoutProperty->GetHideTitleBarValue(false)) ||
378 (toolBarStyle_.value_or(BarStyle::STANDARD) == BarStyle::SAFE_AREA_PADDING &&
379 isHideToolbar_ != layoutProperty->GetHideToolBarValue(false))) {
380 safeAreaPaddingChanged_ = true;
381 }
382 isHideToolbar_ = layoutProperty->GetHideToolBarValue(false);
383 isHideTitlebar_ = layoutProperty->GetHideTitleBarValue(false);
384 }
385
ExpandContentSafeAreaIfNeeded()386 void NavDestinationPatternBase::ExpandContentSafeAreaIfNeeded()
387 {
388 auto hostNode = DynamicCast<NavDestinationNodeBase>(GetHost());
389 CHECK_NULL_VOID(hostNode);
390 auto layoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
391 CHECK_NULL_VOID(layoutProperty);
392 auto&& opts = layoutProperty->GetSafeAreaExpandOpts();
393 auto contentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
394 if (opts && contentNode) {
395 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s SafeArea expand as %{public}s",
396 hostNode->GetTag().c_str(), opts->ToString().c_str());
397 contentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(*opts);
398 contentNode->MarkModifyDone();
399 }
400 }
401
MarkSafeAreaPaddingChangedWithCheckTitleBar(float titleBarHeight)402 void NavDestinationPatternBase::MarkSafeAreaPaddingChangedWithCheckTitleBar(float titleBarHeight)
403 {
404 auto hostNode = DynamicCast<NavDestinationNodeBase>(GetHost());
405 CHECK_NULL_VOID(hostNode);
406 if (titleBarStyle_.value_or(BarStyle::STANDARD) != BarStyle::SAFE_AREA_PADDING) {
407 return;
408 }
409 /**
410 * Mark need update safeAreaPadding when the height of safe-area-padding-title changed.
411 * For example, when titleMode of navigation changed or when free-mode-title is dragged.
412 */
413 if (!NearEqual(titleBarHeight, titleBarHeight_)) {
414 safeAreaPaddingChanged_ = true;
415 return;
416 }
417 /**
418 * Mark need update safeAreaPadding when titleBar onHover mode updated.
419 */
420 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
421 if (titleBarNode && NavigationTitleUtil::CalculateTitlebarOffset(titleBarNode) != titleBarOffsetY_) {
422 safeAreaPaddingChanged_ = true;
423 }
424 }
425 } // namespace OHOS::Ace::NG