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