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