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/tabs/tab_bar_layout_algorithm.h"
17
18 #include "base/geometry/axis.h"
19 #include "base/geometry/dimension.h"
20 #include "base/geometry/ng/offset_t.h"
21 #include "base/geometry/ng/size_t.h"
22 #include "base/log/ace_trace.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/layout/grid_layout_info.h"
25 #include "core/components/common/layout/grid_system_manager.h"
26 #include "core/components/tab_bar/tab_theme.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/image/image_layout_property.h"
30 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
31 #include "core/components_ng/pattern/tabs/tab_bar_paint_property.h"
32 #include "core/components_ng/pattern/tabs/tab_bar_pattern.h"
33 #include "core/components_ng/pattern/text/text_layout_property.h"
34 #include "core/components_ng/property/layout_constraint.h"
35 #include "core/components_ng/property/measure_property.h"
36 #include "core/components_ng/property/measure_utils.h"
37 #include "core/pipeline_ng/pipeline_context.h"
38
39 namespace OHOS::Ace::NG {
40 namespace {
41 constexpr int8_t MASK_COUNT = 2;
42 constexpr int8_t SM_COLUMN_NUM = 4;
43 constexpr int8_t MD_COLUMN_NUM = 8;
44 constexpr int8_t LG_COLUMN_NUM = 12;
45 } // namespace
UpdateChildConstraint(LayoutConstraintF & childConstraint,const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & ideaSize,int32_t childCount,Axis axis)46 void TabBarLayoutAlgorithm::UpdateChildConstraint(LayoutConstraintF& childConstraint,
47 const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& ideaSize, int32_t childCount, Axis axis)
48 {
49 childConstraint.parentIdealSize = OptionalSizeF(ideaSize);
50 const auto& barMode = layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED);
51 auto pipelineContext = PipelineContext::GetCurrentContext();
52 CHECK_NULL_VOID(pipelineContext);
53 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
54 CHECK_NULL_VOID(tabTheme);
55 if (barMode == TabBarMode::FIXED) {
56 auto childIdeaSize = ideaSize;
57 if (axis == Axis::HORIZONTAL) {
58 childIdeaSize.SetWidth(GetContentWidth(layoutProperty, ideaSize) / childCount);
59 childConstraint.maxSize.SetHeight(childConstraint.maxSize.Height());
60 if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
61 childConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
62 }
63 } else if (axis == Axis::VERTICAL) {
64 childIdeaSize.SetHeight(tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE
65 ? ideaSize.Height() / (childCount * 2)
66 : ideaSize.Height() / childCount);
67 }
68 childConstraint.selfIdealSize = OptionalSizeF(childIdeaSize);
69 } else {
70 if (axis == Axis::HORIZONTAL) {
71 childConstraint.maxSize.SetWidth(Infinity<float>());
72 childConstraint.maxSize.SetHeight(childConstraint.maxSize.Height());
73 childConstraint.selfIdealSize.SetHeight(ideaSize.Height());
74 if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
75 childConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
76 }
77 } else if (axis == Axis::VERTICAL) {
78 childConstraint.maxSize.SetHeight(Infinity<float>());
79 childConstraint.selfIdealSize.SetWidth(ideaSize.Width());
80 }
81 }
82 }
83
Measure(LayoutWrapper * layoutWrapper)84 void TabBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
85 {
86 previousChildrenMainSize_ = childrenMainSize_;
87 auto pipelineContext = PipelineContext::GetCurrentContext();
88 CHECK_NULL_VOID(pipelineContext);
89 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
90 CHECK_NULL_VOID(tabTheme);
91 auto geometryNode = layoutWrapper->GetGeometryNode();
92 CHECK_NULL_VOID(geometryNode);
93 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
94 CHECK_NULL_VOID(layoutProperty);
95 auto axis = GetAxis(layoutWrapper);
96 auto constraint = layoutProperty->GetLayoutConstraint();
97 auto idealSize =
98 CreateIdealSize(constraint.value(), axis, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT));
99
100 auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
101 if (childCount <= 0) {
102 return;
103 }
104
105 if (axis == Axis::VERTICAL && constraint->selfIdealSize.Width().has_value() &&
106 constraint->selfIdealSize.Width().value() < constraint->parentIdealSize.Width().value_or(0.0f) &&
107 constraint->selfIdealSize.Width().value() > tabTheme->GetHorizontalBottomTabMinWidth().ConvertToPx()) {
108 // Vertical tab bar may apply LayoutMode.AUTO
109 ApplyLayoutMode(layoutWrapper, constraint->selfIdealSize.Width().value(), childCount);
110 }
111 if (constraint->selfIdealSize.Width().has_value() &&
112 constraint->selfIdealSize.Width().value() > constraint->parentIdealSize.Width().value_or(0.0f)) {
113 idealSize.SetWidth(static_cast<float>(
114 axis == Axis::HORIZONTAL ? constraint->parentIdealSize.Width().value_or(0.0f)
115 : tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE ? tabTheme->GetTabBarDefaultWidth().ConvertToPx()
116 : tabTheme->GetTabBarDefaultHeight().ConvertToPx()));
117 }
118 if (constraint->selfIdealSize.Height().has_value() &&
119 constraint->selfIdealSize.Height().value() > constraint->parentIdealSize.Height().value_or(0.0f)) {
120 idealSize.SetHeight(
121 static_cast<float>(axis == Axis::HORIZONTAL ? tabTheme->GetTabBarDefaultHeight().ConvertToPx()
122 : constraint->parentIdealSize.Height().value_or(0.0f)));
123 }
124 if (!constraint->selfIdealSize.Width().has_value() && axis == Axis::VERTICAL) {
125 idealSize.SetWidth(static_cast<float>(tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE
126 ? tabTheme->GetTabBarDefaultWidth().ConvertToPx()
127 : tabTheme->GetTabBarDefaultHeight().ConvertToPx()));
128 }
129
130 auto frameSize = idealSize.ConvertToSizeT();
131
132 if (axis == Axis::HORIZONTAL) {
133 ConfigHorizontal(layoutWrapper, frameSize, childCount);
134 } else {
135 UpdateHorizontalPadding(layoutWrapper, 0.0f);
136 }
137
138 if (!constraint->selfIdealSize.Height().has_value() && axis == Axis::HORIZONTAL) {
139 idealSize.SetHeight(std::max(static_cast<float>(tabTheme->GetTabBarDefaultHeight().ConvertToPx()), maxHeight_));
140 }
141
142 geometryNode->SetFrameSize(idealSize.ConvertToSizeT());
143
144 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
145 UpdateChildConstraint(childLayoutConstraint, layoutProperty, idealSize.ConvertToSizeT(), childCount, axis);
146
147 // Measure children.
148 childrenMainSize_ = (axis == Axis::VERTICAL ? 0.0f : scrollMargin_ * 2);
149 for (int32_t index = 0; index < childCount; ++index) {
150 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
151 if (!childWrapper) {
152 continue;
153 }
154 if (static_cast<int32_t>(itemWidths_.size()) == childCount && useItemWidth_) {
155 auto childIdeaSize = idealSize.ConvertToSizeT();
156 childIdeaSize.SetWidth(itemWidths_[index]);
157 childLayoutConstraint.selfIdealSize = OptionalSizeF(childIdeaSize);
158 }
159 childWrapper->Measure(childLayoutConstraint);
160 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
161 // In fixed mode, large paddings may overwhelm the constraint after measure
162 AdjustFixedItem(childWrapper, childLayoutConstraint.selfIdealSize, axis);
163 }
164 childrenMainSize_ += childWrapper->GetGeometryNode()->GetMarginFrameSize().MainSize(axis);
165 }
166 MeasureMask(layoutWrapper, childCount);
167 }
168
CheckMarqueeForScrollable(LayoutWrapper * layoutWrapper,int32_t childCount) const169 void TabBarLayoutAlgorithm::CheckMarqueeForScrollable(LayoutWrapper* layoutWrapper, int32_t childCount) const
170 {
171 for (int32_t index = 0; index < childCount; ++index) {
172 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
173 CHECK_NULL_VOID(childWrapper);
174 auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
175 CHECK_NULL_VOID(textWrapper);
176 auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
177 CHECK_NULL_VOID(textLayoutProperty);
178 if (textLayoutProperty->GetTextOverflow().value_or(TextOverflow::NONE) == TextOverflow::MARQUEE) {
179 textLayoutProperty->UpdateTextOverflow(TextOverflow::NONE);
180 }
181 }
182 }
183
MeasureMask(LayoutWrapper * layoutWrapper,int32_t childCount) const184 void TabBarLayoutAlgorithm::MeasureMask(LayoutWrapper* layoutWrapper, int32_t childCount) const
185 {
186 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
187 CHECK_NULL_VOID(layoutProperty);
188 auto maskLayoutConstraint = layoutProperty->CreateChildConstraint();
189 auto selectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount);
190 CHECK_NULL_VOID(selectedMaskWrapper);
191 maskLayoutConstraint.selfIdealSize = OptionalSizeF(selectedMaskWrapper->GetGeometryNode()->GetFrameSize());
192 selectedMaskWrapper->Measure(maskLayoutConstraint);
193
194 auto unselectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount + 1);
195 CHECK_NULL_VOID(unselectedMaskWrapper);
196 maskLayoutConstraint.selfIdealSize = OptionalSizeF(unselectedMaskWrapper->GetGeometryNode()->GetFrameSize());
197 unselectedMaskWrapper->Measure(maskLayoutConstraint);
198 }
199
ConfigHorizontal(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)200 void TabBarLayoutAlgorithm::ConfigHorizontal(LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
201 {
202 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
203 CHECK_NULL_VOID(layoutProperty);
204
205 // Apply grid column options to the tab bar
206 auto horizontalPadding = ApplyBarGridAlign(layoutProperty, frameSize);
207
208 UpdateHorizontalPadding(layoutWrapper, horizontalPadding);
209
210 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
211 HandleFixedMode(layoutWrapper, frameSize, childCount);
212 } else {
213 // Handle scrollable mode
214 auto layoutStyle = layoutProperty->GetScrollableBarModeOptions().value_or(ScrollableBarModeOptions());
215 scrollMargin_ = layoutStyle.margin.ConvertToPx();
216 CheckMarqueeForScrollable(layoutWrapper, childCount);
217 MeasureItemWidths(layoutWrapper, childCount);
218
219 if (layoutStyle.nonScrollableLayoutStyle == LayoutStyle::ALWAYS_AVERAGE_SPLIT) {
220 HandleAlwaysAverageSplitLayoutStyle(layoutWrapper, frameSize, childCount);
221 } else if (layoutStyle.nonScrollableLayoutStyle == LayoutStyle::SPACE_BETWEEN_OR_CENTER) {
222 HandleSpaceBetweenOrCenterLayoutStyle(layoutWrapper, frameSize, childCount);
223 } else if (layoutStyle.nonScrollableLayoutStyle == LayoutStyle::ALWAYS_CENTER) {
224 if (LessOrEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize))) {
225 childrenMainSize_ -= scrollMargin_ * 2;
226 scrollMargin_ = 0.0f;
227 } else {
228 useItemWidth_ = false;
229 }
230 }
231 }
232 if (layoutProperty->GetBarAdaptiveHeight().value_or(false)) {
233 MeasureMaxHeight(layoutWrapper, childCount);
234 }
235 }
236
HandleFixedMode(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)237 void TabBarLayoutAlgorithm::HandleFixedMode(LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
238 {
239 if (childCount <= 0) {
240 return;
241 }
242 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
243 CHECK_NULL_VOID(layoutProperty);
244
245 auto allocatedWidth = GetContentWidth(layoutProperty, frameSize) / childCount;
246 MeasureItemWidths(layoutWrapper, childCount);
247 ApplyLayoutMode(layoutWrapper, allocatedWidth, childCount);
248 ApplySymmetricExtensible(layoutWrapper, allocatedWidth, childCount);
249 }
250
MeasureItemWidths(LayoutWrapper * layoutWrapper,int32_t childCount)251 void TabBarLayoutAlgorithm::MeasureItemWidths(LayoutWrapper* layoutWrapper, int32_t childCount)
252 {
253 auto pipelineContext = PipelineContext::GetCurrentContext();
254 CHECK_NULL_VOID(pipelineContext);
255 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
256 CHECK_NULL_VOID(tabTheme);
257 auto host = layoutWrapper->GetHostNode();
258 CHECK_NULL_VOID(host);
259 auto tabBarPattern = host->GetPattern<TabBarPattern>();
260 CHECK_NULL_VOID(tabBarPattern);
261
262 childrenMainSize_ = scrollMargin_ * 2;
263 itemWidths_.clear();
264 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
265 CHECK_NULL_VOID(layoutProperty);
266 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
267 childLayoutConstraint.maxSize.SetWidth(Infinity<float>());
268 if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
269 childLayoutConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
270 }
271 for (int32_t index = 0; index < childCount; ++index) {
272 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
273 CHECK_NULL_VOID (childWrapper);
274 if (tabBarPattern->GetTabBarStyle(index) == TabBarStyle::BOTTOMTABBATSTYLE) {
275 auto imageWrapper = childWrapper->GetOrCreateChildByIndex(0);
276 CHECK_NULL_VOID(imageWrapper);
277 auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(imageWrapper->GetLayoutProperty());
278 CHECK_NULL_VOID(imageLayoutProperty);
279 imageLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {} });
280 auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
281 CHECK_NULL_VOID(textWrapper);
282 auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
283 CHECK_NULL_VOID(textLayoutProperty);
284 textLayoutProperty->UpdateMargin({ CalcLength(0.0_vp), CalcLength(0.0_vp), {}, {} });
285 }
286
287 childWrapper->Measure(childLayoutConstraint);
288 auto geometryNode = childWrapper->GetGeometryNode();
289 CHECK_NULL_VOID(geometryNode);
290 itemWidths_.emplace_back(geometryNode->GetMarginFrameSize().MainSize(Axis::HORIZONTAL));
291 childrenMainSize_ += itemWidths_.back();
292 }
293 }
294
MeasureMaxHeight(LayoutWrapper * layoutWrapper,int32_t childCount)295 void TabBarLayoutAlgorithm::MeasureMaxHeight(LayoutWrapper* layoutWrapper, int32_t childCount)
296 {
297 auto pipelineContext = PipelineContext::GetCurrentContext();
298 CHECK_NULL_VOID(pipelineContext);
299 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
300 CHECK_NULL_VOID(tabTheme);
301
302 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
303 CHECK_NULL_VOID(layoutProperty);
304 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
305 childLayoutConstraint.maxSize.SetWidth(Infinity<float>());
306 if (tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
307 childLayoutConstraint.minSize.SetWidth(tabTheme->GetSubTabBarMinWidth().ConvertToPx());
308 }
309 for (int32_t index = 0; index < childCount; ++index) {
310 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
311 CHECK_NULL_VOID(childWrapper);
312 if (static_cast<int32_t>(itemWidths_.size()) == childCount) {
313 childLayoutConstraint.selfIdealSize.SetWidth(itemWidths_[index]);
314 }
315 childWrapper->Measure(childLayoutConstraint);
316 auto geometryNode = childWrapper->GetGeometryNode();
317 CHECK_NULL_VOID(geometryNode);
318 maxHeight_ =
319 std::max(maxHeight_, geometryNode->GetMarginFrameSize().MainSize(Axis::VERTICAL));
320 }
321 }
322
HandleAlwaysAverageSplitLayoutStyle(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)323 void TabBarLayoutAlgorithm::HandleAlwaysAverageSplitLayoutStyle(
324 LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
325 {
326 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
327 CHECK_NULL_VOID(layoutProperty);
328
329 if (GreatNotEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize)) || childCount <= 0 ||
330 childCount != static_cast<int32_t>(itemWidths_.size())) {
331 useItemWidth_ = false;
332 return;
333 }
334
335 bool hasLongItem = false;
336 int32_t remainingChildCount = childCount;
337 childrenMainSize_ -= scrollMargin_ * 2;
338 auto totalWidth = GetContentWidth(layoutProperty, frameSize) - scrollMargin_ * 2;
339 scrollMargin_ = 0.0f;
340 auto allocatedItemWidth = totalWidth / remainingChildCount;
341
342 std::vector<float> originalWidth;
343 for (int32_t index = 0; index < childCount; index++) {
344 originalWidth.emplace_back(itemWidths_[index]);
345 itemWidths_[index] = 0.0f;
346 }
347
348 /* Calculate the widths of long items. A long item refers to an item whose length is above the average,
349 so remainingChildCount can't be zero */
350 do {
351 hasLongItem = false;
352 for (int32_t index = 0; index < childCount; index++) {
353 if (NearZero(itemWidths_[index]) && GreatNotEqual(originalWidth[index], allocatedItemWidth)) {
354 itemWidths_[index] = originalWidth[index];
355 hasLongItem = true;
356 remainingChildCount--;
357 totalWidth -= originalWidth[index];
358 }
359 }
360 allocatedItemWidth = totalWidth / remainingChildCount;
361 } while (hasLongItem);
362
363 // Calculate the widths of other items
364 for (int32_t index = 0; index < childCount; index++) {
365 if (NearZero(itemWidths_[index])) {
366 itemWidths_[index] = allocatedItemWidth;
367 }
368 }
369 }
370
HandleSpaceBetweenOrCenterLayoutStyle(LayoutWrapper * layoutWrapper,const SizeF & frameSize,int32_t childCount)371 void TabBarLayoutAlgorithm::HandleSpaceBetweenOrCenterLayoutStyle(
372 LayoutWrapper* layoutWrapper, const SizeF& frameSize, int32_t childCount)
373 {
374 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
375 CHECK_NULL_VOID(layoutProperty);
376
377 if (GreatNotEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize)) || childCount <= 0 ||
378 childCount != static_cast<int32_t>(itemWidths_.size())) {
379 useItemWidth_ = false;
380 return;
381 }
382
383 childrenMainSize_ -= scrollMargin_ * 2;
384 scrollMargin_ = 0.0f;
385
386 if (GreatNotEqual(childrenMainSize_, GetContentWidth(layoutProperty, frameSize) / 2)) {
387 useItemWidth_ = false;
388 return;
389 }
390 auto additionalWidth = (GetContentWidth(layoutProperty, frameSize) / 2 - childrenMainSize_) / childCount;
391
392 for (int32_t index = 0; index < childCount; ++index) {
393 itemWidths_[index] += additionalWidth;
394 }
395 }
396
ApplyLayoutMode(LayoutWrapper * layoutWrapper,float allocatedWidth,int32_t childCount)397 void TabBarLayoutAlgorithm::ApplyLayoutMode(LayoutWrapper* layoutWrapper, float allocatedWidth, int32_t childCount)
398 {
399 auto pipelineContext = PipelineContext::GetCurrentContext();
400 CHECK_NULL_VOID(pipelineContext);
401 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
402 CHECK_NULL_VOID(tabTheme);
403 auto host = layoutWrapper->GetHostNode();
404 CHECK_NULL_VOID(host);
405 auto tabBarPattern = host->GetPattern<TabBarPattern>();
406 CHECK_NULL_VOID(tabBarPattern);
407
408 bool isVertical = true;
409 if (GreatNotEqual(allocatedWidth, tabTheme->GetHorizontalBottomTabMinWidth().ConvertToPx())) {
410 isVertical = false;
411 }
412
413 // Calculate the initial buffer and initial space request of each item.
414 for (int32_t index = 0; index < childCount; ++index) {
415 auto bottomTabBarStyle = tabBarPattern->GetBottomTabBarStyle(index);
416 if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE ||
417 bottomTabBarStyle.layoutMode != LayoutMode::AUTO) {
418 continue;
419 }
420 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
421 CHECK_NULL_VOID(childWrapper);
422 auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
423 CHECK_NULL_VOID(linearLayoutProperty);
424 auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
425 CHECK_NULL_VOID(textWrapper);
426 auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
427 CHECK_NULL_VOID(textLayoutProperty);
428 if (isVertical) {
429 linearLayoutProperty->UpdateFlexDirection(FlexDirection::COLUMN);
430 linearLayoutProperty->UpdateSpace(tabTheme->GetBottomTabBarSpace());
431 linearLayoutProperty->UpdateMainAxisAlign(bottomTabBarStyle.verticalAlign);
432 linearLayoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
433 linearLayoutProperty->SetIsVertical(true);
434 textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
435 } else {
436 linearLayoutProperty->UpdateFlexDirection(FlexDirection::ROW);
437 linearLayoutProperty->UpdateSpace(tabTheme->GetHorizontalBottomTabBarSpace());
438 linearLayoutProperty->UpdateMainAxisAlign(FlexAlign::CENTER);
439 linearLayoutProperty->UpdateCrossAxisAlign(bottomTabBarStyle.verticalAlign);
440 linearLayoutProperty->SetIsVertical(false);
441 textLayoutProperty->UpdateTextAlign(TextAlign::LEFT);
442 }
443 }
444 }
445
ApplySymmetricExtensible(LayoutWrapper * layoutWrapper,float allocatedWidth,int32_t childCount)446 void TabBarLayoutAlgorithm::ApplySymmetricExtensible(
447 LayoutWrapper* layoutWrapper, float allocatedWidth, int32_t childCount)
448 {
449 auto host = layoutWrapper->GetHostNode();
450 CHECK_NULL_VOID(host);
451 auto tabBarPattern = host->GetPattern<TabBarPattern>();
452 CHECK_NULL_VOID(tabBarPattern);
453
454 if (childCount <= 2 || static_cast<int32_t>(itemWidths_.size()) != childCount) {
455 useItemWidth_ = false;
456 for (int32_t index = 0; index < static_cast<int32_t>(itemWidths_.size()); ++index) {
457 itemWidths_[index] = allocatedWidth;
458 }
459 return;
460 }
461
462 std::vector<float> leftBuffers(childCount);
463 std::vector<float> rightBuffers(childCount);
464 std::vector<float> spaceRequests(childCount);
465
466 // Calculate the initial buffer and initial space request of each item.
467 for (int32_t index = 0; index < childCount; ++index) {
468 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
469 CHECK_NULL_VOID(childWrapper);
470 auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
471 CHECK_NULL_VOID(linearLayoutProperty);
472 if (GreatNotEqual(itemWidths_[index], allocatedWidth)) {
473 if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE ||
474 !tabBarPattern->GetBottomTabBarStyle(index).symmetricExtensible || index == 0 ||
475 index == childCount - 1) {
476 spaceRequests[index] = 0.0f;
477 } else {
478 spaceRequests[index] = (itemWidths_[index] - allocatedWidth) / 2;
479 }
480 leftBuffers[index] = 0.0f;
481 rightBuffers[index] = 0.0f;
482 } else {
483 if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE) {
484 leftBuffers[index] = 0.0f;
485 rightBuffers[index] = 0.0f;
486 } else {
487 leftBuffers[index] = (index == 0 ? 0.0f : (allocatedWidth - itemWidths_[index]) / 2);
488 rightBuffers[index] = (index == childCount - 1 ? 0.0f : (allocatedWidth - itemWidths_[index]) / 2);
489 }
490 spaceRequests[index] = 0.0f;
491 }
492 }
493
494 // Decide the used buffer and used space request of each item.
495 for (int32_t index = 1; index < childCount - 1; ++index) {
496 auto actualRequest = std::min(std::min(rightBuffers[index - 1], leftBuffers[index + 1]), spaceRequests[index]);
497 spaceRequests[index] = actualRequest;
498 rightBuffers[index - 1] = actualRequest;
499 leftBuffers[index + 1] = actualRequest;
500 }
501
502 spaceRequests[0] = 0.0f;
503 spaceRequests[childCount - 1] = 0.0f;
504
505 leftBuffers[1] = 0.0f;
506 rightBuffers[childCount - 2] = 0.0f;
507
508 CalculateItemWidthsForSymmetricExtensible(
509 layoutWrapper, childCount, spaceRequests, leftBuffers, rightBuffers, allocatedWidth);
510 }
511
CalculateItemWidthsForSymmetricExtensible(LayoutWrapper * layoutWrapper,int32_t childCount,const std::vector<float> & spaceRequests,const std::vector<float> & leftBuffers,const std::vector<float> & rightBuffers,float allocatedWidth)512 void TabBarLayoutAlgorithm::CalculateItemWidthsForSymmetricExtensible(LayoutWrapper* layoutWrapper, int32_t childCount,
513 const std::vector<float>& spaceRequests, const std::vector<float>& leftBuffers,
514 const std::vector<float>& rightBuffers, float allocatedWidth)
515 {
516 auto host = layoutWrapper->GetHostNode();
517 CHECK_NULL_VOID(host);
518 auto tabBarPattern = host->GetPattern<TabBarPattern>();
519 CHECK_NULL_VOID(tabBarPattern);
520
521 if ((static_cast<int32_t>(spaceRequests.size()) != childCount) ||
522 (static_cast<int32_t>(leftBuffers.size()) != childCount) ||
523 (static_cast<int32_t>(rightBuffers.size()) != childCount) ||
524 (static_cast<int32_t>(itemWidths_.size()) != childCount)) {
525 return;
526 }
527
528 for (int32_t index = 0; index < childCount; ++index) {
529 if (tabBarPattern->GetTabBarStyle(index) != TabBarStyle::BOTTOMTABBATSTYLE) {
530 itemWidths_[index] = allocatedWidth;
531 continue;
532 }
533 if (!NearZero(spaceRequests[index])) {
534 itemWidths_[index] = allocatedWidth + spaceRequests[index] * 2;
535 } else if (!NearZero(leftBuffers[index]) || !NearZero(rightBuffers[index])) {
536 itemWidths_[index] = allocatedWidth - leftBuffers[index] - rightBuffers[index];
537 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
538 CHECK_NULL_VOID(childWrapper);
539 auto imageWrapper = childWrapper->GetOrCreateChildByIndex(0);
540 CHECK_NULL_VOID(imageWrapper);
541 auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(imageWrapper->GetLayoutProperty());
542 CHECK_NULL_VOID(imageLayoutProperty);
543
544 // Adjust margin to keep the position of current item.
545 auto leftMargin = rightBuffers[index];
546 auto rightMargin = leftBuffers[index];
547 if (GreatNotEqual(leftMargin, rightMargin)) {
548 leftMargin -= rightMargin;
549 rightMargin = 0.0f;
550 } else {
551 rightMargin -= leftMargin;
552 leftMargin = 0.0f;
553 }
554 imageLayoutProperty->UpdateMargin(
555 { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {} });
556 auto textWrapper = childWrapper->GetOrCreateChildByIndex(1);
557 CHECK_NULL_VOID(textWrapper);
558 auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
559 CHECK_NULL_VOID(textLayoutProperty);
560 textLayoutProperty->UpdateMargin(
561 { CalcLength(Dimension(leftMargin)), CalcLength(Dimension(rightMargin)), {}, {} });
562 auto linearLayoutProperty = AceType::DynamicCast<LinearLayoutProperty>(childWrapper->GetLayoutProperty());
563 CHECK_NULL_VOID(linearLayoutProperty);
564 if (linearLayoutProperty->GetFlexDirection().value_or(FlexDirection::COLUMN) == FlexDirection::ROW) {
565 imageLayoutProperty->UpdateMargin({ CalcLength(Dimension(leftMargin)), {}, {}, {} });
566 textLayoutProperty->UpdateMargin({ {}, CalcLength(Dimension(rightMargin)), {}, {} });
567 }
568 } else {
569 itemWidths_[index] = allocatedWidth;
570 }
571 }
572 }
573
ApplyBarGridAlign(const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & frameSize) const574 float TabBarLayoutAlgorithm::ApplyBarGridAlign(
575 const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& frameSize) const
576 {
577 if (!layoutProperty->GetBarGridAlign()) {
578 return 0.0f;
579 }
580 auto option = layoutProperty->GetBarGridAlign().value();
581 auto gridSizeType = GetGridSizeType(frameSize);
582 int32_t columnNum = -1;
583 if (gridSizeType == GridSizeType::SM) {
584 columnNum = option.sm;
585 if (columnNum > SM_COLUMN_NUM) {
586 return 0.0f;
587 }
588 } else if (gridSizeType == GridSizeType::MD) {
589 columnNum = option.md;
590 if (columnNum > MD_COLUMN_NUM) {
591 return 0.0f;
592 }
593 } else if (gridSizeType == GridSizeType::LG) {
594 columnNum = option.lg;
595 if (columnNum > LG_COLUMN_NUM) {
596 return 0.0f;
597 }
598 } else {
599 return 0.0f;
600 }
601 if (columnNum < 0 || columnNum % 2) {
602 return 0.0f;
603 }
604 auto gridWidth = GetGridWidth(option, frameSize, columnNum);
605 return (frameSize.Width() - gridWidth) / 2;
606 }
607
Layout(LayoutWrapper * layoutWrapper)608 void TabBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
609 {
610 tabItemOffset_.clear();
611 CHECK_NULL_VOID(layoutWrapper);
612 auto geometryNode = layoutWrapper->GetGeometryNode();
613 CHECK_NULL_VOID(geometryNode);
614 auto axis = GetAxis(layoutWrapper);
615 auto frameSize = geometryNode->GetPaddingSize();
616
617 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
618 CHECK_NULL_VOID(layoutProperty);
619 int32_t indicator = layoutProperty->GetIndicatorValue(0);
620 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED &&
621 tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE && axis == Axis::VERTICAL) {
622 indicator_ = indicator;
623 auto space = frameSize.Height() / 4;
624 OffsetF childOffset = OffsetF(0.0f, space);
625 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
626 return;
627 }
628 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED &&
629 tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
630 indicator_ = indicator;
631 currentOffset_ = 0.0f;
632 OffsetF childOffset = OffsetF(0.0f, 0.0f);
633 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
634 return;
635 }
636 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
637 childrenMainSize_ <= frameSize.MainSize(axis)) {
638 indicator_ = indicator;
639 auto frontSpace = (frameSize.MainSize(axis) - childrenMainSize_) / 2;
640 OffsetF childOffset = (axis == Axis::HORIZONTAL ? OffsetF(frontSpace, 0.0f) : OffsetF(0.0f, frontSpace));
641 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
642 return;
643 }
644 if ((indicator != indicator_ || (indicator == indicator_ && needSetCentered_)) &&
645 layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
646 if (childrenMainSize_ > frameSize.MainSize(axis) && tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE &&
647 axis == Axis::HORIZONTAL) {
648 OffsetF childOffset = OffsetF(currentOffset_, 0.0f);
649 indicator_ = indicator;
650 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
651 return;
652 }
653 indicator_ = indicator;
654 auto space = GetSpace(layoutWrapper, indicator, frameSize, axis);
655 float frontChildrenMainSize = CalculateFrontChildrenMainSize(layoutWrapper, indicator, axis);
656 if (space < 0.0f) {
657 OffsetF childOffset = (axis == Axis::HORIZONTAL ? OffsetF(-frontChildrenMainSize, 0.0f)
658 : OffsetF(0.0f, -frontChildrenMainSize));
659 currentOffset_ = -frontChildrenMainSize;
660 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
661 return;
662 }
663 if (frontChildrenMainSize < space) {
664 OffsetF childOffset = OffsetF(0.0f, 0.0f);
665 currentOffset_ = 0.0f;
666 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
667 return;
668 }
669 float backChildrenMainSize = CalculateBackChildrenMainSize(layoutWrapper, indicator, axis);
670 if (backChildrenMainSize < space) {
671 auto scrollableDistance = std::max(childrenMainSize_ - frameSize.MainSize(axis), 0.0f);
672 currentOffset_ = -scrollableDistance;
673 OffsetF childOffset =
674 (axis == Axis::HORIZONTAL ? OffsetF(-scrollableDistance, 0.0f) : OffsetF(0.0f, -scrollableDistance));
675 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
676 return;
677 }
678 auto scrollableDistance = std::max(frontChildrenMainSize - space, 0.0f);
679 currentOffset_ = -scrollableDistance;
680 OffsetF childOffset =
681 (axis == Axis::HORIZONTAL ? OffsetF(-scrollableDistance, 0.0f) : OffsetF(0.0f, -scrollableDistance));
682 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
683 return;
684 }
685 if (tabBarStyle_ != TabBarStyle::SUBTABBATSTYLE || axis == Axis::VERTICAL ||
686 previousChildrenMainSize_ != childrenMainSize_) {
687 auto scrollableDistance = std::max(childrenMainSize_ - frameSize.MainSize(axis), 0.0f);
688 currentOffset_ = std::clamp(currentOffset_, -scrollableDistance, 0.0f);
689 }
690 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
691 currentOffset_ = 0.0f;
692 }
693 OffsetF childOffset = (axis == Axis::HORIZONTAL ? OffsetF(currentOffset_, 0.0f) : OffsetF(0.0f, currentOffset_));
694 indicator_ = indicator;
695 LayoutChildren(layoutWrapper, frameSize, axis, childOffset);
696 }
697
GetAxis(LayoutWrapper * layoutWrapper) const698 Axis TabBarLayoutAlgorithm::GetAxis(LayoutWrapper* layoutWrapper) const
699 {
700 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
701 CHECK_NULL_RETURN(layoutProperty, Axis::HORIZONTAL);
702 return layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
703 }
704
GetSpace(LayoutWrapper * layoutWrapper,int32_t indicator,const SizeF & frameSize,Axis axis)705 float TabBarLayoutAlgorithm::GetSpace(
706 LayoutWrapper* layoutWrapper, int32_t indicator, const SizeF& frameSize, Axis axis)
707 {
708 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(indicator);
709 if (!childWrapper) {
710 return 0.0f;
711 }
712 auto childGeometryNode = childWrapper->GetGeometryNode();
713 auto childFrameSize = childGeometryNode->GetMarginFrameSize();
714 return (frameSize.MainSize(axis) - childFrameSize.MainSize(axis)) / 2;
715 }
716
CalculateFrontChildrenMainSize(LayoutWrapper * layoutWrapper,int32_t indicator,Axis axis)717 float TabBarLayoutAlgorithm::CalculateFrontChildrenMainSize(LayoutWrapper* layoutWrapper, int32_t indicator, Axis axis)
718 {
719 float frontChildrenMainSize = scrollMargin_;
720 for (int32_t index = 0; index < indicator; ++index) {
721 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
722 if (!childWrapper) {
723 return 0.0f;
724 }
725 auto childGeometryNode = childWrapper->GetGeometryNode();
726 auto childFrameSize = childGeometryNode->GetMarginFrameSize();
727 frontChildrenMainSize += childFrameSize.MainSize(axis);
728 }
729 return indicator == 0 ? 0.0f : frontChildrenMainSize;
730 }
731
LayoutChildren(LayoutWrapper * layoutWrapper,const SizeF & frameSize,Axis axis,OffsetF & childOffset)732 void TabBarLayoutAlgorithm::LayoutChildren(
733 LayoutWrapper* layoutWrapper, const SizeF& frameSize, Axis axis, OffsetF& childOffset)
734 {
735 auto pipelineContext = PipelineContext::GetCurrentContext();
736 CHECK_NULL_VOID(pipelineContext);
737 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
738 CHECK_NULL_VOID(tabTheme);
739 auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
740 if (childCount < 0) {
741 return;
742 }
743 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
744 CHECK_NULL_VOID(layoutProperty);
745
746 if (layoutProperty->GetPaddingProperty()) {
747 childOffset += OffsetF(
748 layoutProperty->GetPaddingProperty()->left.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx(), 0.0f);
749 }
750
751 if (layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
752 childrenMainSize_ > frameSize.MainSize(axis) && axis == Axis::HORIZONTAL) {
753 childOffset += OffsetF(scrollMargin_, 0);
754 }
755
756 std::vector<OffsetF> childOffsetDelta;
757 for (int32_t index = 0; index < childCount; ++index) {
758 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
759 if (!childWrapper) {
760 childOffsetDelta.emplace_back(OffsetF());
761 continue;
762 }
763 auto childGeometryNode = childWrapper->GetGeometryNode();
764 auto childFrameSize = childGeometryNode->GetMarginFrameSize();
765 OffsetF centerOffset = (axis == Axis::HORIZONTAL)
766 ? OffsetF(0, (frameSize.Height() - childFrameSize.Height()) / 2.0)
767 : OffsetF((frameSize.Width() - childFrameSize.Width()) / 2.0, 0);
768 childOffsetDelta.emplace_back(childOffset + centerOffset - childGeometryNode->GetMarginFrameOffset());
769 childGeometryNode->SetMarginFrameOffset(childOffset + centerOffset);
770 childWrapper->Layout();
771 tabItemOffset_.emplace_back(childOffset);
772
773 childOffset +=
774 axis == Axis::HORIZONTAL ? OffsetF(childFrameSize.Width(), 0.0f) : OffsetF(0.0f, childFrameSize.Height());
775 }
776 tabItemOffset_.emplace_back(childOffset);
777 LayoutMask(layoutWrapper, childOffsetDelta);
778 }
779
LayoutMask(LayoutWrapper * layoutWrapper,const std::vector<OffsetF> & childOffsetDelta)780 void TabBarLayoutAlgorithm::LayoutMask(LayoutWrapper* layoutWrapper, const std::vector<OffsetF>& childOffsetDelta)
781 {
782 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
783 CHECK_NULL_VOID(layoutProperty);
784 auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
785 if (childCount < 0) {
786 return;
787 }
788 auto selectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount);
789 CHECK_NULL_VOID(selectedMaskWrapper);
790 auto unselectedMaskWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount + 1);
791 CHECK_NULL_VOID(unselectedMaskWrapper);
792 for (int32_t i = 0; i < MASK_COUNT; i++) {
793 auto currentWrapper = (i == 0 ? selectedMaskWrapper : unselectedMaskWrapper);
794 auto currentMask = (i == 0 ? layoutProperty->GetSelectedMask().value_or(-1)
795 : layoutProperty->GetUnselectedMask().value_or(-1));
796 if (currentMask < 0) {
797 currentWrapper->GetGeometryNode()->SetFrameSize(SizeF());
798 } else {
799 auto offset = currentWrapper->GetGeometryNode()->GetMarginFrameOffset();
800 currentWrapper->GetGeometryNode()->SetMarginFrameOffset(offset + childOffsetDelta[currentMask]);
801 auto imageWrapper = currentWrapper->GetOrCreateChildByIndex(0);
802 CHECK_NULL_VOID(imageWrapper);
803 auto imageNode = imageWrapper->GetHostNode();
804 CHECK_NULL_VOID(imageNode);
805 auto imageRenderContext = imageNode->GetRenderContext();
806 CHECK_NULL_VOID(imageRenderContext);
807 imageRenderContext->SetVisible(true);
808 }
809 currentWrapper->Layout();
810 }
811 }
812
CalculateBackChildrenMainSize(LayoutWrapper * layoutWrapper,int32_t indicator,Axis axis)813 float TabBarLayoutAlgorithm::CalculateBackChildrenMainSize(LayoutWrapper* layoutWrapper, int32_t indicator, Axis axis)
814 {
815 float backChildrenMainSize = scrollMargin_;
816 auto childCount = layoutWrapper->GetTotalChildCount() - MASK_COUNT;
817 for (int32_t index = indicator + 1; index < childCount; ++index) {
818 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
819 if (!childWrapper) {
820 return 0.0f;
821 }
822 auto childGeometryNode = childWrapper->GetGeometryNode();
823 auto childFrameSize = childGeometryNode->GetMarginFrameSize();
824 backChildrenMainSize += childFrameSize.MainSize(axis);
825 }
826 return indicator == childCount - 1 ? 0.0f : backChildrenMainSize;
827 }
828
GetGridSizeType(const SizeF & frameSize) const829 GridSizeType TabBarLayoutAlgorithm::GetGridSizeType(const SizeF& frameSize) const
830 {
831 auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TAB_BAR);
832 CHECK_NULL_RETURN(gridColumnInfo, GridSizeType::UNDEFINED);
833 auto parent = gridColumnInfo->GetParent();
834 CHECK_NULL_RETURN(parent, GridSizeType::UNDEFINED);
835 parent->BuildColumnWidth(frameSize.Width());
836 return parent->GetSizeType();
837 }
838
GetGridWidth(const BarGridColumnOptions & option,const SizeF & frameSize,int32_t columns) const839 float TabBarLayoutAlgorithm::GetGridWidth(
840 const BarGridColumnOptions& option, const SizeF& frameSize, int32_t columns) const
841 {
842 auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::TAB_BAR);
843 CHECK_NULL_RETURN(gridColumnInfo, 0.0f);
844 auto parent = gridColumnInfo->GetParent();
845 CHECK_NULL_RETURN(parent, 0.0f);
846 parent->SetGutterWidth(option.gutter);
847 parent->SetMarginLeft(option.margin);
848 parent->SetMarginRight(option.margin);
849 parent->BuildColumnWidth(frameSize.Width());
850 if (columns < 0) {
851 return gridColumnInfo->GetMaxWidth();
852 }
853 return gridColumnInfo->GetWidth(columns);
854 }
855
GetContentWidth(const RefPtr<TabBarLayoutProperty> & layoutProperty,const SizeF & frameSize) const856 float TabBarLayoutAlgorithm::GetContentWidth(
857 const RefPtr<TabBarLayoutProperty>& layoutProperty, const SizeF& frameSize) const
858 {
859 const auto& padding = layoutProperty->GetPaddingProperty();
860 CHECK_NULL_RETURN(padding, frameSize.Width());
861 auto left = padding->left.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx();
862 auto right = padding->right.value_or(CalcLength(0.0_vp)).GetDimension().ConvertToPx();
863 return Positive(frameSize.Width() - left - right) ? frameSize.Width() - left - right : 0.0f;
864 }
865
UpdateHorizontalPadding(LayoutWrapper * layoutWrapper,float horizontalPadding) const866 void TabBarLayoutAlgorithm::UpdateHorizontalPadding(LayoutWrapper* layoutWrapper, float horizontalPadding) const
867 {
868 auto layoutProperty = AceType::DynamicCast<TabBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
869 CHECK_NULL_VOID(layoutProperty);
870
871 layoutProperty->UpdatePadding(
872 { CalcLength(Dimension(horizontalPadding)), CalcLength(Dimension(horizontalPadding)), {}, {} });
873 auto host = layoutWrapper->GetHostNode();
874 CHECK_NULL_VOID(host);
875 auto hostLayoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
876 CHECK_NULL_VOID(hostLayoutProperty);
877 hostLayoutProperty->UpdatePadding(
878 { CalcLength(Dimension(horizontalPadding)), CalcLength(Dimension(horizontalPadding)), {}, {} });
879 auto geometryNode = layoutWrapper->GetGeometryNode();
880 CHECK_NULL_VOID(geometryNode);
881 geometryNode->UpdatePaddingWithBorder({ horizontalPadding, horizontalPadding, 0.0f, 0.0f });
882 }
883
AdjustFixedItem(const RefPtr<LayoutWrapper> & childWrapper,const OptionalSizeF & frameSize,Axis axis) const884 void TabBarLayoutAlgorithm::AdjustFixedItem(
885 const RefPtr<LayoutWrapper>& childWrapper, const OptionalSizeF& frameSize, Axis axis) const
886 {
887 auto geometryNode = childWrapper->GetGeometryNode();
888 CHECK_NULL_VOID(geometryNode);
889 if (axis == Axis::HORIZONTAL &&
890 GreatNotEqual(geometryNode->GetMarginFrameSize().MainSize(axis), frameSize.Width().value_or(0.0f))) {
891 geometryNode->SetFrameSize(
892 SizeF(frameSize.Width().value_or(0.0f), geometryNode->GetMarginFrameSize().MainSize(Axis::VERTICAL)));
893 } else if (axis == Axis::VERTICAL &&
894 GreatNotEqual(geometryNode->GetMarginFrameSize().MainSize(axis), frameSize.Height().value_or(0.0f))) {
895 geometryNode->SetFrameSize(
896 SizeF(geometryNode->GetMarginFrameSize().MainSize(Axis::HORIZONTAL), frameSize.Height().value_or(0.0f)));
897 }
898 }
899 } // namespace OHOS::Ace::NG
900