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