• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/list/list_item_group_layout_algorithm.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components/common/layout/grid_system_manager.h"
20 #include "core/components_ng/pattern/list/list_item_group_layout_property.h"
21 #include "core/components_ng/pattern/list/list_item_group_pattern.h"
22 #include "core/components_ng/pattern/list/list_item_pattern.h"
23 #include "core/components_ng/pattern/list/list_lanes_layout_algorithm.h"
24 #include "core/components_ng/property/measure_utils.h"
25 
26 namespace OHOS::Ace::NG {
27 
28 namespace {
29 constexpr uint32_t GRID_COUNTS_4 = 4;
30 constexpr uint32_t GRID_COUNTS_6 = 6;
31 constexpr uint32_t GRID_COUNTS_8 = 8;
32 constexpr uint32_t GRID_COUNTS_12 = 12;
33 
GetMaxGridCounts(const RefPtr<GridColumnInfo> & columnInfo)34 uint32_t GetMaxGridCounts(const RefPtr<GridColumnInfo>& columnInfo)
35 {
36     CHECK_NULL_RETURN(columnInfo, GRID_COUNTS_8);
37     auto currentColumns = columnInfo->GetParent()->GetColumns();
38     auto maxGridCounts = GRID_COUNTS_8;
39     switch (currentColumns) {
40         case GRID_COUNTS_4:
41             maxGridCounts = GRID_COUNTS_4;
42             break;
43         case GRID_COUNTS_8:
44             maxGridCounts = GRID_COUNTS_6;
45             break;
46         case GRID_COUNTS_12:
47             maxGridCounts = GRID_COUNTS_8;
48             break;
49         default:
50             break;
51     }
52     return maxGridCounts;
53 }
54 } // namespace
55 
Measure(LayoutWrapper * layoutWrapper)56 void ListItemGroupLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
57 {
58     CHECK_NULL_VOID(listLayoutProperty_);
59     auto layoutProperty = AceType::DynamicCast<ListItemGroupLayoutProperty>(layoutWrapper->GetLayoutProperty());
60     CHECK_NULL_VOID(layoutProperty);
61     axis_ = listLayoutProperty_->GetListDirection().value_or(Axis::VERTICAL);
62     auto contentConstraint = layoutProperty->GetContentLayoutConstraint().value();
63     auto contentIdealSize = CreateIdealSize(
64         contentConstraint, axis_, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT_CROSS_AXIS));
65 
66     auto mainPercentRefer = GetMainAxisSize(contentConstraint.percentReference, axis_);
67     auto space = layoutProperty->GetSpace().value_or(Dimension(0));
68 
69     auto layoutConstraint = layoutProperty->GetLayoutConstraint().value();
70     CalculateLanes(listLayoutProperty_, layoutConstraint, contentIdealSize.CrossSize(axis_), axis_);
71     auto itemLayoutConstraint = layoutProperty->CreateChildConstraint();
72     isCardStyle_ = IsCardStyleForListItemGroup(layoutWrapper);
73     if (isCardStyle_) {
74         auto maxWidth = GetListItemGroupMaxWidth(contentConstraint.parentIdealSize, layoutProperty) -
75                         layoutProperty->CreatePaddingAndBorder().Width();
76         contentIdealSize.SetCrossSize(maxWidth, axis_);
77     }
78     UpdateListItemConstraint(contentIdealSize, itemLayoutConstraint);
79     auto headerFooterLayoutConstraint = layoutProperty->CreateChildConstraint();
80     headerFooterLayoutConstraint.maxSize.SetMainSize(Infinity<float>(), axis_);
81     spaceWidth_ = ConvertToPx(space, layoutConstraint.scaleProperty, mainPercentRefer).value_or(0);
82     if (layoutProperty->GetDivider().has_value()) {
83         auto divider = layoutProperty->GetDivider().value();
84         std::optional<float> dividerSpace = divider.strokeWidth.ConvertToPx();
85         if (dividerSpace.has_value()) {
86             spaceWidth_ = std::max(spaceWidth_, dividerSpace.value());
87         }
88     }
89     UpdateReferencePos(layoutProperty);
90     totalItemCount_ = layoutWrapper->GetTotalChildCount() - itemStartIndex_;
91 
92     totalMainSize_ = layoutWrapper->GetGeometryNode()->GetPaddingSize().MainSize(axis_);
93     if (headerIndex_ >= 0) {
94         auto headerWrapper = layoutWrapper->GetOrCreateChildByIndex(headerIndex_);
95         headerWrapper->Measure(headerFooterLayoutConstraint);
96         headerMainSize_ = GetMainAxisSize(headerWrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
97     }
98     if (footerIndex_ >= 0) {
99         auto footerWrapper = layoutWrapper->GetOrCreateChildByIndex(footerIndex_);
100         footerWrapper->Measure(headerFooterLayoutConstraint);
101         footerMainSize_ = GetMainAxisSize(footerWrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
102     }
103     totalMainSize_ = std::max(totalMainSize_, headerMainSize_ + footerMainSize_);
104     MeasureListItem(layoutWrapper, itemLayoutConstraint);
105     if (!itemPosition_.empty()) {
106         if (GetEndIndex() == totalItemCount_ - 1) {
107             totalMainSize_ = GetEndPosition() + footerMainSize_;
108         } else {
109             totalMainSize_ = std::max(totalMainSize_, GetEndPosition() + footerMainSize_);
110         }
111     }
112 
113     auto crossSize = contentIdealSize.CrossSize(axis_);
114     if (crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) {
115         contentIdealSize.SetCrossSize(GetChildMaxCrossSize(layoutWrapper, axis_), axis_);
116     }
117     contentIdealSize.SetMainSize(totalMainSize_, axis_);
118     const auto& padding = layoutProperty->CreatePaddingAndBorder();
119     AddPaddingToSize(padding, contentIdealSize);
120     layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
121     layoutWrapper->SetCacheCount(listLayoutProperty_->GetCachedCountValue(1) * lanes_);
122 }
123 
GetListItemGroupMaxWidth(const OptionalSizeF & parentIdealSize,RefPtr<LayoutProperty> layoutProperty)124 float ListItemGroupLayoutAlgorithm::GetListItemGroupMaxWidth(
125     const OptionalSizeF& parentIdealSize, RefPtr<LayoutProperty> layoutProperty)
126 {
127     RefPtr<GridColumnInfo> columnInfo;
128     columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::LIST_CARD);
129     columnInfo->GetParent()->BuildColumnWidth();
130     auto maxGridWidth = static_cast<float>(columnInfo->GetWidth(GetMaxGridCounts(columnInfo)));
131     auto parentWidth = parentIdealSize.CrossSize(axis_).value() + layoutProperty->CreatePaddingAndBorder().Width();
132     auto maxWidth = std::min(parentWidth, maxGridWidth);
133     return maxWidth;
134 }
135 
Layout(LayoutWrapper * layoutWrapper)136 void ListItemGroupLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
137 {
138     const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
139     CHECK_NULL_VOID(layoutProperty);
140     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
141     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
142     MinusPaddingToSize(padding, size);
143     auto left = padding.left.value_or(0.0f);
144     auto top = padding.top.value_or(0.0f);
145     auto paddingOffset = OffsetF(left, top);
146     float crossSize = GetCrossAxisSize(size, axis_);
147     CHECK_NULL_VOID(listLayoutProperty_);
148     itemAlign_ = listLayoutProperty_->GetListItemAlign().value_or(V2::ListItemAlign::START);
149 
150     if (headerIndex_ >= 0 || footerIndex_ >= 0) {
151         LayoutHeaderFooter(layoutWrapper, paddingOffset, crossSize);
152     }
153     // layout items.
154     LayoutListItem(layoutWrapper, paddingOffset, crossSize);
155 }
156 
UpdateListItemConstraint(const OptionalSizeF & selfIdealSize,LayoutConstraintF & contentConstraint)157 void ListItemGroupLayoutAlgorithm::UpdateListItemConstraint(const OptionalSizeF& selfIdealSize,
158     LayoutConstraintF& contentConstraint)
159 {
160     contentConstraint.parentIdealSize = selfIdealSize;
161     contentConstraint.maxSize.SetMainSize(Infinity<float>(), axis_);
162     auto crossSizeOptional = selfIdealSize.CrossSize(axis_);
163     if (crossSizeOptional.has_value()) {
164         float crossSize = crossSizeOptional.value();
165         if (lanes_ > 1) {
166             crossSize = (crossSize + laneGutter_) / lanes_ - laneGutter_;
167             crossSize = crossSize <= 0 ? 1 : crossSize;
168         }
169         if (maxLaneLength_.has_value() && maxLaneLength_.value() < crossSize) {
170             crossSize = maxLaneLength_.value();
171         }
172         contentConstraint.percentReference.SetCrossSize(crossSize, axis_);
173         contentConstraint.parentIdealSize.SetCrossSize(crossSize, axis_);
174         contentConstraint.maxSize.SetCrossSize(crossSize, axis_);
175         if (minLaneLength_.has_value()) {
176             contentConstraint.minSize.SetCrossSize(minLaneLength_.value(), axis_);
177         }
178     }
179 }
180 
GetChildMaxCrossSize(LayoutWrapper * layoutWrapper,Axis axis)181 float ListItemGroupLayoutAlgorithm::GetChildMaxCrossSize(LayoutWrapper* layoutWrapper, Axis axis)
182 {
183     float maxCrossSize = 0.0f;
184     for (const auto& pos : itemPosition_) {
185         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(pos.first, false);
186         if (!wrapper) {
187             continue;
188         }
189         auto getGeometryNode = wrapper->GetGeometryNode();
190         if (!getGeometryNode) {
191             continue;
192         }
193         maxCrossSize = std::max(maxCrossSize, getGeometryNode->GetMarginFrameSize().CrossSize(axis));
194     }
195     return maxCrossSize;
196 }
197 
UpdateReferencePos(RefPtr<LayoutProperty> layoutProperty)198 void ListItemGroupLayoutAlgorithm::UpdateReferencePos(RefPtr<LayoutProperty> layoutProperty)
199 {
200     const auto& padding = layoutProperty->CreatePaddingAndBorder();
201     const auto& margin = layoutProperty->CreateMargin();
202     auto offsetBeforeContent_ = axis_ == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
203     auto offsetAfterContent_ = axis_ == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
204     offsetBeforeContent_ += axis_ == Axis::HORIZONTAL ? margin.left.value_or(0) : margin.top.value_or(0);
205     offsetAfterContent_ += axis_ == Axis::HORIZONTAL ? margin.right.value_or(0) : margin.bottom.value_or(0);
206     forwardLayout_ ? referencePos_ += offsetBeforeContent_ : referencePos_ -= offsetAfterContent_;
207 }
208 
NeedMeasureItem() const209 bool ListItemGroupLayoutAlgorithm::NeedMeasureItem() const
210 {
211     if (forwardLayout_ && headerIndex_ >= 0) {
212         if (GreatNotEqual(headerMainSize_, endPos_ - referencePos_)) {
213             return false;
214         }
215     }
216     if (forwardLayout_ && footerIndex_ >= 0) {
217         if (LessNotEqual(totalMainSize_ - footerMainSize_, startPos_ - referencePos_)) {
218             return false;
219         }
220     }
221     if (!forwardLayout_ && headerIndex_ >= 0) {
222         if (GreatNotEqual(headerMainSize_, endPos_ - (referencePos_ - totalMainSize_))) {
223             return false;
224         }
225     }
226     if (!forwardLayout_ && footerIndex_ >= 0) {
227         if (LessNotEqual(totalMainSize_ - footerMainSize_, startPos_ - (referencePos_ - totalMainSize_))) {
228             return false;
229         }
230     }
231     return true;
232 }
233 
LayoutListItemAll(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,float startPos)234 void ListItemGroupLayoutAlgorithm::LayoutListItemAll(LayoutWrapper* layoutWrapper,
235     const LayoutConstraintF& layoutConstraint, float startPos)
236 {
237     int32_t currentIndex = -1;
238     float currentEndPos = startPos;
239     float currentStartPos = 0.0f;
240     while (currentIndex < totalItemCount_) {
241         currentStartPos = currentEndPos;
242         int32_t count = MeasureALineForward(layoutWrapper, layoutConstraint, currentIndex,
243             currentStartPos, currentEndPos);
244         if (count == 0) {
245             break;
246         }
247         if (currentIndex < (totalItemCount_ - 1)) {
248             currentEndPos += spaceWidth_;
249         }
250 
251     }
252 }
253 
MeasureListItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint)254 void ListItemGroupLayoutAlgorithm::MeasureListItem(
255     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint)
256 {
257     if (totalItemCount_ <= 0) {
258         totalMainSize_ = headerMainSize_ + footerMainSize_;
259         layoutWrapper->RemoveAllChildInRenderTree();
260         itemPosition_.clear();
261         return;
262     }
263     int32_t startIndex = 0;
264     int32_t endIndex = totalItemCount_ - 1;
265     float startPos = headerMainSize_;
266     float endPos = totalMainSize_ - footerMainSize_;
267     prevStartPos_ = startPos_;
268     prevEndPos_ = endPos_;
269     if (needAllLayout_) {
270         needAllLayout_ = false;
271         itemPosition_.clear();
272         layoutWrapper->RemoveAllChildInRenderTree();
273         LayoutListItemAll(layoutWrapper, layoutConstraint, startPos);
274         return;
275     }
276     if (targetIndex_) {
277         startPos_ = -Infinity<float>();
278         endPos_ = Infinity<float>();
279     }
280     if (jumpIndex_.has_value()) {
281         if (jumpIndex_.value() == LAST_ITEM) {
282             jumpIndex_ = totalItemCount_ - 1;
283         }
284         auto jumpIndex = jumpIndex_.value();
285         if (jumpIndex < 0 || jumpIndex >= totalItemCount_) {
286             jumpIndex = 0;
287         }
288         if (forwardLayout_) {
289             startIndex = jumpIndex;
290         } else {
291             endIndex = jumpIndex;
292         }
293         itemPosition_.clear();
294         layoutWrapper->RemoveAllChildInRenderTree();
295         jumpIndex_.reset();
296     } else if (!itemPosition_.empty()) {
297         if (itemPosition_.begin()->first > 0 || (forwardLayout_ && Negative(referencePos_))) {
298             startPos = itemPosition_.begin()->second.first;
299         }
300         endPos = itemPosition_.rbegin()->second.second;
301         startIndex = std::min(GetStartIndex(), totalItemCount_ - 1);
302         endIndex = std::min(GetEndIndex(), totalItemCount_ - 1);
303         itemPosition_.clear();
304         layoutWrapper->RemoveAllChildInRenderTree();
305     } else if (!NeedMeasureItem()) {
306         layoutWrapper->RemoveAllChildInRenderTree();
307         itemPosition_.clear();
308         return;
309     }
310     LOGD("referencePos_ is %{public}f, startPos_: %{public}f, endPos_: %{public}f, forward:%{public}d",
311         referencePos_, startPos_, endPos_, forwardLayout_);
312     if (forwardLayout_) {
313         startIndex = GetLanesFloor(startIndex);
314         LOGD("startIndex:%{public}d, startPos:%{public}f", startIndex, startPos);
315         MeasureForward(layoutWrapper, layoutConstraint, startIndex, startPos);
316     } else {
317         endIndex = (lanes_ <= 1) ? endIndex : (endIndex - endIndex % lanes_ + lanes_ - 1);
318         endIndex = endIndex >= totalItemCount_ ? totalItemCount_ - 1 : endIndex;
319         LOGD("endIndex:%{public}d, endPos:%{public}f", endIndex, endPos);
320         MeasureBackward(layoutWrapper, layoutConstraint, endIndex, endPos);
321     }
322 }
323 
MeasureALineForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t & currentIndex,float startPos,float & endPos)324 int32_t ListItemGroupLayoutAlgorithm::MeasureALineForward(LayoutWrapper* layoutWrapper,
325     const LayoutConstraintF& layoutConstraint, int32_t& currentIndex, float startPos, float& endPos)
326 {
327     float mainLen = 0.0f;
328     int32_t cnt = 0;
329     int32_t lanes = lanes_ > 1 ? lanes_ : 1;
330     for (int32_t i = 0; i < lanes && currentIndex + 1 <= totalItemCount_; i++) {
331         auto wrapper = GetListItem(layoutWrapper, currentIndex + 1);
332         if (!wrapper) {
333             break;
334         }
335         cnt++;
336         ++currentIndex;
337         {
338             ACE_SCOPED_TRACE("ListLayoutAlgorithm::MeasureListItem:%d", currentIndex);
339             wrapper->Measure(layoutConstraint);
340         }
341         mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
342     }
343     if (cnt > 0) {
344         endPos = startPos + mainLen;
345         for (int32_t i = 0; i < cnt; i++) {
346             itemPosition_[currentIndex - i] = { startPos, endPos };
347         }
348     }
349     return cnt;
350 }
351 
MeasureALineBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t & currentIndex,float endPos,float & startPos)352 int32_t ListItemGroupLayoutAlgorithm::MeasureALineBackward(LayoutWrapper* layoutWrapper,
353     const LayoutConstraintF& layoutConstraint, int32_t& currentIndex, float endPos, float& startPos)
354 {
355     float mainLen = 0.0f;
356     int32_t cnt = 0;
357     int32_t lanes = lanes_ > 1 ? lanes_ : 1;
358     for (int32_t i = 0; i < lanes && currentIndex - 1 >= 0; i++) {
359         auto wrapper = GetListItem(layoutWrapper, currentIndex - 1);
360         if (!wrapper) {
361             break;
362         }
363         --currentIndex;
364         cnt++;
365         {
366             ACE_SCOPED_TRACE("ListLayoutAlgorithm::MeasureListItem:%d", currentIndex);
367             wrapper->Measure(layoutConstraint);
368         }
369         mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
370         if (currentIndex % lanes == 0) {
371             break;
372         }
373     }
374     if (cnt > 0) {
375         startPos = endPos - mainLen;
376         for (int32_t i = 0; i < cnt; i++) {
377             itemPosition_[currentIndex + i] = { startPos, endPos };
378         }
379     }
380     return cnt;
381 }
382 
MeasureForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex,float startPos)383 void ListItemGroupLayoutAlgorithm::MeasureForward(LayoutWrapper* layoutWrapper,
384     const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos)
385 {
386     float currentEndPos = startPos;
387     float currentStartPos = 0.0f;
388     int32_t currentIndex = startIndex - 1;
389     while (LessOrEqual(currentEndPos, endPos_ - referencePos_)) {
390         currentStartPos = currentEndPos;
391         int32_t count = MeasureALineForward(layoutWrapper, layoutConstraint, currentIndex,
392             currentStartPos, currentEndPos);
393         if (count == 0) {
394             break;
395         }
396         if (currentIndex < (totalItemCount_ - 1)) {
397             currentEndPos += spaceWidth_;
398         }
399         LOGD("LayoutForward: %{public}d current start pos: %{public}f, current end pos: %{public}f", currentIndex,
400             currentStartPos, currentEndPos);
401         if (targetIndex_ && GreatOrEqual(startIndex, targetIndex_.value())) {
402             startPos_ = prevStartPos_;
403             endPos_ = prevEndPos_;
404             targetIndex_.reset();
405         }
406     }
407 
408     currentStartPos = startPos - spaceWidth_;
409     currentIndex = startIndex;
410     while (currentIndex > 0  && GreatOrEqual(currentStartPos, startPos_ - referencePos_)) {
411         currentEndPos = currentStartPos;
412         int32_t count = MeasureALineBackward(layoutWrapper, layoutConstraint, currentIndex,
413             currentEndPos, currentStartPos);
414         if (count == 0) {
415             break;
416         }
417         if (currentIndex > 0) {
418             currentStartPos = currentStartPos - spaceWidth_;
419         }
420     }
421 }
422 
MeasureBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t endIndex,float endPos)423 void ListItemGroupLayoutAlgorithm::MeasureBackward(LayoutWrapper* layoutWrapper,
424     const LayoutConstraintF& layoutConstraint, int32_t endIndex, float endPos)
425 {
426     float currentStartPos = endPos;
427     float currentEndPos = 0.0f;
428     auto currentIndex = endIndex + 1;
429     while (GreatOrEqual(currentStartPos, startPos_ - (referencePos_ - totalMainSize_))) {
430         currentEndPos = currentStartPos;
431         int32_t count = MeasureALineBackward(layoutWrapper, layoutConstraint, currentIndex,
432             currentEndPos, currentStartPos);
433         if (count == 0) {
434             break;
435         }
436         if (currentIndex > 0) {
437             currentStartPos = currentStartPos - spaceWidth_;
438         }
439         LOGD("LayoutBackward: %{public}d current start pos: %{public}f, current end pos: %{public}f", currentIndex,
440             currentStartPos, currentEndPos);
441         if (targetIndex_ && LessOrEqual(endIndex, targetIndex_.value())) {
442             startPos_ = prevStartPos_;
443             endPos_ = prevEndPos_;
444             targetIndex_.reset();
445         }
446     }
447 
448     if (itemPosition_.empty()) {
449         return;
450     }
451 
452     if (currentStartPos < headerMainSize_) {
453         auto delta = headerMainSize_ - currentStartPos;
454         for (auto& pos : itemPosition_) {
455             pos.second.first += delta;
456             pos.second.second += delta;
457         }
458         totalMainSize_ = std::max(totalMainSize_ + delta, GetEndPosition() + footerMainSize_);
459     } else if (GetStartIndex() == 0 && currentStartPos > headerMainSize_) {
460         auto delta = currentStartPos - headerMainSize_;
461         for (auto& pos : itemPosition_) {
462             pos.second.first -= delta;
463             pos.second.second -= delta;
464         }
465         totalMainSize_ -= delta;
466     }
467 }
468 
CheckRecycle(const RefPtr<LayoutWrapper> & layoutWrapper,float startPos,float endPos,float referencePos,bool forwardLayout)469 void ListItemGroupLayoutAlgorithm::CheckRecycle(
470     const RefPtr<LayoutWrapper>& layoutWrapper, float startPos, float endPos, float referencePos, bool forwardLayout)
471 {
472     // Mark inactive in wrapper.
473     if (forwardLayout) {
474         for (auto pos = itemPosition_.begin(); pos != itemPosition_.end();) {
475             if (GreatOrEqual(pos->second.second, startPos - referencePos)) {
476                 break;
477             }
478             LOGI("recycle item:%{public}d", pos->first);
479             layoutWrapper->RemoveChildInRenderTree(pos->first);
480             itemPosition_.erase(pos++);
481         }
482         return;
483     }
484     std::list<int32_t> removeIndexes;
485     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
486         if (LessOrEqual(pos->second.first, endPos - (referencePos - totalMainSize_))) {
487             break;
488         }
489         layoutWrapper->RemoveChildInRenderTree(pos->first);
490         removeIndexes.emplace_back(pos->first);
491     }
492     for (const auto& index : removeIndexes) {
493         itemPosition_.erase(index);
494     }
495 }
496 
LayoutListItem(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize)497 void ListItemGroupLayoutAlgorithm::LayoutListItem(LayoutWrapper* layoutWrapper,
498     const OffsetF& paddingOffset, float crossSize)
499 {
500     // layout items.
501     for (auto& pos : itemPosition_) {
502         auto wrapper = GetListItem(layoutWrapper, pos.first);
503         if (!wrapper) {
504             LOGI("wrapper is out of boundary");
505             continue;
506         }
507 
508         auto offset = paddingOffset;
509         int32_t laneIndex = pos.first % lanes_;
510         float childCrossSize = GetCrossAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
511         float laneCrossOffset = CalculateLaneCrossOffset(crossSize / lanes_, childCrossSize);
512         if (axis_ == Axis::VERTICAL) {
513             offset =
514                 offset + OffsetF(0, pos.second.first) + OffsetF(laneCrossOffset, 0) +
515                 OffsetF(((crossSize + laneGutter_) / lanes_ - laneGutter_) * laneIndex + laneGutter_ * laneIndex, 0);
516         } else {
517             offset =
518                 offset + OffsetF(pos.second.first, 0) + OffsetF(0, laneCrossOffset) +
519                 OffsetF(0, ((crossSize + laneGutter_) / lanes_ - laneGutter_) * laneIndex + laneGutter_ * laneIndex);
520         }
521         SetListItemIndex(layoutWrapper, wrapper, pos.first);
522         wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
523         wrapper->Layout();
524     }
525 }
526 
LayoutHeaderFooter(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize)527 void ListItemGroupLayoutAlgorithm::LayoutHeaderFooter(LayoutWrapper* layoutWrapper,
528     const OffsetF& paddingOffset, float crossSize)
529 {
530     OffsetF selfOffset = layoutWrapper->GetGeometryNode()->GetPaddingOffset();
531     selfOffset = selfOffset - listLayoutProperty_->CreatePaddingAndBorder().Offset();
532     float mainPos = GetMainAxisOffset(selfOffset, axis_);
533     float headerMainSize = 0.0f;
534     V2::StickyStyle sticky = listLayoutProperty_->GetStickyStyle().value_or(V2::StickyStyle::NONE);
535     if (headerIndex_ >= 0) {
536         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(headerIndex_);
537         CHECK_NULL_VOID(wrapper);
538         headerMainSize = wrapper->GetGeometryNode()->GetFrameSize().MainSize(axis_);
539         float headerPos = 0.0f;
540         if (sticky == V2::StickyStyle::BOTH || sticky == V2::StickyStyle::HEADER) {
541             float endPos = itemPosition_.empty() ? headerMainSize : itemPosition_.rbegin()->second.second;
542             float stickyPos = -mainPos;
543             if (stickyPos + headerMainSize > endPos) {
544                 stickyPos = endPos - headerMainSize;
545             }
546             if (stickyPos > headerPos) {
547                 headerPos = stickyPos;
548             }
549         }
550         LayoutIndex(wrapper, paddingOffset, crossSize, headerPos);
551     }
552 
553     if (footerIndex_ >= 0) {
554         float endPos = totalMainSize_ - footerMainSize_;
555         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(footerIndex_);
556         CHECK_NULL_VOID(wrapper);
557         float const listMainSize = endPos_ - startPos_;
558         if (Positive(listMainSize) && (sticky == V2::StickyStyle::BOTH || sticky == V2::StickyStyle::FOOTER)) {
559             auto footerMainSize = wrapper->GetGeometryNode()->GetFrameSize().MainSize(axis_);
560             float stickyPos = listMainSize - mainPos - footerMainSize;
561             if (stickyPos < headerMainSize) {
562                 stickyPos = headerMainSize;
563             }
564             if (stickyPos < endPos) {
565                 endPos = stickyPos;
566             }
567         }
568         LayoutIndex(wrapper, paddingOffset, crossSize, endPos);
569     }
570 }
571 
LayoutIndex(const RefPtr<LayoutWrapper> & wrapper,const OffsetF & paddingOffset,float crossSize,float startPos)572 void ListItemGroupLayoutAlgorithm::LayoutIndex(const RefPtr<LayoutWrapper>& wrapper, const OffsetF& paddingOffset,
573     float crossSize, float startPos)
574 {
575     CHECK_NULL_VOID_NOLOG(wrapper);
576     auto offset = paddingOffset;
577     float childCrossSize = GetCrossAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
578     float laneCrossOffset = CalculateLaneCrossOffset(crossSize, childCrossSize);
579     if (axis_ == Axis::VERTICAL) {
580         offset = offset + OffsetF(laneCrossOffset, startPos);
581     } else {
582         offset = offset + OffsetF(startPos, laneCrossOffset);
583     }
584     wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
585     wrapper->Layout();
586 }
587 
CalculateLaneCrossOffset(float crossSize,float childCrossSize)588 float ListItemGroupLayoutAlgorithm::CalculateLaneCrossOffset(float crossSize, float childCrossSize)
589 {
590     float delta = crossSize - childCrossSize;
591     if (LessOrEqual(delta, 0.0f)) {
592         return 0.0f;
593     }
594     switch (itemAlign_) {
595         case OHOS::Ace::V2::ListItemAlign::START:
596             return 0.0f;
597         case OHOS::Ace::V2::ListItemAlign::CENTER:
598             return delta / 2; /* 2:average */
599         case OHOS::Ace::V2::ListItemAlign::END:
600             return delta;
601         default:
602             LOGW("Invalid ListItemAlign: %{public}d", itemAlign_);
603             return 0.0f;
604     }
605 }
606 
CalculateLanes(const RefPtr<ListLayoutProperty> & layoutProperty,const LayoutConstraintF & layoutConstraint,std::optional<float> crossSizeOptional,Axis axis)607 void ListItemGroupLayoutAlgorithm::CalculateLanes(const RefPtr<ListLayoutProperty>& layoutProperty,
608     const LayoutConstraintF& layoutConstraint, std::optional<float> crossSizeOptional, Axis axis)
609 {
610     int32_t lanes = layoutProperty->GetLanes().value_or(1);
611     lanes = lanes > 1 ? lanes : 1;
612     if (crossSizeOptional.has_value()) {
613         if (layoutProperty->GetLaneMinLength().has_value()) {
614             minLaneLength_ = ConvertToPx(layoutProperty->GetLaneMinLength().value(),
615                 layoutConstraint.scaleProperty, crossSizeOptional.value());
616         }
617         if (layoutProperty->GetLaneMaxLength().has_value()) {
618             maxLaneLength_ = ConvertToPx(layoutProperty->GetLaneMaxLength().value(),
619                 layoutConstraint.scaleProperty, crossSizeOptional.value());
620         }
621         if (layoutProperty->GetLaneGutter().has_value()) {
622             auto laneGutter = ConvertToPx(
623                 layoutProperty->GetLaneGutter().value(), layoutConstraint.scaleProperty, crossSizeOptional.value());
624             laneGutter_ = laneGutter.value();
625         }
626     }
627     lanes_ = ListLanesLayoutAlgorithm::CalculateLanesParam(
628         minLaneLength_, maxLaneLength_, lanes, crossSizeOptional, laneGutter_);
629 }
630 
SetListItemIndex(const LayoutWrapper * groupLayoutWrapper,const RefPtr<LayoutWrapper> & itemLayoutWrapper,int32_t indexInGroup)631 void ListItemGroupLayoutAlgorithm::SetListItemIndex(const LayoutWrapper* groupLayoutWrapper,
632     const RefPtr<LayoutWrapper>& itemLayoutWrapper, int32_t indexInGroup)
633 {
634     auto host = itemLayoutWrapper->GetHostNode();
635     CHECK_NULL_VOID_NOLOG(host);
636     auto listItem = host->GetPattern<ListItemPattern>();
637     CHECK_NULL_VOID_NOLOG(listItem);
638     listItem->SetIndexInListItemGroup(indexInGroup);
639 
640     host = groupLayoutWrapper->GetHostNode();
641     CHECK_NULL_VOID_NOLOG(host);
642     auto listItemGroup = host->GetPattern<ListItemGroupPattern>();
643     CHECK_NULL_VOID_NOLOG(listItemGroup);
644     listItem->SetIndexInList(listItemGroup->GetIndexInList());
645 }
646 
IsCardStyleForListItemGroup(const LayoutWrapper * groupLayoutWrapper)647 bool ListItemGroupLayoutAlgorithm::IsCardStyleForListItemGroup(const LayoutWrapper* groupLayoutWrapper)
648 {
649     auto host = groupLayoutWrapper->GetHostNode();
650     CHECK_NULL_RETURN(host, false);
651     auto listItemGroup = host->GetPattern<ListItemGroupPattern>();
652     CHECK_NULL_RETURN(listItemGroup, false);
653     return listItemGroup->GetListItemGroupStyle() == V2::ListItemGroupStyle::CARD;
654 }
655 } // namespace OHOS::Ace::NG
656