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 <cmath>
19
20 #include "base/geometry/dimension.h"
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/log/ace_trace.h"
24 #include "base/memory/ace_type.h"
25 #include "base/utils/utils.h"
26 #include "core/components/common/layout/constants.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/layout/layout_algorithm.h"
29 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
30 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
31 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
32 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
33 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
34 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
35 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
36 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
37 #include "core/components_ng/property/calc_length.h"
38 #include "core/components_ng/property/layout_constraint.h"
39 #include "core/components_ng/property/measure_property.h"
40 #include "core/components_ng/property/measure_utils.h"
41 #include "core/pipeline_ng/pipeline_context.h"
42
43 namespace OHOS::Ace::NG {
44
45 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
46 constexpr Dimension WINDOW_WIDTH = 520.0_vp;
47
48 namespace {
49
MeasureDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)50 void MeasureDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
51 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
52 {
53 auto dividerNode = hostNode->GetDividerNode();
54 CHECK_NULL_VOID(dividerNode);
55 auto index = hostNode->GetChildIndexById(dividerNode->GetId());
56 auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
57 CHECK_NULL_VOID(dividerWrapper);
58 auto constraint = navigationLayoutProperty->CreateChildConstraint();
59 constraint.selfIdealSize = OptionalSizeF(dividerSize.Width(), dividerSize.Height());
60 dividerWrapper->Measure(constraint);
61 }
62
LayoutNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const NavBarPosition & position,OffsetF & returnNavBarOffset)63 float LayoutNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
64 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const NavBarPosition& position,
65 OffsetF& returnNavBarOffset)
66 {
67 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
68 if (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
69 navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
70 return 0.0f;
71 }
72 auto contentNode = hostNode->GetContentNode();
73 CHECK_NULL_RETURN(contentNode, 0.0f);
74 auto navBarNode = hostNode->GetNavBarNode();
75 CHECK_NULL_RETURN(navBarNode, 0.0f);
76 auto index = hostNode->GetChildIndexById(navBarNode->GetId());
77 auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
78 CHECK_NULL_RETURN(navBarWrapper, 0.0f);
79 auto geometryNode = navBarWrapper->GetGeometryNode();
80 auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
81 if (position == NavBarPosition::END) {
82 auto navBarOffset =
83 OffsetT<float>(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width(),
84 geometryNode->GetFrameOffset().GetY());
85 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
86 navBarOffset.AddX(padding.left.value_or(0));
87 navBarOffset.AddY(padding.top.value_or(0));
88 geometryNode->SetMarginFrameOffset(navBarOffset);
89 navBarWrapper->Layout();
90 returnNavBarOffset = navBarOffset;
91 return geometryNode->GetFrameSize().Width();
92 }
93 auto navBarOffset = OffsetT<float>(0.0f, 0.0f);
94 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
95 navBarOffset.AddX(padding.left.value_or(0));
96 navBarOffset.AddY(padding.top.value_or(0));
97 geometryNode->SetMarginFrameOffset(navBarOffset);
98 navBarWrapper->Layout();
99 returnNavBarOffset = navBarOffset;
100 return geometryNode->GetFrameSize().Width();
101 }
102
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)103 float LayoutDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
104 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
105 {
106 auto dividerNode = hostNode->GetDividerNode();
107 CHECK_NULL_RETURN(dividerNode, 0.0f);
108 auto index = hostNode->GetChildIndexById(dividerNode->GetId());
109 auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
110 CHECK_NULL_RETURN(dividerWrapper, 0.0f);
111 auto geometryNode = dividerWrapper->GetGeometryNode();
112 auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
113 OffsetT<float> dividerOffset;
114 if (position == NavBarPosition::END) {
115 dividerOffset = OffsetT<float>(
116 navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - navBarWidth, 0.0f);
117 } else {
118 dividerOffset = OffsetT<float>(navBarWidth, 0.0f);
119 }
120 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
121 dividerOffset.AddX(padding.left.value_or(0));
122 dividerOffset.AddY(padding.top.value_or(0));
123 geometryNode->SetMarginFrameOffset(dividerOffset);
124 dividerWrapper->Layout();
125 return geometryNode->GetFrameSize().Width();
126 }
127
LayoutContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth,const NavBarPosition & position)128 void LayoutContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
129 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth,
130 const NavBarPosition& position)
131 {
132 auto contentNode = hostNode->GetContentNode();
133 CHECK_NULL_VOID(contentNode);
134 auto index = hostNode->GetChildIndexById(contentNode->GetId());
135 auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
136 CHECK_NULL_VOID(contentWrapper);
137 auto geometryNode = contentWrapper->GetGeometryNode();
138 CHECK_NULL_VOID(geometryNode);
139
140 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
141 auto contentChildSize = contentNode->GetChildren().size();
142
143 // cases that content layouts from start
144 // 1. displaying content pages in STACK mode
145 // 2. placing navBar at the end
146 // 3. hiding navBar in SPLIT mode
147 auto contentOffset = OffsetT<float>(0.0f, 0.0f);
148 if ((contentChildSize != 0 && navigationPattern->GetNavigationMode() == NavigationMode::STACK) ||
149 position == NavBarPosition::END ||
150 (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
151 navigationPattern->GetNavigationMode() == NavigationMode::SPLIT)) {
152 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
153 contentOffset.AddX(padding.left.value_or(0));
154 contentOffset.AddY(padding.top.value_or(0));
155 geometryNode->SetMarginFrameOffset(contentOffset);
156 contentWrapper->Layout();
157 return;
158 }
159 contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
160 const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
161 contentOffset.AddX(padding.left.value_or(0));
162 contentOffset.AddY(padding.top.value_or(0));
163 geometryNode->SetMarginFrameOffset(contentOffset);
164 contentWrapper->Layout();
165 }
166
FitScrollFullWindow(SizeF & frameSize)167 void FitScrollFullWindow(SizeF& frameSize)
168 {
169 auto pipeline = PipelineContext::GetCurrentContext();
170 CHECK_NULL_VOID(pipeline);
171 if (frameSize.Width() == Infinity<float>()) {
172 frameSize.SetWidth(pipeline->GetRootWidth());
173 }
174 if (frameSize.Height() == Infinity<float>()) {
175 frameSize.SetHeight(pipeline->GetRootHeight());
176 }
177 }
178
179 } // namespace
180
IsAutoHeight(const RefPtr<LayoutProperty> & layoutProperty)181 bool NavigationLayoutAlgorithm::IsAutoHeight(const RefPtr<LayoutProperty>& layoutProperty)
182 {
183 CHECK_NULL_RETURN(layoutProperty, false);
184 auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
185 if (!calcLayoutConstraint || !calcLayoutConstraint->selfIdealSize.has_value() ||
186 !calcLayoutConstraint->selfIdealSize->Height().has_value() ||
187 (calcLayoutConstraint->selfIdealSize->Height().value().ToString().find("auto") == std::string::npos)) {
188 return false;
189 }
190 return true;
191 }
192
RangeCalculation(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)193 void NavigationLayoutAlgorithm::RangeCalculation(
194 const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
195 {
196 const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
197 CHECK_NULL_VOID(constraint);
198 auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
199 auto frameSize = parentSize.ConvertToSizeT();
200 float frameSizeWidth = frameSize.Width();
201 Dimension defaultValue = Dimension(-1.0);
202 auto pipeline = PipelineContext::GetCurrentContext();
203 CHECK_NULL_VOID(pipeline);
204
205 minContentWidthValue_ = navigationLayoutProperty->GetMinContentWidthValue(defaultValue);
206 if (minContentWidthValue_ == defaultValue) {
207 userSetMinContentFlag_ = false;
208 minContentWidthValue_ = DEFAULT_MIN_CONTENT_WIDTH;
209 } else {
210 userSetMinContentFlag_ = true;
211 }
212 minNavBarWidthValue_ = navigationLayoutProperty->GetMinNavBarWidthValue(DEFAULT_MIN_NAV_BAR_WIDTH);
213 auto userSetMaxNavBarWidthValue = navigationLayoutProperty->GetMaxNavBarWidthValue(defaultValue);
214
215 float minNavBarWidth =
216 std::min(static_cast<float>(minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f))),
217 frameSizeWidth);
218 float maxNavBarWidth = 0.0f;
219 if (userSetMaxNavBarWidthValue == defaultValue) {
220 userSetNavBarRangeFlag_ = false;
221 maxNavBarWidth = std::min(
222 static_cast<float>(DEFAULT_MAX_NAV_BAR_WIDTH.ConvertToPx()), frameSizeWidth * MAX_NAV_BAR_WIDTH_SCALE);
223 } else {
224 userSetNavBarRangeFlag_ = true;
225 maxNavBarWidth =
226 static_cast<float>(userSetMaxNavBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f)));
227 }
228 maxNavBarWidthValue_ = Dimension(Dimension(std::max(maxNavBarWidth, minNavBarWidth)).ConvertToVp(),
229 DimensionUnit::VP);
230 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
231 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
232 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
233 auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
234 realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
235 realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
236 }
237 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
238 CHECK_NULL_VOID(navigationPattern);
239 navigationPattern->SetMinNavBarWidthValue(minNavBarWidthValue_);
240 navigationPattern->SetMaxNavBarWidthValue(maxNavBarWidthValue_);
241 navigationPattern->SetMinContentWidthValue(minContentWidthValue_);
242 navigationPattern->SetUserSetNavBarRangeFlag(userSetNavBarRangeFlag_);
243 navigationPattern->SetUserSetMinContentFlag(userSetMinContentFlag_);
244 }
245
GetRange(const RefPtr<NavigationGroupNode> & hostNode)246 void NavigationLayoutAlgorithm::GetRange(const RefPtr<NavigationGroupNode>& hostNode)
247 {
248 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
249 CHECK_NULL_VOID(navigationPattern);
250 minNavBarWidthValue_ = navigationPattern->GetMinNavBarWidthValue();
251 maxNavBarWidthValue_ = navigationPattern->GetMaxNavBarWidthValue();
252 minContentWidthValue_ = navigationPattern->GetMinContentWidthValue();
253 userSetNavBarRangeFlag_ = navigationPattern->GetUserSetNavBarRangeFlag();
254 userSetMinContentFlag_ = navigationPattern->GetUserSetMinContentFlag();
255 userSetNavBarWidthFlag_ = navigationPattern->GetUserSetNavBarWidthFlag();
256 }
257
UpdateNavigationMode(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize,const RefPtr<NavigationGroupNode> & hostNode)258 void NavigationLayoutAlgorithm::UpdateNavigationMode(const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
259 const SizeF& frameSize, const RefPtr<NavigationGroupNode>& hostNode)
260 {
261 auto usrNavigationMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
262 auto pipeline = PipelineContext::GetCurrentContext();
263 CHECK_NULL_VOID(pipeline);
264 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
265
266 auto navigationWidth = 0.0f;
267 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
268 const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
269 CHECK_NULL_VOID(constraint);
270 auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
271 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
272 navigationWidth = static_cast<float>(minNavBarWidth + minContentWidthValue_.ConvertToPx());
273 } else {
274 navigationWidth = static_cast<float>(WINDOW_WIDTH.ConvertToPx());
275 }
276 if (usrNavigationMode == NavigationMode::AUTO) {
277 if (frameSize.Width() >= navigationWidth) {
278 usrNavigationMode = NavigationMode::SPLIT;
279 auto navBarNode = hostNode->GetNavBarNode();
280 if (navBarNode) {
281 navBarNode->SetJSViewActive(true);
282 }
283 } else {
284 usrNavigationMode = NavigationMode::STACK;
285 }
286 }
287 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
288 bool modeChange = navigationPattern->GetNavigationMode() != usrNavigationMode;
289 navigationPattern->SetNavigationMode(usrNavigationMode);
290
291 navigationPattern->SetNavigationModeChange(modeChange);
292 navigationPattern->OnNavBarStateChange(modeChange);
293 navigationPattern->OnNavigationModeChange(modeChange);
294 }
295
SizeCalculation(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)296 void NavigationLayoutAlgorithm::SizeCalculation(LayoutWrapper* layoutWrapper,
297 const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
298 const SizeF& frameSize)
299 {
300 auto pipeline = PipelineContext::GetCurrentContext();
301 CHECK_NULL_VOID(pipeline);
302 auto constraint = navigationLayoutProperty->GetLayoutConstraint();
303 auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
304 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
305 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
306 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
307 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
308 auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
309 realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
310 realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
311 } else {
312 auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
313 auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
314 realNavBarWidth_ = navBarWidth;
315 }
316 navBarSize_ = frameSize;
317 contentSize_ = frameSize;
318 dividerSize_ = SizeF(0.0f, frameSize.Height());
319 if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
320 SizeCalculationSplit(navigationLayoutProperty, frameSize);
321 } else {
322 SizeCalculationStack(hostNode, navigationLayoutProperty, frameSize);
323 }
324 }
325
SizeCalculationSplit(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)326 void NavigationLayoutAlgorithm::SizeCalculationSplit(
327 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
328 {
329 float frameWidth = frameSize.Width();
330 auto parentSize = CreateIdealSizeByPercentRef(
331 navigationLayoutProperty->GetLayoutConstraint().value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
332 auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
333 auto userSetNavBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
334 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
335 auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
336 auto minContentWidth = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
337 realContentWidth_ = minContentWidth;
338
339 if (navigationLayoutProperty->GetHideNavBar().value_or(false)) {
340 navBarSize_ = SizeF(0.0f, 0.0f);
341 dividerSize_ = SizeF(0.0f, 0.0f);
342 realNavBarWidth_ = 0.0f;
343 realContentWidth_ = frameWidth;
344 } else {
345 CheckSizeInSplit(frameWidth, userSetNavBarWidth, minNavBarWidth, minContentWidth);
346 }
347
348 realDividerWidth_ = std::max(realDividerWidth_, 0.0f);
349 realContentWidth_ = std::max(realContentWidth_, 0.0f);
350 realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
351 realContentWidth_ = std::min(realContentWidth_, frameWidth);
352 if (realNavBarWidth_ == 0.0f || realContentWidth_ == 0.0f) {
353 realDividerWidth_ = 0.0f;
354 } else {
355 realDividerWidth_ = dividerWidth;
356 }
357 navBarSize_.SetWidth(realNavBarWidth_);
358 dividerSize_.SetWidth(realDividerWidth_);
359 contentSize_.SetWidth(realContentWidth_);
360 }
361
CheckSizeInSplit(const float frameWidth,const float userSetNavBarWidth,const float minNavBarWidth,const float minContentWidth)362 void NavigationLayoutAlgorithm::CheckSizeInSplit(
363 const float frameWidth, const float userSetNavBarWidth, const float minNavBarWidth, const float minContentWidth)
364 {
365 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
366
367 if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
368 if (minContentWidth >= frameWidth) {
369 realContentWidth_ = frameWidth;
370 realNavBarWidth_ = 0.0f;
371 } else if (realNavBarWidth_ + dividerWidth + minContentWidth <= frameWidth) {
372 realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
373 } else {
374 realContentWidth_ = minContentWidth;
375 realNavBarWidth_ = frameWidth - realContentWidth_ - dividerWidth;
376 }
377 } else if (!userSetNavBarRangeFlag_ && !userSetMinContentFlag_ && userSetNavBarWidthFlag_) {
378 realNavBarWidth_ = userSetNavBarWidth;
379 realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
380 } else {
381 float remainingSpace = frameWidth - realNavBarWidth_ - dividerWidth;
382 float remainingMaxSpace = frameWidth - minNavBarWidth - dividerWidth;
383 if (remainingSpace >= minContentWidth) {
384 realContentWidth_ = remainingSpace;
385 } else if (remainingSpace < minContentWidth && remainingMaxSpace > minContentWidth &&
386 realNavBarWidth_ > minNavBarWidth) {
387 realContentWidth_ = minContentWidth;
388 realNavBarWidth_ = frameWidth - minContentWidth - dividerWidth;
389 } else {
390 realNavBarWidth_ = minNavBarWidth;
391 realContentWidth_ = frameWidth - minNavBarWidth - dividerWidth;
392 }
393 }
394 }
395
SizeCalculationStack(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)396 void NavigationLayoutAlgorithm::SizeCalculationStack(const RefPtr<NavigationGroupNode>& hostNode,
397 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
398 {
399 auto contentNode = hostNode->GetContentNode();
400 CHECK_NULL_VOID(contentNode);
401 realDividerWidth_ = 0.0f;
402 float frameWidth = frameSize.Width();
403 navBarSize_.SetWidth(frameWidth);
404 dividerSize_.SetWidth(realDividerWidth_);
405 contentSize_.SetWidth(frameWidth);
406 realContentWidth_ = frameWidth;
407 }
408
MeasureNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & navBarSize)409 void NavigationLayoutAlgorithm::MeasureNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
410 const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& navBarSize)
411 {
412 auto navBarNode = hostNode->GetNavBarNode();
413 CHECK_NULL_VOID(navBarNode);
414 auto index = hostNode->GetChildIndexById(navBarNode->GetId());
415 auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
416 CHECK_NULL_VOID(navBarWrapper);
417 auto constraint = navigationLayoutProperty->CreateChildConstraint();
418 if (IsAutoHeight(navigationLayoutProperty)) {
419 navBarWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
420 navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
421 constraint.selfIdealSize.SetWidth(navBarSize.Width());
422 } else {
423 constraint.selfIdealSize = OptionalSizeF(navBarSize.Width(), navBarSize.Height());
424 }
425 navBarWrapper->Measure(constraint);
426 realNavBarHeight_ = navBarWrapper->GetGeometryNode()->GetFrameSize().Height();
427 }
428
MeasureContentChild(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & contentSize)429 void NavigationLayoutAlgorithm::MeasureContentChild(LayoutWrapper* layoutWrapper,
430 const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
431 const SizeF& contentSize)
432 {
433 auto contentNode = hostNode->GetContentNode();
434 CHECK_NULL_VOID(contentNode);
435 auto index = hostNode->GetChildIndexById(contentNode->GetId());
436 auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
437 CHECK_NULL_VOID(contentWrapper);
438 auto constraint = navigationLayoutProperty->CreateChildConstraint();
439 if (contentNode->GetChildren().empty()) {
440 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
441 } else {
442 if (IsAutoHeight(navigationLayoutProperty)) {
443 constraint.selfIdealSize.SetWidth(contentSize.Width());
444 } else {
445 constraint.selfIdealSize = OptionalSizeF(contentSize.Width(), contentSize.Height());
446 }
447 }
448 contentWrapper->Measure(constraint);
449 realContentHeight_ = contentWrapper->GetGeometryNode()->GetFrameSize().Height();
450 }
451
Measure(LayoutWrapper * layoutWrapper)452 void NavigationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
453 {
454 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
455 CHECK_NULL_VOID(hostNode);
456 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
457 CHECK_NULL_VOID(navigationLayoutProperty);
458 const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
459 CHECK_NULL_VOID(constraint);
460 auto geometryNode = layoutWrapper->GetGeometryNode();
461 auto size =
462 CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT).ConvertToSizeT();
463 FitScrollFullWindow(size);
464
465 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
466 MinusPaddingToSize(padding, size);
467
468 if (ifNeedInit_) {
469 RangeCalculation(hostNode, navigationLayoutProperty);
470 }
471 if (size.Width() == 0.0f) {
472 return;
473 }
474 GetRange(hostNode);
475 UpdateNavigationMode(navigationLayoutProperty, size, hostNode);
476 SizeCalculation(layoutWrapper, hostNode, navigationLayoutProperty, size);
477
478 MeasureNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
479 MeasureContentChild(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
480 MeasureDivider(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
481
482 if (IsAutoHeight(navigationLayoutProperty)) {
483 SetNavigationHeight(layoutWrapper, size);
484 }
485 size.AddWidth(padding.left.value_or(0.0f) + padding.right.value_or(0.0f));
486 size.AddHeight(padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f));
487 layoutWrapper->GetGeometryNode()->SetFrameSize(size);
488 }
489
Layout(LayoutWrapper * layoutWrapper)490 void NavigationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
491 {
492 auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
493 if (layoutAlgorithm && layoutAlgorithm->SkipLayout()) {
494 return;
495 }
496 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
497 CHECK_NULL_VOID(hostNode);
498 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
499 CHECK_NULL_VOID(navigationLayoutProperty);
500 auto navBarPosition = navigationLayoutProperty->GetNavBarPositionValue(NavBarPosition::START);
501 OffsetF navBarOffset(0.0, 0.0);
502 float navBarWidth = LayoutNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
503 float dividerWidth = LayoutDivider(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, navBarPosition);
504 LayoutContent(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, dividerWidth, navBarPosition);
505 }
506
SetNavigationHeight(LayoutWrapper * layoutWrapper,SizeF & size)507 void NavigationLayoutAlgorithm::SetNavigationHeight(LayoutWrapper* layoutWrapper, SizeF& size)
508 {
509 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
510 CHECK_NULL_VOID(hostNode);
511 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
512 CHECK_NULL_VOID(navigationPattern);
513 auto navigationStack = navigationPattern->GetNavigationStack();
514 CHECK_NULL_VOID(navigationStack);
515 if (navigationStack->Empty()) {
516 size.SetHeight(realNavBarHeight_);
517 } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
518 size.SetHeight(realContentHeight_);
519 } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
520 float navHeight = std::max(realContentHeight_, realNavBarHeight_);
521 size.SetHeight(navHeight);
522 }
523 }
524
525 } // namespace OHOS::Ace::NG
526