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/swiper/swiper_layout_algorithm.h"
17
18 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
19 #include "core/components_ng/pattern/swiper_indicator/dot_indicator/dot_indicator_paint_property.h"
20 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_utils.h"
21
22 namespace OHOS::Ace::NG {
23
24 namespace {
25 constexpr Dimension INDICATOR_PADDING = 8.0_vp;
26 constexpr uint32_t INDICATOR_HAS_CHILD = 2;
27 constexpr uint32_t SWIPER_HAS_CHILD = 5;
28 constexpr int32_t DEFAULT_DOUBLE = 2;
29 } // namespace
30
IndicatorAndArrowMeasure(LayoutWrapper * layoutWrapper,const OptionalSizeF & parentIdealSize)31 void SwiperLayoutAlgorithm::IndicatorAndArrowMeasure(LayoutWrapper* layoutWrapper, const OptionalSizeF& parentIdealSize)
32 {
33 auto property = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
34 CHECK_NULL_VOID(property);
35
36 // Measure swiper indicator
37 if (property->GetShowIndicatorValue(true)) {
38 auto hostNode = layoutWrapper->GetHostNode();
39 CHECK_NULL_VOID(hostNode);
40 auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
41 CHECK_NULL_VOID(swiperPattern);
42 auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
43 if (indicatorWrapper) {
44 auto indicatorLayoutConstraint = property->CreateChildConstraint();
45 indicatorLayoutConstraint.parentIdealSize = parentIdealSize;
46 indicatorWrapper->Measure(indicatorLayoutConstraint);
47 }
48 }
49
50 if (property->GetDisplayArrowValue(false)) {
51 auto hostNode = layoutWrapper->GetHostNode();
52 CHECK_NULL_VOID(hostNode);
53 auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
54 CHECK_NULL_VOID(swiperPattern);
55
56 if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
57 auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
58 auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
59 CHECK_NULL_VOID(leftArrowWrapper);
60 CHECK_NULL_VOID(rightArrowWrapper);
61 if (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG &&
62 rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
63 MeasureArrow(leftArrowWrapper, property);
64 MeasureArrow(rightArrowWrapper, property);
65 }
66 }
67 }
68 }
69
UpdateLayoutInfoBeforeMeasureSwiper(const RefPtr<SwiperLayoutProperty> & property,const LayoutConstraintF & layoutConstraint)70 void SwiperLayoutAlgorithm::UpdateLayoutInfoBeforeMeasureSwiper(
71 const RefPtr<SwiperLayoutProperty>& property, const LayoutConstraintF& layoutConstraint)
72 {
73 if (measured_) {
74 // flex property causes Swiper to be measured twice, and itemPosition_ would
75 // reset after the first measure. Restore to that on second measure.
76 itemPosition_ = prevItemPosition_;
77 // targetIndex_ has also been reset during the first measure.
78 targetIndex_ = currentTargetIndex_;
79 if (duringInteraction_ || NearEqual(oldContentMainSize_, contentMainSize_)) {
80 jumpIndex_ = currentJumpIndex_;
81 }
82 ignoreBlankOffset_ = currentIgnoreBlankOffset_;
83 }
84 currentOffset_ = currentDelta_;
85 startMainPos_ = currentOffset_;
86 ACE_SCOPED_TRACE("measure swiper startMainPos_:%f, jumpIndex_:%d, targetIndex_:%d", startMainPos_,
87 jumpIndex_.value_or(-1), targetIndex_.value_or(-1));
88 if (SwiperUtils::IsStretch(property)) {
89 prevMargin_ = property->GetCalculatedPrevMargin();
90 nextMargin_ = property->GetCalculatedNextMargin();
91 placeItemWidth_ = layoutConstraint.selfIdealSize.MainSize(axis_);
92 }
93 auto itemSpace = SwiperUtils::GetItemSpace(property);
94 spaceWidth_ = itemSpace > (contentMainSize_ + paddingBeforeContent_ + paddingAfterContent_) ? 0.0f : itemSpace;
95 auto prevMargin = NearZero(prevMargin_) ? 0.0f : prevMargin_ + spaceWidth_;
96 auto nextMargin = NearZero(nextMargin_) ? 0.0f : nextMargin_ + spaceWidth_;
97 endMainPos_ = currentOffset_ + contentMainSize_ - prevMargin - nextMargin;
98
99 prevMarginIgnoreBlank_ = property->GetPrevMarginIgnoreBlank().value_or(false);
100 if (!isLoop_ && jumpIndex_.has_value() && totalItemCount_ > property->GetDisplayCount().value_or(1)) {
101 if (prevMarginIgnoreBlank_ && jumpIndex_.value() == 0) {
102 ignoreBlankOffset_ = Positive(prevMargin_) ? -(prevMargin_ + spaceWidth_) : 0.0f;
103 } else if (property->GetNextMarginIgnoreBlank().value_or(false) &&
104 jumpIndex_.value() >= (totalItemCount_ - property->GetDisplayCount().value_or(1))) {
105 ignoreBlankOffset_ = Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f;
106 } else {
107 ignoreBlankOffset_ = 0.0f;
108 }
109 }
110 }
111
GetLoopIndex(int32_t originalIndex) const112 int32_t SwiperLayoutAlgorithm::GetLoopIndex(int32_t originalIndex) const
113 {
114 if (totalItemCount_ <= 0) {
115 return originalIndex;
116 }
117 auto loopIndex = originalIndex;
118 while (loopIndex < 0) {
119 loopIndex = loopIndex + totalItemCount_;
120 }
121 loopIndex %= totalItemCount_;
122 return loopIndex;
123 }
124
Measure(LayoutWrapper * layoutWrapper)125 void SwiperLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
126 {
127 std::lock_guard<std::mutex> lock(swiperMutex_);
128 CHECK_NULL_VOID(layoutWrapper);
129 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
130 CHECK_NULL_VOID(swiperLayoutProperty);
131 if (!measured_) {
132 currentTargetIndex_ = targetIndex_;
133 currentJumpIndex_ = jumpIndex_;
134 currentIgnoreBlankOffset_ = ignoreBlankOffset_;
135 }
136 if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
137 MeasureTabsCustomAnimation(layoutWrapper);
138 return;
139 }
140
141 axis_ = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
142 // calculate main size.
143 auto contentConstraint = swiperLayoutProperty->GetContentLayoutConstraint().value();
144 swiperLayoutProperty->ResetIgnorePrevMarginAndNextMargin();
145 auto isSingleCase = SwiperUtils::CheckIsSingleCase(swiperLayoutProperty);
146 OptionalSizeF contentIdealSize;
147 if (isSingleCase) {
148 contentIdealSize = CreateIdealSizeByPercentRef(contentConstraint, axis_, MeasureType::MATCH_CONTENT);
149 if (mainSizeIsMeasured_) {
150 if (!layoutWrapper->ConstraintChanged()) {
151 contentIdealSize.SetMainSize(contentMainSize_, axis_);
152 } else {
153 mainSizeIsMeasured_ = false;
154 }
155 }
156 } else {
157 contentIdealSize = CreateIdealSizeByPercentRef(contentConstraint, axis_, MeasureType::MATCH_PARENT_MAIN_AXIS);
158 if (layoutWrapper->ConstraintChanged()) {
159 mainSizeIsMeasured_ = false;
160 jumpIndex_ = jumpIndex_.value_or(currentIndex_);
161 }
162 }
163
164 auto mainSize = contentIdealSize.MainSize(axis_);
165 if (mainSize.has_value()) {
166 SwiperUtils::CheckAutoFillDisplayCount(swiperLayoutProperty, mainSize.value(), realTotalCount_);
167 }
168 const auto& padding = swiperLayoutProperty->CreatePaddingAndBorder();
169 paddingBeforeContent_ = axis_ == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
170 paddingAfterContent_ = axis_ == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
171 contentMainSize_ = 0.0f;
172 if (!GetMainAxisSize(contentIdealSize, axis_) && (!isSingleCase || !mainSizeIsMeasured_)) {
173 if (totalItemCount_ == 0) {
174 contentMainSize_ = 0.0f;
175 } else {
176 // use parent percentReference size first.
177 auto parentPercentReference = contentConstraint.percentReference;
178 contentMainSize_ =
179 GetMainAxisSize(parentPercentReference, axis_) - paddingBeforeContent_ - paddingAfterContent_;
180 mainSizeIsDefined_ = false;
181 }
182 } else {
183 contentMainSize_ = GetMainAxisSize(contentIdealSize.ConvertToSizeT(), axis_);
184 mainSizeIsDefined_ = true;
185 }
186
187 auto hostNode = layoutWrapper->GetHostNode();
188 CHECK_NULL_VOID(hostNode);
189 auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
190 CHECK_NULL_VOID(swiperPattern);
191 auto getAutoFill = swiperPattern->IsAutoFill();
192 // calculate child layout constraint and check if need to reset prevMargin,nextMargin,itemspace.
193 auto childLayoutConstraint =
194 SwiperUtils::CreateChildConstraint(swiperLayoutProperty, contentIdealSize, getAutoFill);
195 childLayoutConstraint_ = childLayoutConstraint;
196 if (totalItemCount_ > 0) {
197 UpdateLayoutInfoBeforeMeasureSwiper(swiperLayoutProperty, childLayoutConstraint);
198 MeasureSwiper(layoutWrapper, childLayoutConstraint);
199 } else {
200 itemPosition_.clear();
201 }
202
203 auto cachedChildIdealSize = contentIdealSize;
204
205 auto crossSize = contentIdealSize.CrossSize(axis_);
206 if ((crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) || !crossSize.has_value()) {
207 contentCrossSize_ = GetChildMaxSize(layoutWrapper, false);
208 contentIdealSize.SetCrossSize(contentCrossSize_, axis_);
209 crossMatchChild_ = true;
210 } else {
211 contentCrossSize_ = crossSize.value();
212 }
213
214 if (!mainSizeIsDefined_ && isSingleCase) {
215 auto childMaxMainSize = GetChildMaxSize(layoutWrapper, true);
216 if (childMaxMainSize != contentMainSize_) {
217 contentMainSize_ = childMaxMainSize;
218 // CheckInactive
219 SetInactive(layoutWrapper, 0.0f, contentMainSize_, currentTargetIndex_);
220 }
221 }
222
223 if (cachedShow_) {
224 cachedChildIdealSize.SetMainSize(contentMainSize_, axis_);
225 auto cachedChildLayoutConstraint =
226 SwiperUtils::CreateChildConstraint(swiperLayoutProperty, cachedChildIdealSize, getAutoFill);
227 LayoutCachedItem(layoutWrapper, cachedChildLayoutConstraint);
228 }
229
230 MeasureSwiperCustomAnimation(layoutWrapper, childLayoutConstraint);
231 if (itemPosition_.empty()) {
232 layoutWrapper->SetActiveChildRange(-1, -1);
233 } else if (itemPositionInAnimation_.empty()) {
234 AdjustItemPositionOnCachedShow();
235
236 int32_t startIndex = GetLoopIndex(GetStartIndex());
237 int32_t endIndex = GetLoopIndex(GetEndIndex());
238 CheckCachedItem(startIndex, endIndex, layoutWrapper);
239 // startIndex maybe target to invalid blank items in group mode, need to be adjusted.
240 startIndex = startIndex < realTotalCount_ ? startIndex : 0;
241 endIndex = std::min(endIndex, realTotalCount_ - 1);
242 if (!isLoop_) {
243 layoutWrapper->SetActiveChildRange(startIndex, endIndex, std::min(cachedCount_, startIndex),
244 std::min(cachedCount_, totalItemCount_ - 1 - endIndex));
245 } else {
246 layoutWrapper->SetActiveChildRange(startIndex, endIndex, cachedCount_, cachedCount_);
247 }
248 } else {
249 AdjustItemPositionOnCachedShow();
250
251 int32_t startIndex = std::min(GetLoopIndex(itemPositionInAnimation_.begin()->first), realTotalCount_ - 1);
252 int32_t endIndex = std::min(GetLoopIndex(itemPositionInAnimation_.rbegin()->first), realTotalCount_ - 1);
253 while (startIndex + 1 < realTotalCount_ &&
254 itemPositionInAnimation_.find(startIndex + 1) != itemPositionInAnimation_.end()) {
255 startIndex++;
256 }
257 while (endIndex - 1 >= 0 &&
258 itemPositionInAnimation_.find(endIndex - 1) != itemPositionInAnimation_.end()) {
259 endIndex--;
260 }
261 CheckCachedItem(endIndex, startIndex, layoutWrapper);
262 if (!isLoop_) {
263 layoutWrapper->SetActiveChildRange(endIndex, startIndex, std::min(cachedCount_, endIndex),
264 std::min(cachedCount_, totalItemCount_ - 1 - startIndex));
265 } else {
266 layoutWrapper->SetActiveChildRange(endIndex, startIndex, cachedCount_, cachedCount_);
267 }
268 }
269
270 contentIdealSize.SetMainSize(contentMainSize_, axis_);
271 AddPaddingToSize(padding, contentIdealSize);
272 auto geometryNode = layoutWrapper->GetGeometryNode();
273 if (geometryNode) {
274 geometryNode->SetFrameSize(contentIdealSize.ConvertToSizeT());
275 }
276 if (!itemPosition_.empty()) {
277 mainSizeIsMeasured_ = true;
278 }
279
280 // set swiper cache info.
281 auto measuredItemCount = static_cast<int32_t>(measuredItems_.size());
282 auto maxCachedCount =
283 isLoop_ ? static_cast<int32_t>(std::ceil(static_cast<float>(realTotalCount_ - measuredItemCount) / 2))
284 : realTotalCount_;
285 auto cachedCount = cachedShow_ ? 0 : std::min(swiperPattern->GetCachedCount(), maxCachedCount);
286 layoutWrapper->SetCacheCount(cachedCount, childLayoutConstraint);
287 layoutWrapper->SetLongPredictTask();
288
289 IndicatorAndArrowMeasure(layoutWrapper, contentIdealSize);
290 CaptureMeasure(layoutWrapper, childLayoutConstraint);
291
292 measured_ = true;
293
294 // layout may be skipped, need to update contentMianSize after measure.
295 swiperPattern->SetContentMainSize(contentMainSize_);
296 }
297
CaptureMeasure(LayoutWrapper * layoutWrapper,LayoutConstraintF & childLayoutConstraint)298 void SwiperLayoutAlgorithm::CaptureMeasure(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint)
299 {
300 if (!hasCachedCapture_ || itemPosition_.empty()) {
301 return;
302 }
303 auto hostNode = layoutWrapper->GetHostNode();
304 CHECK_NULL_VOID(hostNode);
305 auto leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
306 auto rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
307 if (isCaptureReverse_) {
308 leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
309 rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
310 }
311 CHECK_NULL_VOID(leftCaptureWrapper);
312 CHECK_NULL_VOID(rightCaptureWrapper);
313 auto lastWrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(itemPosition_.rbegin()->first));
314 CHECK_NULL_VOID(lastWrapper);
315 auto lastNode = lastWrapper->GetGeometryNode();
316 CHECK_NULL_VOID(lastNode);
317 auto leftCaptureGeometryNode = leftCaptureWrapper->GetGeometryNode();
318 CHECK_NULL_VOID(leftCaptureGeometryNode);
319 if (!leftCaptureSize_.has_value()) {
320 leftCaptureSize_ = leftCaptureGeometryNode->GetFrameSize();
321 }
322 childLayoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(lastNode->GetMarginFrameSize()));
323 leftCaptureWrapper->Measure(childLayoutConstraint);
324
325 auto firstWrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(itemPosition_.begin()->first));
326 CHECK_NULL_VOID(firstWrapper);
327 auto firstNode = firstWrapper->GetGeometryNode();
328 CHECK_NULL_VOID(firstNode);
329 auto rightCaptureGeometryNode = rightCaptureWrapper->GetGeometryNode();
330 CHECK_NULL_VOID(rightCaptureGeometryNode);
331 if (!rightCaptureSize_.has_value()) {
332 rightCaptureSize_ = rightCaptureGeometryNode->GetFrameSize();
333 }
334 childLayoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(firstNode->GetMarginFrameSize()));
335 rightCaptureWrapper->Measure(childLayoutConstraint);
336
337 isNeedUpdateCapture_ =
338 leftCaptureSize_ != lastNode->GetFrameSize() || rightCaptureSize_ != firstNode->GetFrameSize();
339 }
340
MeasureTabsCustomAnimation(LayoutWrapper * layoutWrapper)341 void SwiperLayoutAlgorithm::MeasureTabsCustomAnimation(LayoutWrapper* layoutWrapper)
342 {
343 auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
344 CHECK_NULL_VOID(layoutProperty);
345 auto axis = layoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
346 auto contentConstraint = layoutProperty->GetContentLayoutConstraint().value();
347 auto contentIdealSize = CreateIdealSizeByPercentRef(contentConstraint, axis, MeasureType::MATCH_PARENT_MAIN_AXIS);
348 auto childLayoutConstraint = SwiperUtils::CreateChildConstraint(layoutProperty, contentIdealSize, false);
349 auto childCrossSize = 0.0f;
350
351 auto currentIndex = layoutProperty->GetIndex().value_or(0);
352 auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
353 CHECK_NULL_VOID(currentIndexWrapper);
354 currentIndexWrapper->Measure(childLayoutConstraint);
355 auto currentIndexGeometryNode = currentIndexWrapper->GetGeometryNode();
356 if (currentIndexGeometryNode) {
357 childCrossSize = std::max(childCrossSize, currentIndexGeometryNode->GetMarginFrameSize().CrossSize(axis));
358 }
359
360 if (customAnimationToIndex_) {
361 auto toIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(customAnimationToIndex_.value());
362 CHECK_NULL_VOID(toIndexWrapper);
363 toIndexWrapper->Measure(childLayoutConstraint);
364 auto toIndexGeometryNode = toIndexWrapper->GetGeometryNode();
365 if (toIndexGeometryNode) {
366 childCrossSize = std::max(childCrossSize, toIndexGeometryNode->GetMarginFrameSize().CrossSize(axis));
367 }
368 }
369
370 auto crossSize = contentIdealSize.CrossSize(axis);
371 if ((crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) || !crossSize.has_value()) {
372 contentIdealSize.SetCrossSize(childCrossSize, axis);
373 }
374 auto geometryNode = layoutWrapper->GetGeometryNode();
375 if (geometryNode) {
376 geometryNode->SetFrameSize(contentIdealSize.ConvertToSizeT());
377 }
378
379 std::set<int32_t> removeIndexs;
380 for (const auto& index : needUnmountIndexs_) {
381 if (indexsInAnimation_.find(index) != indexsInAnimation_.end()) {
382 continue;
383 }
384
385 layoutWrapper->RemoveChildInRenderTree(index);
386 removeIndexs.insert(index);
387 }
388
389 for (const auto& index : removeIndexs) {
390 needUnmountIndexs_.erase(index);
391 }
392 }
393
MeasureSwiperCustomAnimation(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint)394 void SwiperLayoutAlgorithm::MeasureSwiperCustomAnimation(LayoutWrapper* layoutWrapper,
395 const LayoutConstraintF& layoutConstraint)
396 {
397 std::set<int32_t> measureIndexSet;
398 for (const auto& pos : itemPosition_) {
399 measureIndexSet.insert(GetLoopIndex(pos.first));
400 }
401 for (const auto& pos : itemPositionInAnimation_) {
402 if (measureIndexSet.find(pos.first) == measureIndexSet.end()) {
403 auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(pos.first);
404 CHECK_NULL_VOID(currentIndexWrapper);
405 currentIndexWrapper->Measure(layoutConstraint);
406 }
407 }
408 }
409
GetChildMaxSize(LayoutWrapper * layoutWrapper,bool isMainAxis) const410 float SwiperLayoutAlgorithm::GetChildMaxSize(LayoutWrapper* layoutWrapper, bool isMainAxis) const
411 {
412 if (itemPosition_.empty()) {
413 return 0.0f;
414 }
415 float maxSize = 0.0f;
416 float size = 0.0f;
417 for (const auto& pos : itemPosition_) {
418 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(pos.first), false);
419 if (!wrapper) {
420 continue;
421 }
422 auto geometryNode = wrapper->GetGeometryNode();
423 if (!geometryNode) {
424 continue;
425 }
426 size = isMainAxis ? geometryNode->GetMarginFrameSize().MainSize(axis_)
427 : geometryNode->GetMarginFrameSize().CrossSize(axis_);
428 maxSize = std::max(size, maxSize);
429 }
430 return maxSize;
431 }
432
AdjustStartInfoOnSwipeByGroup(int32_t startIndex,const PositionMap & itemPosition,int32_t & startIndexInVisibleWindow,float & startPos)433 void SwiperLayoutAlgorithm::AdjustStartInfoOnSwipeByGroup(
434 int32_t startIndex, const PositionMap& itemPosition, int32_t& startIndexInVisibleWindow, float& startPos)
435 {
436 if (!swipeByGroup_ || isFrameAnimation_) {
437 return;
438 }
439
440 startIndexInVisibleWindow = startIndex;
441 auto iter = itemPosition.find(startIndex);
442 if (iter != itemPosition.end()) {
443 startPos = iter->second.startPos;
444 }
445 }
446
AdjustItemPositionOnCachedShow()447 void SwiperLayoutAlgorithm::AdjustItemPositionOnCachedShow()
448 {
449 if (!cachedShow_) {
450 return;
451 }
452
453 auto startIndex = GetStartIndex();
454 while (startIndex < cachedStartIndex_) {
455 itemPosition_.erase(startIndex);
456 startIndex++;
457 }
458
459 auto endIndex = GetEndIndex();
460 while (endIndex > cachedEndIndex_) {
461 itemPosition_.erase(endIndex);
462 endIndex--;
463 }
464 }
465
GetCurrentFirstIndexInWindow(LayoutWrapper * layoutWrapper) const466 int32_t SwiperLayoutAlgorithm::GetCurrentFirstIndexInWindow(LayoutWrapper* layoutWrapper) const
467 {
468 if (itemPosition_.empty()) {
469 return currentIndex_;
470 }
471
472 auto property = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
473 CHECK_NULL_RETURN(property, currentIndex_);
474 auto nextMarginIgnoreBlank = property->GetNextMarginIgnoreBlank().value_or(false);
475 for (const auto& item : itemPosition_) {
476 auto windowStartPos = startMainPos_ - (Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f);
477 if (!isLoop_ && GetLoopIndex(item.first) == totalItemCount_ - 1 && nextMarginIgnoreBlank &&
478 Positive(nextMargin_)) {
479 windowStartPos -= nextMargin_;
480 }
481
482 if (LessNotEqual(item.second.startPos, windowStartPos) && LessNotEqual(item.second.endPos, windowStartPos)) {
483 continue;
484 }
485
486 if (LessOrEqual(item.second.startPos, windowStartPos) && GreatNotEqual(item.second.endPos, windowStartPos)) {
487 return item.first;
488 }
489 }
490
491 return itemPosition_.begin()->first;
492 }
493
GetCurrentLastIndexInWindow(LayoutWrapper * layoutWrapper) const494 int32_t SwiperLayoutAlgorithm::GetCurrentLastIndexInWindow(LayoutWrapper* layoutWrapper) const
495 {
496 if (itemPosition_.empty()) {
497 return currentIndex_;
498 }
499
500 auto property = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
501 CHECK_NULL_RETURN(property, currentIndex_);
502 auto prevMarginIgnoreBlank = property->GetPrevMarginIgnoreBlank().value_or(false);
503 for (const auto& item : itemPosition_) {
504 auto windowEndPos = endMainPos_ + (Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f);
505 if (!isLoop_ && GetLoopIndex(item.first) == 0 && prevMarginIgnoreBlank && Positive(prevMargin_)) {
506 windowEndPos += prevMargin_;
507 }
508
509 if (LessNotEqual(item.second.startPos, windowEndPos) && LessNotEqual(item.second.endPos, windowEndPos)) {
510 continue;
511 }
512
513 if (LessNotEqual(item.second.startPos, windowEndPos) && GreatOrEqual(item.second.endPos, windowEndPos)) {
514 return item.first;
515 }
516 }
517
518 return itemPosition_.rbegin()->first;
519 }
520
CalcCachedItemIndex(LayoutWrapper * layoutWrapper)521 void SwiperLayoutAlgorithm::CalcCachedItemIndex(LayoutWrapper* layoutWrapper)
522 {
523 auto cachedCount = GetUserSetCachedCount(layoutWrapper);
524 auto displayCount = GetDisplayCount(layoutWrapper);
525 auto firstIndexInWindow = GetCurrentFirstIndexInWindow(layoutWrapper);
526 auto lastIndexInWindow = GetCurrentLastIndexInWindow(layoutWrapper);
527 if (swipeByGroup_) {
528 cachedCount *= displayCount;
529 firstIndexInWindow = SwiperUtils::ComputePageIndex(firstIndexInWindow, displayCount);
530 lastIndexInWindow = SwiperUtils::ComputePageEndIndex(lastIndexInWindow, displayCount);
531 }
532
533 if (!isLoop_) {
534 firstIndexInWindow = GetLoopIndex(firstIndexInWindow);
535 lastIndexInWindow = GetLoopIndex(lastIndexInWindow);
536 cachedStartIndex_ = std::max(firstIndexInWindow - cachedCount, 0);
537 cachedEndIndex_ = std::min(lastIndexInWindow + cachedCount, totalItemCount_ - 1);
538 return;
539 }
540
541 auto outWindowCount = totalItemCount_ - (lastIndexInWindow - firstIndexInWindow + 1);
542 if (outWindowCount >= cachedCount * DEFAULT_DOUBLE) {
543 cachedStartIndex_ = firstIndexInWindow - cachedCount;
544 cachedEndIndex_ = lastIndexInWindow + cachedCount;
545 return;
546 }
547
548 cachedStartIndex_ = firstIndexInWindow;
549 cachedEndIndex_ = lastIndexInWindow;
550 auto step = swipeByGroup_ ? displayCount : 1;
551 while (outWindowCount > 0) {
552 cachedEndIndex_ += step;
553 outWindowCount -= step;
554 if (outWindowCount <= 0) {
555 break;
556 }
557
558 cachedStartIndex_ -= step;
559 outWindowCount -= step;
560 }
561 }
562
GetUserSetCachedCount(LayoutWrapper * layoutWrapper) const563 int32_t SwiperLayoutAlgorithm::GetUserSetCachedCount(LayoutWrapper* layoutWrapper) const
564 {
565 auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
566 CHECK_NULL_RETURN(layoutProperty, 1);
567 return layoutProperty->GetCachedCount().value_or(1);
568 }
569
LayoutCachedItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & constraint)570 void SwiperLayoutAlgorithm::LayoutCachedItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& constraint)
571 {
572 if (!cachedShow_) {
573 return;
574 }
575
576 CalcCachedItemIndex(layoutWrapper);
577 if (GetStartIndex() > cachedStartIndex_) {
578 LayoutBackward(layoutWrapper, constraint, GetStartIndex() - 1, GetStartPosition(), true);
579 }
580
581 if (GetEndIndex() < cachedEndIndex_) {
582 LayoutForward(layoutWrapper, constraint, GetEndIndex() + 1, GetEndPosition(), true);
583 }
584 }
585
MeasureSwiperOnJump(LayoutWrapper * layoutWrapper,const LayoutConstraintF & constraint,int32_t jumpIndex)586 void SwiperLayoutAlgorithm::MeasureSwiperOnJump(
587 LayoutWrapper* layoutWrapper, const LayoutConstraintF& constraint, int32_t jumpIndex)
588 {
589 needUnmountIndexs_.clear();
590 itemPositionInAnimation_.clear();
591 auto startPos = (jumpIndex == 0) && Negative(startMainPos_) ? startMainPos_ : 0;
592 LayoutForward(layoutWrapper, constraint, jumpIndex, startPos);
593 auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
594 if (Positive(ignoreBlankOffset_)) {
595 prevMarginMontage += ignoreBlankOffset_;
596 }
597
598 if ((jumpIndex > 0 && GreatNotEqual(GetStartPosition(), startMainPos_ - prevMarginMontage)) ||
599 (isLoop_ && Positive(prevMargin_))) {
600 LayoutBackward(layoutWrapper, constraint, jumpIndex - 1, GetStartPosition());
601 }
602 currentIndex_ = jumpIndex;
603 }
604
MeasureSwiper(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint)605 void SwiperLayoutAlgorithm::MeasureSwiper(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint)
606 {
607 int32_t startIndex = 0;
608 int32_t endIndex = 0;
609 float startPos = 0.0f;
610 float endPos = 0.0f;
611 int32_t startIndexInVisibleWindow = 0;
612 prevItemPosition_ = itemPosition_;
613 if (!itemPosition_.empty()) {
614 startPos = itemPosition_.begin()->second.startPos;
615 endPos = itemPosition_.rbegin()->second.endPos;
616 for (const auto& item : itemPosition_) {
617 float itemEndPos =
618 Positive(prevMargin_) ? item.second.endPos + prevMargin_ + spaceWidth_ : item.second.endPos;
619 if (Positive(itemEndPos)) {
620 startIndexInVisibleWindow = item.first;
621 startPos = item.second.startPos;
622 break;
623 }
624 }
625 if (!isLoop_) {
626 startIndex = std::min(GetLoopIndex(GetStartIndex()), totalItemCount_ - 1);
627 endIndex = std::min(GetLoopIndex(GetEndIndex()), totalItemCount_ - 1);
628 startIndexInVisibleWindow = std::min(GetLoopIndex(startIndexInVisibleWindow), totalItemCount_ - 1);
629 if (targetIndex_.has_value()) {
630 targetIndex_ = GetLoopIndex(targetIndex_.value());
631 }
632 } else {
633 startIndex = GetStartIndex();
634 endIndex = GetEndIndex();
635 }
636
637 itemPosition_.clear();
638 }
639
640 if (jumpIndex_.has_value()) {
641 MeasureSwiperOnJump(layoutWrapper, layoutConstraint, jumpIndex_.value());
642 } else if (hasCachedCapture_) {
643 for (auto it = prevItemPosition_.rbegin(); it != prevItemPosition_.rend(); ++it) {
644 auto pos = Positive(prevMargin_) ? it->second.startPos + prevMargin_ : it->second.startPos;
645 // search for last item in visible window as endIndex
646 if (LessNotEqual(pos, contentMainSize_)) {
647 endIndex = it->first;
648 endPos = it->second.endPos;
649 break;
650 }
651 }
652 if ((targetIndex_.has_value() && targetIndex_.value() >= startIndexInVisibleWindow)
653 || (!targetIndex_.has_value() && Negative(currentOffset_))) {
654 LayoutForward(layoutWrapper, layoutConstraint, startIndexInVisibleWindow, startPos);
655 LayoutBackward(layoutWrapper, layoutConstraint, GetStartIndex() - 1, GetStartPosition());
656 } else {
657 LayoutBackward(layoutWrapper, layoutConstraint, endIndex, endPos);
658 LayoutForward(layoutWrapper, layoutConstraint, GetEndIndex() + 1, GetEndPosition());
659 }
660 // captures need to be updated, swap capture to avoid flickering of disappearing real node's position
661 if (targetIndex_.has_value() && itemPosition_.begin()->first != prevItemPosition_.begin()->first) {
662 isCaptureReverse_ = !isCaptureReverse_;
663 }
664 } else if (targetIndex_.has_value()) {
665 // isMeasureOneMoreItem_ param is used to ensure item continuity when play property animation.
666 if (LessNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
667 if (isMeasureOneMoreItem_) {
668 targetIndex_ =
669 isLoop_ ? targetIndex_.value() + 1 : std::clamp(targetIndex_.value() + 1, 0, realTotalCount_ - 1);
670 }
671 AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
672 LayoutForward(layoutWrapper, layoutConstraint, startIndexInVisibleWindow, startPos);
673 if (GreatNotEqualCustomPrecision(GetStartPosition(), startMainPos_, 0.01f)) {
674 LayoutBackward(layoutWrapper, layoutConstraint, GetStartIndex() - 1, GetStartPosition());
675 }
676 } else if (GreatNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
677 if (isMeasureOneMoreItem_) {
678 targetIndex_ =
679 isLoop_ ? targetIndex_.value() - 1 : std::clamp(targetIndex_.value() - 1, 0, realTotalCount_ - 1);
680 }
681 LayoutBackward(layoutWrapper, layoutConstraint, endIndex, endPos);
682 if (LessNotEqualCustomPrecision(GetEndPosition(), endMainPos_, -0.01f)) {
683 LayoutForward(layoutWrapper, layoutConstraint, GetEndIndex() + 1, GetEndPosition());
684 }
685 } else {
686 targetIsSameWithStartFlag_ = true;
687 AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
688 LayoutForward(layoutWrapper, layoutConstraint, startIndexInVisibleWindow, startPos);
689 if (isMeasureOneMoreItem_ || Positive(prevMargin_)) {
690 float startPosition =
691 itemPosition_.empty() ? 0.0f : itemPosition_.begin()->second.startPos - spaceWidth_;
692 LayoutBackward(layoutWrapper, layoutConstraint, GetStartIndex() - 1, startPosition);
693 }
694 }
695 } else {
696 AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
697 bool overScrollTop = startIndexInVisibleWindow == 0 && GreatNotEqual(startPos, startMainPos_);
698 if ((!overScrollFeature_ && NonNegative(currentOffset_)) || (overScrollFeature_ && overScrollTop)) {
699 LayoutForward(layoutWrapper, layoutConstraint, startIndexInVisibleWindow, startPos);
700 auto adjustStartMainPos =
701 startMainPos_ - prevMargin_ - spaceWidth_ - (Positive(ignoreBlankOffset_) ? ignoreBlankOffset_ : 0.0f);
702 if (GetStartIndex() > 0 && GreatNotEqual(GetStartPosition(), adjustStartMainPos)) {
703 LayoutBackward(layoutWrapper, layoutConstraint, GetStartIndex() - 1, GetStartPosition());
704 }
705 } else {
706 LayoutBackward(layoutWrapper, layoutConstraint, endIndex, endPos);
707 if (GetEndIndex() < (totalItemCount_ - 1) && LessNotEqual(GetEndPosition(), endMainPos_)) {
708 LayoutForward(layoutWrapper, layoutConstraint, GetEndIndex() + 1, GetEndPosition());
709 }
710 }
711 }
712 }
713
LayoutForwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t & currentIndex,float startPos,float & endPos)714 bool SwiperLayoutAlgorithm::LayoutForwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
715 int32_t& currentIndex, float startPos, float& endPos)
716 {
717 if ((currentIndex + 1 >= totalItemCount_ && !isLoop_) ||
718 (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_)) {
719 return false;
720 }
721
722 auto measureIndex = GetLoopIndex(currentIndex + 1);
723 if (isMeasureOneMoreItem_ && !itemPosition_.empty() && measureIndex == GetLoopIndex(itemPosition_.begin()->first)) {
724 return false;
725 }
726
727 if (swipeByGroup_ && measureIndex >= realTotalCount_) {
728 ++currentIndex;
729 endPos = startPos + placeItemWidth_.value_or(0.0f);
730 itemPosition_[currentIndex] = { startPos, endPos, nullptr };
731 return true;
732 }
733
734 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(measureIndex);
735 if (!IsNormalItem(wrapper)) {
736 return false;
737 }
738 ++currentIndex;
739 wrapper->Measure(layoutConstraint);
740 measuredItems_.insert(measureIndex);
741
742 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
743 CHECK_NULL_RETURN(swiperLayoutProperty, false);
744
745 float mainAxisSize = GetChildMainAxisSize(wrapper, swiperLayoutProperty);
746 if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
747 mainAxisSize = placeItemWidth_.value_or(mainAxisSize);
748 }
749 endPos = startPos + mainAxisSize;
750 itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
751 return true;
752 }
753
LayoutBackwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t & currentIndex,float endPos,float & startPos)754 bool SwiperLayoutAlgorithm::LayoutBackwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
755 int32_t& currentIndex, float endPos, float& startPos)
756 {
757 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
758 CHECK_NULL_RETURN(swiperLayoutProperty, false);
759 int32_t displayCount =
760 swiperLayoutProperty->GetDisplayCount().has_value() ? swiperLayoutProperty->GetDisplayCount().value() : 1;
761 bool itemPositionIsFull = static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_ + displayCount - 1;
762 if ((currentIndex - 1 < 0 && !isLoop_) || (SwiperUtils::IsStretch(swiperLayoutProperty) && itemPositionIsFull)) {
763 return false;
764 }
765 if (hasCachedCapture_ && static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_) {
766 return false;
767 }
768
769 auto measureIndex = GetLoopIndex(currentIndex - 1);
770 if (isMeasureOneMoreItem_ && !itemPosition_.empty() &&
771 measureIndex == GetLoopIndex(itemPosition_.rbegin()->first)) {
772 return false;
773 }
774
775 if (swipeByGroup_ && measureIndex >= realTotalCount_) {
776 --currentIndex;
777 startPos = endPos - placeItemWidth_.value_or(0.0f);
778 itemPosition_[currentIndex] = { startPos, endPos, nullptr };
779 return true;
780 }
781
782 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(measureIndex));
783 if (!IsNormalItem(wrapper)) {
784 return false;
785 }
786 --currentIndex;
787 wrapper->Measure(layoutConstraint);
788 measuredItems_.insert(measureIndex);
789
790 float mainAxisSize = GetChildMainAxisSize(wrapper, swiperLayoutProperty);
791 if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
792 mainAxisSize = placeItemWidth_.value_or(mainAxisSize);
793 }
794 startPos = endPos - mainAxisSize;
795 if (!itemPositionIsFull) {
796 itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
797 }
798 if (targetIndex_ && currentIndex == targetIndex_.value()) {
799 targetStartPos_ = startPos;
800 }
801 return true;
802 }
803
SetInactiveOnForward(LayoutWrapper * layoutWrapper)804 void SwiperLayoutAlgorithm::SetInactiveOnForward(LayoutWrapper* layoutWrapper)
805 {
806 auto displayCount = GetDisplayCount(layoutWrapper);
807 for (auto pos = itemPosition_.begin(); pos != itemPosition_.end();) {
808 auto endPos = pos->second.endPos;
809 auto index = pos->first;
810 if (swipeByGroup_) {
811 auto endPageIndex = SwiperUtils::ComputePageEndIndex(index, displayCount);
812 auto iter = itemPosition_.find(endPageIndex);
813 if (iter != itemPosition_.end()) {
814 endPos = iter->second.endPos;
815 }
816 }
817 endPos += ignoreBlankOffset_;
818 if (GreatNotEqual(endPos, prevMargin_ != 0.0f ? startMainPos_ - prevMargin_ - spaceWidth_ : startMainPos_)) {
819 break;
820 }
821
822 ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(pos->first), true);
823 pos = itemPosition_.erase(pos);
824 }
825 }
826
GetDisplayCount(LayoutWrapper * layoutWrapper) const827 int32_t SwiperLayoutAlgorithm::GetDisplayCount(LayoutWrapper* layoutWrapper) const
828 {
829 auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
830 CHECK_NULL_RETURN(layoutProperty, 1);
831 return layoutProperty->GetDisplayCount().value_or(1);
832 }
833
GetChildMainAxisSize(const RefPtr<LayoutWrapper> & childWrapper,const RefPtr<SwiperLayoutProperty> & swiperProperty)834 float SwiperLayoutAlgorithm::GetChildMainAxisSize(
835 const RefPtr<LayoutWrapper>& childWrapper, const RefPtr<SwiperLayoutProperty>& swiperProperty)
836 {
837 CHECK_NULL_RETURN(childWrapper, 0.0f);
838 auto geometryNode = childWrapper->GetGeometryNode();
839 CHECK_NULL_RETURN(geometryNode, 0.0f);
840
841 float mainAxisSize = GetMainAxisSize(geometryNode->GetMarginFrameSize(), axis_);
842 if (!placeItemWidth_.has_value()) {
843 placeItemWidth_ = mainAxisSize;
844 }
845
846 auto displayCount = swiperProperty->GetDisplayCountValue(1);
847 if (!SwiperUtils::IsStretch(swiperProperty) || displayCount == 0) {
848 return mainAxisSize;
849 }
850
851 auto childProperty = childWrapper->GetLayoutProperty();
852 CHECK_NULL_RETURN(childProperty, mainAxisSize);
853 auto visibilityValue = childProperty->GetVisibilityValue(VisibleType::VISIBLE);
854 if (visibilityValue == VisibleType::INVISIBLE || visibilityValue == VisibleType::GONE) {
855 mainAxisSize = (contentMainSize_ - nextMargin_ - prevMargin_ - (displayCount - 1) * spaceWidth_)
856 / displayCount;
857 }
858
859 return mainAxisSize;
860 }
861
NeedMeasureForward(int32_t currentIndex,float currentEndPos,float forwardEndPos,bool cachedLayout) const862 bool SwiperLayoutAlgorithm::NeedMeasureForward(
863 int32_t currentIndex, float currentEndPos, float forwardEndPos, bool cachedLayout) const
864 {
865 if (cachedLayout) {
866 return currentIndex < cachedEndIndex_;
867 }
868 auto contentMainSize = contentMainSize_;
869 if (Positive(prevMargin_) && !prevMarginIgnoreBlank_) {
870 contentMainSize -= prevMargin_ + spaceWidth_;
871 }
872 bool isLayoutOver = overScrollFeature_ && GreatOrEqual(currentEndPos, contentMainSize);
873 return !isLayoutOver &&
874 (LessNotEqual(currentEndPos, forwardEndPos) || (targetIndex_ && currentIndex < targetIndex_.value()));
875 }
876
AdjustOffsetOnForward(float currentEndPos)877 void SwiperLayoutAlgorithm::AdjustOffsetOnForward(float currentEndPos)
878 {
879 if (itemPosition_.empty()) {
880 return;
881 }
882
883 auto firstItemTop = itemPosition_.begin()->second.startPos;
884 auto itemTotalSize = currentEndPos - firstItemTop;
885 if (LessOrEqual(itemTotalSize, contentMainSize_) && (itemPosition_.begin()->first == 0)) {
886 // all items size is less than swiper.
887 if (!canOverScroll_) {
888 currentOffset_ = firstItemTop;
889 startMainPos_ = currentOffset_;
890 }
891 if (!mainSizeIsDefined_) {
892 // adapt child size.
893 contentMainSize_ = itemTotalSize;
894 }
895 } else {
896 // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
897 if (!canOverScroll_ || jumpIndex_.has_value()) {
898 auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
899 auto nextMarginMontage = Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f;
900 currentOffset_ = currentEndPos - contentMainSize_ + prevMarginMontage + nextMarginMontage;
901 }
902 startMainPos_ = currentEndPos - contentMainSize_;
903 endMainPos_ = currentEndPos;
904 }
905 }
906
LayoutForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t startIndex,float startPos,bool cachedLayout)907 void SwiperLayoutAlgorithm::LayoutForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
908 int32_t startIndex, float startPos, bool cachedLayout)
909 {
910 float currentEndPos = startPos;
911 float currentStartPos = 0.0f;
912 float endMainPos = overScrollFeature_ ? std::max(startPos + contentMainSize_, endMainPos_) : endMainPos_;
913 if (targetIndex_) {
914 endMainPos = Infinity<float>();
915 }
916 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
917 CHECK_NULL_VOID(swiperLayoutProperty);
918
919 auto currentIndex = startIndex - 1;
920 auto marginValue = NearZero(nextMargin_) ? 0.0f : nextMargin_ + spaceWidth_;
921 if (!NearZero(prevMargin_) && startIndex == 0 && swiperLayoutProperty->GetPrevMarginIgnoreBlankValue(false)) {
922 marginValue += prevMargin_ + spaceWidth_;
923 }
924 do {
925 currentStartPos = currentEndPos;
926 auto result = LayoutForwardItem(layoutWrapper, layoutConstraint, currentIndex, currentStartPos, currentEndPos);
927 if (!result) {
928 break;
929 }
930 if (SwiperUtils::CheckIsSingleCase(swiperLayoutProperty) && !mainSizeIsDefined_) {
931 endMainPos = itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
932 if (measured_) {
933 endMainPos += currentOffset_;
934 }
935 endMainPos_ = endMainPos;
936 }
937 if ((currentIndex >= 0 && currentIndex < (totalItemCount_ - 1)) || isLoop_) {
938 currentEndPos += spaceWidth_;
939 }
940 // reach the valid target index
941 if (targetIndex_ && currentIndex >= targetIndex_.value()) {
942 endMainPos = targetIsSameWithStartFlag_ ? endMainPos_ : currentStartPos + contentMainSize_;
943 targetIndex_.reset();
944 }
945 } while (NeedMeasureForward(currentIndex, currentEndPos, endMainPos + marginValue, cachedLayout));
946
947 if (overScrollFeature_ && canOverScroll_) {
948 return;
949 }
950
951 if (LessNotEqual(currentEndPos, endMainPos_)) {
952 AdjustOffsetOnForward(currentEndPos);
953 }
954
955 if (!cachedLayout) {
956 // Mark inactive in wrapper.
957 SetInactiveOnForward(layoutWrapper);
958 }
959 }
960
SetInactive(LayoutWrapper * layoutWrapper,float startMainPos,float endMainPos,std::optional<int32_t> targetIndex)961 void SwiperLayoutAlgorithm::SetInactive(
962 LayoutWrapper* layoutWrapper, float startMainPos, float endMainPos, std::optional<int32_t> targetIndex)
963 {
964 if (cachedShow_) {
965 return;
966 }
967
968 if (measured_) {
969 // Theoretically, offset should be added in all cases to get correct results. Only apply in flex for now.
970 startMainPos += currentOffset_;
971 endMainPos += currentOffset_;
972 }
973 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
974 CHECK_NULL_VOID(swiperLayoutProperty);
975 std::list<int32_t> removeIndexes;
976 for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
977 if (targetIndex.has_value() && targetIndex.value() == pos->first) {
978 continue;
979 }
980 if (LessOrEqual(
981 pos->second.endPos, prevMargin_ != 0.0f ? startMainPos - prevMargin_ - spaceWidth_ : startMainPos) ||
982 GreatOrEqual(
983 pos->second.startPos, nextMargin_ != 0.0f ? endMainPos + nextMargin_ + spaceWidth_ : endMainPos)) {
984 removeIndexes.emplace_back(pos->first);
985 }
986 }
987 for (const auto& index : removeIndexes) {
988 itemPosition_.erase(index);
989 }
990 }
991
SetInactiveOnBackward(LayoutWrapper * layoutWrapper)992 void SwiperLayoutAlgorithm::SetInactiveOnBackward(LayoutWrapper* layoutWrapper)
993 {
994 std::list<int32_t> removeIndexes;
995 auto displayCount = GetDisplayCount(layoutWrapper);
996 for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
997 auto startPos = pos->second.startPos;
998 auto index = pos->first;
999
1000 if (swipeByGroup_) {
1001 auto startPageIndex = SwiperUtils::ComputePageIndex(index, displayCount);
1002 auto iter = itemPosition_.find(startPageIndex);
1003 if (iter != itemPosition_.end()) {
1004 startPos = iter->second.startPos;
1005 }
1006 }
1007 startPos += ignoreBlankOffset_;
1008 if (LessNotEqual(startPos, nextMargin_ != 0.0f ? endMainPos_ + nextMargin_ + spaceWidth_ : endMainPos_)) {
1009 break;
1010 }
1011
1012 ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(index), false);
1013 removeIndexes.emplace_back(index);
1014 }
1015
1016 for (const auto& index : removeIndexes) {
1017 itemPosition_.erase(index);
1018 }
1019 }
1020
NeedMeasureBackward(int32_t currentIndex,float currentStartPos,float backwardStartPos,bool isStretch,bool cachedLayout) const1021 bool SwiperLayoutAlgorithm::NeedMeasureBackward(
1022 int32_t currentIndex, float currentStartPos, float backwardStartPos, bool isStretch, bool cachedLayout) const
1023 {
1024 if (cachedLayout) {
1025 return currentIndex > cachedStartIndex_;
1026 }
1027
1028 return GreatNotEqual(currentStartPos, backwardStartPos) ||
1029 (!isStretch && targetIndex_ && currentIndex > targetIndex_.value());
1030 }
1031
LayoutBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,int32_t endIndex,float endPos,bool cachedLayout)1032 void SwiperLayoutAlgorithm::LayoutBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
1033 int32_t endIndex, float endPos, bool cachedLayout)
1034 {
1035 float currentStartPos = endPos;
1036 float currentEndPos = 0.0f;
1037 float startMainPos = overScrollFeature_ ? std::min(endPos - contentMainSize_, startMainPos_) : startMainPos_;
1038 if (targetIndex_) {
1039 startMainPos = -Infinity<float>();
1040 }
1041 auto currentIndex = endIndex + 1;
1042
1043 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1044 CHECK_NULL_VOID(swiperLayoutProperty);
1045 auto isStretch = SwiperUtils::IsStretch(swiperLayoutProperty);
1046 float adjustStartMainPos = 0.0f;
1047 do {
1048 currentEndPos = currentStartPos;
1049 auto result = LayoutBackwardItem(layoutWrapper, layoutConstraint, currentIndex, currentEndPos, currentStartPos);
1050 if (!result) {
1051 break;
1052 }
1053 if (currentIndex > 0 || isLoop_) {
1054 currentStartPos = currentStartPos - spaceWidth_;
1055 }
1056 // reach the valid target index
1057 if (targetIndex_ && LessOrEqual(currentIndex, targetIndex_.value())) {
1058 startMainPos = currentStartPos;
1059 targetIndex_.reset();
1060 }
1061 adjustStartMainPos = startMainPos - (Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f) -
1062 (Positive(ignoreBlankOffset_) ? ignoreBlankOffset_ : 0.0f);
1063 } while (NeedMeasureBackward(currentIndex, currentStartPos, adjustStartMainPos, isStretch, cachedLayout));
1064
1065 // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
1066 if (GreatNotEqual(currentStartPos, startMainPos_)) {
1067 AdjustOffsetOnBackward(currentStartPos);
1068 }
1069
1070 if (overScrollFeature_) {
1071 return;
1072 }
1073
1074 if (!cachedLayout) {
1075 // Mark inactive in wrapper.
1076 SetInactiveOnBackward(layoutWrapper);
1077 }
1078 }
1079
AdjustOffsetOnBackward(float currentStartPos)1080 void SwiperLayoutAlgorithm::AdjustOffsetOnBackward(float currentStartPos)
1081 {
1082 if (!canOverScroll_ || jumpIndex_.has_value()) {
1083 currentOffset_ = currentStartPos;
1084 if (!mainSizeIsDefined_ && GetEndIndex() == totalItemCount_ - 1) {
1085 auto itemTotalSize = GetEndPosition() - currentStartPos;
1086 contentMainSize_ = std::min(contentMainSize_, itemTotalSize);
1087 }
1088 }
1089 endMainPos_ = currentStartPos + contentMainSize_;
1090 startMainPos_ = currentStartPos;
1091 }
1092
LayoutCustomAnimation(LayoutWrapper * layoutWrapper) const1093 void SwiperLayoutAlgorithm::LayoutCustomAnimation(LayoutWrapper* layoutWrapper) const
1094 {
1095 auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1096 CHECK_NULL_VOID(layoutProperty);
1097 auto geometryNode = layoutWrapper->GetGeometryNode();
1098 CHECK_NULL_VOID(geometryNode);
1099
1100 auto size = geometryNode->GetFrameSize();
1101 auto padding = layoutProperty->CreatePaddingAndBorder();
1102 MinusPaddingToSize(padding, size);
1103 auto paddingOffset = padding.Offset();
1104
1105 if (customAnimationToIndex_) {
1106 auto toIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(customAnimationToIndex_.value());
1107 CHECK_NULL_VOID(toIndexWrapper);
1108 CHECK_NULL_VOID(toIndexWrapper->GetGeometryNode());
1109 toIndexWrapper->GetGeometryNode()->SetMarginFrameOffset(paddingOffset);
1110 toIndexWrapper->Layout();
1111 }
1112
1113 auto currentIndex = layoutProperty->GetIndex().value_or(0);
1114 auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
1115 CHECK_NULL_VOID(currentIndexWrapper);
1116 CHECK_NULL_VOID(currentIndexWrapper->GetGeometryNode());
1117 currentIndexWrapper->GetGeometryNode()->SetMarginFrameOffset(paddingOffset);
1118 currentIndexWrapper->Layout();
1119 }
1120
Layout(LayoutWrapper * layoutWrapper)1121 void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1122 {
1123 CHECK_NULL_VOID(layoutWrapper);
1124 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1125 CHECK_NULL_VOID(swiperLayoutProperty);
1126 auto geometryNode = layoutWrapper->GetGeometryNode();
1127 CHECK_NULL_VOID(geometryNode);
1128
1129 if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
1130 LayoutCustomAnimation(layoutWrapper);
1131 return;
1132 }
1133
1134 axis_ = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1135 auto size = geometryNode->GetFrameSize();
1136 auto padding = swiperLayoutProperty->CreatePaddingAndBorder();
1137 MinusPaddingToSize(padding, size);
1138 auto paddingOffset = padding.Offset();
1139
1140 // layout items.
1141 std::set<int32_t> layoutIndexSet;
1142 for (auto& pos : itemPosition_) {
1143 layoutIndexSet.insert(GetLoopIndex(pos.first));
1144 pos.second.startPos -= currentOffset_;
1145 pos.second.endPos -= currentOffset_;
1146 LayoutItem(layoutWrapper, paddingOffset, pos);
1147 }
1148 for (auto& pos : itemPositionInAnimation_) {
1149 if (layoutIndexSet.find(pos.first) == layoutIndexSet.end()) {
1150 LayoutItem(layoutWrapper, paddingOffset, pos);
1151 }
1152 }
1153 LayoutSwiperIndicator(layoutWrapper, swiperLayoutProperty, padding);
1154 CaptureLayout(layoutWrapper);
1155 }
1156
LayoutSwiperIndicator(LayoutWrapper * layoutWrapper,const RefPtr<SwiperLayoutProperty> & swiperLayoutProperty,const PaddingPropertyF & padding)1157 void SwiperLayoutAlgorithm::LayoutSwiperIndicator(
1158 LayoutWrapper* layoutWrapper, const RefPtr<SwiperLayoutProperty>& swiperLayoutProperty,
1159 const PaddingPropertyF& padding)
1160 {
1161 auto hostNode = layoutWrapper->GetHostNode();
1162 CHECK_NULL_VOID(hostNode);
1163 auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
1164 CHECK_NULL_VOID(swiperPattern);
1165
1166 // Layout swiper indicator
1167 if (swiperLayoutProperty->GetShowIndicatorValue(true)) {
1168 auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
1169 if (indicatorWrapper) {
1170 if (swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DIGIT) {
1171 PlaceDigitChild(indicatorWrapper, swiperLayoutProperty);
1172 }
1173 indicatorWrapper->Layout();
1174 }
1175 }
1176
1177 if (swiperLayoutProperty->GetDisplayArrowValue(false)) {
1178 if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
1179 auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
1180 auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
1181 if (leftArrowWrapper && (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG)) {
1182 ArrowLayout(layoutWrapper, leftArrowWrapper, padding);
1183 }
1184 if (rightArrowWrapper && (rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG)) {
1185 ArrowLayout(layoutWrapper, rightArrowWrapper, padding);
1186 }
1187 }
1188 }
1189 }
1190
LayoutItem(LayoutWrapper * layoutWrapper,OffsetF offset,std::pair<int32_t,SwiperItemInfo> pos)1191 void SwiperLayoutAlgorithm::LayoutItem(LayoutWrapper* layoutWrapper, OffsetF offset,
1192 std::pair<int32_t, SwiperItemInfo> pos)
1193 {
1194 pos.second.startPos += ignoreBlankOffset_;
1195 pos.second.endPos += ignoreBlankOffset_;
1196
1197 auto layoutIndex = GetLoopIndex(pos.first);
1198 if (swipeByGroup_ && layoutIndex >= realTotalCount_) {
1199 return;
1200 }
1201
1202 auto wrapper = layoutWrapper->GetOrCreateChildByIndex(layoutIndex);
1203 if (!IsNormalItem(wrapper)) {
1204 return;
1205 }
1206
1207 float crossOffset = 0.0f;
1208 if (axis_ == Axis::VERTICAL) {
1209 offset += OffsetF(crossOffset, pos.second.startPos);
1210 if (!NearZero(prevMargin_)) {
1211 offset += OffsetF(crossOffset, prevMargin_ + spaceWidth_);
1212 }
1213 } else {
1214 CHECK_NULL_VOID(layoutWrapper->GetLayoutProperty());
1215 bool isRtl = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection() == TextDirection::RTL;
1216 float offsetPos = isRtl ? contentMainSize_ - pos.second.endPos : pos.second.startPos;
1217 offset += OffsetF(offsetPos, crossOffset);
1218 if (!NearZero(prevMargin_) && !isRtl) {
1219 offset += OffsetF(prevMargin_ + spaceWidth_, crossOffset);
1220 }
1221 if (!NearZero(prevMargin_) && isRtl) {
1222 offset -= OffsetF(prevMargin_ + spaceWidth_, crossOffset);
1223 }
1224 }
1225 CHECK_NULL_VOID(wrapper->GetGeometryNode());
1226 wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
1227 wrapper->Layout();
1228 }
1229
CaptureLayout(LayoutWrapper * layoutWrapper)1230 void SwiperLayoutAlgorithm::CaptureLayout(LayoutWrapper* layoutWrapper)
1231 {
1232 if (!hasCachedCapture_ || itemPosition_.empty()) {
1233 return;
1234 }
1235 auto leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
1236 auto rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
1237 if (isCaptureReverse_) {
1238 leftCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_CAPTURE_ETS_TAG);
1239 rightCaptureWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_CAPTURE_ETS_TAG);
1240 }
1241 CHECK_NULL_VOID(leftCaptureWrapper);
1242 CHECK_NULL_VOID(rightCaptureWrapper);
1243 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1244 CHECK_NULL_VOID(swiperLayoutProperty);
1245 auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1246 auto leftGeometryNode = leftCaptureWrapper->GetGeometryNode();
1247 CHECK_NULL_VOID(leftGeometryNode);
1248 auto rightGeometryNode = rightCaptureWrapper->GetGeometryNode();
1249 CHECK_NULL_VOID(rightGeometryNode);
1250 auto leftCaptureSize = axis == Axis::VERTICAL ? leftGeometryNode->GetMarginFrameSize().Height()
1251 : leftGeometryNode->GetMarginFrameSize().Width();
1252 auto leftPosition = itemPosition_.begin()->second.startPos - spaceWidth_ - leftCaptureSize;
1253 auto rightPosition = itemPosition_.rbegin()->second.endPos + spaceWidth_;
1254
1255 auto padding = swiperLayoutProperty->CreatePaddingAndBorder();
1256 auto leftOffset = padding.Offset();
1257 auto rightOffset = padding.Offset();
1258 auto deltaOffset = 0.0f;
1259 if (!NearZero(prevMargin_)) {
1260 deltaOffset = prevMargin_ + spaceWidth_;
1261 }
1262 if (axis == Axis::VERTICAL) {
1263 leftOffset += OffsetF(0.0f, leftPosition + deltaOffset);
1264 rightOffset += OffsetF(0.0f, rightPosition + deltaOffset);
1265 } else {
1266 bool isRtl = swiperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
1267 if (isRtl) {
1268 leftPosition = contentMainSize_ - itemPosition_.begin()->second.startPos + spaceWidth_;
1269 rightPosition = contentMainSize_ - itemPosition_.rbegin()->second.endPos - spaceWidth_ - leftCaptureSize;
1270 leftOffset += OffsetF(leftPosition - deltaOffset, 0.0f);
1271 rightOffset += OffsetF(rightPosition - deltaOffset, 0.0f);
1272 } else {
1273 leftOffset += OffsetF(leftPosition + deltaOffset, 0.0f);
1274 rightOffset += OffsetF(rightPosition + deltaOffset, 0.0f);
1275 }
1276 }
1277 leftGeometryNode->SetMarginFrameOffset(leftOffset);
1278 leftCaptureWrapper->Layout();
1279 rightGeometryNode->SetMarginFrameOffset(rightOffset);
1280 rightCaptureWrapper->Layout();
1281 }
1282
PlaceDigitChild(const RefPtr<LayoutWrapper> & indicatorWrapper,const RefPtr<LayoutProperty> & layoutProperty)1283 void SwiperLayoutAlgorithm::PlaceDigitChild(
1284 const RefPtr<LayoutWrapper>& indicatorWrapper, const RefPtr<LayoutProperty>& layoutProperty)
1285 {
1286 if (indicatorWrapper->GetTotalChildCount() != INDICATOR_HAS_CHILD) {
1287 return;
1288 }
1289 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
1290 CHECK_NULL_VOID(swiperLayoutProperty);
1291 auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
1292 CHECK_NULL_VOID(indicatorGeometryNode);
1293 auto indicatorWidth = INDICATOR_PADDING.ConvertToPx() * 2.0;
1294 auto indicatorHeight = 0.0f;
1295 for (auto&& child : indicatorWrapper->GetAllChildrenWithBuild()) {
1296 auto textGeometryNode = child->GetGeometryNode();
1297 CHECK_NULL_VOID(textGeometryNode);
1298 auto textFrameSize = textGeometryNode->GetFrameSize();
1299 indicatorWidth += textFrameSize.Width();
1300 if (indicatorHeight < textFrameSize.Height()) {
1301 indicatorHeight = textFrameSize.Height();
1302 }
1303 }
1304
1305 auto pipelineContext = PipelineBase::GetCurrentContext();
1306 CHECK_NULL_VOID(pipelineContext);
1307 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1308 CHECK_NULL_VOID(swiperIndicatorTheme);
1309 if (LessNotEqual(indicatorHeight, swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx())) {
1310 indicatorHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
1311 }
1312
1313 auto frameNode = indicatorWrapper->GetHostNode();
1314 CHECK_NULL_VOID(frameNode);
1315 auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
1316 CHECK_NULL_VOID(indicatorlayoutProperty);
1317
1318 auto currentOffset = SwiperIndicatorUtils::CalcIndicatrFrameOffSet(
1319 swiperLayoutProperty, indicatorlayoutProperty, indicatorWidth, indicatorHeight);
1320
1321 if (swiperLayoutProperty->GetDisplayArrowValue(false) && !swiperLayoutProperty->GetIsSidebarMiddleValue(false) &&
1322 HasCustomIndicatorOffset(indicatorWrapper)) {
1323 useCustomIndicatorOffset = true;
1324 auto indicatorOffset = CalculateCustomOffset(indicatorWrapper, currentOffset);
1325 if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1326 currentOffset.SetX(indicatorOffset.GetX());
1327 } else {
1328 currentOffset.SetY(indicatorOffset.GetY());
1329 }
1330 }
1331 if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1332 auto top = indicatorlayoutProperty->GetTop();
1333 auto bottom = indicatorlayoutProperty->GetBottom();
1334 if ((!top.has_value() || NearZero(top.value().Value())) &&
1335 (!bottom.has_value() || NearZero(bottom.value().Value()))) {
1336 auto themeHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
1337 auto dightPadding = 0.0;
1338 if (themeHeight > indicatorHeight) {
1339 dightPadding = (themeHeight - indicatorHeight) / 2;
1340 }
1341 auto dightVerPadding = swiperIndicatorTheme->GetIndicatorDigitVerticalPadding().ConvertToPx();
1342 currentOffset.SetY(currentOffset.GetY() - dightVerPadding + dightPadding);
1343 }
1344 }
1345
1346 indicatorGeometryNode->SetMarginFrameOffset(currentOffset);
1347 }
1348
GetNodeLayoutWrapperByTag(LayoutWrapper * layoutWrapper,const std::string & tagName) const1349 RefPtr<LayoutWrapper> SwiperLayoutAlgorithm::GetNodeLayoutWrapperByTag(
1350 LayoutWrapper* layoutWrapper, const std::string& tagName) const
1351 {
1352 CHECK_NULL_RETURN(layoutWrapper, nullptr);
1353 auto hostNode = layoutWrapper->GetHostNode();
1354 CHECK_NULL_RETURN(hostNode, nullptr);
1355 auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
1356 CHECK_NULL_RETURN(swiperPattern, nullptr);
1357 if (swiperPattern->IsBindIndicator() && V2::SWIPER_INDICATOR_ETS_TAG == tagName) {
1358 return nullptr;
1359 }
1360 RefPtr<LayoutWrapper> nodeWrapper = nullptr;
1361 int32_t totalChildCount = layoutWrapper->GetTotalChildCount();
1362 if (totalChildCount == 0) {
1363 return nullptr;
1364 }
1365 int32_t lastChildIndex = totalChildCount - 1;
1366 int32_t endLoopChildIndex = lastChildIndex - SWIPER_HAS_CHILD;
1367 for (int32_t index = lastChildIndex; index > endLoopChildIndex && index >= 0; index--) {
1368 nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1369 if (nodeWrapper && (nodeWrapper->GetHostTag() == tagName)) {
1370 return nodeWrapper;
1371 }
1372 }
1373
1374 return nullptr;
1375 }
1376
HasCustomIndicatorOffset(const RefPtr<LayoutWrapper> & indicatorWrapper)1377 bool SwiperLayoutAlgorithm::HasCustomIndicatorOffset(const RefPtr<LayoutWrapper>& indicatorWrapper)
1378 {
1379 auto frameNode = indicatorWrapper->GetHostNode();
1380 CHECK_NULL_RETURN(frameNode, false);
1381 auto indicatorLayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
1382 CHECK_NULL_RETURN(indicatorLayoutProperty, false);
1383 return indicatorLayoutProperty->GetLeft().has_value() || indicatorLayoutProperty->GetRight().has_value() ||
1384 indicatorLayoutProperty->GetTop().has_value() || indicatorLayoutProperty->GetBottom().has_value();
1385 }
1386
CalculateCustomOffset(const RefPtr<LayoutWrapper> & indicatorWrapper,const OffsetF & currentOffset)1387 const OffsetF SwiperLayoutAlgorithm::CalculateCustomOffset(
1388 const RefPtr<LayoutWrapper>& indicatorWrapper, const OffsetF& currentOffset)
1389 {
1390 OffsetF indicatorOffset(currentOffset.GetX(), currentOffset.GetY());
1391 auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
1392 CHECK_NULL_RETURN(indicatorGeometryNode, indicatorOffset);
1393 SizeF indicatorFrameSize = indicatorGeometryNode->GetFrameSize();
1394 auto indicatorLayoutProperty =
1395 AceType::DynamicCast<SwiperIndicatorLayoutProperty>(indicatorWrapper->GetLayoutProperty());
1396 CHECK_NULL_RETURN(indicatorLayoutProperty, indicatorOffset);
1397
1398 auto indicatorNode = indicatorWrapper->GetHostNode();
1399 CHECK_NULL_RETURN(indicatorNode, indicatorOffset);
1400 auto swiperNode = DynamicCast<FrameNode>(indicatorNode->GetParent());
1401 CHECK_NULL_RETURN(swiperNode, indicatorOffset);
1402 auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
1403 CHECK_NULL_RETURN(swiperLayoutProperty, indicatorOffset);
1404 CHECK_NULL_RETURN(swiperNode->GetGeometryNode(), indicatorOffset);
1405 SizeF swiperFrameSize = swiperNode->GetGeometryNode()->GetFrameSize();
1406 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
1407 CHECK_NULL_RETURN(swiperPattern, indicatorOffset);
1408 auto arrowNode = DynamicCast<FrameNode>(
1409 swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(swiperPattern->GetLeftButtonId())));
1410 CHECK_NULL_RETURN(arrowNode, indicatorOffset);
1411 CHECK_NULL_RETURN(arrowNode->GetGeometryNode(), indicatorOffset);
1412 SizeF arrowFrameSize = arrowNode->GetGeometryNode()->GetFrameSize();
1413 auto left = indicatorLayoutProperty->GetLeft();
1414 auto right = indicatorLayoutProperty->GetRight();
1415 auto top = indicatorLayoutProperty->GetTop();
1416 auto bottom = indicatorLayoutProperty->GetBottom();
1417 auto pipelineContext = PipelineBase::GetCurrentContext();
1418 CHECK_NULL_RETURN(pipelineContext, indicatorOffset);
1419 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1420 CHECK_NULL_RETURN(swiperIndicatorTheme, indicatorOffset);
1421 auto indicatorPadding = swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx();
1422
1423 if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1424 auto horizonOffset = arrowFrameSize.Width() + indicatorPadding;
1425 auto offset = 0.0;
1426 if (left.has_value()) {
1427 offset = currentOffset.GetX() + horizonOffset;
1428 indicatorOffset.SetX(
1429 std::min(offset, swiperFrameSize.Width() - indicatorFrameSize.Width() - horizonOffset));
1430 } else if (right.has_value()) {
1431 offset = currentOffset.GetX() - horizonOffset;
1432 indicatorOffset.SetX(std::max(offset, horizonOffset));
1433 }
1434 } else {
1435 auto verticleOffset = arrowFrameSize.Height() + indicatorPadding;
1436 auto offset = 0.0;
1437 if (top.has_value()) {
1438 offset = currentOffset.GetY() + verticleOffset;
1439 indicatorOffset.SetY(
1440 std::min(offset, swiperFrameSize.Height() - indicatorFrameSize.Height() - verticleOffset));
1441 } else if (bottom.has_value()) {
1442 offset = currentOffset.GetY() - verticleOffset;
1443 indicatorOffset.SetY(std::max(offset, verticleOffset));
1444 }
1445 }
1446 return indicatorOffset;
1447 }
1448
MeasureArrow(const RefPtr<LayoutWrapper> & arrowWrapper,const RefPtr<LayoutProperty> & layoutProperty) const1449 void SwiperLayoutAlgorithm::MeasureArrow(
1450 const RefPtr<LayoutWrapper>& arrowWrapper, const RefPtr<LayoutProperty>& layoutProperty) const
1451 {
1452 CHECK_NULL_VOID(arrowWrapper);
1453 CHECK_NULL_VOID(layoutProperty);
1454 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
1455 CHECK_NULL_VOID(swiperLayoutProperty);
1456 auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
1457 CHECK_NULL_VOID(arrowGeometryNode);
1458
1459 auto pipelineContext = PipelineBase::GetCurrentContext();
1460 CHECK_NULL_VOID(pipelineContext);
1461 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1462 CHECK_NULL_VOID(swiperIndicatorTheme);
1463
1464 arrowGeometryNode->SetFrameSize(
1465 SizeF { static_cast<float>(
1466 swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
1467 .ConvertToPx()),
1468 static_cast<float>(
1469 swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
1470 .ConvertToPx()) });
1471 auto indicatorLayoutConstraint = swiperLayoutProperty->CreateChildConstraint();
1472 arrowWrapper->Measure(indicatorLayoutConstraint);
1473 }
1474
GetHeightForDigit(LayoutWrapper * layoutWrapper,float height) const1475 float SwiperLayoutAlgorithm::GetHeightForDigit(LayoutWrapper* layoutWrapper, float height) const
1476 {
1477 CHECK_NULL_RETURN(layoutWrapper, height);
1478 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1479 CHECK_NULL_RETURN(swiperLayoutProperty, height);
1480 auto indicatorType = swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
1481 if (indicatorType == SwiperIndicatorType::DIGIT) {
1482 auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
1483 CHECK_NULL_RETURN(indicatorWrapper, height);
1484 auto frameNode = indicatorWrapper->GetHostNode();
1485 CHECK_NULL_RETURN(frameNode, height);
1486 auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
1487 CHECK_NULL_RETURN(indicatorlayoutProperty, height);
1488 auto ignoreSize = indicatorlayoutProperty->GetIgnoreSize();
1489 if (ignoreSize.has_value() && ignoreSize.value() == true) {
1490 return 0.0f;
1491 }
1492 }
1493 return height;
1494 }
1495
ArrowLayout(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & arrowWrapper,const PaddingPropertyF padding) const1496 void SwiperLayoutAlgorithm::ArrowLayout(
1497 LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& arrowWrapper, const PaddingPropertyF padding) const
1498 {
1499 CHECK_NULL_VOID(layoutWrapper);
1500 CHECK_NULL_VOID(arrowWrapper);
1501 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1502 CHECK_NULL_VOID(swiperLayoutProperty);
1503 auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1504 auto indicatorType = swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
1505 auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
1506 CHECK_NULL_VOID(arrowGeometryNode);
1507 auto arrowFrameSize = arrowGeometryNode->GetFrameSize();
1508 auto layoutGeometryNode = layoutWrapper->GetGeometryNode();
1509 CHECK_NULL_VOID(layoutGeometryNode);
1510 auto swiperFrameSize = layoutGeometryNode->GetFrameSize();
1511 auto isShowIndicatorArrow =
1512 (!swiperLayoutProperty->GetIsSidebarMiddleValue(false) && swiperLayoutProperty->GetShowIndicatorValue(true));
1513 SizeF indicatorFrameSize;
1514 RectF indicatorFrameRect;
1515 auto normalArrowMargin = 0.0f;
1516 if (isShowIndicatorArrow) {
1517 auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
1518 CHECK_NULL_VOID(indicatorWrapper);
1519 auto indicatorGeometry = indicatorWrapper->GetGeometryNode();
1520 CHECK_NULL_VOID(indicatorGeometry);
1521 indicatorFrameSize = indicatorGeometry->GetFrameSize();
1522 indicatorFrameRect = indicatorGeometry->GetFrameRect();
1523 if (indicatorType == SwiperIndicatorType::DOT) {
1524 auto hostNode = layoutWrapper->GetHostNode();
1525 CHECK_NULL_VOID(hostNode);
1526 auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
1527 CHECK_NULL_VOID(swiperPattern);
1528 auto itemCount = swiperPattern->TotalCount();
1529 auto indicatorNode = indicatorWrapper->GetHostNode();
1530 CHECK_NULL_VOID(indicatorNode);
1531 auto pipeline = PipelineBase::GetCurrentContext();
1532 CHECK_NULL_VOID(pipeline);
1533 auto theme = pipeline->GetTheme<SwiperIndicatorTheme>();
1534 CHECK_NULL_VOID(theme);
1535 auto indicatorPaintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
1536 CHECK_NULL_VOID(indicatorPaintProperty);
1537 auto itemWidth =
1538 static_cast<float>(indicatorPaintProperty->GetItemWidthValue(theme->GetSize()).ConvertToPx());
1539 auto selectedItemWidth =
1540 static_cast<float>(indicatorPaintProperty->GetSelectedItemWidthValue(theme->GetSize()).ConvertToPx());
1541 auto indicatorPadding = static_cast<float>(theme->GetIndicatorDotPadding().ConvertToPx());
1542 auto allPointDiameterSum = itemWidth * static_cast<float>(itemCount + 1);
1543 if (indicatorPaintProperty->GetIsCustomSizeValue(false)) {
1544 allPointDiameterSum = itemWidth * static_cast<float>(itemCount - 1) + selectedItemWidth;
1545 }
1546 auto indicatorDotItemSpace = indicatorPaintProperty->GetSpaceValue(theme->GetIndicatorDotItemSpace());
1547 auto allPointSpaceSum =
1548 static_cast<float>(indicatorDotItemSpace.ConvertToPx()) * (itemCount - 1);
1549 auto indicatorWidth = indicatorPadding + allPointDiameterSum + allPointSpaceSum + indicatorPadding;
1550 normalArrowMargin = ((axis == Axis::HORIZONTAL ? indicatorFrameSize.Width() : indicatorFrameSize.Height()) -
1551 indicatorWidth) * 0.5f;
1552 }
1553 }
1554 auto isLeftArrow = arrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG;
1555 auto pipelineContext = PipelineBase::GetCurrentContext();
1556 CHECK_NULL_VOID(pipelineContext);
1557 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1558 CHECK_NULL_VOID(swiperIndicatorTheme);
1559 OffsetF arrowOffset(0.0f, 0.0f);
1560 float startPoint = 0.0f;
1561 if (axis == Axis::HORIZONTAL && isShowIndicatorArrow) {
1562 auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
1563 ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
1564 : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
1565 if (useCustomIndicatorOffset && indicatorType == SwiperIndicatorType::DIGIT) {
1566 startPoint = isLeftArrow ? (indicatorFrameRect.Left() - arrowFrameSize.Width() - indicatorPadding)
1567 : (indicatorFrameRect.Right() + indicatorPadding);
1568 } else {
1569 startPoint =
1570 isLeftArrow
1571 ? (indicatorFrameRect.Left() - arrowFrameSize.Width() -
1572 swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding + normalArrowMargin)
1573 : (indicatorFrameRect.Right() + swiperIndicatorTheme->GetArrowScale().ConvertToPx() -
1574 indicatorPadding - normalArrowMargin);
1575 }
1576 arrowOffset.SetX(startPoint);
1577 if (isLeftArrow && !NonNegative(arrowOffset.GetX() - padding.left.value_or(0.0f))) {
1578 arrowOffset.SetX(padding.left.value_or(0.0f));
1579 }
1580 if (GreatOrEqual(
1581 arrowOffset.GetX() + arrowFrameSize.Width(), swiperFrameSize.Width() - padding.right.value_or(0.0f))) {
1582 arrowOffset.SetX(swiperFrameSize.Width() - arrowFrameSize.Width() - padding.right.value_or(0.0f));
1583 }
1584 auto offsetY = indicatorFrameRect.Top() +
1585 (indicatorFrameSize.Height() - GetHeightForDigit(layoutWrapper, arrowFrameSize.Height())) * 0.5f;
1586 arrowOffset.SetY(offsetY);
1587 } else if (axis == Axis::HORIZONTAL && !isShowIndicatorArrow) {
1588 startPoint = isLeftArrow
1589 ? swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx() + padding.left.value_or(0.0f)
1590 : (swiperFrameSize.Width() - padding.right.value_or(0.0f) - arrowFrameSize.Width() -
1591 swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx());
1592 arrowOffset.SetX(startPoint);
1593 arrowOffset.SetY((swiperFrameSize.Height() - padding.top.value_or(0.0f) - padding.bottom.value_or(0.0f) -
1594 arrowFrameSize.Height()) *
1595 0.5f +
1596 padding.top.value_or(0.0f));
1597 } else if (axis != Axis::HORIZONTAL && isShowIndicatorArrow) {
1598 auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
1599 ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
1600 : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
1601 if (useCustomIndicatorOffset && indicatorType == SwiperIndicatorType::DIGIT) {
1602 startPoint = isLeftArrow ? (indicatorFrameRect.Top() - arrowFrameSize.Height() -
1603 padding.top.value_or(0.0f) - indicatorPadding)
1604 : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) + indicatorPadding);
1605 } else {
1606 startPoint =
1607 isLeftArrow
1608 ? (indicatorFrameRect.Top() - arrowFrameSize.Height() - padding.top.value_or(0.0f) -
1609 swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding + normalArrowMargin)
1610 : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) +
1611 swiperIndicatorTheme->GetArrowScale().ConvertToPx() - indicatorPadding - normalArrowMargin);
1612 }
1613 arrowOffset.SetX(indicatorFrameRect.Left() + (indicatorFrameSize.Width() - arrowFrameSize.Width()) * 0.5f);
1614 arrowOffset.SetY(startPoint);
1615 if (isLeftArrow && !NonNegative(arrowOffset.GetY() - padding.top.value_or(0.0f))) {
1616 arrowOffset.SetY(padding.top.value_or(0.0f));
1617 }
1618 if (GreatOrEqual(arrowOffset.GetY() + arrowFrameSize.Height(),
1619 swiperFrameSize.Height() - padding.bottom.value_or(0.0f))) {
1620 arrowOffset.SetY(swiperFrameSize.Height() - arrowFrameSize.Height() - padding.bottom.value_or(0.0f));
1621 }
1622 } else {
1623 startPoint = isLeftArrow
1624 ? swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx() + padding.top.value_or(0.0f)
1625 : (swiperFrameSize.Height() - arrowFrameSize.Width() - padding.bottom.value_or(0.0f) -
1626 swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx());
1627 arrowOffset.SetX(padding.left.value_or(0.0f) + (swiperFrameSize.Width() - padding.left.value_or(0.0f) -
1628 padding.right.value_or(0.0f) - arrowFrameSize.Width()) *
1629 0.5f);
1630 arrowOffset.SetY(startPoint);
1631 }
1632 arrowGeometryNode->SetMarginFrameOffset(arrowOffset);
1633 arrowWrapper->Layout();
1634 }
1635
ResetOffscreenItemPosition(LayoutWrapper * layoutWrapper,int32_t index,bool isForward) const1636 void SwiperLayoutAlgorithm::ResetOffscreenItemPosition(
1637 LayoutWrapper* layoutWrapper, int32_t index, bool isForward) const
1638 {
1639 auto swiperGeometryNode = layoutWrapper->GetGeometryNode();
1640 CHECK_NULL_VOID(swiperGeometryNode);
1641 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1642 CHECK_NULL_VOID(childWrapper);
1643
1644 if (childWrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
1645 childWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
1646 childWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
1647 return;
1648 }
1649
1650 auto childGeometryNode = childWrapper->GetGeometryNode();
1651 CHECK_NULL_VOID(childGeometryNode);
1652 auto swiperFrameRect = swiperGeometryNode->GetFrameRect();
1653 auto childFrameRect = childGeometryNode->GetFrameRect();
1654
1655 OffsetF offset(0.0f, 0.0f);
1656 if (axis_ == Axis::HORIZONTAL) {
1657 offset.SetX(isForward ? -childFrameRect.Width() : swiperFrameRect.Width());
1658 } else {
1659 offset.SetY(isForward ? -childFrameRect.Height() : swiperFrameRect.Height());
1660 }
1661
1662 childGeometryNode->SetMarginFrameOffset(offset);
1663 childWrapper->Layout();
1664 }
1665
IsNormalItem(const RefPtr<LayoutWrapper> & wrapper) const1666 bool SwiperLayoutAlgorithm::IsNormalItem(const RefPtr<LayoutWrapper>& wrapper) const
1667 {
1668 CHECK_NULL_RETURN(wrapper, false);
1669 auto tag = wrapper->GetHostTag();
1670 if (tag == V2::SWIPER_INDICATOR_ETS_TAG || tag == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
1671 tag == V2::SWIPER_RIGHT_ARROW_ETS_TAG || tag == V2::SWIPER_LEFT_CAPTURE_ETS_TAG ||
1672 tag == V2::SWIPER_RIGHT_CAPTURE_ETS_TAG) {
1673 return false;
1674 }
1675 return true;
1676 }
1677
CheckCachedItem(int32_t startIndex,int32_t endIndex,LayoutWrapper * layoutWrapper)1678 void SwiperLayoutAlgorithm::CheckCachedItem(int32_t startIndex, int32_t endIndex, LayoutWrapper* layoutWrapper)
1679 {
1680 if (!layoutWrapper || cachedShow_) {
1681 return;
1682 }
1683 if (startIndex <= endIndex) {
1684 for (auto i = startIndex; i <= endIndex; ++i) {
1685 activeItems_.insert(i);
1686 }
1687 } else {
1688 for (auto i = 0; i <= endIndex; ++i) {
1689 activeItems_.insert(i);
1690 }
1691 for (auto i = startIndex; i < totalItemCount_; ++i) {
1692 activeItems_.insert(i);
1693 }
1694 }
1695 auto cachedCount = cachedCount_;
1696 while (cachedCount > 0) {
1697 if (isLoop_) {
1698 startIndex = GetLoopIndex(startIndex - 1);
1699 endIndex = GetLoopIndex(endIndex + 1);
1700 } else {
1701 startIndex = startIndex >= 0 ? startIndex - 1 : startIndex;
1702 endIndex = endIndex < totalItemCount_ ? endIndex + 1 : endIndex;
1703 }
1704 if (startIndex >= 0) {
1705 if (activeItems_.find(startIndex) == activeItems_.end()
1706 && layoutWrapper->GetChildByIndex(startIndex, true) == nullptr) {
1707 cachedItems_.insert(startIndex);
1708 }
1709 }
1710 if (endIndex < totalItemCount_) {
1711 if (activeItems_.find(endIndex) == activeItems_.end()
1712 && layoutWrapper->GetChildByIndex(endIndex, true) == nullptr) {
1713 cachedItems_.insert(endIndex);
1714 }
1715 }
1716 --cachedCount;
1717 }
1718 if (swipeByGroup_) {
1719 for (auto i = realTotalCount_; i < totalItemCount_; ++i) {
1720 activeItems_.erase(i);
1721 cachedItems_.erase(i);
1722 }
1723 }
1724 }
1725 } // namespace OHOS::Ace::NG
1726