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