1 /* 2 * Copyright (c) 2022-2025 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_ITEM_GROUP_LAYOUT_ALGORITHM_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_ITEM_GROUP_LAYOUT_ALGORITHM_H 18 19 #include <optional> 20 #include "base/geometry/axis.h" 21 #include "core/components_ng/layout/layout_algorithm.h" 22 #include "core/components_ng/layout/layout_wrapper.h" 23 #include "core/components_ng/pattern/list/list_layout_property.h" 24 #include "core/components_v2/list/list_properties.h" 25 26 namespace OHOS::Ace::NG { 27 class ListPositionMap; 28 class ListChildrenMainSize; 29 struct ListItemGroupLayoutInfo; 30 struct LayoutedItemInfo { 31 int32_t startIndex = 0; 32 float startPos = 0.0f; 33 int32_t endIndex = 0; 34 float endPos = 0.0f; 35 }; 36 37 struct ListItemGroupInfo { 38 int32_t id = -1; 39 float startPos = 0.0f; 40 float endPos = 0.0f; 41 bool isPressed = false; 42 }; 43 44 struct ListItemGroupCacheParam { 45 bool forward = true; 46 bool backward = false; 47 bool show = false; 48 int32_t cacheCountForward = 0; 49 int32_t cacheCountBackward = 0; 50 int32_t forwardCachedIndex = -1; 51 int32_t backwardCachedIndex = INT_MAX; 52 int64_t deadline = 0; 53 }; 54 55 struct CachedIndexInfo { 56 int32_t forwardCachedCount = 0; 57 int32_t backwardCachedCount = 0; 58 int32_t forwardCacheMax = 0; 59 int32_t backwardCacheMax = 0; 60 }; 61 62 // TextLayoutAlgorithm acts as the underlying text layout. 63 class ACE_EXPORT ListItemGroupLayoutAlgorithm : public LayoutAlgorithm { 64 DECLARE_ACE_TYPE(ListItemGroupLayoutAlgorithm, LayoutAlgorithm); 65 public: 66 using PositionMap = std::map<int32_t, ListItemGroupInfo>; 67 68 static const int32_t LAST_ITEM = -1; 69 70 ListItemGroupLayoutAlgorithm(int32_t headerIndex, int32_t footerIndex, int32_t itemStartIndex, 71 int32_t footerCount = 0) headerIndex_(headerIndex)72 : headerIndex_(headerIndex), footerIndex_(footerIndex), itemStartIndex_(itemStartIndex), 73 footerCount_(footerCount) 74 {} 75 76 void Measure(LayoutWrapper* layoutWrapper) override; 77 78 void Layout(LayoutWrapper* layoutWrapper) override; 79 GetItemPosition()80 const PositionMap& GetItemPosition() const 81 { 82 return itemPosition_; 83 } 84 GetCachedItemPosition()85 const PositionMap& GetCachedItemPosition() const 86 { 87 return cachedItemPosition_; 88 } 89 ResetCachedItemPosition()90 void ResetCachedItemPosition() 91 { 92 cachedItemPosition_.clear(); 93 } 94 ResetCachedIndex()95 void ResetCachedIndex() 96 { 97 forwardCachedIndex_ = -1; 98 backwardCachedIndex_ = INT_MAX; 99 } 100 SetItemsPosition(const PositionMap & itemPosition)101 void SetItemsPosition(const PositionMap& itemPosition) 102 { 103 itemPosition_ = itemPosition; 104 } 105 SetCachedItemsPosition(const PositionMap & itemPosition)106 void SetCachedItemsPosition(const PositionMap& itemPosition) 107 { 108 cachedItemPosition_ = itemPosition; 109 } 110 111 void ClearItemPosition(); 112 GetSpaceWidth()113 float GetSpaceWidth() const 114 { 115 return spaceWidth_; 116 } 117 GetAxis()118 Axis GetAxis() const 119 { 120 return axis_; 121 } 122 GetLayoutDirection()123 TextDirection GetLayoutDirection() const 124 { 125 return layoutDirection_; 126 } 127 GetMainSize()128 float GetMainSize() const 129 { 130 return totalMainSize_; 131 } 132 GetLanes()133 int32_t GetLanes() const 134 { 135 return lanes_; 136 } 137 GetLaneGutter()138 float GetLaneGutter() const 139 { 140 return laneGutter_; 141 } 142 GetLanesFloor(int32_t index)143 int32_t GetLanesFloor(int32_t index) const 144 { 145 if (lanes_ <= 1) { 146 return index; 147 } 148 return index - index % lanes_; 149 } 150 GetLanesCeil(int32_t index)151 int32_t GetLanesCeil(int32_t index) const 152 { 153 int32_t tmpIndex = (lanes_ <= 1) ? index : (index - index % lanes_ + lanes_ - 1); 154 tmpIndex = tmpIndex >= totalItemCount_ ? totalItemCount_ - 1 : tmpIndex; 155 return tmpIndex; 156 } 157 SetListMainSize(float startPos,float endPos,float referencePos,float prevContentSize,bool forwardLayout)158 void SetListMainSize(float startPos, float endPos, float referencePos, float prevContentSize, bool forwardLayout) 159 { 160 startPos_ = startPos; 161 endPos_ = endPos; 162 referencePos_ = referencePos; 163 forwardLayout_ = forwardLayout; 164 refPos_ = referencePos; 165 prevContentMainSize_ = prevContentSize; 166 } 167 GetListContentSize()168 float GetListContentSize() const 169 { 170 return endPos_ - startPos_; 171 } 172 173 void ModifyReferencePos(int32_t index, float pos); 174 SetNeedAdjustRefPos(bool needAdjust)175 void SetNeedAdjustRefPos(bool needAdjust) 176 { 177 needAdjustRefPos_ = needAdjust; 178 } 179 SetNeedCheckOffset(bool needCheckOffset,float averageHeight)180 void SetNeedCheckOffset(bool needCheckOffset, float averageHeight) 181 { 182 isNeedCheckOffset_ = needCheckOffset; 183 groupItemAverageHeight_ = averageHeight; 184 } 185 GetRefPos()186 float GetRefPos() const 187 { 188 return refPos_; 189 } 190 SetContentOffset(float contentStartOffset,float contentEndOffset)191 void SetContentOffset(float contentStartOffset, float contentEndOffset) 192 { 193 contentStartOffset_ = contentStartOffset; 194 contentEndOffset_ = contentEndOffset; 195 } 196 SetListLayoutProperty(RefPtr<ListLayoutProperty> layoutProperty)197 void SetListLayoutProperty(RefPtr<ListLayoutProperty> layoutProperty) 198 { 199 listLayoutProperty_ = std::move(layoutProperty); 200 } 201 SetJumpIndex(int32_t index)202 void SetJumpIndex(int32_t index) 203 { 204 jumpIndex_ = index; 205 } 206 SetTargetIndex(int32_t index)207 void SetTargetIndex(int32_t index) 208 { 209 targetIndex_ = index; 210 } 211 GetStartIndex()212 int32_t GetStartIndex() const 213 { 214 return itemPosition_.empty() ? 0 : itemPosition_.begin()->first; 215 } 216 GetEndIndex()217 int32_t GetEndIndex() const 218 { 219 return itemPosition_.empty() ? 0 : itemPosition_.rbegin()->first; 220 } 221 GetCacheStartIndex()222 int32_t GetCacheStartIndex() const 223 { 224 return cachedItemPosition_.empty() ? -1 : cachedItemPosition_.begin()->first; 225 } 226 GetCacheEndIndex()227 int32_t GetCacheEndIndex() const 228 { 229 return cachedItemPosition_.empty() ? -1 : cachedItemPosition_.rbegin()->first; 230 } 231 GetStartPosition()232 float GetStartPosition() const 233 { 234 if (itemPosition_.empty()) { 235 return 0.0f; 236 } 237 if (GetStartIndex() == 0) { 238 return itemPosition_.begin()->second.startPos; 239 } 240 return itemPosition_.begin()->second.startPos - spaceWidth_; 241 } 242 GetEndPosition()243 float GetEndPosition() const 244 { 245 if (itemPosition_.empty()) { 246 return 0.0f; 247 } 248 if (GetEndIndex() == totalItemCount_ - 1) { 249 return itemPosition_.rbegin()->second.endPos; 250 } 251 return itemPosition_.rbegin()->second.endPos + spaceWidth_; 252 } 253 GetCacheStartPosition()254 float GetCacheStartPosition() const 255 { 256 if (cachedItemPosition_.empty()) { 257 return 0.0f; 258 } 259 if (GetCacheStartIndex() == 0) { 260 return cachedItemPosition_.begin()->second.startPos; 261 } 262 return cachedItemPosition_.begin()->second.startPos - spaceWidth_; 263 } 264 GetCacheEndPosition()265 float GetCacheEndPosition() const 266 { 267 if (cachedItemPosition_.empty()) { 268 return 0.0f; 269 } 270 if (GetCacheEndIndex() == totalItemCount_ - 1) { 271 return cachedItemPosition_.rbegin()->second.endPos; 272 } 273 return cachedItemPosition_.rbegin()->second.endPos + spaceWidth_; 274 } 275 GetTotalItemCount()276 int32_t GetTotalItemCount() const 277 { 278 return totalItemCount_; 279 } 280 GetFooterIndex()281 int32_t GetFooterIndex() const 282 { 283 return footerIndex_; 284 } 285 286 float GetChildMaxCrossSize(LayoutWrapper* layoutWrapper, Axis axis); 287 288 void CheckRecycle(const RefPtr<LayoutWrapper>& layoutWrapper, float startPos, float endPos, float referencePos, 289 bool forwardLayout); 290 SetNeedAllLayout()291 void SetNeedAllLayout() 292 { 293 needAllLayout_ = true; 294 } 295 296 void CheckNeedAllLayout(const RefPtr<LayoutWrapper>& layoutWrapper, bool forwardLayout); 297 SetScrollAlign(ScrollAlign align)298 void SetScrollAlign(ScrollAlign align) 299 { 300 scrollAlign_ = align; 301 } 302 303 std::pair<float, float> GetItemGroupPosition(int32_t index); 304 GetHeaderMainSize()305 float GetHeaderMainSize() const 306 { 307 return headerMainSize_; 308 } 309 GetFooterMainSize()310 float GetFooterMainSize() const 311 { 312 return footerMainSize_; 313 } 314 315 float GetItemHeight(int32_t index); 316 GetItemStartIndex()317 int32_t GetItemStartIndex() 318 { 319 return itemStartIndex_; 320 } 321 SetLayoutedItemInfo(const std::optional<LayoutedItemInfo> & itemInfo)322 void SetLayoutedItemInfo(const std::optional<LayoutedItemInfo>& itemInfo) 323 { 324 layoutedItemInfo_ = itemInfo; 325 } 326 GetLayoutedItemInfo()327 std::optional<LayoutedItemInfo> GetLayoutedItemInfo() const 328 { 329 return layoutedItemInfo_; 330 } 331 SetListChildrenMainSize(const RefPtr<ListChildrenMainSize> & childrenMainSize)332 void SetListChildrenMainSize(const RefPtr<ListChildrenMainSize>& childrenMainSize) 333 { 334 childrenSize_ = childrenMainSize; 335 } 336 SetListPositionMap(const RefPtr<ListPositionMap> & posMap)337 void SetListPositionMap(const RefPtr<ListPositionMap>& posMap) 338 { 339 posMap_ = posMap; 340 } 341 342 void AdjustByPosMap(); 343 344 static void SyncGeometry(RefPtr<LayoutWrapper>& wrapper); 345 GetStartHeaderPos()346 float GetStartHeaderPos() const 347 { 348 return startHeaderPos_; 349 } 350 GetEndFooterPos()351 float GetEndFooterPos() const 352 { 353 return endFooterPos_; 354 } 355 SetCacheParam(std::optional<ListItemGroupCacheParam> param)356 void SetCacheParam(std::optional<ListItemGroupCacheParam> param) 357 { 358 cacheParam_ = param; 359 } 360 GetCacheParam()361 std::optional<ListItemGroupCacheParam> GetCacheParam() const 362 { 363 return cacheParam_; 364 } 365 SetNeedMeasureFormLastItem(bool needMeasureFormLastItem)366 void SetNeedMeasureFormLastItem(bool needMeasureFormLastItem) 367 { 368 isNeedMeasureFormLastItem_ = needMeasureFormLastItem; 369 } 370 SetNeedSyncLoad(bool value)371 void SetNeedSyncLoad(bool value) 372 { 373 isNeedSyncLoad_ = value; 374 } 375 SetPrevMeasureBreak(bool value)376 void SetPrevMeasureBreak(bool value) 377 { 378 prevMeasureBreak_ = value; 379 } 380 GroupMeasureInNextFrame()381 bool GroupMeasureInNextFrame() const 382 { 383 return measureInNextFrame_; 384 } 385 ReachResponseDeadline(LayoutWrapper * layoutWrapper)386 bool ReachResponseDeadline(LayoutWrapper* layoutWrapper) const 387 { 388 return !itemPosition_.empty() && !isNeedSyncLoad_ && layoutWrapper->ReachResponseDeadline(); 389 } 390 391 ListItemGroupLayoutInfo GetLayoutInfo() const; 392 GetAdjustReferenceDelta()393 float GetAdjustReferenceDelta() const 394 { 395 return adjustReferenceDelta_; 396 } 397 GetAdjustTotalSize()398 float GetAdjustTotalSize() const 399 { 400 return adjustTotalSize_; 401 } 402 SetCachedIndex(int32_t forwardIndex,int32_t backwardIndex)403 void SetCachedIndex(int32_t forwardIndex, int32_t backwardIndex) 404 { 405 forwardCachedIndex_ = forwardIndex; 406 backwardCachedIndex_ = backwardIndex; 407 } 408 GetCachedIndex()409 std::pair<int32_t, int32_t> GetCachedIndex() const 410 { 411 return { forwardCachedIndex_, backwardCachedIndex_ }; 412 } 413 GetListItemCount()414 int32_t GetListItemCount() const 415 { 416 return static_cast<int32_t>(itemPosition_.size()); 417 } 418 SetPrevTotalItemCount(int32_t prevTotalItemCount)419 void SetPrevTotalItemCount(int32_t prevTotalItemCount) 420 { 421 prevTotalItemCount_ = prevTotalItemCount; 422 } 423 SetPrevTotalMainSize(float prevTotalMainSize)424 void SetPrevTotalMainSize(float prevTotalMainSize) 425 { 426 prevTotalMainSize_ = prevTotalMainSize; 427 } 428 GetStackFromEnd()429 bool GetStackFromEnd() const 430 { 431 return isStackFromEnd_; 432 } 433 434 void ReverseItemPosition(ListItemGroupLayoutAlgorithm::PositionMap &itemPosition, int32_t totalItemCount, 435 float mainSize); 436 437 void ReverseLayoutedItemInfo(int32_t totalItemCount, float mainSize); 438 439 void ResetLayoutItem(LayoutWrapper* layoutWrapper); 440 441 private: 442 float CalculateLaneCrossOffset(float crossSize, float childCrossSize); 443 void UpdateRecycledItems(); 444 void UpdateListItemConstraint(const OptionalSizeF& selfIdealSize, LayoutConstraintF& contentConstraint); 445 void LayoutListItem(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize); 446 void LayoutListItemAll(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, float startPos); 447 void LayoutHeaderFooterRTL(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize); 448 void LayoutHeaderFooterLTR(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize); 449 void UpdateZIndex(const RefPtr<LayoutWrapper>& layoutWrapper); 450 void LayoutIndex(const RefPtr<LayoutWrapper>& wrapper, const OffsetF& paddingOffset, 451 float crossSize, float startPos); 452 RefPtr<LayoutWrapper> GetListItem(LayoutWrapper *layoutWrapper, int32_t index, bool addToRenderTree = true, 453 bool isCache = false) const 454 { 455 index = !isStackFromEnd_ ? index : totalItemCount_ - index - 1; 456 if (index < 0) { 457 return nullptr; 458 } 459 return layoutWrapper->GetOrCreateChildByIndex(index + itemStartIndex_, addToRenderTree, isCache); 460 } 461 void CalculateLanes(const RefPtr<ListLayoutProperty>& layoutProperty, 462 const LayoutConstraintF& layoutConstraint, std::optional<float> crossSizeOptional, Axis axis); 463 464 void MeasureListItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint); 465 int32_t MeasureALineForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, 466 int32_t& currentIndex, float startPos, float& endPos); 467 int32_t MeasureALineBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, 468 int32_t& currentIndex, float endPos, float& startPos); 469 int32_t MeasureALineCenter(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, 470 int32_t currentIndex); 471 int32_t MeasureALineAuto(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, 472 int32_t currentIndex); 473 bool CheckJumpForwardForBigOffset(int32_t& startIndex, float& startPos); 474 bool CheckJumpBackwardForBigOffset(int32_t& endIndex, float& endPos); 475 void MeasureForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, 476 int32_t startIndex, float startPos); 477 void MeasureBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, 478 int32_t endIndex, float endPos); 479 void MeasureJumpToItemForward(LayoutWrapper* layoutWrapper, 480 const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos); 481 void MeasureJumpToItemBackward(LayoutWrapper* layoutWrapper, 482 const LayoutConstraintF& layoutConstraint, int32_t endIndex, float endPos); 483 void MeasureCenter(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex); 484 void MeasureStart(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex); 485 void MeasureEnd(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex); 486 void MeasureAuto(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex); 487 void MeasureHeaderFooter(LayoutWrapper* layoutWrapper); 488 void SetActiveChildRange(LayoutWrapper* layoutWrapper, int32_t cacheCount, bool show); 489 float UpdateReferencePos(RefPtr<LayoutProperty> layoutProperty, bool forwardLayout, float referencePos); 490 bool NeedMeasureItem(LayoutWrapper* layoutWrapper); 491 static void SetListItemIndex(const LayoutWrapper* groupLayoutWrapper, 492 const RefPtr<LayoutWrapper>& itemLayoutWrapper, int32_t indexInGroup); 493 bool IsCardStyleForListItemGroup(const LayoutWrapper* groupLayoutWrapper); 494 void UpdateListItemGroupMaxWidth(const OptionalSizeF& parentIdealSize, RefPtr<LayoutProperty> layoutProperty, 495 OptionalSizeF& contentIdealSize); 496 void AdjustItemPosition(); 497 bool CheckNeedMeasure(const RefPtr<LayoutWrapper>& layoutWrapper) const; 498 void MeasureCacheItem(LayoutWrapper* layoutWrapper); 499 void MeasureCacheForward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param); 500 void MeasureCacheBackward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param); 501 void LayoutCacheItem(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize, bool show); 502 void CheckUpdateGroupAndItemPos(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize); 503 void UpdateCachedItemPosition(int32_t cacheCount); 504 void UpdateLayoutedItemInfo(); 505 void ReportGetChildError(const std::string& funcName, int32_t index) const; 506 bool IsRoundingMode(LayoutWrapper* layoutWrapper); 507 508 bool isCardStyle_ = false; 509 int32_t headerIndex_; 510 int32_t footerIndex_; 511 int32_t itemStartIndex_; 512 int32_t footerCount_; 513 RefPtr<ListLayoutProperty> listLayoutProperty_; 514 float paddingBeforeContent_ = 0.0f; 515 float paddingAfterContent_ = 0.0f; 516 517 PositionMap itemPosition_; 518 RefPtr<ListChildrenMainSize> childrenSize_; 519 RefPtr<ListPositionMap> posMap_; 520 Axis axis_ = Axis::VERTICAL; 521 int32_t lanes_ = 1; 522 float laneGutter_ = 0.0f; 523 std::optional<float> minLaneLength_; 524 std::optional<float> maxLaneLength_; 525 V2::ListItemAlign itemAlign_ = V2::ListItemAlign::START; 526 float spaceWidth_ = 0.0f; 527 528 std::optional<int32_t> jumpIndex_; 529 std::optional<int32_t> targetIndex_; 530 ScrollAlign scrollAlign_ = ScrollAlign::NONE; 531 int32_t totalItemCount_ = 0; 532 int32_t prevTotalItemCount_ = 0; 533 int32_t forwardCachedIndex_ = -1; 534 int32_t backwardCachedIndex_ = INT_MAX; 535 float totalMainSize_ = 0.0f; 536 float prevTotalMainSize_ = 0.0f; 537 float headerMainSize_ = 0.0f; 538 float footerMainSize_ = 0.0f; 539 float startPos_ = 0.0f; 540 float startHeaderPos_ = 0.0f; 541 float endFooterPos_ = 0.0f; 542 float prevStartPos_ = 0.0f; 543 float prevEndPos_ = 0.0f; 544 float endPos_ = 0.0f; 545 float referencePos_ = 0.0f; 546 float adjustReferenceDelta_ = 0.0f; 547 float adjustTotalSize_ = 0.0f; 548 float refPos_ = 0.0f; 549 float prevContentMainSize_ = 0.0f; 550 float contentStartOffset_ = 0.0f; 551 float contentEndOffset_ = 0.0f; 552 float groupItemAverageHeight_ = 0.0f; 553 bool forwardLayout_ = true; 554 bool needAllLayout_ = false; 555 bool needAdjustRefPos_ = false; 556 bool isNeedCheckOffset_ = false; 557 bool isNeedMeasureFormLastItem_ = false; 558 bool isNeedSyncLoad_ = false; 559 bool measureInNextFrame_ = false; 560 bool prevMeasureBreak_ = false; 561 int32_t pauseMeasureCacheItem_ = -1; 562 563 std::optional<LayoutedItemInfo> layoutedItemInfo_; 564 LayoutConstraintF childLayoutConstraint_; 565 TextDirection layoutDirection_ = TextDirection::LTR; 566 567 std::optional<ListItemGroupCacheParam> cacheParam_; 568 PositionMap cachedItemPosition_; 569 PositionMap recycledItemPosition_; 570 571 bool isStackFromEnd_ = false; 572 bool isLayouted_ = true; 573 }; 574 } // namespace OHOS::Ace::NG 575 576 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_LAYOUT_ALGORITHM_H 577