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 totalItemCount_ = layoutWrapper->GetTotalChildCount() - itemStartIndex_;
59 CHECK_NULL_VOID(listLayoutProperty_);
60 auto layoutProperty = AceType::DynamicCast<ListItemGroupLayoutProperty>(layoutWrapper->GetLayoutProperty());
61 CHECK_NULL_VOID(layoutProperty);
62 axis_ = listLayoutProperty_->GetListDirection().value_or(Axis::VERTICAL);
63 layoutDirection_ = listLayoutProperty_->GetNonAutoLayoutDirection();
64 const auto& padding = layoutProperty->CreatePaddingAndBorder();
65 paddingBeforeContent_ = axis_ == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
66 paddingAfterContent_ = axis_ == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
67 auto contentConstraint = layoutProperty->GetContentLayoutConstraint().value();
68 auto contentIdealSize = CreateIdealSize(
69 contentConstraint, axis_, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT_CROSS_AXIS));
70
71 auto mainPercentRefer = GetMainAxisSize(contentConstraint.percentReference, axis_);
72 auto space = layoutProperty->GetSpace().value_or(Dimension(0));
73
74 auto layoutConstraint = layoutProperty->GetLayoutConstraint().value();
75 CalculateLanes(listLayoutProperty_, layoutConstraint, contentIdealSize.CrossSize(axis_), axis_);
76 childLayoutConstraint_ = layoutProperty->CreateChildConstraint();
77 isCardStyle_ = IsCardStyleForListItemGroup(layoutWrapper);
78 if (isCardStyle_) {
79 auto maxWidth = GetListItemGroupMaxWidth(contentConstraint.parentIdealSize, layoutProperty) -
80 layoutProperty->CreatePaddingAndBorder().Width();
81 contentIdealSize.SetCrossSize(maxWidth, axis_);
82 }
83 UpdateListItemConstraint(contentIdealSize, childLayoutConstraint_);
84 referencePos_ = UpdateReferencePos(layoutProperty, forwardLayout_, referencePos_);
85 totalMainSize_ = layoutWrapper->GetGeometryNode()->GetPaddingSize().MainSize(axis_);
86 spaceWidth_ = ConvertToPx(space, layoutConstraint.scaleProperty, mainPercentRefer).value_or(0);
87 if (Negative(spaceWidth_) || GreatOrEqual(spaceWidth_, endPos_ - startPos_)) {
88 spaceWidth_ = 0.0f;
89 }
90 if (layoutProperty->GetDivider().has_value()) {
91 auto divider = layoutProperty->GetDivider().value();
92 std::optional<float> dividerSpace = divider.strokeWidth.ConvertToPx();
93 if (GreatOrEqual(dividerSpace.value(), endPos_ - startPos_)) {
94 dividerSpace.reset();
95 }
96 if (dividerSpace.has_value()) {
97 spaceWidth_ = std::max(spaceWidth_, dividerSpace.value());
98 }
99 }
100 MeasureHeaderFooter(layoutWrapper);
101 totalMainSize_ = std::max(totalMainSize_, headerMainSize_ + footerMainSize_);
102 if (childrenSize_) {
103 posMap_->UpdateGroupPosMap(totalItemCount_, GetLanes(), spaceWidth_, childrenSize_,
104 headerMainSize_, footerMainSize_);
105 totalMainSize_ = posMap_->GetTotalHeight();
106 }
107 if (cacheParam_) {
108 MeasureCacheItem(layoutWrapper);
109 } else {
110 MeasureListItem(layoutWrapper, childLayoutConstraint_);
111 UpdateCachedItemPosition(listLayoutProperty_->GetCachedCountWithDefault() * lanes_);
112 }
113 childrenSize_ ? AdjustByPosMap() : AdjustItemPosition();
114
115 auto crossSize = contentIdealSize.CrossSize(axis_);
116 if (crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) {
117 contentIdealSize.SetCrossSize(GetChildMaxCrossSize(layoutWrapper, axis_), axis_);
118 }
119 contentIdealSize.SetMainSize(totalMainSize_, axis_);
120 AddPaddingToSize(padding, contentIdealSize);
121 layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
122 layoutWrapper->SetCacheCount(listLayoutProperty_->GetCachedCountWithDefault() * lanes_);
123 }
124
UpdateCachedItemPosition(int32_t cacheCount)125 void ListItemGroupLayoutAlgorithm::UpdateCachedItemPosition(int32_t cacheCount)
126 {
127 if (!itemPosition_.empty()) {
128 auto iter = cachedItemPosition_.begin();
129 while (iter != cachedItemPosition_.end()) {
130 if ((iter->first >= GetStartIndex() && iter->first <= GetEndIndex()) ||
131 iter->first < (GetStartIndex() - cacheCount) || iter->first > (GetEndIndex() + cacheCount)) {
132 iter = cachedItemPosition_.erase(iter);
133 } else {
134 iter++;
135 }
136 }
137 }
138 }
139
GetListItemGroupMaxWidth(const OptionalSizeF & parentIdealSize,RefPtr<LayoutProperty> layoutProperty)140 float ListItemGroupLayoutAlgorithm::GetListItemGroupMaxWidth(
141 const OptionalSizeF& parentIdealSize, RefPtr<LayoutProperty> layoutProperty)
142 {
143 RefPtr<GridColumnInfo> columnInfo;
144 columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::LIST_CARD);
145 columnInfo->GetParent()->BuildColumnWidth();
146 auto maxGridWidth = static_cast<float>(columnInfo->GetWidth(GetMaxGridCounts(columnInfo)));
147 auto parentWidth = parentIdealSize.CrossSize(axis_).value() + layoutProperty->CreatePaddingAndBorder().Width();
148 auto maxWidth = std::min(parentWidth, maxGridWidth);
149 if (LessNotEqual(maxGridWidth, layoutProperty->CreatePaddingAndBorder().Width())) {
150 TAG_LOGI(AceLogTag::ACE_LIST,
151 "ListItemGroup reset to parentWidth since grid_col width:%{public}f, border:%{public}f",
152 maxGridWidth, layoutProperty->CreatePaddingAndBorder().Width());
153 maxWidth = parentWidth;
154 }
155 return maxWidth;
156 }
157
Layout(LayoutWrapper * layoutWrapper)158 void ListItemGroupLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
159 {
160 const auto& layoutProperty = AceType::DynamicCast<ListItemGroupLayoutProperty>(layoutWrapper->GetLayoutProperty());
161 CHECK_NULL_VOID(layoutProperty);
162 auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
163 auto padding = layoutProperty->CreatePaddingAndBorder();
164 MinusPaddingToSize(padding, size);
165 auto left = padding.left.value_or(0.0f);
166 auto top = padding.top.value_or(0.0f);
167 auto paddingOffset = OffsetF(left, top);
168 float crossSize = GetCrossAxisSize(size, axis_);
169 CHECK_NULL_VOID(listLayoutProperty_);
170 itemAlign_ = listLayoutProperty_->GetListItemAlign().value_or(V2::ListItemAlign::START);
171 bool show = listLayoutProperty_->GetShowCachedItemsValue(false);
172 layoutProperty->UpdateListLanes(listLayoutProperty_->GetLanes(),
173 listLayoutProperty_->GetLaneMinLength(), listLayoutProperty_->GetLaneMaxLength());
174 SetActiveChildRange(layoutWrapper, listLayoutProperty_->GetCachedCountWithDefault(), show);
175
176 if (cacheParam_) {
177 LayoutCacheItem(layoutWrapper, paddingOffset, crossSize, show);
178 CheckUpdateGroupAndItemPos(layoutWrapper, paddingOffset, crossSize);
179 } else {
180 LayoutListItem(layoutWrapper, paddingOffset, crossSize);
181 }
182 if (headerIndex_ >= 0 || footerIndex_ >= 0) {
183 if (layoutDirection_ == TextDirection::RTL && axis_ == Axis::HORIZONTAL) {
184 LayoutHeaderFooterRTL(layoutWrapper, paddingOffset, crossSize);
185 } else {
186 LayoutHeaderFooterLTR(layoutWrapper, paddingOffset, crossSize);
187 }
188 }
189 }
190
CheckUpdateGroupAndItemPos(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize)191 void ListItemGroupLayoutAlgorithm::CheckUpdateGroupAndItemPos(LayoutWrapper* layoutWrapper,
192 const OffsetF& paddingOffset, float crossSize)
193 {
194 if (childrenSize_ || (NearZero(adjustReferenceDelta_) && NearZero(adjustTotalSize_))) {
195 return;
196 }
197 auto offset = layoutWrapper->GetGeometryNode()->GetMarginFrameOffset();
198 if (axis_ == Axis::VERTICAL) {
199 offset += OffsetF(0.0f, adjustReferenceDelta_);
200 } else {
201 if (layoutDirection_ == TextDirection::RTL) {
202 offset -= OffsetF(adjustTotalSize_ + adjustReferenceDelta_, 0.0f);
203 } else {
204 offset += OffsetF(adjustReferenceDelta_, 0.0f);
205 }
206 }
207 layoutWrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
208 LayoutListItem(layoutWrapper, paddingOffset, crossSize);
209 }
210
SyncGeometry(RefPtr<LayoutWrapper> & wrapper)211 void ListItemGroupLayoutAlgorithm::SyncGeometry(RefPtr<LayoutWrapper>& wrapper)
212 {
213 CHECK_NULL_VOID(wrapper);
214 auto host = wrapper->GetHostNode();
215 CHECK_NULL_VOID(host);
216 host->ForceSyncGeometryNode();
217 host->ResetLayoutAlgorithm();
218 }
219
CheckNeedMeasure(const RefPtr<LayoutWrapper> & layoutWrapper) const220 bool ListItemGroupLayoutAlgorithm::CheckNeedMeasure(const RefPtr<LayoutWrapper>& layoutWrapper) const
221 {
222 if (layoutWrapper->CheckNeedForceMeasureAndLayout()) {
223 return true;
224 }
225 auto geometryNode = layoutWrapper->GetGeometryNode();
226 CHECK_NULL_RETURN(geometryNode, true);
227 auto constraint = geometryNode->GetParentLayoutConstraint();
228 CHECK_NULL_RETURN(constraint, true);
229 return constraint.value() != childLayoutConstraint_;
230 }
231
MeasureHeaderFooter(LayoutWrapper * layoutWrapper)232 void ListItemGroupLayoutAlgorithm::MeasureHeaderFooter(LayoutWrapper* layoutWrapper)
233 {
234 const auto& layoutProperty = layoutWrapper->GetLayoutProperty();
235 auto headerFooterLayoutConstraint = layoutProperty->CreateChildConstraint();
236 headerFooterLayoutConstraint.maxSize.SetMainSize(Infinity<float>(), axis_);
237 RefPtr<LayoutWrapper> headerWrapper = headerIndex_ >= 0 ?
238 layoutWrapper->GetOrCreateChildByIndex(headerIndex_) : nullptr;
239 RefPtr<LayoutWrapper> footerWrapper = footerIndex_ >= 0 ?
240 layoutWrapper->GetOrCreateChildByIndex(footerIndex_) : nullptr;
241 if (headerWrapper) {
242 headerWrapper->Measure(headerFooterLayoutConstraint);
243 headerMainSize_ = GetMainAxisSize(headerWrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
244 }
245 if (footerWrapper) {
246 footerWrapper->Measure(headerFooterLayoutConstraint);
247 footerMainSize_ = GetMainAxisSize(footerWrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
248 }
249 }
250
SetActiveChildRange(LayoutWrapper * layoutWrapper,int32_t cacheCount,bool show)251 void ListItemGroupLayoutAlgorithm::SetActiveChildRange(LayoutWrapper* layoutWrapper, int32_t cacheCount, bool show)
252 {
253 if (!itemPosition_.empty()) {
254 auto start = itemStartIndex_ + itemPosition_.begin()->first;
255 auto end = itemStartIndex_ + itemPosition_.rbegin()->first;
256 int32_t cachedCountForward = cachedItemPosition_.empty() ? 0 :
257 std::max(itemStartIndex_ + cachedItemPosition_.rbegin()->first - end, 0);
258 int32_t cachedCountBackward = cachedItemPosition_.empty() ? 0 :
259 std::max(start - itemStartIndex_ - cachedItemPosition_.begin()->first, 0);
260 layoutWrapper->SetActiveChildRange(start, end, cachedCountBackward, cachedCountForward, show);
261 return;
262 } else if (show && !cachedItemPosition_.empty()) {
263 int32_t start = cachedItemPosition_.begin()->first;
264 int32_t end = cachedItemPosition_.rbegin()->first;
265 int32_t count = end - start + 1;
266 if (start == 0) {
267 layoutWrapper->SetActiveChildRange(-1, itemStartIndex_ - 1, 0, count, show);
268 } else if (end == totalItemCount_ - 1) {
269 int32_t endLimit = end + itemStartIndex_ + 1;
270 layoutWrapper->SetActiveChildRange(endLimit, endLimit, count, 0, show);
271 }
272 return;
273 }
274 auto listPadding = listLayoutProperty_->CreatePaddingAndBorder().Offset();
275 auto offset = layoutWrapper->GetGeometryNode()->GetMarginFrameOffset();
276 if (LessNotEqual(GetMainAxisOffset(offset, axis_), GetMainAxisOffset(listPadding, axis_))) {
277 int32_t index = totalItemCount_ + itemStartIndex_;
278 layoutWrapper->SetActiveChildRange(index, index, cacheCount * lanes_, 0);
279 } else {
280 layoutWrapper->SetActiveChildRange(-1, itemStartIndex_ - 1, 0, cacheCount * lanes_);
281 }
282 }
283
UpdateListItemConstraint(const OptionalSizeF & selfIdealSize,LayoutConstraintF & contentConstraint)284 void ListItemGroupLayoutAlgorithm::UpdateListItemConstraint(const OptionalSizeF& selfIdealSize,
285 LayoutConstraintF& contentConstraint)
286 {
287 contentConstraint.parentIdealSize = selfIdealSize;
288 contentConstraint.maxSize.SetMainSize(Infinity<float>(), axis_);
289 auto crossSizeOptional = selfIdealSize.CrossSize(axis_);
290 if (crossSizeOptional.has_value()) {
291 float crossSize = crossSizeOptional.value();
292 if (lanes_ > 1) {
293 crossSize = (crossSize + laneGutter_) / lanes_ - laneGutter_;
294 crossSize = crossSize <= 0 ? 1 : crossSize;
295 }
296 if (maxLaneLength_.has_value() && maxLaneLength_.value() < crossSize) {
297 crossSize = maxLaneLength_.value();
298 }
299 contentConstraint.percentReference.SetCrossSize(crossSize, axis_);
300 contentConstraint.parentIdealSize.SetCrossSize(crossSize, axis_);
301 contentConstraint.maxSize.SetCrossSize(crossSize, axis_);
302 if (minLaneLength_.has_value()) {
303 contentConstraint.minSize.SetCrossSize(minLaneLength_.value(), axis_);
304 }
305 }
306 }
307
GetChildMaxCrossSize(LayoutWrapper * layoutWrapper,Axis axis)308 float ListItemGroupLayoutAlgorithm::GetChildMaxCrossSize(LayoutWrapper* layoutWrapper, Axis axis)
309 {
310 float maxCrossSize = 0.0f;
311 for (const auto& pos : itemPosition_) {
312 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(pos.first, false);
313 if (!wrapper) {
314 continue;
315 }
316 auto getGeometryNode = wrapper->GetGeometryNode();
317 if (!getGeometryNode) {
318 continue;
319 }
320 maxCrossSize = std::max(maxCrossSize, getGeometryNode->GetMarginFrameSize().CrossSize(axis));
321 }
322 for (const auto& pos : cachedItemPosition_) {
323 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(pos.first, false);
324 if (!wrapper) {
325 continue;
326 }
327 auto getGeometryNode = wrapper->GetGeometryNode();
328 if (!getGeometryNode) {
329 continue;
330 }
331 maxCrossSize = std::max(maxCrossSize, getGeometryNode->GetMarginFrameSize().CrossSize(axis));
332 }
333 return maxCrossSize;
334 }
335
UpdateReferencePos(RefPtr<LayoutProperty> layoutProperty,bool forwardLayout,float referencePos)336 float ListItemGroupLayoutAlgorithm::UpdateReferencePos(
337 RefPtr<LayoutProperty> layoutProperty, bool forwardLayout, float referencePos)
338 {
339 const auto& padding = layoutProperty->CreatePaddingAndBorder();
340 const auto& margin = layoutProperty->CreateMargin();
341 auto offsetBeforeContent = axis_ == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
342 auto offsetAfterContent = axis_ == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
343 offsetBeforeContent += axis_ == Axis::HORIZONTAL ? margin.left.value_or(0) : margin.top.value_or(0);
344 offsetAfterContent += axis_ == Axis::HORIZONTAL ? margin.right.value_or(0) : margin.bottom.value_or(0);
345 forwardLayout ? referencePos += offsetBeforeContent : referencePos -= offsetAfterContent;
346 return referencePos;
347 }
348
NeedMeasureItem(LayoutWrapper * layoutWrapper)349 bool ListItemGroupLayoutAlgorithm::NeedMeasureItem(LayoutWrapper* layoutWrapper)
350 {
351 auto contentMainSize = layoutWrapper->GetGeometryNode()->GetPaddingSize().MainSize(axis_);
352 if (NearZero(contentMainSize)) {
353 return true;
354 }
355 bool layoutedEntirely = layoutedItemInfo_ && layoutedItemInfo_.value().startIndex <= 0 &&
356 layoutedItemInfo_.value().endIndex >= totalItemCount_ - 1;
357 if (forwardLayout_) {
358 if (childrenSize_ && needAdjustRefPos_) {
359 referencePos_ -= (totalMainSize_ - posMap_->GetPrevTotalHeight());
360 refPos_ -= (totalMainSize_ - posMap_->GetPrevTotalHeight());
361 }
362 if (GreatNotEqual(headerMainSize_, endPos_ - referencePos_)) {
363 return false;
364 }
365 if (LessNotEqual(totalMainSize_ - footerMainSize_, startPos_ - referencePos_)) {
366 auto listPadding = listLayoutProperty_->CreatePaddingAndBorder().Offset();
367 auto offset = layoutWrapper->GetGeometryNode()->GetMarginFrameOffset();
368 bool belowList = GreatOrEqual(GetMainAxisOffset(offset, axis_), GetMainAxisOffset(listPadding, axis_));
369 if (belowList && totalItemCount_ > 0 && !layoutedEntirely) {
370 return true;
371 }
372 return false;
373 }
374 } else {
375 if (childrenSize_ && needAdjustRefPos_) {
376 referencePos_ += (totalMainSize_ - posMap_->GetPrevTotalHeight());
377 refPos_ += (totalMainSize_ - posMap_->GetPrevTotalHeight());
378 }
379 if (GreatNotEqual(headerMainSize_, endPos_ - (referencePos_ - totalMainSize_))) {
380 auto listPadding = GetMainAxisOffset(listLayoutProperty_->CreatePaddingAndBorder().Offset(), axis_);
381 auto offset = GetMainAxisOffset(layoutWrapper->GetGeometryNode()->GetMarginFrameOffset(), axis_);
382 auto groupBottom = offset + totalMainSize_;
383 auto aboveList = LessOrEqual(groupBottom, listPadding);
384 if (aboveList && totalItemCount_ > 0 && !layoutedEntirely) {
385 return true;
386 }
387 return false;
388 }
389 if (LessNotEqual(totalMainSize_ - footerMainSize_, startPos_ - (referencePos_ - totalMainSize_))) {
390 return false;
391 }
392 }
393 return true;
394 }
395
LayoutListItemAll(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,float startPos)396 void ListItemGroupLayoutAlgorithm::LayoutListItemAll(LayoutWrapper* layoutWrapper,
397 const LayoutConstraintF& layoutConstraint, float startPos)
398 {
399 int32_t currentIndex = -1;
400 float currentEndPos = startPos;
401 float currentStartPos = 0.0f;
402 while (currentIndex < totalItemCount_) {
403 currentStartPos = currentEndPos;
404 int32_t count = MeasureALineForward(layoutWrapper, layoutConstraint, currentIndex,
405 currentStartPos, currentEndPos);
406 if (count == 0) {
407 break;
408 }
409 if (currentIndex < (totalItemCount_ - 1)) {
410 currentEndPos += spaceWidth_;
411 }
412 }
413 }
414
ClearItemPosition()415 void ListItemGroupLayoutAlgorithm::ClearItemPosition()
416 {
417 itemPosition_.clear();
418 cachedItemPosition_.clear();
419 forwardCachedIndex_ = -1;
420 backwardCachedIndex_ = INT_MAX;
421 }
422
CheckNeedAllLayout(const RefPtr<LayoutWrapper> & layoutWrapper,bool forwardLayout)423 void ListItemGroupLayoutAlgorithm::CheckNeedAllLayout(const RefPtr<LayoutWrapper>& layoutWrapper, bool forwardLayout)
424 {
425 if (itemPosition_.empty()) {
426 needAllLayout_ = true;
427 return;
428 }
429 int32_t totalItemCount = layoutWrapper->GetTotalChildCount() - itemStartIndex_;
430 if (!(forwardLayout && itemPosition_.rbegin()->first == totalItemCount - 1) &&
431 !(!forwardLayout && itemPosition_.begin()->first == 0)) {
432 needAllLayout_ = true;
433 }
434 }
435
MeasureListItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint)436 void ListItemGroupLayoutAlgorithm::MeasureListItem(
437 LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint)
438 {
439 if (totalItemCount_ <= 0) {
440 if (LessNotEqual(totalMainSize_ - footerMainSize_, startPos_ - referencePos_)) {
441 adjustReferenceDelta_ = totalMainSize_ - (headerMainSize_ + footerMainSize_);
442 }
443 totalMainSize_ = headerMainSize_ + footerMainSize_;
444 itemPosition_.clear();
445 cachedItemPosition_.clear();
446 layoutedItemInfo_.reset();
447 return;
448 }
449 int32_t startIndex = 0;
450 int32_t endIndex = totalItemCount_ - 1;
451 float startPos = headerMainSize_;
452 float endPos = totalMainSize_ - footerMainSize_;
453 prevStartPos_ = startPos_;
454 prevEndPos_ = endPos_;
455 if (needAllLayout_) {
456 needAllLayout_ = false;
457 itemPosition_.clear();
458 cachedItemPosition_.clear();
459 LayoutListItemAll(layoutWrapper, layoutConstraint, startPos);
460 return;
461 }
462 if (targetIndex_) {
463 startPos_ = -Infinity<float>();
464 endPos_ = Infinity<float>();
465 }
466 if (jumpIndex_.has_value()) {
467 if (jumpIndex_.value() == LAST_ITEM) {
468 jumpIndex_ = totalItemCount_ - 1;
469 }
470 auto jumpIndex = jumpIndex_.value();
471 if (jumpIndex < 0 || jumpIndex >= totalItemCount_) {
472 jumpIndex = 0;
473 }
474 if (scrollAlign_ == ScrollAlign::CENTER || scrollAlign_ == ScrollAlign::START ||
475 scrollAlign_ == ScrollAlign::AUTO) {
476 startIndex = jumpIndex;
477 } else if (scrollAlign_ == ScrollAlign::END) {
478 endIndex = jumpIndex;
479 } else if (forwardLayout_) {
480 startIndex = jumpIndex;
481 } else {
482 endIndex = jumpIndex;
483 }
484 itemPosition_.clear();
485 cachedItemPosition_.clear();
486 jumpIndex_.reset();
487 layoutedItemInfo_.reset();
488 } else if (!itemPosition_.empty()) {
489 if (itemPosition_.begin()->first > 0 || (forwardLayout_ && Negative(referencePos_))) {
490 startPos = itemPosition_.begin()->second.startPos;
491 }
492 startIndex = GetStartIndex();
493 if (startIndex >= totalItemCount_) {
494 startIndex = totalItemCount_ - 1;
495 if (itemPosition_.begin()->first > 0) {
496 startPos = ((startPos - headerMainSize_) / GetLanesFloor(itemPosition_.begin()->first)) *
497 GetLanesFloor(startIndex) + headerMainSize_;
498 }
499 }
500 if (!isNeedMeasureFormLastItem_) {
501 endIndex = std::min(GetEndIndex(), totalItemCount_ - 1);
502 endPos = itemPosition_.rbegin()->second.endPos;
503 }
504 if (forwardLayout_) {
505 ModifyReferencePos(GetLanesFloor(startIndex), startPos);
506 } else {
507 ModifyReferencePos(GetLanesCeil(endIndex), endPos);
508 }
509 itemPosition_.clear();
510 } else if (!NeedMeasureItem(layoutWrapper)) {
511 itemPosition_.clear();
512 return;
513 }
514 if (scrollAlign_ == ScrollAlign::CENTER) {
515 startIndex = GetLanesFloor(startIndex);
516 MeasureCenter(layoutWrapper, layoutConstraint, startIndex);
517 } else if (scrollAlign_ == ScrollAlign::START) {
518 startIndex = GetLanesFloor(startIndex);
519 MeasureStart(layoutWrapper, layoutConstraint, startIndex);
520 } else if (scrollAlign_ == ScrollAlign::END) {
521 endIndex = GetLanesCeil(endIndex);
522 MeasureEnd(layoutWrapper, layoutConstraint, endIndex);
523 } else if (jumpIndex_.has_value() && scrollAlign_ == ScrollAlign::AUTO) {
524 startIndex = GetLanesFloor(startIndex);
525 MeasureAuto(layoutWrapper, layoutConstraint, startIndex);
526 } else if (forwardLayout_) {
527 startIndex = GetLanesFloor(startIndex);
528 CheckJumpForwardForBigOffset(startIndex, startPos);
529 startPos = childrenSize_ ? posMap_->GetPos(startIndex) : startPos;
530 MeasureForward(layoutWrapper, layoutConstraint, startIndex, startPos);
531 } else {
532 endIndex = GetLanesCeil(endIndex);
533 CheckJumpBackwardForBigOffset(endIndex, endPos);
534 endPos = childrenSize_ ? posMap_->GetPos(endIndex) + posMap_->GetRowHeight(endIndex) : endPos;
535 MeasureBackward(layoutWrapper, layoutConstraint, endIndex, endPos);
536 }
537 }
538
GetItemGroupPosition(int32_t index)539 std::pair<float, float> ListItemGroupLayoutAlgorithm::GetItemGroupPosition(int32_t index)
540 {
541 V2::StickyStyle sticky = listLayoutProperty_->GetStickyStyle().value_or(V2::StickyStyle::NONE);
542 if (scrollAlign_ == ScrollAlign::CENTER) {
543 auto pos = itemPosition_.find(index);
544 if (pos != itemPosition_.end()) {
545 float refPos = (pos->second.endPos + pos->second.startPos) / 2 + paddingBeforeContent_; // 2:average
546 float delta = (startPos_ + endPos_) / 2 - refPos;
547 return { delta, totalMainSize_ + paddingBeforeContent_ + paddingAfterContent_ + delta };
548 }
549 } else if (scrollAlign_ == ScrollAlign::START) {
550 auto pos = itemPosition_.find(index);
551 if (pos != itemPosition_.end()) {
552 float top = startPos_ + contentStartOffset_;
553 if (sticky == V2::StickyStyle::HEADER || sticky == V2::StickyStyle::BOTH) {
554 top += headerMainSize_;
555 }
556 float refPos = pos->second.startPos + paddingBeforeContent_;
557 float delta = top - refPos;
558 return { delta, totalMainSize_ + paddingBeforeContent_ + paddingAfterContent_ + delta };
559 }
560 } else if (scrollAlign_ == ScrollAlign::END) {
561 auto pos = itemPosition_.find(index);
562 if (pos != itemPosition_.end()) {
563 float bottom = endPos_ - contentEndOffset_;
564 if (sticky == V2::StickyStyle::FOOTER || sticky == V2::StickyStyle::BOTH) {
565 bottom -= footerMainSize_;
566 }
567 float refPos = pos->second.endPos + paddingBeforeContent_;
568 float delta = bottom - refPos;
569 return { delta, totalMainSize_ + paddingBeforeContent_ + paddingAfterContent_ + delta };
570 }
571 }
572 return { 0.0f, 0.0f };
573 }
574
GetItemHeight(int32_t index)575 float ListItemGroupLayoutAlgorithm::GetItemHeight(int32_t index)
576 {
577 auto it = itemPosition_.find(index);
578 if (it != itemPosition_.end()) {
579 return it->second.endPos - it->second.startPos;
580 }
581 return 0.0f;
582 }
583
MeasureALineAuto(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t currentIndex)584 int32_t ListItemGroupLayoutAlgorithm::MeasureALineAuto(LayoutWrapper* layoutWrapper,
585 const LayoutConstraintF& layoutConstraint, int32_t currentIndex)
586 {
587 auto wrapper = GetListItem(layoutWrapper, currentIndex);
588 if (!wrapper) {
589 return 0;
590 }
591 if (CheckNeedMeasure(wrapper)) {
592 ACE_SCOPED_TRACE("ListLayoutAlgorithm::MeasureListItem:%d", currentIndex);
593 wrapper->Measure(layoutConstraint);
594 }
595 float mainLen = GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
596 int32_t id = wrapper->GetHostNode()->GetId();
597 itemPosition_[currentIndex] = { id, 0.0f, mainLen };
598 return 1;
599 }
600
MeasureALineCenter(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t currentIndex)601 int32_t ListItemGroupLayoutAlgorithm::MeasureALineCenter(LayoutWrapper* layoutWrapper,
602 const LayoutConstraintF& layoutConstraint, int32_t currentIndex)
603 {
604 float mainLen = 0;
605 int32_t cnt = 0;
606 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
607 for (int32_t i = 0; i < lanes && currentIndex + cnt < totalItemCount_; i++) {
608 auto wrapper = GetListItem(layoutWrapper, currentIndex + cnt);
609 if (!wrapper) {
610 break;
611 }
612 if (CheckNeedMeasure(wrapper)) {
613 ACE_SCOPED_TRACE("ListLayoutAlgorithm::MeasureListItem:%d", currentIndex + cnt);
614 wrapper->Measure(layoutConstraint);
615 }
616 mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
617 cnt++;
618 }
619 if (cnt > 0) {
620 auto startPos = (startPos_ + endPos_ - mainLen) / 2; // 2:average
621 auto endPos = startPos + mainLen; // 2:average
622 for (int32_t i = 0; i < cnt; i++) {
623 auto wrapper = GetListItem(layoutWrapper, currentIndex + i);
624 int32_t id = wrapper->GetHostNode()->GetId();
625 itemPosition_[currentIndex + i] = { id, startPos, endPos };
626 }
627 }
628 return cnt;
629 }
630
MeasureALineForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t & currentIndex,float startPos,float & endPos)631 int32_t ListItemGroupLayoutAlgorithm::MeasureALineForward(LayoutWrapper* layoutWrapper,
632 const LayoutConstraintF& layoutConstraint, int32_t& currentIndex, float startPos, float& endPos)
633 {
634 float mainLen = 0.0f;
635 int32_t cnt = 0;
636 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
637 for (int32_t i = 0; i < lanes && currentIndex + 1 <= totalItemCount_; i++) {
638 auto wrapper = GetListItem(layoutWrapper, currentIndex + 1);
639 if (!wrapper) {
640 break;
641 }
642 cnt++;
643 ++currentIndex;
644 if (CheckNeedMeasure(wrapper)) {
645 ACE_SCOPED_TRACE("ListLayoutAlgorithm::MeasureListItem:%d", currentIndex);
646 wrapper->Measure(layoutConstraint);
647 }
648 mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
649 }
650 if (cnt > 0) {
651 endPos = startPos + mainLen;
652 for (int32_t i = 0; i < cnt; i++) {
653 auto wrapper = GetListItem(layoutWrapper, currentIndex - i);
654 int32_t id = wrapper->GetHostNode()->GetId();
655 itemPosition_[currentIndex - i] = { id, startPos, endPos };
656 }
657 }
658 return cnt;
659 }
660
MeasureALineBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t & currentIndex,float endPos,float & startPos)661 int32_t ListItemGroupLayoutAlgorithm::MeasureALineBackward(LayoutWrapper* layoutWrapper,
662 const LayoutConstraintF& layoutConstraint, int32_t& currentIndex, float endPos, float& startPos)
663 {
664 float mainLen = 0.0f;
665 int32_t cnt = 0;
666 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
667 for (int32_t i = 0; i < lanes && currentIndex - 1 >= 0; i++) {
668 auto wrapper = GetListItem(layoutWrapper, currentIndex - 1);
669 if (!wrapper) {
670 break;
671 }
672 --currentIndex;
673 cnt++;
674 if (CheckNeedMeasure(wrapper)) {
675 ACE_SCOPED_TRACE("ListLayoutAlgorithm::MeasureListItem:%d", currentIndex);
676 wrapper->Measure(layoutConstraint);
677 }
678 mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
679 if (currentIndex % lanes == 0) {
680 break;
681 }
682 }
683 if (cnt > 0) {
684 startPos = endPos - mainLen;
685 for (int32_t i = 0; i < cnt; i++) {
686 auto wrapper = GetListItem(layoutWrapper, currentIndex + i);
687 int32_t id = wrapper->GetHostNode()->GetId();
688 itemPosition_[currentIndex + i] = { id, startPos, endPos };
689 }
690 }
691 return cnt;
692 }
693
MeasureCenter(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex)694 void ListItemGroupLayoutAlgorithm::MeasureCenter(LayoutWrapper* layoutWrapper,
695 const LayoutConstraintF& layoutConstraint, int32_t startIndex)
696 {
697 MeasureALineCenter(layoutWrapper, layoutConstraint, startIndex);
698 MeasureJumpToItemForward(layoutWrapper, layoutConstraint, GetEndIndex() + 1, GetEndPosition());
699 MeasureJumpToItemBackward(layoutWrapper, layoutConstraint, GetStartIndex() - 1, GetStartPosition());
700
701 totalMainSize_ = GetEndPosition() - GetStartPosition() + headerMainSize_ + footerMainSize_;
702 float currentStartPos = headerMainSize_;
703 int32_t i = 0;
704 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
705 for (auto& pos : itemPosition_) {
706 float len = pos.second.endPos - pos.second.startPos;
707 pos.second.startPos = currentStartPos;
708 pos.second.endPos = currentStartPos + len;
709 i++;
710 if (i % lanes == 0) {
711 currentStartPos = pos.second.endPos + spaceWidth_;
712 }
713 }
714 }
715
MeasureAuto(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex)716 void ListItemGroupLayoutAlgorithm::MeasureAuto(LayoutWrapper* layoutWrapper,
717 const LayoutConstraintF& layoutConstraint, int32_t startIndex)
718 {
719 if (MeasureALineAuto(layoutWrapper, layoutConstraint, startIndex) == 0) {
720 return;
721 }
722
723 totalMainSize_ = GetEndPosition() - GetStartPosition() + headerMainSize_ + footerMainSize_;
724 }
725
MeasureJumpToItemForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex,float startPos)726 void ListItemGroupLayoutAlgorithm::MeasureJumpToItemForward(LayoutWrapper* layoutWrapper,
727 const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos)
728 {
729 float currentStartPos = startPos;
730 float currentEndPos = startPos;
731 int32_t currentIndex = startIndex - 1;
732 while (LessOrEqual(currentEndPos, endPos_)) {
733 currentStartPos = currentEndPos;
734 int32_t count = MeasureALineForward(layoutWrapper, layoutConstraint, currentIndex,
735 currentStartPos, currentEndPos);
736 if (count == 0) {
737 break;
738 }
739 if (currentIndex < (totalItemCount_ - 1)) {
740 currentEndPos += spaceWidth_;
741 }
742 }
743 }
744
MeasureJumpToItemBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t endIndex,float endPos)745 void ListItemGroupLayoutAlgorithm::MeasureJumpToItemBackward(LayoutWrapper* layoutWrapper,
746 const LayoutConstraintF& layoutConstraint, int32_t endIndex, float endPos)
747 {
748 float currentEndPos = endPos;
749 float currentStartPos = endPos;
750 int32_t currentIndex = endIndex + 1;
751 while (GreatOrEqual(currentStartPos, startPos_)) {
752 currentEndPos = currentStartPos;
753 int32_t count = MeasureALineBackward(layoutWrapper, layoutConstraint, currentIndex,
754 currentEndPos, currentStartPos);
755 if (count == 0) {
756 break;
757 }
758 if (currentIndex > 0) {
759 currentStartPos -= spaceWidth_;
760 }
761 }
762 }
763
MeasureStart(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex)764 void ListItemGroupLayoutAlgorithm::MeasureStart(LayoutWrapper* layoutWrapper,
765 const LayoutConstraintF& layoutConstraint, int32_t startIndex)
766 {
767 V2::StickyStyle sticky = listLayoutProperty_->GetStickyStyle().value_or(V2::StickyStyle::NONE);
768 float currentStartPos = startPos_ + contentStartOffset_;
769 if (sticky == V2::StickyStyle::HEADER || sticky == V2::StickyStyle::BOTH) {
770 currentStartPos += headerMainSize_;
771 }
772
773 MeasureJumpToItemForward(layoutWrapper, layoutConstraint, startIndex, currentStartPos);
774 if (GreatNotEqual(currentStartPos, startPos_)) {
775 MeasureJumpToItemBackward(layoutWrapper, layoutConstraint, startIndex - 1, currentStartPos);
776 }
777
778 totalMainSize_ = GetEndPosition() - GetStartPosition() + headerMainSize_ + footerMainSize_;
779 currentStartPos = headerMainSize_;
780 int32_t i = 0;
781 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
782 for (auto& pos : itemPosition_) {
783 float len = pos.second.endPos - pos.second.startPos;
784 pos.second.startPos = currentStartPos;
785 pos.second.endPos = currentStartPos + len;
786 i++;
787 if (i % lanes == 0) {
788 currentStartPos = pos.second.endPos + spaceWidth_;
789 }
790 }
791 }
792
MeasureEnd(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t endIndex)793 void ListItemGroupLayoutAlgorithm::MeasureEnd(LayoutWrapper* layoutWrapper,
794 const LayoutConstraintF& layoutConstraint, int32_t endIndex)
795 {
796 V2::StickyStyle sticky = listLayoutProperty_->GetStickyStyle().value_or(V2::StickyStyle::NONE);
797 float currentEndPos = endPos_ - contentEndOffset_;
798 if (sticky == V2::StickyStyle::FOOTER || sticky == V2::StickyStyle::BOTH) {
799 currentEndPos -= footerMainSize_;
800 }
801
802 MeasureJumpToItemBackward(layoutWrapper, layoutConstraint, endIndex, currentEndPos);
803 if (LessNotEqual(currentEndPos, endPos_)) {
804 MeasureJumpToItemForward(layoutWrapper, layoutConstraint, endIndex + 1, currentEndPos);
805 }
806
807 totalMainSize_ = GetEndPosition() - GetStartPosition() + headerMainSize_ + footerMainSize_;
808 float currentStartPos = headerMainSize_;
809 int32_t i = 0;
810 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
811 for (auto& pos : itemPosition_) {
812 float len = pos.second.endPos - pos.second.startPos;
813 pos.second.startPos = currentStartPos;
814 pos.second.endPos = currentStartPos + len;
815 i++;
816 if (i % lanes == 0) {
817 currentStartPos = pos.second.endPos + spaceWidth_;
818 }
819 }
820 }
821
CheckJumpForwardForBigOffset(int32_t & startIndex,float & startPos)822 void ListItemGroupLayoutAlgorithm::CheckJumpForwardForBigOffset(int32_t& startIndex, float& startPos)
823 {
824 if (!isNeedCheckOffset_ || childrenSize_ || !layoutedItemInfo_.has_value()) {
825 return;
826 }
827 float th = startPos_ - (endPos_ - startPos_) - referencePos_;
828 if (LessOrEqual(startPos, th)) {
829 const auto& itemInfo = layoutedItemInfo_.value();
830 auto totalHeight = (itemInfo.endPos - itemInfo.startPos + spaceWidth_);
831 auto itemCount = itemInfo.endIndex - itemInfo.startIndex + 1;
832 float averageHeight = totalHeight / itemCount;
833 float distance = startPos_ - referencePos_ - startPos;
834 int32_t jumpCount = distance / averageHeight;
835 jumpCount = std::min(jumpCount, totalItemCount_ - 1 - startIndex);
836 startPos += jumpCount * averageHeight;
837 startIndex += jumpCount;
838 }
839 }
840
CheckJumpBackwardForBigOffset(int32_t & endIndex,float & endPos)841 void ListItemGroupLayoutAlgorithm::CheckJumpBackwardForBigOffset(int32_t& endIndex, float& endPos)
842 {
843 if (!isNeedCheckOffset_ || childrenSize_ || !layoutedItemInfo_.has_value()) {
844 return;
845 }
846 float th = endPos_ + (endPos_ - startPos_) - (referencePos_ - totalMainSize_);
847 if (GreatOrEqual(endPos, th)) {
848 const auto& itemInfo = layoutedItemInfo_.value();
849 auto totalHeight = (itemInfo.endPos - itemInfo.startPos + spaceWidth_);
850 auto itemCount = itemInfo.endIndex - itemInfo.startIndex + 1;
851 float averageHeight = totalHeight / itemCount;
852 float distance = endPos - (endPos_ - (referencePos_ - totalMainSize_));
853 int32_t jumpCount = distance / averageHeight;
854 jumpCount = std::min(jumpCount, endIndex);
855 endPos -= jumpCount * averageHeight;
856 endIndex -= jumpCount;
857 }
858 }
859
MeasureForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex,float startPos)860 void ListItemGroupLayoutAlgorithm::MeasureForward(LayoutWrapper* layoutWrapper,
861 const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos)
862 {
863 float currentEndPos = startPos;
864 float currentStartPos = 0.0f;
865 int32_t currentIndex = startIndex - 1;
866 while (LessOrEqual(currentEndPos, endPos_ - referencePos_)) {
867 currentStartPos = currentEndPos;
868 int32_t count = MeasureALineForward(layoutWrapper, layoutConstraint, currentIndex,
869 currentStartPos, currentEndPos);
870 if (count == 0) {
871 break;
872 }
873 if (currentIndex < (totalItemCount_ - 1)) {
874 currentEndPos += spaceWidth_;
875 }
876 if (targetIndex_ && GreatOrEqual(startIndex, targetIndex_.value())) {
877 startPos_ = prevStartPos_;
878 endPos_ = prevEndPos_;
879 targetIndex_.reset();
880 }
881 }
882
883 currentStartPos = startPos - spaceWidth_;
884 currentIndex = startIndex;
885 float th = std::max(startPos_ - referencePos_, headerMainSize_);
886 while (currentIndex > 0 && GreatNotEqual(currentStartPos, th)) {
887 currentEndPos = currentStartPos;
888 int32_t count = MeasureALineBackward(layoutWrapper, layoutConstraint, currentIndex,
889 currentEndPos, currentStartPos);
890 if (count == 0) {
891 break;
892 }
893 if (currentIndex > 0) {
894 currentStartPos = currentStartPos - spaceWidth_;
895 }
896 }
897 }
898
MeasureBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t endIndex,float endPos)899 void ListItemGroupLayoutAlgorithm::MeasureBackward(LayoutWrapper* layoutWrapper,
900 const LayoutConstraintF& layoutConstraint, int32_t endIndex, float endPos)
901 {
902 float currentStartPos = endPos;
903 float currentEndPos = 0.0f;
904 auto currentIndex = endIndex + 1;
905 while (GreatOrEqual(currentStartPos, startPos_ - (referencePos_ - totalMainSize_))) {
906 currentEndPos = currentStartPos;
907 int32_t count = MeasureALineBackward(layoutWrapper, layoutConstraint, currentIndex,
908 currentEndPos, currentStartPos);
909 if (count == 0) {
910 break;
911 }
912 if (currentIndex > 0) {
913 currentStartPos = currentStartPos - spaceWidth_;
914 }
915 if (targetIndex_ && LessOrEqual(endIndex, targetIndex_.value())) {
916 startPos_ = prevStartPos_;
917 endPos_ = prevEndPos_;
918 targetIndex_.reset();
919 }
920 }
921 currentIndex = endIndex;
922 currentEndPos = endPos + spaceWidth_;
923 while (childrenSize_ && LessOrEqual(currentEndPos, endPos_ - (referencePos_ - totalMainSize_))) {
924 currentStartPos = currentEndPos;
925 int32_t count = MeasureALineForward(layoutWrapper, layoutConstraint, currentIndex,
926 currentStartPos, currentEndPos);
927 if (count == 0) {
928 break;
929 }
930 if (currentIndex < (totalItemCount_ - 1)) {
931 currentEndPos += spaceWidth_;
932 }
933 }
934 }
935
ModifyReferencePos(int32_t index,float pos)936 void ListItemGroupLayoutAlgorithm::ModifyReferencePos(int32_t index, float pos)
937 {
938 if (!childrenSize_ || !needAdjustRefPos_) {
939 return;
940 }
941 if (forwardLayout_ && Negative(referencePos_)) {
942 float offset = referencePos_ + pos;
943 float newReferencePos = offset - posMap_->GetPos(index);
944 refPos_ = refPos_ + newReferencePos - referencePos_;
945 referencePos_ = newReferencePos;
946 } else if (!forwardLayout_ && GreatNotEqual(referencePos_, prevContentMainSize_)) {
947 float offset = referencePos_ - posMap_->GetPrevTotalHeight() + pos - prevContentMainSize_;
948 float newReferencePos = offset + endPos_ - startPos_ + totalMainSize_ -
949 (posMap_->GetPos(index) + posMap_->GetRowHeight(index));
950 refPos_ = refPos_ + newReferencePos - referencePos_;
951 referencePos_ = newReferencePos;
952 }
953 }
954
AdjustByPosMap()955 void ListItemGroupLayoutAlgorithm::AdjustByPosMap()
956 {
957 totalMainSize_ = posMap_->GetTotalHeight();
958 if (itemPosition_.empty()) {
959 return;
960 }
961 float startPos = itemPosition_.begin()->second.startPos;
962 float offset = posMap_->GetGroupLayoutOffset(GetStartIndex(), startPos);
963 for (auto& pos : itemPosition_) {
964 pos.second.startPos += offset;
965 pos.second.endPos += offset;
966 }
967 }
968
AdjustItemPosition()969 void ListItemGroupLayoutAlgorithm::AdjustItemPosition()
970 {
971 if (itemPosition_.empty()) {
972 return;
973 }
974 float currentStartPos = GetStartPosition();
975 if (currentStartPos < headerMainSize_) {
976 auto delta = headerMainSize_ - currentStartPos;
977 for (auto& pos : itemPosition_) {
978 pos.second.startPos += delta;
979 pos.second.endPos += delta;
980 }
981 for (auto& pos : cachedItemPosition_) {
982 pos.second.startPos += delta;
983 pos.second.endPos += delta;
984 }
985 totalMainSize_ = std::max(totalMainSize_ + delta, GetEndPosition() + footerMainSize_);
986 adjustReferenceDelta_ = -delta;
987 } else if (GetStartIndex() == 0 && currentStartPos > headerMainSize_) {
988 auto delta = currentStartPos - headerMainSize_;
989 for (auto& pos : itemPosition_) {
990 pos.second.startPos -= delta;
991 pos.second.endPos -= delta;
992 }
993 for (auto& pos : cachedItemPosition_) {
994 pos.second.startPos -= delta;
995 pos.second.endPos -= delta;
996 }
997 totalMainSize_ -= delta;
998 adjustReferenceDelta_ = delta;
999 }
1000 if (GetEndIndex() == totalItemCount_ - 1) {
1001 totalMainSize_ = GetEndPosition() + footerMainSize_;
1002 } else {
1003 float endPos = GetCacheEndIndex() > GetEndIndex() ? GetCacheEndPosition() : GetEndPosition();
1004 totalMainSize_ = std::max(totalMainSize_, endPos + footerMainSize_);
1005 }
1006 UpdateLayoutedItemInfo();
1007 }
1008
UpdateLayoutedItemInfo()1009 void ListItemGroupLayoutAlgorithm::UpdateLayoutedItemInfo()
1010 {
1011 const auto& start = *itemPosition_.begin();
1012 const auto& end = *itemPosition_.rbegin();
1013 if (layoutedItemInfo_.has_value()) {
1014 auto& itemInfo = layoutedItemInfo_.value();
1015 auto prevStartIndex = itemInfo.startIndex;
1016 if (start.first <= itemInfo.startIndex || LessNotEqual(start.second.startPos, itemInfo.startPos) ||
1017 start.first > itemInfo.endIndex) {
1018 itemInfo.startIndex = start.first;
1019 itemInfo.startPos = start.second.startPos;
1020 }
1021 if (end.first >= itemInfo.endIndex || GreatNotEqual(end.second.endPos, itemInfo.endPos) ||
1022 itemInfo.endIndex > totalItemCount_ - 1 || end.first < prevStartIndex) {
1023 itemInfo.endIndex = end.first;
1024 itemInfo.endPos = end.second.endPos;
1025 }
1026 } else {
1027 layoutedItemInfo_ = { start.first, start.second.startPos, end.first, end.second.endPos };
1028 }
1029 }
1030
CheckRecycle(const RefPtr<LayoutWrapper> & layoutWrapper,float startPos,float endPos,float referencePos,bool forwardLayout)1031 void ListItemGroupLayoutAlgorithm::CheckRecycle(
1032 const RefPtr<LayoutWrapper>& layoutWrapper, float startPos, float endPos, float referencePos, bool forwardLayout)
1033 {
1034 referencePos = UpdateReferencePos(layoutWrapper->GetLayoutProperty(), forwardLayout, referencePos);
1035 // Mark inactive in wrapper.
1036 if (forwardLayout) {
1037 for (auto pos = itemPosition_.begin(); pos != itemPosition_.end();) {
1038 if (GreatOrEqual(pos->second.endPos, startPos - referencePos)) {
1039 break;
1040 }
1041 cachedItemPosition_.insert(*pos);
1042 pos = itemPosition_.erase(pos);
1043 }
1044 return;
1045 }
1046 std::list<int32_t> removeIndexes;
1047 for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
1048 if (LessOrEqual(pos->second.startPos, endPos - (referencePos - totalMainSize_))) {
1049 break;
1050 }
1051 cachedItemPosition_.insert(*pos);
1052 removeIndexes.emplace_back(pos->first);
1053 }
1054 for (const auto& index : removeIndexes) {
1055 itemPosition_.erase(index);
1056 }
1057 }
1058
LayoutListItem(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize)1059 void ListItemGroupLayoutAlgorithm::LayoutListItem(LayoutWrapper* layoutWrapper,
1060 const OffsetF& paddingOffset, float crossSize)
1061 {
1062 // layout items.
1063 for (auto& pos : itemPosition_) {
1064 auto wrapper = GetListItem(layoutWrapper, pos.first);
1065 if (!wrapper) {
1066 LOGI("wrapper is out of boundary");
1067 continue;
1068 }
1069
1070 auto offset = paddingOffset;
1071 int32_t laneIndex = pos.first % lanes_;
1072 float childCrossSize = GetCrossAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
1073 float laneCrossOffset = CalculateLaneCrossOffset((crossSize + GetLaneGutter()) / lanes_, childCrossSize);
1074 if (layoutDirection_ == TextDirection::RTL) {
1075 if (axis_ == Axis::VERTICAL) {
1076 auto size = wrapper->GetGeometryNode()->GetMarginFrameSize();
1077 auto tmpX = crossSize - laneCrossOffset -
1078 ((crossSize + laneGutter_) / lanes_) * laneIndex - size.Width();
1079 offset = offset + OffsetF(tmpX, pos.second.startPos);
1080 } else {
1081 auto tmpY = laneCrossOffset + ((crossSize + laneGutter_) / lanes_) * laneIndex;
1082 offset = offset + OffsetF(totalMainSize_ - pos.second.endPos, tmpY);
1083 }
1084 } else {
1085 if (axis_ == Axis::VERTICAL) {
1086 offset =
1087 offset + OffsetF(0, pos.second.startPos) + OffsetF(laneCrossOffset, 0) +
1088 OffsetF(((crossSize + laneGutter_) / lanes_) * laneIndex, 0);
1089 } else {
1090 offset =
1091 offset + OffsetF(pos.second.startPos, 0) + OffsetF(0, laneCrossOffset) +
1092 OffsetF(0, ((crossSize + laneGutter_) / lanes_) * laneIndex);
1093 }
1094 }
1095 SetListItemIndex(layoutWrapper, wrapper, pos.first);
1096 wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
1097 if (wrapper->CheckNeedForceMeasureAndLayout()) {
1098 wrapper->Layout();
1099 } else {
1100 SyncGeometry(wrapper);
1101 }
1102 }
1103 }
1104
UpdateZIndex(const RefPtr<LayoutWrapper> & layoutWrapper)1105 void ListItemGroupLayoutAlgorithm::UpdateZIndex(const RefPtr<LayoutWrapper>& layoutWrapper)
1106 {
1107 auto host = layoutWrapper->GetHostNode();
1108 CHECK_NULL_VOID(host);
1109 auto renderContext = host->GetRenderContext();
1110 CHECK_NULL_VOID(renderContext);
1111 renderContext->UpdateZIndex(1);
1112 }
1113
LayoutHeaderFooterRTL(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize)1114 void ListItemGroupLayoutAlgorithm::LayoutHeaderFooterRTL(LayoutWrapper* layoutWrapper,
1115 const OffsetF& paddingOffset, float crossSize)
1116 {
1117 OffsetF selfOffset = layoutWrapper->GetGeometryNode()->GetPaddingOffset();
1118 selfOffset = selfOffset - listLayoutProperty_->CreatePaddingAndBorder().Offset();
1119 float mainPos = GetMainAxisOffset(selfOffset, axis_);
1120 float footerMainSize = 0.0f;
1121 V2::StickyStyle sticky = listLayoutProperty_->GetStickyStyle().value_or(V2::StickyStyle::NONE);
1122 RefPtr<LayoutWrapper> headerWrapper = headerIndex_ >= 0 ?
1123 layoutWrapper->GetOrCreateChildByIndex(headerIndex_) : nullptr;
1124 RefPtr<LayoutWrapper> footerWrapper = footerIndex_ >= 0 ?
1125 layoutWrapper->GetOrCreateChildByIndex(footerIndex_) : nullptr;
1126 if (footerWrapper) {
1127 UpdateZIndex(footerWrapper);
1128 footerMainSize = footerWrapper->GetGeometryNode()->GetFrameSize().MainSize(axis_);
1129 float footerPos = 0.0f;
1130 if (sticky == V2::StickyStyle::BOTH || sticky == V2::StickyStyle::FOOTER) {
1131 contentStartOffset_ = std::max(contentStartOffset_, 0.0f);
1132 float stickyPos = contentStartOffset_ - mainPos;
1133 stickyPos = std::min(stickyPos, totalMainSize_ - footerMainSize_ - headerMainSize_);
1134 footerPos = std::max(footerPos, stickyPos);
1135 footerPos = std::min(footerPos, totalMainSize_ - footerMainSize_ - headerMainSize_);
1136 }
1137 LayoutIndex(footerWrapper, paddingOffset, crossSize, footerPos);
1138 endFooterPos_ = endFooterPos_ > mainPos ? mainPos : endFooterPos_;
1139 }
1140
1141 if (headerWrapper) {
1142 float headPos = totalMainSize_ - headerMainSize_;
1143 UpdateZIndex(headerWrapper);
1144 float const listMainSize = endPos_ - startPos_;
1145 if (Positive(listMainSize) && (sticky == V2::StickyStyle::BOTH || sticky == V2::StickyStyle::HEADER)) {
1146 auto headerMainSize = headerWrapper->GetGeometryNode()->GetFrameSize().MainSize(axis_);
1147 float stickyPos = listMainSize - contentEndOffset_ - mainPos - headerMainSize;
1148 if (stickyPos < footerMainSize) {
1149 stickyPos = footerMainSize;
1150 }
1151 if (stickyPos < headPos) {
1152 headPos = stickyPos;
1153 }
1154 }
1155 LayoutIndex(headerWrapper, paddingOffset, crossSize, headPos);
1156 startHeaderPos_ = mainPos + totalMainSize_ - headerMainSize_ - listMainSize;
1157 }
1158 }
1159
LayoutHeaderFooterLTR(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize)1160 void ListItemGroupLayoutAlgorithm::LayoutHeaderFooterLTR(LayoutWrapper* layoutWrapper,
1161 const OffsetF& paddingOffset, float crossSize)
1162 {
1163 OffsetF selfOffset = layoutWrapper->GetGeometryNode()->GetPaddingOffset();
1164 selfOffset = selfOffset - listLayoutProperty_->CreatePaddingAndBorder().Offset();
1165 float mainPos = GetMainAxisOffset(selfOffset, axis_);
1166 float headerMainSize = 0.0f;
1167 V2::StickyStyle sticky = listLayoutProperty_->GetStickyStyle().value_or(V2::StickyStyle::NONE);
1168 RefPtr<LayoutWrapper> headerWrapper = headerIndex_ >= 0 ?
1169 layoutWrapper->GetOrCreateChildByIndex(headerIndex_) : nullptr;
1170 RefPtr<LayoutWrapper> footerWrapper = footerIndex_ >= 0 ?
1171 layoutWrapper->GetOrCreateChildByIndex(footerIndex_) : nullptr;
1172 if (headerWrapper) {
1173 UpdateZIndex(headerWrapper);
1174 headerMainSize = headerWrapper->GetGeometryNode()->GetFrameSize().MainSize(axis_);
1175 float headerPos = 0.0f;
1176 if (sticky == V2::StickyStyle::BOTH || sticky == V2::StickyStyle::HEADER) {
1177 contentStartOffset_ = std::max(contentStartOffset_, 0.0f);
1178 float stickyPos = contentStartOffset_ - mainPos;
1179 stickyPos = std::min(stickyPos, totalMainSize_ - footerMainSize_ - headerMainSize_);
1180 headerPos = std::max(headerPos, stickyPos);
1181 }
1182 LayoutIndex(headerWrapper, paddingOffset, crossSize, headerPos);
1183 startHeaderPos_ = startHeaderPos_ > mainPos ? mainPos : startHeaderPos_;
1184 }
1185
1186 if (footerWrapper) {
1187 float endPos = totalMainSize_ - footerMainSize_;
1188 UpdateZIndex(footerWrapper);
1189 float const listMainSize = endPos_ - startPos_;
1190 if (Positive(listMainSize) && (sticky == V2::StickyStyle::BOTH || sticky == V2::StickyStyle::FOOTER)) {
1191 auto footerMainSize = footerWrapper->GetGeometryNode()->GetFrameSize().MainSize(axis_);
1192 float stickyPos = listMainSize - contentEndOffset_ - mainPos - footerMainSize;
1193 if (stickyPos < headerMainSize) {
1194 stickyPos = headerMainSize;
1195 }
1196 if (stickyPos < endPos) {
1197 endPos = stickyPos;
1198 }
1199 }
1200 LayoutIndex(footerWrapper, paddingOffset, crossSize, endPos);
1201 endFooterPos_ = mainPos + totalMainSize_ - footerMainSize_ - listMainSize;
1202 }
1203 }
1204
LayoutIndex(const RefPtr<LayoutWrapper> & wrapper,const OffsetF & paddingOffset,float crossSize,float startPos)1205 void ListItemGroupLayoutAlgorithm::LayoutIndex(const RefPtr<LayoutWrapper>& wrapper, const OffsetF& paddingOffset,
1206 float crossSize, float startPos)
1207 {
1208 CHECK_NULL_VOID(wrapper);
1209 auto offset = paddingOffset;
1210 float childCrossSize = GetCrossAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
1211 float laneCrossOffset = CalculateLaneCrossOffset(crossSize, childCrossSize);
1212 if (axis_ == Axis::VERTICAL) {
1213 if (layoutDirection_ == TextDirection::RTL) {
1214 auto size = wrapper->GetGeometryNode()->GetMarginFrameSize();
1215 offset = offset + OffsetF(crossSize - laneCrossOffset - size.Width(), startPos);
1216 } else {
1217 offset = offset + OffsetF(laneCrossOffset, startPos);
1218 }
1219 } else {
1220 offset = offset + OffsetF(startPos, laneCrossOffset);
1221 }
1222 wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
1223 wrapper->Layout();
1224 }
1225
CalculateLaneCrossOffset(float crossSize,float childCrossSize)1226 float ListItemGroupLayoutAlgorithm::CalculateLaneCrossOffset(float crossSize, float childCrossSize)
1227 {
1228 float delta = crossSize - GetLaneGutter() - childCrossSize;
1229 if (LessOrEqual(delta, 0.0f)) {
1230 return 0.0f;
1231 }
1232 switch (itemAlign_) {
1233 case OHOS::Ace::V2::ListItemAlign::START:
1234 return 0.0f;
1235 case OHOS::Ace::V2::ListItemAlign::CENTER:
1236 return delta / 2; /* 2:average */
1237 case OHOS::Ace::V2::ListItemAlign::END:
1238 return delta;
1239 default:
1240 LOGW("Invalid ListItemAlign: %{public}d", itemAlign_);
1241 return 0.0f;
1242 }
1243 }
1244
CalculateLanes(const RefPtr<ListLayoutProperty> & layoutProperty,const LayoutConstraintF & layoutConstraint,std::optional<float> crossSizeOptional,Axis axis)1245 void ListItemGroupLayoutAlgorithm::CalculateLanes(const RefPtr<ListLayoutProperty>& layoutProperty,
1246 const LayoutConstraintF& layoutConstraint, std::optional<float> crossSizeOptional, Axis axis)
1247 {
1248 int32_t lanes = layoutProperty->GetLanes().value_or(1);
1249 lanes = lanes > 1 ? lanes : 1;
1250 if (crossSizeOptional.has_value()) {
1251 if (layoutProperty->GetLaneMinLength().has_value()) {
1252 minLaneLength_ = ConvertToPx(layoutProperty->GetLaneMinLength().value(),
1253 layoutConstraint.scaleProperty, crossSizeOptional.value());
1254 }
1255 if (layoutProperty->GetLaneMaxLength().has_value()) {
1256 maxLaneLength_ = ConvertToPx(layoutProperty->GetLaneMaxLength().value(),
1257 layoutConstraint.scaleProperty, crossSizeOptional.value());
1258 }
1259 if (layoutProperty->GetLaneGutter().has_value()) {
1260 auto laneGutter = ConvertToPx(
1261 layoutProperty->GetLaneGutter().value(), layoutConstraint.scaleProperty, crossSizeOptional.value());
1262 laneGutter_ = laneGutter.value();
1263 }
1264 }
1265 lanes_ = ListLanesLayoutAlgorithm::CalculateLanesParam(
1266 minLaneLength_, maxLaneLength_, lanes, crossSizeOptional, laneGutter_);
1267 }
1268
SetListItemIndex(const LayoutWrapper * groupLayoutWrapper,const RefPtr<LayoutWrapper> & itemLayoutWrapper,int32_t indexInGroup)1269 void ListItemGroupLayoutAlgorithm::SetListItemIndex(const LayoutWrapper* groupLayoutWrapper,
1270 const RefPtr<LayoutWrapper>& itemLayoutWrapper, int32_t indexInGroup)
1271 {
1272 auto host = itemLayoutWrapper->GetHostNode();
1273 CHECK_NULL_VOID(host);
1274 auto listItem = host->GetPattern<ListItemPattern>();
1275 CHECK_NULL_VOID(listItem);
1276 listItem->SetIndexInListItemGroup(indexInGroup);
1277
1278 host = groupLayoutWrapper->GetHostNode();
1279 CHECK_NULL_VOID(host);
1280 auto listItemGroup = host->GetPattern<ListItemGroupPattern>();
1281 CHECK_NULL_VOID(listItemGroup);
1282 listItem->SetIndexInList(listItemGroup->GetIndexInList());
1283 }
1284
GetLayoutInfo() const1285 ListItemGroupLayoutInfo ListItemGroupLayoutAlgorithm::GetLayoutInfo() const
1286 {
1287 ListItemGroupLayoutInfo info;
1288 if (totalItemCount_ == 0 || childrenSize_) {
1289 info.atStart = true;
1290 info.atEnd = true;
1291 return info;
1292 }
1293 if (layoutedItemInfo_.has_value()) {
1294 const auto& itemInfo = layoutedItemInfo_.value();
1295 info.atStart = itemInfo.startIndex == 0;
1296 info.atEnd = itemInfo.endIndex >= totalItemCount_ - 1;
1297 auto totalHeight = (itemInfo.endPos - itemInfo.startPos + spaceWidth_);
1298 auto itemCount = itemInfo.endIndex - itemInfo.startIndex + 1;
1299 info.averageHeight = totalHeight / itemCount;
1300 }
1301 return info;
1302 }
1303
IsCardStyleForListItemGroup(const LayoutWrapper * groupLayoutWrapper)1304 bool ListItemGroupLayoutAlgorithm::IsCardStyleForListItemGroup(const LayoutWrapper* groupLayoutWrapper)
1305 {
1306 auto host = groupLayoutWrapper->GetHostNode();
1307 CHECK_NULL_RETURN(host, false);
1308 auto listItemGroup = host->GetPattern<ListItemGroupPattern>();
1309 CHECK_NULL_RETURN(listItemGroup, false);
1310 return listItemGroup->GetListItemGroupStyle() == V2::ListItemGroupStyle::CARD;
1311 }
1312
MeasureCacheForward(LayoutWrapper * layoutWrapper,ListItemGroupCacheParam & param)1313 void ListItemGroupLayoutAlgorithm::MeasureCacheForward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param)
1314 {
1315 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
1316 int32_t endIndex = itemPosition_.empty() ? -1 : GetEndIndex();
1317 if (endIndex >= totalItemCount_ - 1) {
1318 return;
1319 }
1320 int32_t limit = std::min(endIndex + param.cacheCountForward * lanes_, totalItemCount_ - 1);
1321 float startPos = itemPosition_.empty() ? headerMainSize_ : GetEndPosition();
1322 int32_t curIndex = GetLanesFloor(endIndex + 1);
1323 while (curIndex <= limit) {
1324 if (GetSysTimestamp() > param.deadline) {
1325 return;
1326 }
1327 float mainLen = 0.0f;
1328 int32_t cnt = 0;
1329 for (int32_t i = 0; i < lanes && curIndex + i < totalItemCount_; i++) {
1330 auto wrapper =
1331 layoutWrapper->GetOrCreateChildByIndex(curIndex + i + itemStartIndex_, param.show, !param.show);
1332 if (!wrapper || !wrapper->GetHostNode() || !wrapper->GetHostNode()->RenderCustomChild(param.deadline)) {
1333 return;
1334 }
1335 cnt++;
1336 if (CheckNeedMeasure(wrapper)) {
1337 ACE_SCOPED_TRACE("ListItemGroupLayoutAlgorithm::MeasureCacheForward:%d", curIndex + i);
1338 wrapper->Measure(childLayoutConstraint_);
1339 }
1340 mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
1341 }
1342 for (int32_t i = 0; i < cnt; i++) {
1343 cachedItemPosition_[curIndex + i] = { -1, startPos, startPos + mainLen };
1344 }
1345 curIndex += cnt;
1346 startPos += mainLen + spaceWidth_;
1347 param.forwardCachedIndex = curIndex - 1;
1348 }
1349 }
1350
MeasureCacheBackward(LayoutWrapper * layoutWrapper,ListItemGroupCacheParam & param)1351 void ListItemGroupLayoutAlgorithm::MeasureCacheBackward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param)
1352 {
1353 int32_t lanes = lanes_ > 1 ? lanes_ : 1;
1354 int32_t startIndex = itemPosition_.empty() ? totalItemCount_ : GetStartIndex();
1355 if (startIndex <= 0) {
1356 return;
1357 }
1358 int32_t limit = std::max(startIndex - param.cacheCountBackward * lanes_, 0);
1359 if (limit % lanes_ != 0) {
1360 limit += (lanes_ - limit % lanes_);
1361 }
1362 float endPos = itemPosition_.empty() ? totalMainSize_ - footerMainSize_ : GetStartPosition();
1363 int32_t curIndex = GetLanesCeil(startIndex - 1);
1364 while (curIndex >= limit) {
1365 if (GetSysTimestamp() > param.deadline) {
1366 return;
1367 }
1368 float mainLen = 0.0f;
1369 int32_t cnt = 0;
1370 for (int32_t i = 0; i < lanes && curIndex - i >= 0; i++) {
1371 auto wrapper =
1372 layoutWrapper->GetOrCreateChildByIndex(curIndex - i + itemStartIndex_, param.show, !param.show);
1373 if (!wrapper || !wrapper->GetHostNode() || !wrapper->GetHostNode()->RenderCustomChild(param.deadline)) {
1374 return;
1375 }
1376 cnt++;
1377 if (CheckNeedMeasure(wrapper)) {
1378 ACE_SCOPED_TRACE("ListItemGroupLayoutAlgorithm::MeasureCacheForward:%d", curIndex - i);
1379 wrapper->Measure(childLayoutConstraint_);
1380 }
1381 mainLen = std::max(mainLen, GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_));
1382 if (0 == (curIndex - i) % lanes) {
1383 break;
1384 }
1385 }
1386 for (int32_t i = 0; i < cnt; i++) {
1387 cachedItemPosition_[curIndex - i] = { -1, endPos - mainLen, endPos };
1388 }
1389 curIndex -= cnt;
1390 endPos -= (mainLen + spaceWidth_);
1391 param.backwardCachedIndex = curIndex + 1;
1392 }
1393 }
1394
MeasureCacheItem(LayoutWrapper * layoutWrapper)1395 void ListItemGroupLayoutAlgorithm::MeasureCacheItem(LayoutWrapper* layoutWrapper)
1396 {
1397 ListItemGroupCacheParam& param = cacheParam_.value();
1398 if (param.forward) {
1399 MeasureCacheForward(layoutWrapper, param);
1400 }
1401 if (param.backward) {
1402 MeasureCacheBackward(layoutWrapper, param);
1403 }
1404 if (cachedItemPosition_.empty()) {
1405 return;
1406 }
1407 float originHeight = totalMainSize_;
1408 float currentStartPos = GetCacheStartPosition();
1409 if (currentStartPos < headerMainSize_) {
1410 auto delta = headerMainSize_ - currentStartPos;
1411 for (auto& pos : itemPosition_) {
1412 pos.second.startPos += delta;
1413 pos.second.endPos += delta;
1414 }
1415 for (auto& pos : cachedItemPosition_) {
1416 pos.second.startPos += delta;
1417 pos.second.endPos += delta;
1418 }
1419 totalMainSize_ = std::max(totalMainSize_ + delta,
1420 std::max(GetCacheEndPosition(), GetEndPosition()) + footerMainSize_);
1421 adjustReferenceDelta_ = -delta;
1422 } else if (GetCacheStartIndex() == 0 && currentStartPos > headerMainSize_) {
1423 auto delta = currentStartPos - headerMainSize_;
1424 for (auto& pos : itemPosition_) {
1425 pos.second.startPos -= delta;
1426 pos.second.endPos -= delta;
1427 }
1428 for (auto& pos : cachedItemPosition_) {
1429 pos.second.startPos -= delta;
1430 pos.second.endPos -= delta;
1431 }
1432 totalMainSize_ -= delta;
1433 adjustReferenceDelta_ = delta;
1434 }
1435 if (GetCacheEndIndex() == totalItemCount_ - 1) {
1436 totalMainSize_ = GetCacheEndPosition() + footerMainSize_;
1437 } else {
1438 float endPos = GetCacheEndIndex() > GetEndIndex() || itemPosition_.empty() ?
1439 GetCacheEndPosition() : GetEndPosition();
1440 totalMainSize_ = std::max(totalMainSize_, endPos + footerMainSize_);
1441 }
1442 adjustTotalSize_ = totalMainSize_ - originHeight;
1443 }
1444
LayoutCacheItem(LayoutWrapper * layoutWrapper,const OffsetF & paddingOffset,float crossSize,bool show)1445 void ListItemGroupLayoutAlgorithm::LayoutCacheItem(LayoutWrapper* layoutWrapper,
1446 const OffsetF& paddingOffset, float crossSize, bool show)
1447 {
1448 for (auto& pos : cachedItemPosition_) {
1449 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(pos.first + itemStartIndex_, show, !show);
1450 if (!wrapper) {
1451 continue;
1452 }
1453 auto offset = paddingOffset;
1454 int32_t laneIndex = pos.first % lanes_;
1455 float childCrossSize = GetCrossAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis_);
1456 float laneCrossOffset = CalculateLaneCrossOffset((crossSize + GetLaneGutter()) / lanes_, childCrossSize);
1457 if (layoutDirection_ == TextDirection::RTL) {
1458 if (axis_ == Axis::VERTICAL) {
1459 auto size = wrapper->GetGeometryNode()->GetMarginFrameSize();
1460 auto tmpX = crossSize - laneCrossOffset -
1461 ((crossSize + laneGutter_) / lanes_) * laneIndex - size.Width();
1462 offset = offset + OffsetF(tmpX, pos.second.startPos);
1463 } else {
1464 auto tmpY = laneCrossOffset + ((crossSize + laneGutter_) / lanes_) * laneIndex;
1465 offset = offset + OffsetF(totalMainSize_ - pos.second.endPos, tmpY);
1466 }
1467 } else {
1468 if (axis_ == Axis::VERTICAL) {
1469 offset =
1470 offset + OffsetF(0, pos.second.startPos) + OffsetF(laneCrossOffset, 0) +
1471 OffsetF(((crossSize + laneGutter_) / lanes_) * laneIndex, 0);
1472 } else {
1473 offset =
1474 offset + OffsetF(pos.second.startPos, 0) + OffsetF(0, laneCrossOffset) +
1475 OffsetF(0, ((crossSize + laneGutter_) / lanes_) * laneIndex);
1476 }
1477 }
1478 SetListItemIndex(layoutWrapper, wrapper, pos.first);
1479 wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
1480 if (wrapper->CheckNeedForceMeasureAndLayout()) {
1481 wrapper->Layout();
1482 } else {
1483 SyncGeometry(wrapper);
1484 }
1485 }
1486 }
1487 } // namespace OHOS::Ace::NG
1488