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_layout_algorithm.h"
17
18 #include "core/components_ng/pattern/navigation/navigation_layout_util.h"
19 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
20 #include "core/components_ng/property/measure_utils.h"
21
22 namespace OHOS::Ace::NG {
23
24 constexpr static float HALF = 0.5f;
25 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
26 constexpr Dimension WINDOW_WIDTH = 520.0_vp;
27
28 namespace {
29 constexpr NavigationMode INITIAL_MODE = NavigationMode::AUTO;
30 constexpr int32_t MODE_SWITCH_ANIMATION_DURATION = 500; // ms
31 const RefPtr<CubicCurve> MODE_SWITCH_CURVE = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.2f, 0.1f, 1.0f);
32 constexpr Dimension DIVIDER_DRAG_BAR_WIDTH = 12.0_vp;
33 constexpr Dimension DIVIDER_DRAG_BAR_HEIGHT = 48.0_vp;
34 constexpr Dimension DRAG_BAR_ITEM_WIDTH = 2.0_vp;
35 constexpr Dimension DRAG_BAR_ITEM_HEIGHT = 24.0_vp;
36
IsNavBarVisible(const RefPtr<NavigationGroupNode> & navigation)37 bool IsNavBarVisible(const RefPtr<NavigationGroupNode>& navigation)
38 {
39 CHECK_NULL_RETURN(navigation, false);
40 auto navBar = AceType::DynamicCast<FrameNode>(navigation->GetNavBarNode());
41 CHECK_NULL_RETURN(navBar, false);
42 auto navBarProperty = navBar->GetLayoutProperty();
43 CHECK_NULL_RETURN(navBarProperty, false);
44 return navBarProperty->GetVisibilityValue(VisibleType::INVISIBLE) == VisibleType::VISIBLE;
45 }
46
MeasureDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)47 void MeasureDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
48 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
49 {
50 auto dividerNode = hostNode->GetDividerNode();
51 CHECK_NULL_VOID(dividerNode);
52 auto index = hostNode->GetChildIndexById(dividerNode->GetId());
53 auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
54 CHECK_NULL_VOID(dividerWrapper);
55 auto constraint = navigationLayoutProperty->CreateChildConstraint();
56 constraint.selfIdealSize = OptionalSizeF(dividerSize.Width(), dividerSize.Height());
57 dividerWrapper->Measure(constraint);
58 }
59
MeasureSplitPlaceholder(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & splitPlaceholderSize)60 void MeasureSplitPlaceholder(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
61 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& splitPlaceholderSize)
62 {
63 auto splitPlaceholder = hostNode->GetPlaceholderContentNode();
64 CHECK_NULL_VOID(splitPlaceholder);
65 auto index = hostNode->GetChildIndexById(splitPlaceholder->GetId());
66 auto splitPlaceholderWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
67 CHECK_NULL_VOID(splitPlaceholderWrapper);
68 auto constraint = navigationLayoutProperty->CreateChildConstraint();
69 auto placeholderLayoutProperty = AceType::DynamicCast<FrameNode>(splitPlaceholder)->GetLayoutProperty();
70 CHECK_NULL_VOID(placeholderLayoutProperty);
71 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
72 CHECK_NULL_VOID(navigationPattern);
73 auto navigationStack = navigationPattern->GetNavigationStack();
74 CHECK_NULL_VOID(navigationStack);
75 bool isHideNavBar = navigationLayoutProperty->GetHideNavBar().value_or(false);
76 // cases that require measure of placeholder content
77 // 1. navigation stack is empty
78 // 2. navigation mode is SPLIT
79 // 3. navBar is not hidden
80 if (navigationStack->Empty() && navigationPattern->GetNavigationMode() == NavigationMode::SPLIT && !isHideNavBar) {
81 placeholderLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
82 if (NavigationLayoutAlgorithm::IsAutoHeight(navigationLayoutProperty)) {
83 constraint.selfIdealSize.SetWidth(splitPlaceholderSize.Width());
84 } else {
85 constraint.selfIdealSize = OptionalSizeF(splitPlaceholderSize.Width(), splitPlaceholderSize.Height());
86 }
87 } else {
88 placeholderLayoutProperty->UpdateVisibility(VisibleType::GONE);
89 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
90 }
91 splitPlaceholderWrapper->Measure(constraint);
92 }
93
MeasureDragBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)94 void MeasureDragBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
95 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
96 {
97 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
98 CHECK_NULL_VOID(navigationPattern);
99 auto dragNode = hostNode->GetDragBarNode();
100 CHECK_NULL_VOID(dragNode);
101 auto index = hostNode->GetChildIndexById(dragNode->GetId());
102 auto dargWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
103 CHECK_NULL_VOID(dargWrapper);
104 auto dragBarItem = AceType::DynamicCast<FrameNode>(dragNode->GetChildAtIndex(0));
105 CHECK_NULL_VOID(dragBarItem);
106 auto dragBarItemLayoutProperty = dragBarItem->GetLayoutProperty();
107 CHECK_NULL_VOID(dragBarItemLayoutProperty);
108 auto constraint = navigationLayoutProperty->CreateChildConstraint();
109 if (NearZero(dividerSize.Width()) || !navigationPattern->GetEnableDragBar()) {
110 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
111 dragBarItemLayoutProperty->UpdateUserDefinedIdealSize(
112 CalcSize(CalcLength(0.0f), CalcLength(0.0f)));
113 } else {
114 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(DIVIDER_DRAG_BAR_WIDTH.ConvertToPx()),
115 static_cast<float>(DIVIDER_DRAG_BAR_HEIGHT.ConvertToPx()));
116 dragBarItemLayoutProperty->UpdateUserDefinedIdealSize(
117 CalcSize(CalcLength(DRAG_BAR_ITEM_WIDTH), CalcLength(DRAG_BAR_ITEM_HEIGHT)));
118 }
119 dargWrapper->Measure(constraint);
120 }
121
LayoutDragBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)122 void LayoutDragBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
123 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
124 {
125 auto dargNode = hostNode->GetDragBarNode();
126 CHECK_NULL_VOID(dargNode);
127 auto index = hostNode->GetChildIndexById(dargNode->GetId());
128 auto dargWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
129 CHECK_NULL_VOID(dargWrapper);
130 auto geometryNode = dargWrapper->GetGeometryNode();
131 CHECK_NULL_VOID(geometryNode);
132 auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
133 CHECK_NULL_VOID(navigationGeometryNode);
134 auto navigationWidth = navigationGeometryNode->GetFrameSize().Width();
135 auto navigationHeight = navigationGeometryNode->GetFrameSize().Height();
136 auto offsetX = navBarWidth - geometryNode->GetFrameSize().Width() * HALF;
137 auto offsetY = navigationHeight * HALF - geometryNode->GetFrameSize().Height() * HALF;
138 OffsetT<float> dragOffset = OffsetT<float>(offsetX, offsetY);
139 bool isNavBarInRight = (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
140 (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
141 if (isNavBarInRight) {
142 dragOffset.SetX(navigationWidth - navBarWidth - geometryNode->GetFrameSize().Width() * HALF);
143 }
144 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
145 dragOffset.AddX(padding.left.value_or(0.0f));
146 dragOffset.AddY(padding.top.value_or(0.0f));
147 geometryNode->SetMarginFrameOffset(dragOffset);
148 dargWrapper->Layout();
149 }
150
LayoutPrimaryContentNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)151 float LayoutPrimaryContentNode(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
152 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
153 {
154 CHECK_NULL_RETURN(hostNode, 0.0f);
155 auto primaryContentNode = hostNode->GetPrimaryContentNode();
156 CHECK_NULL_RETURN(primaryContentNode, 0.0f);
157 auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
158 bool isNavBarInRight = AceApplicationInfo::GetInstance().IsRightToLeft();
159 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
160 auto index = hostNode->GetChildIndexById(primaryContentNode->GetId());
161 auto nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
162 CHECK_NULL_RETURN(nodeWrapper, 0.0f);
163 auto geometryNode = nodeWrapper->GetGeometryNode();
164 auto nodeOffset = OffsetT<float>(0.0f, 0.0f);
165 if (isNavBarInRight) {
166 nodeOffset.SetX(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width());
167 }
168 nodeOffset.AddX(padding.left.value_or(0.0f));
169 nodeOffset.AddY(padding.top.value_or(0.0f));
170 geometryNode->SetMarginFrameOffset(nodeOffset);
171 nodeWrapper->Layout();
172 return geometryNode->GetFrameSize().Width();
173 }
174
LayoutNavBarOrHomeDestination(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,NavBarPosition position,OffsetF & returnNavBarOffset)175 float LayoutNavBarOrHomeDestination(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
176 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, NavBarPosition position,
177 OffsetF& returnNavBarOffset)
178 {
179 CHECK_NULL_RETURN(hostNode, 0.0f);
180 auto navigationPattern = hostNode->GetPattern<NavigationPattern>();
181 CHECK_NULL_RETURN(navigationPattern, 0.0f);
182 auto targetNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
183 CHECK_NULL_RETURN(targetNode, 0.0f);
184 auto contentNode = hostNode->GetContentNode();
185 CHECK_NULL_RETURN(contentNode, 0.0f);
186 auto index = hostNode->GetChildIndexById(targetNode->GetId());
187 auto targetNodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
188 CHECK_NULL_RETURN(targetNodeWrapper, 0.0f);
189 auto geometryNode = targetNodeWrapper->GetGeometryNode();
190 auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
191 auto navBarOffset = OffsetT<float>(0.0f, 0.0f);
192 bool isNavBarInRight = (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
193 (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
194 bool isHideNavBar = navigationLayoutProperty->GetHideNavBar().value_or(false);
195 NavigationMode navigationMode = navigationPattern->GetNavigationMode();
196 if (isNavBarInRight && !isHideNavBar && navigationMode == NavigationMode::SPLIT) {
197 // only in SPLIT mode can navBar show on the left or right side of navigation, otherwise it is centered.
198 navBarOffset.SetX(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width());
199 }
200 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
201 navBarOffset.AddX(padding.left.value_or(0.0f));
202 navBarOffset.AddY(padding.top.value_or(0.0f));
203 geometryNode->SetMarginFrameOffset(navBarOffset);
204 targetNodeWrapper->Layout();
205 returnNavBarOffset = navBarOffset;
206 return isHideNavBar && navigationMode == NavigationMode::SPLIT ? 0.0f : geometryNode->GetFrameSize().Width();
207 }
208
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)209 float LayoutDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
210 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
211 {
212 auto dividerNode = hostNode->GetDividerNode();
213 CHECK_NULL_RETURN(dividerNode, 0.0f);
214 auto index = hostNode->GetChildIndexById(dividerNode->GetId());
215 auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
216 CHECK_NULL_RETURN(dividerWrapper, 0.0f);
217 auto geometryNode = dividerWrapper->GetGeometryNode();
218 auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
219 auto dividerOffsetX = navBarWidth;
220 if (position == NavBarPosition::END) {
221 dividerOffsetX =
222 navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - dividerOffsetX;
223 }
224 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
225 dividerOffsetX =
226 navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - dividerOffsetX;
227 }
228 OffsetT<float> dividerOffset = OffsetT<float>(dividerOffsetX, 0.0f);
229 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
230 dividerOffset.AddX(padding.left.value_or(0));
231 dividerOffset.AddY(padding.top.value_or(0));
232 geometryNode->SetMarginFrameOffset(dividerOffset);
233 dividerWrapper->Layout();
234 return geometryNode->GetFrameSize().Width();
235 }
236
LayoutContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth,const NavBarPosition & position)237 void LayoutContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
238 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth,
239 const NavBarPosition& position)
240 {
241 auto pattern = hostNode->GetPattern<NavigationPattern>();
242 CHECK_NULL_VOID(pattern);
243 auto contentNode = hostNode->GetContentNode();
244 CHECK_NULL_VOID(contentNode);
245 auto index = hostNode->GetChildIndexById(contentNode->GetId());
246 auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
247 CHECK_NULL_VOID(contentWrapper);
248 auto geometryNode = contentWrapper->GetGeometryNode();
249 CHECK_NULL_VOID(geometryNode);
250
251 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
252 auto contentChildSize = contentNode->GetChildren().size();
253
254 if (pattern->IsForceSplitSuccess()) {
255 auto contentOffset = OffsetT<float>(0.0f, 0.0f);
256 if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
257 contentOffset = OffsetF(navBarWidth + dividerWidth, 0.0f);
258 }
259 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
260 contentOffset.AddX(padding.left.value_or(0));
261 contentOffset.AddY(padding.top.value_or(0));
262 geometryNode->SetMarginFrameOffset(contentOffset);
263 contentWrapper->Layout();
264 return;
265 }
266
267 // cases that content layouts from start
268 // 1. displaying content pages in STACK mode
269 // 2. placing navBar at the end
270 // 3. hiding navBar in SPLIT mode
271 auto contentOffset = OffsetT<float>(0.0f, 0.0f);
272 if ((contentChildSize != 0 && navigationPattern->GetNavigationMode() == NavigationMode::STACK) ||
273 position == NavBarPosition::END ||
274 (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
275 navigationPattern->GetNavigationMode() == NavigationMode::SPLIT)) {
276 if (AceApplicationInfo::GetInstance().IsRightToLeft() &&
277 navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
278 contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
279 }
280 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
281 contentOffset.AddX(padding.left.value_or(0));
282 contentOffset.AddY(padding.top.value_or(0));
283 geometryNode->SetMarginFrameOffset(contentOffset);
284 contentWrapper->Layout();
285 return;
286 }
287 if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
288 contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
289 }
290 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
291 contentOffset.AddX(padding.left.value_or(0));
292 contentOffset.AddY(padding.top.value_or(0));
293 geometryNode->SetMarginFrameOffset(contentOffset);
294 contentWrapper->Layout();
295 }
296
LayoutSplitPalceholderContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float splitPlaceholderOffsetX,const NavBarPosition & position)297 void LayoutSplitPalceholderContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
298 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float splitPlaceholderOffsetX,
299 const NavBarPosition& position)
300 {
301 CHECK_NULL_VOID(hostNode);
302 auto splitPlaceholder = hostNode->GetPlaceholderContentNode();
303 CHECK_NULL_VOID(splitPlaceholder);
304 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
305 auto navigationStack = navigationPattern->GetNavigationStack();
306 CHECK_NULL_VOID(navigationStack);
307 bool isHideNavBar = navigationLayoutProperty->GetHideNavBar().value_or(false);
308 // cases that require layout of placeholder content
309 // 1. navigation stack is empty
310 // 2. navigation mode is SPLIT
311 // 3. navBar is not hidden
312 if (navigationStack->Empty() && navigationPattern->GetNavigationMode() == NavigationMode::SPLIT && !isHideNavBar) {
313 bool isNavBarInRight =
314 (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
315 (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
316 auto index = hostNode->GetChildIndexById(splitPlaceholder->GetId());
317 auto splitPlaceholderWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
318 CHECK_NULL_VOID(splitPlaceholderWrapper);
319 auto splitPlaceholderGeometryNode = splitPlaceholderWrapper->GetGeometryNode();
320 CHECK_NULL_VOID(splitPlaceholderGeometryNode);
321 if (isNavBarInRight) {
322 splitPlaceholderOffsetX = 0.0f;
323 }
324 auto splitPlaceholderOffset = OffsetT<float>(splitPlaceholderOffsetX, 0.0f);
325 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
326 splitPlaceholderOffset.AddX(padding.left.value_or(0));
327 splitPlaceholderOffset.AddY(padding.top.value_or(0));
328 splitPlaceholderGeometryNode->SetMarginFrameOffset(splitPlaceholderOffset);
329 splitPlaceholderWrapper->Layout();
330 }
331 }
332
FitScrollFullWindow(SizeF & frameSize)333 void FitScrollFullWindow(SizeF& frameSize)
334 {
335 auto pipeline = PipelineContext::GetCurrentContext();
336 CHECK_NULL_VOID(pipeline);
337 if (frameSize.Width() == Infinity<float>()) {
338 frameSize.SetWidth(pipeline->GetRootWidth());
339 }
340 if (frameSize.Height() == Infinity<float>()) {
341 frameSize.SetHeight(pipeline->GetRootHeight());
342 }
343 }
344
SwitchModeWithAnimation(const RefPtr<NavigationGroupNode> & hostNode)345 void SwitchModeWithAnimation(const RefPtr<NavigationGroupNode>& hostNode)
346 {
347 CHECK_NULL_VOID(hostNode);
348 hostNode->SetDoingModeSwitchAnimationFlag(true);
349 hostNode->SetNeedSetInvisible(false);
350 AnimationOption option;
351 option.SetCurve(MODE_SWITCH_CURVE);
352 option.SetFillMode(FillMode::FORWARDS);
353 option.SetDuration(MODE_SWITCH_ANIMATION_DURATION);
354 option.SetOnFinishEvent([weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
355 auto hostNode = weakHost.Upgrade();
356 CHECK_NULL_VOID(hostNode);
357 hostNode->ReduceModeSwitchAnimationCnt();
358 if (hostNode->GetModeSwitchAnimationCnt() == 0) {
359 auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
360 CHECK_NULL_VOID(dividerNode);
361 auto layoutProperty = dividerNode->GetLayoutProperty();
362 CHECK_NULL_VOID(layoutProperty);
363 layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
364 auto pattern = hostNode->GetPattern<NavigationPattern>();
365 CHECK_NULL_VOID(pattern);
366 auto lastStandardIndex = hostNode->GetLastStandardIndex();
367 auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
368 CHECK_NULL_VOID(navigationLayoutProperty);
369 bool navbarIsHidden = (pattern->GetNavigationMode() == NavigationMode::STACK && lastStandardIndex >= 0) ||
370 navigationLayoutProperty->GetHideNavBar().value_or(false);
371 hostNode->SetNeedSetInvisible(navbarIsHidden);
372 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
373 }
374 });
375 AnimationUtils::Animate(option, [weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
376 auto hostNode = weakHost.Upgrade();
377 CHECK_NULL_VOID(hostNode);
378 auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
379 CHECK_NULL_VOID(dividerNode);
380 auto layoutProperty = dividerNode->GetLayoutProperty();
381 CHECK_NULL_VOID(layoutProperty);
382 layoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
383 hostNode->IncreaseModeSwitchAnimationCnt();
384 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
385 hostNode->GetContext()->FlushUITasks();
386 hostNode->SetDoingModeSwitchAnimationFlag(false);
387 }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, hostNode->GetContextRefPtr());
388 }
389
390 } // namespace
391
LayoutForceSplitPlaceHolderNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth)392 void NavigationLayoutAlgorithm::LayoutForceSplitPlaceHolderNode(
393 LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
394 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth)
395 {
396 auto phNode = AceType::DynamicCast<FrameNode>(hostNode->GetForceSplitPlaceHolderNode());
397 CHECK_NULL_VOID(phNode);
398 auto index = hostNode->GetChildIndexById(phNode->GetId());
399 auto phWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
400 CHECK_NULL_VOID(phWrapper);
401 auto geometryNode = phWrapper->GetGeometryNode();
402 CHECK_NULL_VOID(geometryNode);
403 auto phOffset = OffsetT<float>(0.0f, 0.0f);
404 if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
405 phOffset = OffsetF(navBarWidth + dividerWidth, 0.0f);
406 }
407 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
408 phOffset.AddX(padding.left.value_or(0));
409 phOffset.AddY(padding.top.value_or(0));
410 geometryNode->SetMarginFrameOffset(phOffset);
411 phWrapper->Layout();
412 }
413
IsAutoHeight(const RefPtr<LayoutProperty> & layoutProperty)414 bool NavigationLayoutAlgorithm::IsAutoHeight(const RefPtr<LayoutProperty>& layoutProperty)
415 {
416 CHECK_NULL_RETURN(layoutProperty, false);
417 auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
418 if (!calcLayoutConstraint || !calcLayoutConstraint->selfIdealSize.has_value() ||
419 !calcLayoutConstraint->selfIdealSize->Height().has_value() ||
420 (calcLayoutConstraint->selfIdealSize->Height().value().ToString().find("auto") == std::string::npos)) {
421 return false;
422 }
423 return true;
424 }
425
RangeCalculation(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)426 void NavigationLayoutAlgorithm::RangeCalculation(
427 const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
428 {
429 const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
430 CHECK_NULL_VOID(constraint);
431 auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
432 auto frameSize = parentSize.ConvertToSizeT();
433 float frameSizeWidth = frameSize.Width();
434 Dimension defaultValue = Dimension(-1.0);
435 auto pipeline = PipelineContext::GetCurrentContext();
436 CHECK_NULL_VOID(pipeline);
437
438 minContentWidthValue_ = navigationLayoutProperty->GetMinContentWidthValue(defaultValue);
439 if (minContentWidthValue_ == defaultValue) {
440 userSetMinContentFlag_ = false;
441 minContentWidthValue_ = DEFAULT_MIN_CONTENT_WIDTH;
442 } else {
443 userSetMinContentFlag_ = true;
444 }
445 minNavBarWidthValue_ = navigationLayoutProperty->GetMinNavBarWidthValue(DEFAULT_MIN_NAV_BAR_WIDTH);
446 auto userSetMaxNavBarWidthValue = navigationLayoutProperty->GetMaxNavBarWidthValue(defaultValue);
447
448 float minNavBarWidth =
449 std::min(static_cast<float>(minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f))),
450 frameSizeWidth);
451 float maxNavBarWidth = 0.0f;
452 if (userSetMaxNavBarWidthValue == defaultValue) {
453 userSetNavBarRangeFlag_ = false;
454 maxNavBarWidth = std::min(
455 static_cast<float>(DEFAULT_MAX_NAV_BAR_WIDTH.ConvertToPx()), frameSizeWidth * MAX_NAV_BAR_WIDTH_SCALE);
456 } else {
457 userSetNavBarRangeFlag_ = true;
458 maxNavBarWidth =
459 static_cast<float>(userSetMaxNavBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f)));
460 }
461 maxNavBarWidthValue_ = Dimension(Dimension(std::max(maxNavBarWidth, minNavBarWidth)).ConvertToVp(),
462 DimensionUnit::VP);
463 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
464 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
465 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
466 auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
467 realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
468 realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
469 }
470 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
471 CHECK_NULL_VOID(navigationPattern);
472 navigationPattern->SetMinNavBarWidthValue(minNavBarWidthValue_);
473 navigationPattern->SetMaxNavBarWidthValue(maxNavBarWidthValue_);
474 navigationPattern->SetMinContentWidthValue(minContentWidthValue_);
475 navigationPattern->SetUserSetNavBarRangeFlag(userSetNavBarRangeFlag_);
476 navigationPattern->SetUserSetMinContentFlag(userSetMinContentFlag_);
477 }
478
GetRange(const RefPtr<NavigationGroupNode> & hostNode)479 void NavigationLayoutAlgorithm::GetRange(const RefPtr<NavigationGroupNode>& hostNode)
480 {
481 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
482 CHECK_NULL_VOID(navigationPattern);
483 minNavBarWidthValue_ = navigationPattern->GetMinNavBarWidthValue();
484 maxNavBarWidthValue_ = navigationPattern->GetMaxNavBarWidthValue();
485 minContentWidthValue_ = navigationPattern->GetMinContentWidthValue();
486 userSetNavBarRangeFlag_ = navigationPattern->GetUserSetNavBarRangeFlag();
487 userSetMinContentFlag_ = navigationPattern->GetUserSetMinContentFlag();
488 userSetNavBarWidthFlag_ = navigationPattern->GetUserSetNavBarWidthFlag();
489 }
490
CalculateNavigationWidth(const RefPtr<NavigationGroupNode> & hostNode)491 float NavigationLayoutAlgorithm::CalculateNavigationWidth(const RefPtr<NavigationGroupNode>& hostNode)
492 {
493 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
494 auto pipeline = hostNode->GetContext();
495 CHECK_NULL_RETURN(pipeline, 0.0f);
496 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
497 auto navigationWidth = 0.0f;
498 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
499 CHECK_NULL_RETURN(navigationLayoutProperty, navigationWidth);
500 const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
501 auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
502 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
503 navigationWidth = static_cast<float>(minNavBarWidth + minContentWidthValue_.ConvertToPx());
504 } else {
505 navigationWidth = static_cast<float>(WINDOW_WIDTH.ConvertToPx());
506 }
507 return navigationWidth;
508 }
509
UpdateNavigationMode(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize,const RefPtr<NavigationGroupNode> & hostNode)510 void NavigationLayoutAlgorithm::UpdateNavigationMode(const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
511 const SizeF& frameSize, const RefPtr<NavigationGroupNode>& hostNode)
512 {
513 CHECK_NULL_VOID(hostNode);
514 CHECK_NULL_VOID(navigationLayoutProperty);
515 auto usrNavigationMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
516 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
517 CHECK_NULL_VOID(navigationPattern);
518 if (navigationPattern->IsForceSplitSuccess()) {
519 usrNavigationMode = NavigationMode::SPLIT;
520 }
521 if (usrNavigationMode == NavigationMode::AUTO) {
522 if (frameSize.Width() >= CalculateNavigationWidth(hostNode)) {
523 usrNavigationMode = NavigationMode::SPLIT;
524 auto targetNode = hostNode->GetNavBarOrHomeDestinationNode();
525 if (targetNode) {
526 targetNode->SetJSViewActive(true);
527 }
528 } else {
529 usrNavigationMode = NavigationMode::STACK;
530 }
531 }
532 bool modeChange = navigationPattern->GetNavigationMode() != usrNavigationMode;
533 bool isFirstTimeLayout = (navigationPattern->GetNavigationMode() == INITIAL_MODE);
534 bool enableModeChangeAnimation = navigationLayoutProperty->GetEnableModeChangeAnimation().value_or(true);
535 bool doModeSwitchAnimationInAnotherTask =
536 enableModeChangeAnimation && modeChange && !isFirstTimeLayout && !hostNode->IsOnModeSwitchAnimation();
537 if (doModeSwitchAnimationInAnotherTask) {
538 auto container = Container::Current();
539 CHECK_NULL_VOID(container);
540 if (container->IsFoldable()) {
541 // If screen-fold-state changed, no need to do mode switch animation.
542 // Only when navigation-mode changed, it is necessary to update the current screen-fold-state.
543 doModeSwitchAnimationInAnotherTask =
544 !navigationPattern->JudgeFoldStateChangeAndUpdateState() && doModeSwitchAnimationInAnotherTask;
545 }
546 }
547 if (!doModeSwitchAnimationInAnotherTask) {
548 navigationPattern->SetNavigationMode(usrNavigationMode);
549 navigationPattern->SetNavigationModeChange(modeChange);
550 }
551
552 auto pipeline = hostNode->GetContext();
553 CHECK_NULL_VOID(pipeline);
554 pipeline->AddAfterLayoutTask([weakNavigationPattern = WeakPtr<NavigationPattern>(navigationPattern),
555 modeChange, doModeSwitchAnimationInAnotherTask]() {
556 auto navigationPattern = weakNavigationPattern.Upgrade();
557 CHECK_NULL_VOID(navigationPattern);
558 if (doModeSwitchAnimationInAnotherTask) {
559 navigationPattern->OnNavBarStateChange(false);
560 SwitchModeWithAnimation(AceType::DynamicCast<NavigationGroupNode>(navigationPattern->GetHost()));
561 } else {
562 if (navigationPattern->IsHomeDestinationVisible()) {
563 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_SHOW, true);
564 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_ACTIVE, true);
565 } else {
566 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_INACTIVE, true);
567 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_HIDE, true);
568 }
569 navigationPattern->OnNavBarStateChange(modeChange);
570 navigationPattern->OnNavigationModeChange(modeChange);
571 }
572 });
573 }
574
SizeCalculationForForceSplit(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)575 void NavigationLayoutAlgorithm::SizeCalculationForForceSplit(
576 LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
577 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
578 {
579 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
580 dividerSize_ = SizeF(dividerWidth, frameSize.Height());
581 auto halfWidth = (frameSize.Width() - dividerWidth) / 2.0f;
582 navBarSize_ = SizeF(halfWidth, frameSize.Height());
583 primaryNodeSize_ = SizeF(halfWidth, frameSize.Height());
584 contentSize_ = SizeF(halfWidth, frameSize.Height());
585 realNavBarWidth_ = halfWidth;
586 realContentWidth_ = halfWidth;
587 realDividerWidth_ = halfWidth;
588 }
589
SizeCalculation(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)590 void NavigationLayoutAlgorithm::SizeCalculation(LayoutWrapper* layoutWrapper,
591 const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
592 const SizeF& frameSize)
593 {
594 auto pipeline = PipelineContext::GetCurrentContext();
595 CHECK_NULL_VOID(pipeline);
596 auto constraint = navigationLayoutProperty->GetLayoutConstraint();
597 auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
598 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
599 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
600 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
601 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
602 auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
603 realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
604 realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
605 } else {
606 auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
607 auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
608 realNavBarWidth_ = navBarWidth;
609 }
610 navBarSize_ = frameSize;
611 contentSize_ = frameSize;
612 dividerSize_ = SizeF(0.0f, frameSize.Height());
613 if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT ||
614 (navigationPattern->IsForceSplitSuccess() && navigationPattern->IsForceSplitUseNavBar())) {
615 SizeCalculationSplit(hostNode, navigationLayoutProperty, frameSize);
616 } else {
617 SizeCalculationStack(hostNode, navigationLayoutProperty, frameSize);
618 }
619 }
620
SizeCalculationSplit(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)621 void NavigationLayoutAlgorithm::SizeCalculationSplit(const RefPtr<NavigationGroupNode>& hostNode,
622 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
623 {
624 auto pattern = hostNode->GetPattern<NavigationPattern>();
625 CHECK_NULL_VOID(pattern);
626 float frameWidth = frameSize.Width();
627 auto parentSize = CreateIdealSizeByPercentRef(
628 navigationLayoutProperty->GetLayoutConstraint().value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
629 auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
630 auto userSetNavBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
631 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
632 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
633 auto minContentWidth = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
634 realContentWidth_ = minContentWidth;
635
636 bool isHideNavbar = navigationLayoutProperty->GetHideNavBar().value_or(false);
637 if (pattern->IsForceSplitSuccess() && pattern->IsForceSplitUseNavBar()) {
638 dividerSize_.SetWidth(dividerWidth);
639 auto halfWidth = (frameSize.Width() - dividerWidth) / 2.0f;
640 navBarSize_.SetWidth(halfWidth);
641 realNavBarWidth_ = halfWidth;
642 realContentWidth_ = halfWidth;
643 } else if (isHideNavbar) {
644 CHECK_NULL_VOID(hostNode);
645 auto targetNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
646 CHECK_NULL_VOID(targetNode);
647 auto geometryNode = targetNode->GetGeometryNode();
648 CHECK_NULL_VOID(geometryNode);
649 navBarSize_.SetWidth(geometryNode->GetFrameSize().Width());
650 dividerSize_.SetWidth(0.0f);
651 realNavBarWidth_ = 0.0f;
652 realContentWidth_ = frameWidth;
653 } else {
654 CheckSizeInSplit(frameWidth, userSetNavBarWidth, minNavBarWidth, minContentWidth);
655 }
656
657 realDividerWidth_ = std::max(realDividerWidth_, 0.0f);
658 realContentWidth_ = std::max(realContentWidth_, 0.0f);
659 realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
660 realContentWidth_ = std::min(realContentWidth_, frameWidth);
661 if (realNavBarWidth_ == 0.0f || realContentWidth_ == 0.0f) {
662 realDividerWidth_ = 0.0f;
663 } else {
664 realDividerWidth_ = dividerWidth;
665 }
666 if (!isHideNavbar) {
667 navBarSize_.SetWidth(realNavBarWidth_);
668 dividerSize_.SetWidth(realDividerWidth_);
669 }
670 contentSize_.SetWidth(realContentWidth_);
671 }
672
CheckSizeInSplit(const float frameWidth,const float userSetNavBarWidth,const float minNavBarWidth,const float minContentWidth)673 void NavigationLayoutAlgorithm::CheckSizeInSplit(
674 const float frameWidth, const float userSetNavBarWidth, const float minNavBarWidth, const float minContentWidth)
675 {
676 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
677
678 if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
679 if (minContentWidth >= frameWidth) {
680 realContentWidth_ = frameWidth;
681 realNavBarWidth_ = 0.0f;
682 } else if (realNavBarWidth_ + dividerWidth + minContentWidth <= frameWidth) {
683 realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
684 } else {
685 realContentWidth_ = minContentWidth;
686 realNavBarWidth_ = frameWidth - realContentWidth_ - dividerWidth;
687 }
688 } else if (!userSetNavBarRangeFlag_ && !userSetMinContentFlag_ && userSetNavBarWidthFlag_) {
689 realNavBarWidth_ = userSetNavBarWidth;
690 realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
691 } else {
692 float remainingSpace = frameWidth - realNavBarWidth_ - dividerWidth;
693 float remainingMaxSpace = frameWidth - minNavBarWidth - dividerWidth;
694 if (remainingSpace >= minContentWidth) {
695 realContentWidth_ = remainingSpace;
696 } else if (remainingSpace < minContentWidth && remainingMaxSpace > minContentWidth &&
697 realNavBarWidth_ > minNavBarWidth) {
698 realContentWidth_ = minContentWidth;
699 realNavBarWidth_ = frameWidth - minContentWidth - dividerWidth;
700 } else {
701 realNavBarWidth_ = minNavBarWidth;
702 realContentWidth_ = frameWidth - minNavBarWidth - dividerWidth;
703 }
704 }
705 }
706
SizeCalculationStack(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)707 void NavigationLayoutAlgorithm::SizeCalculationStack(const RefPtr<NavigationGroupNode>& hostNode,
708 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
709 {
710 auto contentNode = hostNode->GetContentNode();
711 CHECK_NULL_VOID(contentNode);
712 realDividerWidth_ = 0.0f;
713 float frameWidth = frameSize.Width();
714 navBarSize_.SetWidth(frameWidth);
715 dividerSize_.SetWidth(realDividerWidth_);
716 contentSize_.SetWidth(frameWidth);
717 realContentWidth_ = frameWidth;
718 }
719
MeasurePrimaryContentNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & primaryNodeSize)720 void NavigationLayoutAlgorithm::MeasurePrimaryContentNode(
721 LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
722 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& primaryNodeSize)
723 {
724 CHECK_NULL_VOID(hostNode);
725 auto primaryContentNode = hostNode->GetPrimaryContentNode();
726 CHECK_NULL_VOID(primaryContentNode);
727 auto constraint = navigationLayoutProperty->CreateChildConstraint();
728 bool isAutoHeight = IsAutoHeight(navigationLayoutProperty);
729 auto index = hostNode->GetChildIndexById(primaryContentNode->GetId());
730 auto nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
731 CHECK_NULL_VOID(nodeWrapper);
732 if (isAutoHeight) {
733 nodeWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
734 navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
735 constraint.selfIdealSize.SetWidth(primaryNodeSize.Width());
736 } else {
737 constraint.selfIdealSize = OptionalSizeF(primaryNodeSize.Width(), primaryNodeSize.Height());
738 }
739 nodeWrapper->Measure(constraint);
740 realNavBarHeight_ = nodeWrapper->GetGeometryNode()->GetFrameSize().Height();
741 }
742
MeasureNavBarOrHomeDestination(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & navBarSize)743 void NavigationLayoutAlgorithm::MeasureNavBarOrHomeDestination(
744 LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
745 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& navBarSize)
746 {
747 CHECK_NULL_VOID(hostNode);
748 auto targetNode = AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
749 CHECK_NULL_VOID(targetNode);
750 auto index = hostNode->GetChildIndexById(targetNode->GetId());
751 auto targetNodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
752 CHECK_NULL_VOID(targetNodeWrapper);
753 auto constraint = navigationLayoutProperty->CreateChildConstraint();
754 if (IsAutoHeight(navigationLayoutProperty)) {
755 targetNodeWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
756 navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
757 constraint.selfIdealSize.SetWidth(navBarSize.Width());
758 } else {
759 constraint.selfIdealSize = OptionalSizeF(navBarSize.Width(), navBarSize.Height());
760 }
761 auto adjustConstraint = targetNode->AdjustLayoutConstarintIfNeeded(constraint);
762 targetNodeWrapper->Measure(adjustConstraint);
763 realNavBarHeight_ = targetNodeWrapper->GetGeometryNode()->GetFrameSize().Height();
764 realNavBarWidth_ = targetNodeWrapper->GetGeometryNode()->GetFrameSize().Width();
765 }
766
MeasureContentChild(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & contentSize)767 void NavigationLayoutAlgorithm::MeasureContentChild(LayoutWrapper* layoutWrapper,
768 const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
769 const SizeF& contentSize)
770 {
771 auto contentNode = hostNode->GetContentNode();
772 CHECK_NULL_VOID(contentNode);
773 auto index = hostNode->GetChildIndexById(contentNode->GetId());
774 auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
775 CHECK_NULL_VOID(contentWrapper);
776 auto constraint = navigationLayoutProperty->CreateChildConstraint();
777 if (contentNode->GetChildren().empty()) {
778 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
779 } else {
780 NavigationLayoutUtil::UpdateConstraintWhenFixOrWrap(navigationLayoutProperty, constraint, contentSize);
781 }
782 contentWrapper->Measure(constraint);
783 realContentHeight_ = contentWrapper->GetGeometryNode()->GetFrameSize().Height();
784 realContentWidth_ = contentWrapper->GetGeometryNode()->GetFrameSize().Width();
785 }
786
MeasureForceSplitPlaceHolderNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & phSize)787 void NavigationLayoutAlgorithm::MeasureForceSplitPlaceHolderNode(
788 LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
789 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& phSize)
790 {
791 auto phNode = AceType::DynamicCast<FrameNode>(hostNode->GetForceSplitPlaceHolderNode());
792 CHECK_NULL_VOID(phNode);
793 auto phProperty = phNode->GetLayoutProperty();
794 CHECK_NULL_VOID(phProperty);
795 auto index = hostNode->GetChildIndexById(phNode->GetId());
796 auto phWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
797 CHECK_NULL_VOID(phWrapper);
798 auto constraint = navigationLayoutProperty->CreateChildConstraint();
799 if (phProperty->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
800 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
801 } else {
802 if (IsAutoHeight(navigationLayoutProperty)) {
803 constraint.selfIdealSize.SetWidth(phSize.Width());
804 } else {
805 constraint.selfIdealSize = OptionalSizeF(phSize.Width(), phSize.Height());
806 }
807 }
808 phWrapper->Measure(constraint);
809 }
810
Measure(LayoutWrapper * layoutWrapper)811 void NavigationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
812 {
813 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
814 CHECK_NULL_VOID(hostNode);
815 auto pattern = hostNode->GetPattern<NavigationPattern>();
816 CHECK_NULL_VOID(pattern);
817 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
818 CHECK_NULL_VOID(navigationLayoutProperty);
819 const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
820 CHECK_NULL_VOID(constraint);
821 auto geometryNode = layoutWrapper->GetGeometryNode();
822 auto size =
823 CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT).ConvertToSizeT();
824 FitScrollFullWindow(size);
825 pattern->SetNavigationSize(size);
826
827 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
828 MinusPaddingToSize(padding, size);
829
830 pattern->TryForceSplitIfNeeded(size);
831 if (ifNeedInit_) {
832 RangeCalculation(hostNode, navigationLayoutProperty);
833 }
834 if (size.Width() == 0.0f) {
835 auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
836 if (layoutAlgorithm) {
837 layoutAlgorithm->SetSkipLayout();
838 }
839 return;
840 }
841 GetRange(hostNode);
842 UpdateNavigationMode(navigationLayoutProperty, size, hostNode);
843
844 if (pattern->IsForceSplitSuccess() && !pattern->IsForceSplitUseNavBar()) {
845 SizeCalculationForForceSplit(layoutWrapper, hostNode, navigationLayoutProperty, size);
846 if (IsNavBarVisible(hostNode)) {
847 MeasureNavBarOrHomeDestination(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
848 }
849 MeasurePrimaryContentNode(layoutWrapper, hostNode, navigationLayoutProperty, primaryNodeSize_);
850 } else {
851 SizeCalculation(layoutWrapper, hostNode, navigationLayoutProperty, size);
852 MeasureNavBarOrHomeDestination(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
853 }
854 if (pattern->IsForceSplitSuccess()) {
855 MeasureForceSplitPlaceHolderNode(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
856 }
857
858 MeasureContentChild(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
859 MeasureDivider(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
860 MeasureDragBar(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
861 MeasureSplitPlaceholder(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
862
863 ReCalcNavigationSize(layoutWrapper, size);
864 }
865
Layout(LayoutWrapper * layoutWrapper)866 void NavigationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
867 {
868 auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
869 if (layoutAlgorithm && layoutAlgorithm->SkipLayout()) {
870 return;
871 }
872 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
873 CHECK_NULL_VOID(hostNode);
874 auto pattern = hostNode->GetPattern<NavigationPattern>();
875 CHECK_NULL_VOID(pattern);
876 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
877 CHECK_NULL_VOID(navigationLayoutProperty);
878
879 NavBarPosition navBarPosition = NavBarPosition::START;
880 float navBarOrPrimarNodeWidth = 0.0f;
881 if (pattern->IsForceSplitSuccess() && !pattern->IsForceSplitUseNavBar()) {
882 if (IsNavBarVisible(hostNode)) {
883 OffsetF navBarOffset(0.0, 0.0);
884 LayoutNavBarOrHomeDestination(
885 layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
886 }
887 navBarOrPrimarNodeWidth = LayoutPrimaryContentNode(layoutWrapper, hostNode, navigationLayoutProperty);
888 } else {
889 navBarPosition = pattern->IsForceSplitUseNavBar() ? NavBarPosition::START :
890 navigationLayoutProperty->GetNavBarPositionValue(NavBarPosition::START);
891 OffsetF navBarOffset(0.0, 0.0);
892 navBarOrPrimarNodeWidth = LayoutNavBarOrHomeDestination(
893 layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
894 }
895
896 float dividerWidth = LayoutDivider(
897 layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, navBarPosition);
898 auto splitPlaceholderOffsetX = navBarOrPrimarNodeWidth + dividerWidth;
899 LayoutSplitPalceholderContent(
900 layoutWrapper, hostNode, navigationLayoutProperty, splitPlaceholderOffsetX, navBarPosition);
901 LayoutContent(
902 layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, dividerWidth, navBarPosition);
903 LayoutDragBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, navBarPosition);
904 if (pattern->IsForceSplitSuccess()) {
905 LayoutForceSplitPlaceHolderNode(
906 layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, dividerWidth);
907 }
908
909 auto&& opts = navigationLayoutProperty->GetSafeAreaExpandOpts();
910 if (opts) {
911 auto geometryNode = hostNode->GetGeometryNode();
912 CHECK_NULL_VOID(geometryNode);
913 TAG_LOGD(AceLogTag::ACE_NAVIGATION,
914 "Navigation id is %{public}d, frameRect is %{public}s",
915 hostNode->GetId(), geometryNode->GetFrameRect().ToString().c_str());
916 }
917 }
918
SetNavigationHeight(LayoutWrapper * layoutWrapper,SizeF & size)919 void NavigationLayoutAlgorithm::SetNavigationHeight(LayoutWrapper* layoutWrapper, SizeF& size)
920 {
921 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
922 CHECK_NULL_VOID(hostNode);
923 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
924 CHECK_NULL_VOID(navigationPattern);
925 auto navigationStack = navigationPattern->GetNavigationStack();
926 CHECK_NULL_VOID(navigationStack);
927 if (navigationStack->Empty()) {
928 size.SetHeight(realNavBarHeight_);
929 } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
930 size.SetHeight(realContentHeight_);
931 } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
932 float navHeight = std::max(realContentHeight_, realNavBarHeight_);
933 size.SetHeight(navHeight);
934 }
935 }
936
SetNavigationWidth(LayoutWrapper * layoutWrapper,SizeF & size)937 void NavigationLayoutAlgorithm::SetNavigationWidth(LayoutWrapper* layoutWrapper, SizeF& size)
938 {
939 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
940 CHECK_NULL_VOID(hostNode);
941 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
942 CHECK_NULL_VOID(navigationPattern);
943 auto navigationStack = navigationPattern->GetNavigationStack();
944 CHECK_NULL_VOID(navigationStack);
945 auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
946 CHECK_NULL_VOID(navigationLayoutProperty);
947 if (navigationStack->Empty()) {
948 size.SetWidth(realNavBarWidth_);
949 } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
950 size.SetWidth(realContentWidth_);
951 } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
952 float navWidth = realContentWidth_ + realNavBarWidth_;
953 size.SetWidth(navWidth);
954 size.AddWidth(realDividerWidth_);
955 }
956 }
957
ReCalcNavigationSize(LayoutWrapper * layoutWrapper,SizeF & size)958 void NavigationLayoutAlgorithm::ReCalcNavigationSize(LayoutWrapper* layoutWrapper, SizeF& size)
959 {
960 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
961 CHECK_NULL_VOID(navigationLayoutProperty);
962 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
963
964 auto layoutPolicy = navigationLayoutProperty->GetLayoutPolicyProperty();
965 bool isHeightWrapOrFix =
966 layoutPolicy.has_value() ? (layoutPolicy->IsHeightWrap() || layoutPolicy->IsHeightFix()) : false;
967 bool isWidthWrapOrFix =
968 layoutPolicy.has_value() ? (layoutPolicy->IsWidthWrap() || layoutPolicy->IsWidthFix()) : false;
969 if (IsAutoHeight(navigationLayoutProperty) || isHeightWrapOrFix) {
970 SetNavigationHeight(layoutWrapper, size);
971 }
972 if (isWidthWrapOrFix) {
973 SetNavigationWidth(layoutWrapper, size);
974 }
975 size.AddWidth(padding.left.value_or(0.0f) + padding.right.value_or(0.0f));
976 size.AddHeight(padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f));
977
978 auto realSize = UpdateOptionSizeByCalcLayoutConstraint(OptionalSizeF(size.Width(), size.Height()),
979 navigationLayoutProperty->GetCalcLayoutConstraint(),
980 navigationLayoutProperty->GetLayoutConstraint()->percentReference);
981
982 layoutWrapper->GetGeometryNode()->SetFrameSize(realSize.ConvertToSizeT());
983 }
984
985 } // namespace OHOS::Ace::NG
986