• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_pattern.h"
17 
18 #include "base/log/dump_log.h"
19 #include "core/components/list/list_item_theme.h"
20 #include "core/components_ng/pattern/list/list_item_group_layout_algorithm.h"
21 #include "core/components_ng/pattern/list/list_item_group_paint_method.h"
22 #include "core/components_ng/pattern/list/list_pattern.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 
25 namespace OHOS::Ace::NG {
26 
OnAttachToFrameNode()27 void ListItemGroupPattern::OnAttachToFrameNode()
28 {
29     auto host = GetHost();
30     CHECK_NULL_VOID(host);
31     if (listItemGroupStyle_ == V2::ListItemGroupStyle::CARD) {
32         SetListItemGroupDefaultAttributes(host);
33     }
34 }
35 
OnColorConfigurationUpdate()36 void ListItemGroupPattern::OnColorConfigurationUpdate()
37 {
38     if (listItemGroupStyle_ != V2::ListItemGroupStyle::CARD) {
39         return;
40     }
41     auto itemGroupNode = GetHost();
42     CHECK_NULL_VOID(itemGroupNode);
43     auto renderContext = itemGroupNode->GetRenderContext();
44     CHECK_NULL_VOID(renderContext);
45     auto pipeline = itemGroupNode->GetContext();
46     CHECK_NULL_VOID(pipeline);
47     auto listItemGroupTheme = pipeline->GetTheme<ListItemTheme>();
48     CHECK_NULL_VOID(listItemGroupTheme);
49 
50     renderContext->UpdateBackgroundColor(listItemGroupTheme->GetItemGroupDefaultColor());
51 }
52 
SetListItemGroupDefaultAttributes(const RefPtr<FrameNode> & itemGroupNode)53 void ListItemGroupPattern::SetListItemGroupDefaultAttributes(const RefPtr<FrameNode>& itemGroupNode)
54 {
55     auto renderContext = itemGroupNode->GetRenderContext();
56     CHECK_NULL_VOID(renderContext);
57     auto layoutProperty = itemGroupNode->GetLayoutProperty<ListItemGroupLayoutProperty>();
58     CHECK_NULL_VOID(layoutProperty);
59 
60     auto pipeline = GetContext();
61     CHECK_NULL_VOID(pipeline);
62     auto listItemGroupTheme = pipeline->GetTheme<ListItemTheme>();
63     CHECK_NULL_VOID(listItemGroupTheme);
64 
65     renderContext->UpdateBackgroundColor(listItemGroupTheme->GetItemGroupDefaultColor());
66 
67     MarginProperty itemGroupMargin;
68     itemGroupMargin.left = CalcLength(listItemGroupTheme->GetItemGroupDefaultLeftMargin());
69     itemGroupMargin.right = CalcLength(listItemGroupTheme->GetItemGroupDefaultRightMargin());
70     layoutProperty->UpdateMargin(itemGroupMargin);
71 
72     PaddingProperty itemGroupPadding;
73     itemGroupPadding.left = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Left());
74     itemGroupPadding.right = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Right());
75     itemGroupPadding.top = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Top());
76     itemGroupPadding.bottom = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Bottom());
77     layoutProperty->UpdatePadding(itemGroupPadding);
78 
79     renderContext->UpdateBorderRadius(listItemGroupTheme->GetItemGroupDefaultBorderRadius());
80 }
81 
DumpAdvanceInfo()82 void ListItemGroupPattern::DumpAdvanceInfo()
83 {
84     DumpLog::GetInstance().AddDesc("itemStartIndex:" + std::to_string(itemStartIndex_));
85     DumpLog::GetInstance().AddDesc("itemTotalCount:" + std::to_string(itemTotalCount_));
86     DumpLog::GetInstance().AddDesc("itemDisplayEndIndex:" + std::to_string(itemDisplayEndIndex_));
87     DumpLog::GetInstance().AddDesc("itemDisplayStartIndex:" + std::to_string(itemDisplayStartIndex_));
88     DumpLog::GetInstance().AddDesc("headerMainSize:" + std::to_string(headerMainSize_));
89     DumpLog::GetInstance().AddDesc("footerMainSize:" + std::to_string(footerMainSize_));
90     DumpLog::GetInstance().AddDesc("spaceWidth:" + std::to_string(spaceWidth_));
91     DumpLog::GetInstance().AddDesc("lanes:" + std::to_string(lanes_));
92     DumpLog::GetInstance().AddDesc("laneGutter:" + std::to_string(laneGutter_));
93     DumpLog::GetInstance().AddDesc("startHeaderPos:" + std::to_string(startHeaderPos_));
94     DumpLog::GetInstance().AddDesc("endFooterPos:" + std::to_string(endFooterPos_));
95 }
96 
CreateLayoutAlgorithm()97 RefPtr<LayoutAlgorithm> ListItemGroupPattern::CreateLayoutAlgorithm()
98 {
99     CalculateItemStartIndex();
100     auto layoutAlgorithm = MakeRefPtr<ListItemGroupLayoutAlgorithm>(headerIndex_, footerIndex_, itemStartIndex_);
101     layoutAlgorithm->SetItemsPosition(itemPosition_);
102     layoutAlgorithm->SetLayoutedItemInfo(layoutedItemInfo_);
103     if (childrenSize_ && ListChildrenSizeExist()) {
104         if (!posMap_) {
105             posMap_ = MakeRefPtr<ListPositionMap>();
106         }
107         layoutAlgorithm->SetListChildrenMainSize(childrenSize_);
108         layoutAlgorithm->SetListPositionMap(posMap_);
109     }
110     return layoutAlgorithm;
111 }
112 
CreateNodePaintMethod()113 RefPtr<NodePaintMethod> ListItemGroupPattern::CreateNodePaintMethod()
114 {
115     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
116     V2::ItemDivider itemDivider;
117     auto divider = layoutProperty->GetDivider().value_or(itemDivider);
118     auto drawVertical = (axis_ == Axis::HORIZONTAL);
119     ListItemGroupPaintInfo listItemGroupPaintInfo { layoutDirection_, mainSize_, drawVertical, lanes_,
120         spaceWidth_, laneGutter_, itemTotalCount_ };
121     return MakeRefPtr<ListItemGroupPaintMethod>(divider, listItemGroupPaintInfo, itemPosition_, pressedItem_);
122 }
123 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)124 bool ListItemGroupPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
125 {
126     if (config.skipMeasure && config.skipLayout) {
127         return false;
128     }
129     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
130     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
131     auto layoutAlgorithm = DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
132     CHECK_NULL_RETURN(layoutAlgorithm, false);
133     itemTotalCount_ = layoutAlgorithm->GetTotalItemCount();
134     auto cacheParam = layoutAlgorithm->GetCacheParam();
135     if (cacheParam) {
136         forwardCachedIndex_ = cacheParam.value().forwardCachedIndex;
137         backwardCachedIndex_ = cacheParam.value().backwardCachedIndex;
138         layoutAlgorithm->SetCacheParam(std::nullopt);
139         return false;
140     }
141     itemPosition_ = layoutAlgorithm->GetItemPosition();
142     spaceWidth_ = layoutAlgorithm->GetSpaceWidth();
143     lanes_ = layoutAlgorithm->GetLanes();
144     axis_ = layoutAlgorithm->GetAxis();
145     layoutDirection_ = layoutAlgorithm->GetLayoutDirection();
146     mainSize_ = layoutAlgorithm->GetMainSize();
147     laneGutter_ = layoutAlgorithm->GetLaneGutter();
148     itemDisplayEndIndex_ = layoutAlgorithm->GetEndIndex();
149     itemDisplayStartIndex_ = layoutAlgorithm->GetStartIndex();
150     headerMainSize_ = layoutAlgorithm->GetHeaderMainSize();
151     footerMainSize_ = layoutAlgorithm->GetFooterMainSize();
152     layoutedItemInfo_ = layoutAlgorithm->GetLayoutedItemInfo();
153     startHeaderPos_ = layoutAlgorithm->GetStartHeaderPos();
154     endFooterPos_ = layoutAlgorithm->GetEndFooterPos();
155     layouted_ = true;
156     CheckListDirectionInCardStyle();
157     auto host = GetHost();
158     CHECK_NULL_RETURN(host, false);
159     auto accessibilityProperty = host->GetAccessibilityProperty<ListItemGroupAccessibilityProperty>();
160     if (accessibilityProperty != nullptr) {
161         accessibilityProperty->SetCollectionItemCounts(layoutAlgorithm->GetTotalItemCount());
162     }
163     auto listLayoutProperty = host->GetLayoutProperty<ListItemGroupLayoutProperty>();
164     return listLayoutProperty && listLayoutProperty->GetDivider().has_value() && !itemPosition_.empty();
165 }
166 
GetPaddingAndMargin() const167 float ListItemGroupPattern::GetPaddingAndMargin() const
168 {
169     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
170     CHECK_NULL_RETURN(layoutProperty, 0.0f);
171     const auto& padding = layoutProperty->CreatePaddingAndBorder();
172     const auto& margin = layoutProperty->CreateMargin();
173     auto offsetBeforeContent = axis_ == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
174     auto offsetAfterContent = axis_ == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
175     offsetBeforeContent += axis_ == Axis::HORIZONTAL ? margin.left.value_or(0) : margin.top.value_or(0);
176     offsetAfterContent += axis_ == Axis::HORIZONTAL ? margin.right.value_or(0) : margin.bottom.value_or(0);
177     return offsetBeforeContent + offsetAfterContent;
178 }
179 
GetEstimateOffset(float height,const std::pair<float,float> & targetPos) const180 float ListItemGroupPattern::GetEstimateOffset(float height, const std::pair<float, float>& targetPos) const
181 {
182     if (layoutedItemInfo_.has_value() && layoutedItemInfo_.value().startIndex > 0) {
183         float averageHeight = 0.0f;
184         float estimateHeight = GetEstimateHeight(averageHeight);
185         if (layoutedItemInfo_.value().endIndex >= itemTotalCount_ - 1) {
186             return height + estimateHeight - targetPos.second;
187         } else {
188             return height - targetPos.first + layoutedItemInfo_.value().startIndex * averageHeight - spaceWidth_;
189         }
190     }
191     return height - targetPos.first;
192 }
193 
GetEstimateHeight(float & averageHeight) const194 float ListItemGroupPattern::GetEstimateHeight(float& averageHeight) const
195 {
196     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
197     CHECK_NULL_RETURN(layoutProperty, 0.0f);
198     auto visible = layoutProperty->GetVisibility().value_or(VisibleType::VISIBLE);
199     if (visible == VisibleType::GONE) {
200         return 0.0f;
201     }
202     float paddingAndMargin = GetPaddingAndMargin();
203     if (layoutedItemInfo_.has_value()) {
204         auto totalHeight = (layoutedItemInfo_.value().endPos - layoutedItemInfo_.value().startPos + spaceWidth_);
205         auto itemCount = layoutedItemInfo_.value().endIndex - layoutedItemInfo_.value().startIndex + 1;
206         averageHeight = totalHeight / itemCount;
207     }
208     if (layouted_) {
209         if (itemTotalCount_ > 0) {
210             return itemTotalCount_ * averageHeight + headerMainSize_ + footerMainSize_ + paddingAndMargin - spaceWidth_;
211         } else {
212             return headerMainSize_ + footerMainSize_ + paddingAndMargin;
213         }
214     }
215     auto host = GetHost();
216     auto totalItem = host->GetTotalChildCount();
217     return averageHeight * totalItem + paddingAndMargin;
218 }
219 
CheckListDirectionInCardStyle()220 void ListItemGroupPattern::CheckListDirectionInCardStyle()
221 {
222     if (axis_ == Axis::HORIZONTAL && listItemGroupStyle_ == V2::ListItemGroupStyle::CARD) {
223         auto host = GetHost();
224         CHECK_NULL_VOID(host);
225         RefPtr<FrameNode> listNode = AceType::DynamicCast<FrameNode>(host->GetParent());
226         CHECK_NULL_VOID(listNode);
227         auto listPattern = listNode->GetPattern<ListPattern>();
228         CHECK_NULL_VOID(listPattern);
229         listPattern->SetNeedToUpdateListDirectionInCardStyle(true);
230     }
231 }
232 
GetListFrameNode() const233 RefPtr<FrameNode> ListItemGroupPattern::GetListFrameNode() const
234 {
235     auto host = GetHost();
236     CHECK_NULL_RETURN(host, nullptr);
237     auto parent = host->GetParent();
238     RefPtr<FrameNode> frameNode = AceType::DynamicCast<FrameNode>(parent);
239     while (parent && !frameNode) {
240         parent = parent->GetParent();
241         frameNode = AceType::DynamicCast<FrameNode>(parent);
242     }
243     return frameNode;
244 }
245 
ListChildrenSizeExist()246 bool ListItemGroupPattern::ListChildrenSizeExist()
247 {
248     RefPtr<FrameNode> listNode = GetListFrameNode();
249     CHECK_NULL_RETURN(listNode, false);
250     auto listPattern = listNode->GetPattern<ListPattern>();
251     CHECK_NULL_RETURN(listPattern, false);
252     return listPattern->ListChildrenSizeExist();
253 }
254 
GetOrCreateListChildrenMainSize()255 RefPtr<ListChildrenMainSize> ListItemGroupPattern::GetOrCreateListChildrenMainSize()
256 {
257     if (childrenSize_) {
258         return childrenSize_;
259     }
260     childrenSize_ = AceType::MakeRefPtr<ListChildrenMainSize>();
261     auto callback = [weakPattern = WeakClaim(this)](std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag) {
262         auto pattern = weakPattern.Upgrade();
263         CHECK_NULL_VOID(pattern);
264         auto context = PipelineContext::GetCurrentContext();
265         CHECK_NULL_VOID(context);
266         context->AddBuildFinishCallBack([weakPattern, change, flag]() {
267             auto pattern = weakPattern.Upgrade();
268             CHECK_NULL_VOID(pattern);
269             pattern->OnChildrenSizeChanged(change, flag);
270         });
271         context->RequestFrame();
272     };
273     childrenSize_->SetOnDataChange(callback);
274     return childrenSize_;
275 }
276 
SetListChildrenMainSize(float defaultSize,const std::vector<float> & mainSize)277 void ListItemGroupPattern::SetListChildrenMainSize(
278     float defaultSize, const std::vector<float>& mainSize)
279 {
280     childrenSize_ = AceType::MakeRefPtr<ListChildrenMainSize>(mainSize, defaultSize);
281     OnChildrenSizeChanged({ -1, -1, -1 }, LIST_UPDATE_CHILD_SIZE);
282 }
283 
OnChildrenSizeChanged(std::tuple<int32_t,int32_t,int32_t> change,ListChangeFlag flag)284 void ListItemGroupPattern::OnChildrenSizeChanged(std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag)
285 {
286     if (!posMap_) {
287         posMap_ = MakeRefPtr<ListPositionMap>();
288     }
289     posMap_->MarkDirty(flag);
290     auto host = GetHost();
291     CHECK_NULL_VOID(host);
292     host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
293 }
294 
GetStartListItemIndex()295 VisibleContentInfo ListItemGroupPattern::GetStartListItemIndex()
296 {
297     bool isHeader = false;
298     auto startHeaderMainSize = GetHeaderMainSize();
299     auto startFooterMainSize = GetFooterMainSize();
300     if (GetDisplayStartIndexInGroup() == 0) {
301         auto startHeaderPos = startHeaderPos_;
302         isHeader = (startHeaderPos + startHeaderMainSize) > 0 ? true : false;
303     }
304     auto startPositionSize = GetItemPosition().size();
305     auto startItemIndexInGroup = GetDisplayStartIndexInGroup();
306     auto startArea = ListItemGroupArea::IN_LIST_ITEM_AREA;
307     if (startPositionSize == 0 && startFooterMainSize > 0) {
308         startArea = ListItemGroupArea::IN_FOOTER_AREA;
309         startItemIndexInGroup = -1;
310     }
311     if (GetDisplayStartIndexInGroup() == 0 && isHeader && startHeaderMainSize > 0) {
312         startArea = ListItemGroupArea::IN_HEADER_AREA;
313         startItemIndexInGroup = -1;
314     }
315     if (startHeaderMainSize == 0 && startFooterMainSize == 0 && GetTotalItemCount() == 0) {
316         startArea = ListItemGroupArea::NONE_AREA;
317     }
318     VisibleContentInfo startInfo = { startArea, startItemIndexInGroup };
319     return startInfo;
320 }
321 
GetEndListItemIndex()322 VisibleContentInfo ListItemGroupPattern::GetEndListItemIndex()
323 {
324     bool isFooter = endFooterPos_ < 0 ? true : false;
325     auto endHeaderMainSize = GetHeaderMainSize();
326     auto endFooterMainSize = GetFooterMainSize();
327     auto endPositionSize = GetItemPosition().size();
328     auto endItemIndexInGroup = GetDisplayEndIndexInGroup();
329     auto endArea = ListItemGroupArea::IN_LIST_ITEM_AREA;
330     if (endPositionSize == 0 && endHeaderMainSize > 0) {
331         endArea = ListItemGroupArea::IN_HEADER_AREA;
332         endItemIndexInGroup = -1;
333     }
334     if (isFooter && endFooterMainSize > 0) {
335         endArea = ListItemGroupArea::IN_FOOTER_AREA;
336         endItemIndexInGroup = -1;
337     }
338     if (endHeaderMainSize == 0 && endFooterMainSize == 0 && GetTotalItemCount() == 0) {
339         endArea = ListItemGroupArea::NONE_AREA;
340     }
341     VisibleContentInfo endInfo = { endArea, endItemIndexInGroup };
342     return endInfo;
343 }
344 
ResetChildrenSize()345 void ListItemGroupPattern::ResetChildrenSize()
346 {
347     if (childrenSize_) {
348         childrenSize_ = nullptr;
349         auto host = GetHost();
350         CHECK_NULL_VOID(host);
351         host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
352         OnChildrenSizeChanged({ -1, -1, -1 }, LIST_UPDATE_CHILD_SIZE);
353     }
354 }
355 
ClearItemPosition()356 void ListItemGroupPattern::ClearItemPosition()
357 {
358     itemPosition_.clear();
359 }
360 
CalculateItemStartIndex()361 void ListItemGroupPattern::CalculateItemStartIndex()
362 {
363     int32_t headerIndex = -1;
364     int32_t footerIndex = -1;
365     int32_t itemStartIndex = 0;
366     auto header = header_.Upgrade();
367     if (header) {
368         auto count = header->FrameCount();
369         if (count > 0) {
370             headerIndex = itemStartIndex;
371             itemStartIndex += count;
372         }
373     }
374     auto footer = footer_.Upgrade();
375     if (footer) {
376         int32_t count = footer->FrameCount();
377         if (count > 0) {
378             footerIndex = itemStartIndex;
379             itemStartIndex += count;
380         }
381     }
382     headerIndex_ = headerIndex;
383     footerIndex_ = footerIndex;
384     itemStartIndex_ = itemStartIndex;
385 }
386 
UpdateActiveChildRange(bool forward,int32_t cacheCount)387 void ListItemGroupPattern::UpdateActiveChildRange(bool forward, int32_t cacheCount)
388 {
389     auto host = GetHost();
390     CHECK_NULL_VOID(host);
391     if (forward) {
392         host->SetActiveChildRange(-1, itemStartIndex_ - 1, 0, cacheCount);
393     } else {
394         int32_t index = itemTotalCount_ + itemStartIndex_;
395         host->SetActiveChildRange(index, index, cacheCount, 0);
396     }
397 }
398 
UpdateForwardCachedIndex(int32_t cacheCount,bool outOfView)399 int32_t ListItemGroupPattern::UpdateForwardCachedIndex(int32_t cacheCount, bool outOfView)
400 {
401     int32_t endIndex = (outOfView || itemPosition_.empty()) ? -1 : itemPosition_.rbegin()->first;
402     int32_t limit = std::min(endIndex + cacheCount * lanes_, itemTotalCount_ - 1);
403     int32_t forwardCachedIndex = std::clamp(forwardCachedIndex_, endIndex, limit);
404     if (outOfView && forwardCachedIndex < forwardCachedIndex_) {
405         UpdateActiveChildRange(true, forwardCachedIndex + 1);
406     }
407     forwardCachedIndex_ = forwardCachedIndex;
408     return forwardCachedIndex_;
409 }
410 
UpdateBackwardCachedIndex(int32_t cacheCount,bool outOfView)411 int32_t ListItemGroupPattern::UpdateBackwardCachedIndex(int32_t cacheCount, bool outOfView)
412 {
413     int32_t startIndex = (outOfView || itemPosition_.empty()) ? itemTotalCount_ : itemPosition_.begin()->first;
414     int32_t limit = std::max(startIndex - cacheCount * lanes_, 0);
415     int32_t backwardCachedIndex = std::clamp(backwardCachedIndex_, limit, startIndex);
416     if (outOfView && backwardCachedIndex > backwardCachedIndex_) {
417         UpdateActiveChildRange(false, itemTotalCount_ - backwardCachedIndex);
418     }
419     backwardCachedIndex_ = backwardCachedIndex;
420     return backwardCachedIndex_;
421 }
422 
LayoutCache(const LayoutConstraintF & constraint,bool forward,int64_t deadline,int32_t cached,ListMainSizeValues listSizeValues)423 void ListItemGroupPattern::LayoutCache(const LayoutConstraintF& constraint, bool forward, int64_t deadline,
424     int32_t cached, ListMainSizeValues listSizeValues)
425 {
426     ACE_SCOPED_TRACE("Group LayoutCache:%d,%d", forward, cached);
427     auto listNode = GetListFrameNode();
428     CHECK_NULL_VOID(listNode);
429     auto listLayoutProperty = listNode->GetLayoutProperty<ListLayoutProperty>();
430     CHECK_NULL_VOID(listLayoutProperty);
431     auto cacheCount = listLayoutProperty->GetCachedCountWithDefault() - cached;
432     if (cacheCount < 1) {
433         return;
434     }
435     auto host = GetHost();
436     CHECK_NULL_VOID(host);
437     auto layoutAlgorithmWrapper = host->GetLayoutAlgorithm(true);
438     CHECK_NULL_VOID(layoutAlgorithmWrapper);
439     auto itemGroup = AceType::DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
440     CHECK_NULL_VOID(itemGroup);
441     ListItemGroupCacheParam param = {
442         .forward = forward,
443         .cacheCount = cacheCount,
444         .forwardCachedIndex = forwardCachedIndex_,
445         .backwardCachedIndex = backwardCachedIndex_,
446         .deadline = deadline,
447     };
448     itemGroup->SetCacheParam(param);
449     itemGroup->SetListLayoutProperty(listLayoutProperty);
450     itemGroup->SetListMainSize(listSizeValues.startPos, listSizeValues.endPos, listSizeValues.referencePos,
451         listSizeValues.prevContentMainSize, forward);
452     host->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
453     host->GetGeometryNode()->SetParentLayoutConstraint(constraint);
454     FrameNode::ProcessOffscreenNode(host);
455 }
456 
SetListItemGroupStyle(V2::ListItemGroupStyle style)457 void ListItemGroupPattern::SetListItemGroupStyle(V2::ListItemGroupStyle style)
458 {
459     auto host = GetHost();
460     CHECK_NULL_VOID(host);
461     if (listItemGroupStyle_ == V2::ListItemGroupStyle::NONE && style == V2::ListItemGroupStyle::CARD) {
462         listItemGroupStyle_ = style;
463         SetListItemGroupDefaultAttributes(host);
464     }
465 }
466 
GetListPaddingOffset(const RefPtr<FrameNode> & listNode) const467 float ListItemGroupPattern::GetListPaddingOffset(const RefPtr<FrameNode>& listNode) const
468 {
469     float offset = 0;
470     CHECK_NULL_RETURN(listNode, offset);
471     auto layoutProperty = listNode->GetLayoutProperty<ListLayoutProperty>();
472     CHECK_NULL_RETURN(layoutProperty, offset);
473     auto padding = layoutProperty->CreatePaddingAndBorder();
474     return GetMainAxisOffset(padding.Offset(), axis_);
475 }
476 
FirstItemFullVisible(const RefPtr<FrameNode> & listNode) const477 bool ListItemGroupPattern::FirstItemFullVisible(const RefPtr<FrameNode>& listNode) const
478 {
479     auto host = GetHost();
480     CHECK_NULL_RETURN(host, true);
481     auto geometryNode = host->GetGeometryNode();
482     CHECK_NULL_RETURN(geometryNode, true);
483     OffsetF selfOffset = geometryNode->GetPaddingOffset();
484     float mainPos = GetMainAxisOffset(selfOffset, axis_) + headerMainSize_;
485     float listPadding = GetListPaddingOffset(listNode);
486     return GreatNotEqual(mainPos, listPadding);
487 }
488 
CheckDataChangeOutOfStart(int32_t index,int32_t count,int32_t startIndex)489 bool ListItemGroupPattern::CheckDataChangeOutOfStart(int32_t index, int32_t count, int32_t startIndex)
490 {
491     if (count == 0 || (count > 0 && index > startIndex) ||
492         (count < 0 && index >= startIndex)) {
493         return false;
494     }
495 
496     RefPtr<FrameNode> listNode = GetListFrameNode();
497     CHECK_NULL_RETURN(listNode, false);
498     auto listPattern = listNode->GetPattern<ListPattern>();
499     CHECK_NULL_RETURN(listPattern, false);
500     if (!listPattern->GetMaintainVisibleContentPosition()) {
501         return false;
502     }
503 
504     if (startIndex == 0 && index == 0 && count > 0 && FirstItemFullVisible(listNode)) {
505         return false;
506     }
507     listPattern->MarkNeedReEstimateOffset();
508     return true;
509 }
510 
NotifyDataChange(int32_t index,int32_t count)511 void ListItemGroupPattern::NotifyDataChange(int32_t index, int32_t count)
512 {
513     if (itemPosition_.empty()) {
514         return;
515     }
516     index -= itemStartIndex_;
517     int32_t startIndex = itemPosition_.begin()->first;
518     if (!CheckDataChangeOutOfStart(index, count, startIndex)) {
519         return;
520     }
521 
522     count = std::max(count, index - startIndex);
523     int32_t mod = 0;
524     if (count < 0 && lanes_ > 1) {
525         mod = -count % lanes_;
526     }
527     auto prevPosMap = std::move(itemPosition_);
528     for (auto &pos : prevPosMap) {
529         if (mod > 0) {
530             mod--;
531         } else {
532             itemPosition_[pos.first + count] = pos.second;
533         }
534     }
535     if (layoutedItemInfo_ && layoutedItemInfo_.value().startIndex >= index) {
536         auto& info = layoutedItemInfo_.value();
537         info.startIndex = std::max(info.startIndex + count, 0);
538         info.endIndex = std::max(info.endIndex + count, 0);
539         if (lanes_ > 1) {
540             if (count < 0) {
541                 info.startIndex += -count % lanes_;
542             } else {
543                 info.endIndex -= count % lanes_;
544             }
545         }
546     }
547 }
548 } // namespace OHOS::Ace::NG
549