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