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