• 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 = 3;
44 } // namespace
45 
GetLoopIndex(int32_t originalIndex) const46 int32_t SwiperLayoutAlgorithm::GetLoopIndex(int32_t originalIndex) const
47 {
48     auto loopIndex = originalIndex;
49     while (loopIndex < 0) {
50         loopIndex = loopIndex + totalItemCount_;
51     }
52     loopIndex %= totalItemCount_;
53     return loopIndex;
54 }
55 
Measure(LayoutWrapper * layoutWrapper)56 void SwiperLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
57 {
58     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
59     CHECK_NULL_VOID(swiperLayoutProperty);
60 
61     if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
62         MeasureCustomAnimation(layoutWrapper);
63         return;
64     }
65 
66     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
67 
68     // calculate main size.
69     auto contentConstraint = swiperLayoutProperty->GetContentLayoutConstraint().value();
70     bool hasMinSize = swiperLayoutProperty->GetMinSize().has_value() &&
71                       !LessOrEqual(swiperLayoutProperty->GetMinSizeValue().Value(), 0);
72     bool hasPrevMargin = swiperLayoutProperty->GetPrevMargin().has_value() &&
73                          !LessOrEqual(swiperLayoutProperty->GetPrevMarginValue().ConvertToPx(), 0);
74     bool hasNextMargin = swiperLayoutProperty->GetNextMargin().has_value() &&
75                          !LessOrEqual(swiperLayoutProperty->GetNextMarginValue().ConvertToPx(), 0);
76 
77     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
78         prevMargin_ = static_cast<float>(swiperLayoutProperty->GetPrevMarginValue(0.0_px).ConvertToPx());
79         nextMargin_ = static_cast<float>(swiperLayoutProperty->GetNextMarginValue(0.0_px).ConvertToPx());
80     }
81     auto isSingleCase =
82         !hasMinSize && (!hasPrevMargin && !hasNextMargin) &&
83         ((swiperLayoutProperty->GetDisplayCount().has_value() && swiperLayoutProperty->GetDisplayCountValue() == 1) ||
84             (!swiperLayoutProperty->GetDisplayCount().has_value() && SwiperUtils::IsStretch(swiperLayoutProperty)));
85 
86     OptionalSizeF contentIdealSize;
87     if (isSingleCase) {
88         contentIdealSize = CreateIdealSize(contentConstraint, axis, MeasureType::MATCH_CONTENT);
89         if (mainSizeIsMeasured_) {
90             if (layoutWrapper->IsContraintNoChanged()) {
91                 contentIdealSize.SetMainSize(contentMainSize_, axis);
92             } else {
93                 mainSizeIsMeasured_ = false;
94             }
95         }
96     } else {
97         contentIdealSize = CreateIdealSize(contentConstraint, axis, MeasureType::MATCH_PARENT_MAIN_AXIS);
98     }
99 
100     const auto& padding = swiperLayoutProperty->CreatePaddingAndBorder();
101     paddingBeforeContent_ = axis == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
102     paddingAfterContent_ = axis == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
103     contentMainSize_ = 0.0f;
104     if (!GetMainAxisSize(contentIdealSize, axis) && (!isSingleCase || !mainSizeIsMeasured_)) {
105         if (totalItemCount_ == 0) {
106             contentMainSize_ = 0.0f;
107         } else {
108             // use parent percentReference size first.
109             auto parentPercentReference = contentConstraint.percentReference;
110             contentMainSize_ =
111                 GetMainAxisSize(parentPercentReference, axis) - paddingBeforeContent_ - paddingAfterContent_;
112             mainSizeIsDefined_ = false;
113         }
114     } else {
115         contentMainSize_ = GetMainAxisSize(contentIdealSize.ConvertToSizeT(), axis);
116         mainSizeIsDefined_ = true;
117     }
118     auto hostNode = layoutWrapper->GetHostNode();
119     CHECK_NULL_VOID(hostNode);
120     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
121     CHECK_NULL_VOID(swiperPattern);
122     auto getAutoFill = swiperPattern->IsAutoFill();
123 
124     // calculate child layout constraint.
125     auto childLayoutConstraint =
126         SwiperUtils::CreateChildConstraint(swiperLayoutProperty, contentIdealSize, getAutoFill);
127     auto itemSpace = SwiperUtils::GetItemSpace(swiperLayoutProperty);
128     spaceWidth_ = itemSpace > (contentMainSize_ + paddingBeforeContent_ + paddingAfterContent_) ? 0.0f : itemSpace;
129     if (totalItemCount_ > 0) {
130         currentOffset_ = currentDelta_;
131         startMainPos_ = currentOffset_;
132         if ((Positive(prevMargin_) && NonPositive(swiperLayoutProperty->GetPrevMarginValue(0.0_px).ConvertToPx())) ||
133             (Positive(nextMargin_) && NonPositive(swiperLayoutProperty->GetNextMarginValue(0.0_px).ConvertToPx()))) {
134             prevMargin_ = 0.0f;
135             nextMargin_ = 0.0f;
136             isNeedResetPrevMarginAndNextMargin_ = true;
137         }
138         if (prevMargin_ != 0.0f) {
139             if (nextMargin_ != 0.0f) {
140                 endMainPos_ = currentOffset_ + contentMainSize_ - prevMargin_ - nextMargin_ - 2 * spaceWidth_;
141             } else {
142                 endMainPos_ = currentOffset_ + contentMainSize_ - prevMargin_ - spaceWidth_;
143             }
144         } else {
145             if (nextMargin_ != 0.0f) {
146                 endMainPos_ = currentOffset_ + contentMainSize_ - nextMargin_ - spaceWidth_;
147             } else {
148                 endMainPos_ = currentOffset_ + contentMainSize_;
149             }
150         }
151 
152         MeasureSwiper(layoutWrapper, childLayoutConstraint, axis);
153     } else {
154         itemPosition_.clear();
155     }
156 
157     auto crossSize = contentIdealSize.CrossSize(axis);
158     if ((crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) || !crossSize.has_value()) {
159         contentCrossSize_ = GetChildMaxSize(layoutWrapper, axis, false) == 0.0f
160                                 ? contentCrossSize_
161                                 : GetChildMaxSize(layoutWrapper, axis, false);
162         contentIdealSize.SetCrossSize(contentCrossSize_, axis);
163         crossMatchChild_ = true;
164     }
165 
166     if (!mainSizeIsDefined_ && isSingleCase) {
167         auto childMaxMainSize = GetChildMaxSize(layoutWrapper, axis, true);
168 
169         if (childMaxMainSize != contentMainSize_) {
170             contentMainSize_ = childMaxMainSize;
171             // CheckInactive
172             SetInactive(layoutWrapper, 0.0f, contentMainSize_, currentTargetIndex_);
173         }
174     }
175     if (itemPosition_.empty()) {
176         layoutWrapper->SetActiveChildRange(-1, -1);
177     } else {
178         int32_t startIndex = std::min(GetLoopIndex(GetStartIndex()), totalItemCount_ - 1);
179         int32_t endIndex = std::min(GetLoopIndex(GetEndIndex()), totalItemCount_ - 1);
180         layoutWrapper->SetActiveChildRange(startIndex, endIndex);
181     }
182 
183     contentIdealSize.SetMainSize(contentMainSize_, axis);
184     AddPaddingToSize(padding, contentIdealSize);
185     layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
186     if (!itemPosition_.empty()) {
187         mainSizeIsMeasured_ = true;
188     }
189 
190     // set swiper cache info.
191     auto displayCount = GetDisplayCount(layoutWrapper);
192     auto maxCachedCount = static_cast<int32_t>(std::ceil(static_cast<float>(totalItemCount_ - displayCount) / 2));
193     layoutWrapper->SetCacheCount(std::min(swiperPattern->GetCachedCount(), maxCachedCount), childLayoutConstraint);
194     layoutWrapper->SetLongPredictTask();
195 
196     // Measure swiper indicator
197     if (swiperLayoutProperty->GetShowIndicatorValue(true)) {
198         auto hostNode = layoutWrapper->GetHostNode();
199         CHECK_NULL_VOID(hostNode);
200         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
201         CHECK_NULL_VOID(swiperPattern);
202         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
203         if (indicatorWrapper) {
204             auto indicatorLayoutConstraint = swiperLayoutProperty->CreateChildConstraint();
205             indicatorLayoutConstraint.parentIdealSize = contentIdealSize;
206             indicatorWrapper->Measure(indicatorLayoutConstraint);
207         }
208     }
209 
210     if (swiperLayoutProperty->GetDisplayArrowValue(false)) {
211         auto hostNode = layoutWrapper->GetHostNode();
212         CHECK_NULL_VOID(hostNode);
213         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
214         CHECK_NULL_VOID(swiperPattern);
215 
216         if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
217             auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
218             auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
219             CHECK_NULL_VOID(leftArrowWrapper);
220             CHECK_NULL_VOID(rightArrowWrapper);
221             if (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG &&
222                 rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
223                 MeasureArrow(leftArrowWrapper, swiperLayoutProperty);
224                 MeasureArrow(rightArrowWrapper, swiperLayoutProperty);
225             }
226         }
227     }
228     if (swiperLayoutProperty->GetFlexItemProperty()) {
229         measured_ = true;
230     }
231 }
232 
MeasureCustomAnimation(LayoutWrapper * layoutWrapper)233 void SwiperLayoutAlgorithm::MeasureCustomAnimation(
234     LayoutWrapper* layoutWrapper)
235 {
236     auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
237     CHECK_NULL_VOID(layoutProperty);
238     auto axis = layoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
239     auto contentConstraint = layoutProperty->GetContentLayoutConstraint().value();
240     auto contentIdealSize = CreateIdealSize(contentConstraint, axis, MeasureType::MATCH_PARENT_MAIN_AXIS);
241     auto childLayoutConstraint = SwiperUtils::CreateChildConstraint(layoutProperty, contentIdealSize, false);
242 
243     auto currentIndex = layoutProperty->GetIndex().value_or(0);
244     auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
245     CHECK_NULL_VOID(currentIndexWrapper);
246     currentIndexWrapper->Measure(childLayoutConstraint);
247 
248     if (customAnimationToIndex_) {
249         auto toIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(customAnimationToIndex_.value());
250         CHECK_NULL_VOID(toIndexWrapper);
251         toIndexWrapper->Measure(childLayoutConstraint);
252     }
253 
254     layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
255 
256     std::set<int32_t> removeIndexs;
257     for (const auto& index : needUnmountIndexs_) {
258         if (indexsInAnimation_.find(index) != indexsInAnimation_.end()) {
259             continue;
260         }
261 
262         layoutWrapper->RemoveChildInRenderTree(index);
263         removeIndexs.insert(index);
264     }
265 
266     for (const auto& index : removeIndexs) {
267         needUnmountIndexs_.erase(index);
268     }
269 }
270 
GetChildMaxSize(LayoutWrapper * layoutWrapper,Axis axis,bool isMainAxis) const271 float SwiperLayoutAlgorithm::GetChildMaxSize(LayoutWrapper* layoutWrapper, Axis axis, bool isMainAxis) const
272 {
273     if (itemPosition_.empty()) {
274         return 0.0f;
275     }
276     float maxSize = 0.0f;
277     float size = 0.0f;
278     float prevPos = itemPosition_.begin()->second.startPos;
279     for (const auto& pos : itemPosition_) {
280         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(pos.first), false);
281         if (!wrapper) {
282             continue;
283         }
284         auto geometryNode = wrapper->GetGeometryNode();
285         if (!geometryNode) {
286             continue;
287         }
288         size = isMainAxis ? geometryNode->GetMarginFrameSize().MainSize(axis)
289                           : geometryNode->GetMarginFrameSize().CrossSize(axis);
290         prevPos = pos.second.startPos;
291         maxSize = std::max(size, maxSize);
292     }
293     return maxSize;
294 }
295 
AdjustStartInfoOnSwipeByGroup(int32_t startIndex,const PositionMap & itemPosition,int32_t & startIndexInVisibleWindow,float & startPos)296 void SwiperLayoutAlgorithm::AdjustStartInfoOnSwipeByGroup(
297     int32_t startIndex, const PositionMap& itemPosition, int32_t& startIndexInVisibleWindow, float& startPos)
298 {
299     if (!swipeByGroup_) {
300         return;
301     }
302 
303     startIndexInVisibleWindow = startIndex;
304     auto iter = itemPosition.find(startIndex);
305     if (iter != itemPosition.end()) {
306         startPos = iter->second.startPos;
307     }
308 }
309 
MeasureSwiper(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis)310 void SwiperLayoutAlgorithm::MeasureSwiper(
311     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis)
312 {
313     if (layoutWrapper->GetLayoutProperty()->GetFlexItemProperty() && measured_) {
314         // flex property causes Swiper to be measured twice, and itemPosition_ would
315         // reset after the first measure. Restore to that on second measure.
316         itemPosition_ = prevItemPosition_;
317         // targetIndex_ has also been reset during the first measure.
318         targetIndex_ = currentTargetIndex_;
319     }
320     int32_t startIndex = 0;
321     int32_t endIndex = 0;
322     float startPos = 0.0f;
323     float endPos = 0.0f;
324     int32_t startIndexInVisibleWindow = 0;
325     prevItemPosition_ = itemPosition_;
326     if (!itemPosition_.empty()) {
327         startPos = itemPosition_.begin()->second.startPos;
328         endPos = itemPosition_.rbegin()->second.endPos;
329         for (const auto& item : itemPosition_) {
330             if (GreatNotEqual(
331                 Positive(prevMargin_) ? item.second.endPos + prevMargin_ + spaceWidth_ : item.second.endPos, 0.0f)) {
332                 startIndexInVisibleWindow = item.first;
333                 startPos = item.second.startPos;
334                 break;
335             }
336         }
337         if (!isLoop_) {
338             startIndex = std::min(GetLoopIndex(GetStartIndex()), totalItemCount_ - 1);
339             endIndex = std::min(GetLoopIndex(GetEndIndex()), totalItemCount_ - 1);
340             startIndexInVisibleWindow = std::min(GetLoopIndex(startIndexInVisibleWindow), totalItemCount_ - 1);
341             if (targetIndex_.has_value()) {
342                 targetIndex_ = GetLoopIndex(targetIndex_.value());
343             }
344         } else {
345             startIndex = GetStartIndex();
346             endIndex = GetEndIndex();
347         }
348 
349         itemPosition_.clear();
350     }
351 
352     if (jumpIndex_) {
353         startPos = (jumpIndex_.value() == 0) && Negative(startMainPos_) ? startMainPos_ : 0;
354         LayoutForward(layoutWrapper, layoutConstraint, axis, jumpIndex_.value(), startPos);
355         auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
356         if ((jumpIndex_.value() > 0 && GreatNotEqual(GetStartPosition(), startMainPos_ - prevMarginMontage)) ||
357             (isLoop_ && Positive(prevMargin_))) {
358             auto prevItemWidth = (Positive(prevMargin_) && NearZero(GetStartIndex()) ? spaceWidth_ : 0.0f);
359             LayoutBackward(
360                 layoutWrapper, layoutConstraint, axis, jumpIndex_.value() - 1, GetStartPosition() - prevItemWidth);
361         }
362         currentIndex_ = jumpIndex_.value();
363     } else if (targetIndex_.has_value()) {
364         if (LessNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
365             AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
366             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
367             if (GreatNotEqualCustomPrecision(GetStartPosition(), startMainPos_, 0.01f)) {
368                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
369             }
370         } else if (GreatNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
371             int32_t stepsFromCurrentToTarget = endIndex - targetIndex_.value();
372             endIndex -= (stepsFromCurrentToTarget > (totalItemCount_ - 1))
373                 ? (stepsFromCurrentToTarget - totalItemCount_ + 1) : 0;
374 
375             auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
376             auto iter = prevItemPosition_.find(endIndex);
377             if (swiperLayoutProperty && !SwiperUtils::IsStretch(swiperLayoutProperty) &&
378                 iter != prevItemPosition_.end()) {
379                 endPos = iter->second.endPos;
380             }
381 
382             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
383             if (LessNotEqualCustomPrecision(GetEndPosition(), endMainPos_, -0.01f)) {
384                 LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
385             }
386         } else {
387             targetIsSameWithStartFlag_ = true;
388             AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
389             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
390             if (Positive(prevMargin_)) {
391                 float startPosition =
392                     itemPosition_.empty() ? 0.0f : itemPosition_.begin()->second.startPos - spaceWidth_;
393                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, startPosition);
394             }
395         }
396     } else {
397         AdjustStartInfoOnSwipeByGroup(startIndex, prevItemPosition_, startIndexInVisibleWindow, startPos);
398         bool overScrollTop = startIndexInVisibleWindow == 0 && GreatNotEqual(startPos, startMainPos_);
399         if ((!overScrollFeature_ && NonNegative(currentOffset_)) || (overScrollFeature_ && overScrollTop)) {
400             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
401             if (GetStartIndex() > 0 && GreatNotEqual(GetStartPosition(), startMainPos_)) {
402                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
403             }
404         } else {
405             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
406             if (GetEndIndex() < (totalItemCount_ - 1) && LessNotEqual(GetEndPosition(), endMainPos_)) {
407                 LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
408             }
409         }
410     }
411 }
412 
LayoutForwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t & currentIndex,float startPos,float & endPos)413 bool SwiperLayoutAlgorithm::LayoutForwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
414     Axis axis, int32_t& currentIndex, float startPos, float& endPos)
415 {
416     if ((currentIndex + 1 >= totalItemCount_ && !isLoop_) ||
417         (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_)) {
418         return false;
419     }
420 
421     auto measureIndex = GetLoopIndex(currentIndex + 1);
422     if (swipeByGroup_ && measureIndex >= realTotalCount_) {
423         ++currentIndex;
424         endPos = startPos + placeItemWidth_.value_or(0.0f);
425         itemPosition_[currentIndex] = { startPos, endPos, nullptr };
426         return true;
427     }
428 
429     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(measureIndex);
430     CHECK_NULL_RETURN(wrapper, 0);
431     if (wrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
432         wrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
433         wrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
434         return false;
435     }
436     ++currentIndex;
437     {
438         if (wrapper->GetHostNode()) {
439             ACE_SCOPED_TRACE("[MeasureSwiperForwardItem:%d][self:%d][parent:%d]", currentIndex,
440                 wrapper->GetHostNode()->GetId(), wrapper->GetHostNode()->GetParent() ?
441                     wrapper->GetHostNode()->GetParent()->GetId() : 0);
442         }
443         wrapper->Measure(layoutConstraint);
444     }
445 
446     float mainLen = GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis);
447 
448     if (!placeItemWidth_.has_value()) {
449         placeItemWidth_ = mainLen;
450     }
451 
452     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
453     CHECK_NULL_RETURN(swiperLayoutProperty, 0);
454 
455     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
456         auto layoutProperty = wrapper->GetLayoutProperty();
457         CHECK_NULL_RETURN(layoutProperty, 0);
458         auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
459         if (visibilityValue == VisibleType::INVISIBLE || visibilityValue == VisibleType::GONE) {
460             if (swiperLayoutProperty->GetDisplayCountValue(1) != 0) {
461                 mainLen = (contentMainSize_ - (swiperLayoutProperty->GetDisplayCountValue(1) - 1) * spaceWidth_) /
462                           swiperLayoutProperty->GetDisplayCountValue(1);
463             }
464         }
465     }
466     endPos = startPos + mainLen;
467     itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
468     return true;
469 }
470 
LayoutBackwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t & currentIndex,float endPos,float & startPos)471 bool SwiperLayoutAlgorithm::LayoutBackwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
472     Axis axis, int32_t& currentIndex, float endPos, float& startPos)
473 {
474     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
475     CHECK_NULL_RETURN(swiperLayoutProperty, 0);
476     int32_t displayCount = swiperLayoutProperty->GetDisplayCount().has_value() ?
477         swiperLayoutProperty->GetDisplayCount().value() : 1;
478     if ((currentIndex - 1 < 0 && !isLoop_) ||
479         static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_ + displayCount - 1) {
480         return false;
481     }
482 
483     auto measureIndex = GetLoopIndex(currentIndex - 1);
484     if (swipeByGroup_ && measureIndex >= realTotalCount_) {
485         --currentIndex;
486         startPos = endPos - placeItemWidth_.value_or(0.0f);
487         itemPosition_[currentIndex] = { startPos, endPos, nullptr };
488         return true;
489     }
490 
491     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(measureIndex));
492     CHECK_NULL_RETURN(wrapper, 0);
493     if (wrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
494         wrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
495         wrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
496         return false;
497     }
498     --currentIndex;
499     {
500         if (wrapper->GetHostNode()) {
501             ACE_SCOPED_TRACE("[MeasureSwiperBackwardItem:%d][self:%d][parent:%d]", currentIndex,
502                 wrapper->GetHostNode()->GetId(), wrapper->GetHostNode()->GetParent() ?
503                     wrapper->GetHostNode()->GetParent()->GetId() : 0);
504         }
505         wrapper->Measure(layoutConstraint);
506     }
507     float mainLen = GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis);
508 
509     if (!placeItemWidth_.has_value()) {
510         placeItemWidth_ = mainLen;
511     }
512 
513     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
514         auto layoutProperty = wrapper->GetLayoutProperty();
515         CHECK_NULL_RETURN(layoutProperty, 0);
516         auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
517         if (visibilityValue == VisibleType::INVISIBLE || visibilityValue == VisibleType::GONE) {
518             if (swiperLayoutProperty->GetDisplayCountValue(1) != 0) {
519                 mainLen = (contentMainSize_ - (swiperLayoutProperty->GetDisplayCountValue(1) - 1) * spaceWidth_) /
520                           swiperLayoutProperty->GetDisplayCountValue(1);
521             }
522         }
523     }
524     startPos = endPos - mainLen;
525     itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
526     return true;
527 }
528 
SetInactiveOnForward(LayoutWrapper * layoutWrapper,Axis axis)529 void SwiperLayoutAlgorithm::SetInactiveOnForward(LayoutWrapper* layoutWrapper, Axis axis)
530 {
531     auto displayCount = GetDisplayCount(layoutWrapper);
532     for (auto pos = itemPosition_.begin(); pos != itemPosition_.end();) {
533         auto endPos = pos->second.endPos;
534         auto index = pos->first;
535         if (swipeByGroup_) {
536             auto endPageIndex = SwiperUtils::ComputePageEndIndex(index, displayCount);
537             auto iter = itemPosition_.find(endPageIndex);
538             if (iter != itemPosition_.end()) {
539                 endPos = iter->second.endPos;
540             }
541         }
542 
543         if (GreatNotEqual(endPos, prevMargin_ != 0.0f ? startMainPos_ - prevMargin_ - spaceWidth_ : startMainPos_)) {
544             break;
545         }
546 
547         ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(pos->first), true, axis);
548         itemPosition_.erase(pos++);
549     }
550 }
551 
GetDisplayCount(LayoutWrapper * layoutWrapper) const552 int32_t SwiperLayoutAlgorithm::GetDisplayCount(LayoutWrapper* layoutWrapper) const
553 {
554     auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
555     CHECK_NULL_RETURN(layoutProperty, 1);
556     return layoutProperty->GetDisplayCount().value_or(1);
557 }
558 
LayoutForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t startIndex,float startPos)559 void SwiperLayoutAlgorithm::LayoutForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
560     Axis axis, int32_t startIndex, float startPos)
561 {
562     float currentEndPos = startPos;
563     float currentStartPos = 0.0f;
564     float endMainPos = overScrollFeature_ ? std::max(startPos + contentMainSize_, endMainPos_) : endMainPos_;
565     if (targetIndex_) {
566         endMainPos = Infinity<float>();
567     }
568     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
569     CHECK_NULL_VOID(swiperLayoutProperty);
570 
571     auto currentIndex = startIndex - 1;
572     do {
573         currentStartPos = currentEndPos;
574         auto result =
575             LayoutForwardItem(layoutWrapper, layoutConstraint, axis, currentIndex, currentStartPos, currentEndPos);
576         if (!result) {
577             break;
578         }
579         bool hasMinSize = !LessOrEqual(swiperLayoutProperty->GetMinSizeValue(Dimension(0)).Value(), 0);
580         bool hasPrevMargin = !LessOrEqual(swiperLayoutProperty->GetPrevMarginValue(Dimension(0)).ConvertToPx(), 0);
581         bool hasNextMargin = !LessOrEqual(swiperLayoutProperty->GetNextMarginValue(Dimension(0)).ConvertToPx(), 0);
582         auto isSingleCase = !hasMinSize && !hasPrevMargin && !hasNextMargin &&
583             (swiperLayoutProperty->GetDisplayCountValue(0) == 1 ||
584                 (!swiperLayoutProperty->GetDisplayCount().has_value() && SwiperUtils::IsStretch(swiperLayoutProperty)));
585         if (isSingleCase && !mainSizeIsDefined_) {
586             endMainPos = itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
587             if (measured_) {
588                 endMainPos += currentOffset_;
589             }
590             endMainPos_ = endMainPos;
591         }
592         if ((currentIndex >= 0 && currentIndex < (totalItemCount_ - 1)) || isLoop_) {
593             currentEndPos += spaceWidth_;
594         }
595         // reach the valid target index
596         if (targetIndex_ && currentIndex >= targetIndex_.value()) {
597             endMainPos = targetIsSameWithStartFlag_ ? endMainPos_ : currentStartPos + contentMainSize_;
598             currentTargetIndex_ = targetIndex_.value();
599             targetIndex_.reset();
600         }
601         if (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_) {
602             break;
603         }
604     } while (LessNotEqual(currentEndPos, nextMargin_ != 0.0f ? endMainPos + nextMargin_ + spaceWidth_ : endMainPos) ||
605              (targetIndex_ && currentIndex < targetIndex_.value()));
606 
607     if (overScrollFeature_ && canOverScroll_) {
608         return;
609     }
610 
611     // adjust offset.
612     if (LessNotEqual(currentEndPos, endMainPos_) && !itemPosition_.empty()) {
613         auto firstItemTop = itemPosition_.begin()->second.startPos;
614         auto itemTotalSize = currentEndPos - firstItemTop;
615         if (LessOrEqual(itemTotalSize, contentMainSize_) && (itemPosition_.begin()->first == 0)) {
616             // all items size is less than swiper.
617             if (!canOverScroll_) {
618                 currentOffset_ = firstItemTop;
619                 startMainPos_ = currentOffset_;
620             }
621             if (!mainSizeIsDefined_) {
622                 // adapt child size.
623                 contentMainSize_ = itemTotalSize;
624             }
625         } else {
626             // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
627             if (!canOverScroll_ || jumpIndex_.has_value()) {
628                 auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
629                 auto nextMarginMontage = Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f;
630                 currentOffset_ = currentEndPos - contentMainSize_ + prevMarginMontage + nextMarginMontage;
631             }
632             startMainPos_ = currentEndPos - contentMainSize_;
633             endMainPos_ = currentEndPos;
634         }
635     }
636 
637     // Mark inactive in wrapper.
638     SetInactiveOnForward(layoutWrapper, axis);
639 }
640 
SetInactive(LayoutWrapper * layoutWrapper,float startMainPos,float endMainPos,std::optional<int32_t> targetIndex)641 void SwiperLayoutAlgorithm::SetInactive(
642     LayoutWrapper* layoutWrapper, float startMainPos, float endMainPos, std::optional<int32_t> targetIndex)
643 {
644     if (measured_) {
645         // Theoretically, offset should be added in all cases to get correct results. Only apply in flex for now.
646         startMainPos += currentOffset_;
647         endMainPos += currentOffset_;
648     }
649     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
650     CHECK_NULL_VOID(swiperLayoutProperty);
651     std::list<int32_t> removeIndexes;
652     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
653         if (targetIndex.has_value() && targetIndex.value() == pos->first) {
654             continue;
655         }
656         if (LessOrEqual(
657                 pos->second.endPos, prevMargin_ != 0.0f ? startMainPos - prevMargin_ - spaceWidth_ : startMainPos) ||
658             GreatOrEqual(
659                 pos->second.startPos, nextMargin_ != 0.0f ? endMainPos + nextMargin_ + spaceWidth_ : endMainPos)) {
660             removeIndexes.emplace_back(pos->first);
661         }
662     }
663     for (const auto& index : removeIndexes) {
664         itemPosition_.erase(index);
665     }
666 }
667 
SetInactiveOnBackward(LayoutWrapper * layoutWrapper,Axis axis)668 void SwiperLayoutAlgorithm::SetInactiveOnBackward(LayoutWrapper* layoutWrapper, Axis axis)
669 {
670     std::list<int32_t> removeIndexes;
671     auto displayCount = GetDisplayCount(layoutWrapper);
672     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
673         auto startPos = pos->second.startPos;
674         auto index = pos->first;
675 
676         if (swipeByGroup_) {
677             auto startPageIndex = SwiperUtils::ComputePageIndex(index, displayCount);
678             auto iter = itemPosition_.find(startPageIndex);
679             if (iter != itemPosition_.end()) {
680                 startPos = iter->second.startPos;
681             }
682         }
683 
684         if (LessNotEqual(startPos, nextMargin_ != 0.0f ? endMainPos_ + nextMargin_ + spaceWidth_ : endMainPos_)) {
685             break;
686         }
687 
688         ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(index), false, axis);
689         removeIndexes.emplace_back(index);
690     }
691 
692     for (const auto& index : removeIndexes) {
693         itemPosition_.erase(index);
694     }
695 }
696 
LayoutBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t endIndex,float endPos)697 void SwiperLayoutAlgorithm::LayoutBackward(
698     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis, int32_t endIndex, float endPos)
699 {
700     float currentStartPos = endPos;
701     float currentEndPos = 0.0f;
702     float startMainPos = overScrollFeature_ ? std::min(endPos - contentMainSize_, startMainPos_) : startMainPos_;
703     if (targetIndex_) {
704         startMainPos = -Infinity<float>();
705     }
706     auto currentIndex = endIndex + 1;
707 
708     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
709     CHECK_NULL_VOID(swiperLayoutProperty);
710     int32_t displayCount = swiperLayoutProperty->GetDisplayCount().has_value() ?
711         swiperLayoutProperty->GetDisplayCount().value() : 1;
712     do {
713         currentEndPos = currentStartPos;
714         auto result =
715             LayoutBackwardItem(layoutWrapper, layoutConstraint, axis, currentIndex, currentEndPos, currentStartPos);
716         if (!result) {
717             break;
718         }
719         if (currentIndex > 0 || isLoop_) {
720             currentStartPos = currentStartPos - spaceWidth_;
721         }
722         // reach the valid target index
723         if (targetIndex_ && LessOrEqual(currentIndex, targetIndex_.value())) {
724             startMainPos = currentStartPos;
725             currentTargetIndex_ = targetIndex_.value();
726             targetIndex_.reset();
727         }
728         if (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_ + displayCount - 1) {
729             break;
730         }
731     } while (
732         GreatNotEqual(currentStartPos, prevMargin_ != 0.0f ? startMainPos - prevMargin_ - spaceWidth_ : startMainPos));
733 
734     // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
735     if (GreatNotEqual(currentStartPos, startMainPos_)) {
736         if (!canOverScroll_ || jumpIndex_.has_value()) {
737             currentOffset_ = currentStartPos;
738             if (!mainSizeIsDefined_ && GetEndIndex() == totalItemCount_ - 1) {
739                 auto itemTotalSize = GetEndPosition() - currentStartPos;
740                 contentMainSize_ = std::min(contentMainSize_, itemTotalSize);
741             }
742         }
743         endMainPos_ = currentStartPos + contentMainSize_;
744         startMainPos_ = currentStartPos;
745     }
746 
747     if (overScrollFeature_) {
748         return;
749     }
750 
751     // Mark inactive in wrapper.
752     SetInactiveOnBackward(layoutWrapper, axis);
753 }
754 
LayoutCustomAnimation(LayoutWrapper * layoutWrapper) const755 void SwiperLayoutAlgorithm::LayoutCustomAnimation(LayoutWrapper* layoutWrapper) const
756 {
757     auto layoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
758     CHECK_NULL_VOID(layoutProperty);
759 
760     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
761     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
762     MinusPaddingToSize(padding, size);
763     auto paddingOffset = padding.Offset();
764 
765     if (customAnimationToIndex_) {
766         auto toIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(customAnimationToIndex_.value());
767         CHECK_NULL_VOID(toIndexWrapper);
768 
769         toIndexWrapper->GetGeometryNode()->SetMarginFrameOffset(paddingOffset);
770         toIndexWrapper->Layout();
771     }
772 
773     auto currentIndex = layoutProperty->GetIndex().value_or(0);
774     auto currentIndexWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex);
775     CHECK_NULL_VOID(currentIndexWrapper);
776 
777     currentIndexWrapper->GetGeometryNode()->SetMarginFrameOffset(paddingOffset);
778     currentIndexWrapper->Layout();
779 }
780 
Layout(LayoutWrapper * layoutWrapper)781 void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
782 {
783     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
784     CHECK_NULL_VOID(swiperLayoutProperty);
785 
786     if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
787         LayoutCustomAnimation(layoutWrapper);
788         return;
789     }
790 
791     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
792     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
793     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
794     MinusPaddingToSize(padding, size);
795     auto paddingOffset = padding.Offset();
796 
797     // layout items.
798     for (auto& pos : itemPosition_) {
799         int32_t index = pos.first;
800 
801         auto layoutIndex = GetLoopIndex(index);
802         if (swipeByGroup_ && layoutIndex >= realTotalCount_) {
803             pos.second.startPos -= currentOffset_;
804             pos.second.endPos -= currentOffset_;
805             continue;
806         }
807 
808         auto offset = paddingOffset;
809         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(index));
810         if (!wrapper) {
811             continue;
812         }
813         if (wrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
814             wrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
815             wrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
816             continue;
817         }
818         float crossOffset = 0.0f;
819         pos.second.startPos -= currentOffset_;
820         pos.second.endPos -= currentOffset_;
821 
822         if (axis == Axis::VERTICAL) {
823             offset += OffsetF(crossOffset, pos.second.startPos);
824             if (prevMargin_ != 0.0f) {
825                 offset += OffsetF(0.0f, prevMargin_ + spaceWidth_);
826             }
827         } else {
828             offset += OffsetF(pos.second.startPos, crossOffset);
829             if (prevMargin_ != 0.0f) {
830                 offset += OffsetF(prevMargin_ + spaceWidth_, 0.0f);
831             }
832         }
833         wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
834         wrapper->Layout();
835     }
836     // Layout swiper indicator
837     if (swiperLayoutProperty->GetShowIndicatorValue(true)) {
838         auto hostNode = layoutWrapper->GetHostNode();
839         CHECK_NULL_VOID(hostNode);
840         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
841         CHECK_NULL_VOID(swiperPattern);
842         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
843         if (indicatorWrapper) {
844             if (swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DIGIT) {
845                 PlaceDigitChild(indicatorWrapper, swiperLayoutProperty);
846             }
847             indicatorWrapper->Layout();
848         }
849     }
850 
851     if (swiperLayoutProperty->GetDisplayArrowValue(false)) {
852         auto hostNode = layoutWrapper->GetHostNode();
853         CHECK_NULL_VOID(hostNode);
854         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
855         CHECK_NULL_VOID(swiperPattern);
856 
857         if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
858             auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
859             auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
860             if (leftArrowWrapper && (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG)) {
861                 ArrowLayout(layoutWrapper, leftArrowWrapper, padding);
862             }
863             if (rightArrowWrapper && (rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG)) {
864                 ArrowLayout(layoutWrapper, rightArrowWrapper, padding);
865             }
866         }
867     }
868 }
869 
PlaceDigitChild(const RefPtr<LayoutWrapper> & indicatorWrapper,const RefPtr<LayoutProperty> & layoutProperty)870 void SwiperLayoutAlgorithm::PlaceDigitChild(
871     const RefPtr<LayoutWrapper>& indicatorWrapper, const RefPtr<LayoutProperty>& layoutProperty)
872 {
873     if (indicatorWrapper->GetTotalChildCount() != INDICATOR_HAS_CHILD) {
874         return;
875     }
876     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
877     CHECK_NULL_VOID(swiperLayoutProperty);
878     auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
879     CHECK_NULL_VOID(indicatorGeometryNode);
880     auto indicatorWidth = INDICATOR_PADDING.ConvertToPx() * 2.0;
881     auto indicatorHeight = 0.0f;
882     for (auto&& child : indicatorWrapper->GetAllChildrenWithBuild()) {
883         auto textGeometryNode = child->GetGeometryNode();
884         CHECK_NULL_VOID(textGeometryNode);
885         auto textFrameSize = textGeometryNode->GetFrameSize();
886         indicatorWidth += textFrameSize.Width();
887         if (indicatorHeight < textFrameSize.Height()) {
888             indicatorHeight = textFrameSize.Height();
889         }
890     }
891 
892     auto pipelineContext = PipelineBase::GetCurrentContext();
893     CHECK_NULL_VOID(pipelineContext);
894     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
895     CHECK_NULL_VOID(swiperIndicatorTheme);
896     if (LessNotEqual(indicatorHeight, swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx())) {
897         indicatorHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
898     }
899 
900     auto frameNode = indicatorWrapper->GetHostNode();
901     CHECK_NULL_VOID(frameNode);
902     auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
903     CHECK_NULL_VOID(indicatorlayoutProperty);
904 
905     auto currentOffset = SwiperIndicatorUtils::CalcIndicatrFrameOffSet(swiperLayoutProperty,
906                                                                        indicatorlayoutProperty,
907                                                                        indicatorWidth, indicatorHeight);
908 
909     if (swiperLayoutProperty->GetDisplayArrowValue(false) &&
910         !swiperLayoutProperty->GetIsSidebarMiddleValue(false) &&
911         HasCustomIndicatorOffset(indicatorWrapper)) {
912         useCustomIndicatorOffset = true;
913         auto indicatorOffset = CalculateCustomOffset(indicatorWrapper, currentOffset);
914         if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
915             currentOffset.SetX(indicatorOffset.GetX());
916         } else {
917             currentOffset.SetY(indicatorOffset.GetY());
918         }
919     }
920     if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
921         auto top = indicatorlayoutProperty->GetTop();
922         auto bottom = indicatorlayoutProperty->GetBottom();
923         if ((!top.has_value() || NearZero(top.value().Value())) &&
924             (!bottom.has_value() || NearZero(bottom.value().Value()))) {
925             auto themeHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
926             auto dightPadding = 0.0;
927             if (themeHeight > indicatorHeight) {
928                 dightPadding = (themeHeight - indicatorHeight) / 2;
929             }
930             auto dightVerPadding = swiperIndicatorTheme->GetIndicatorDigitVerticalPadding().ConvertToPx();
931             currentOffset.SetY(currentOffset.GetY() - dightVerPadding + dightPadding);
932         }
933     }
934 
935     indicatorGeometryNode->SetMarginFrameOffset(currentOffset);
936 }
937 
GetNodeLayoutWrapperByTag(LayoutWrapper * layoutWrapper,const std::string & tagName) const938 RefPtr<LayoutWrapper> SwiperLayoutAlgorithm::GetNodeLayoutWrapperByTag(
939     LayoutWrapper* layoutWrapper, const std::string& tagName) const
940 {
941     CHECK_NULL_RETURN(layoutWrapper, nullptr);
942     auto hostNode = layoutWrapper->GetHostNode();
943     CHECK_NULL_RETURN(hostNode, nullptr);
944     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
945     CHECK_NULL_RETURN(swiperPattern, nullptr);
946     RefPtr<LayoutWrapper> nodeWrapper = nullptr;
947     int32_t totalChildCount = layoutWrapper->GetTotalChildCount();
948     if (totalChildCount == 0) {
949         return nullptr;
950     }
951     int32_t lastChildIndex = totalChildCount - 1;
952     if (swiperPattern->HasIndicatorNode() && !swiperPattern->HasLeftButtonNode() &&
953         !swiperPattern->HasRightButtonNode()) {
954         nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(lastChildIndex);
955         return nodeWrapper;
956     }
957     int32_t endLoopChildIndex = lastChildIndex - SWIPER_HAS_CHILD;
958     for (int32_t index = lastChildIndex; index > endLoopChildIndex && index >= 0; index--) {
959         nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
960         if (nodeWrapper && (nodeWrapper->GetHostTag() == tagName)) {
961             return nodeWrapper;
962         }
963     }
964 
965     return nullptr;
966 }
967 
HasCustomIndicatorOffset(const RefPtr<LayoutWrapper> & indicatorWrapper)968 bool SwiperLayoutAlgorithm::HasCustomIndicatorOffset(const RefPtr<LayoutWrapper>& indicatorWrapper)
969 {
970     auto frameNode = indicatorWrapper->GetHostNode();
971     CHECK_NULL_RETURN(frameNode, false);
972     auto indicatorLayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
973     CHECK_NULL_RETURN(indicatorLayoutProperty, false);
974     return indicatorLayoutProperty->GetLeft().has_value() || indicatorLayoutProperty->GetRight().has_value() ||
975            indicatorLayoutProperty->GetTop().has_value() || indicatorLayoutProperty->GetBottom().has_value();
976 }
977 
CalculateCustomOffset(const RefPtr<LayoutWrapper> & indicatorWrapper,const OffsetF & currentOffset)978 const OffsetF SwiperLayoutAlgorithm::CalculateCustomOffset(
979     const RefPtr<LayoutWrapper>& indicatorWrapper, const OffsetF& currentOffset)
980 {
981     OffsetF indicatorOffset(currentOffset.GetX(), currentOffset.GetY());
982     auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
983     CHECK_NULL_RETURN(indicatorGeometryNode, indicatorOffset);
984     SizeF indicatorFrameSize = indicatorGeometryNode->GetFrameSize();
985     auto indicatorLayoutProperty =
986         AceType::DynamicCast<SwiperIndicatorLayoutProperty>(indicatorWrapper->GetLayoutProperty());
987     CHECK_NULL_RETURN(indicatorLayoutProperty, indicatorOffset);
988 
989     auto swiperNode = DynamicCast<FrameNode>(indicatorWrapper->GetHostNode()->GetParent());
990     CHECK_NULL_RETURN(swiperNode, indicatorOffset);
991     auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
992     CHECK_NULL_RETURN(swiperLayoutProperty, indicatorOffset);
993     SizeF swiperFrameSize = swiperNode->GetGeometryNode()->GetFrameSize();
994     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
995     CHECK_NULL_RETURN(swiperPattern, indicatorOffset);
996     auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(
997         swiperNode->GetChildIndexById(swiperPattern->GetLeftButtonId())));
998     CHECK_NULL_RETURN(arrowNode, indicatorOffset);
999     SizeF arrowFrameSize = arrowNode->GetGeometryNode()->GetFrameSize();
1000     auto left = indicatorLayoutProperty->GetLeft();
1001     auto right = indicatorLayoutProperty->GetRight();
1002     auto top = indicatorLayoutProperty->GetTop();
1003     auto bottom = indicatorLayoutProperty->GetBottom();
1004     auto pipelineContext = PipelineBase::GetCurrentContext();
1005     CHECK_NULL_RETURN(pipelineContext, indicatorOffset);
1006     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1007     CHECK_NULL_RETURN(swiperIndicatorTheme, indicatorOffset);
1008     auto indicatorPadding = swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx();
1009 
1010     if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1011         auto horizonOffset = arrowFrameSize.Width() + indicatorPadding;
1012         auto offset = 0.0;
1013         if (left.has_value()) {
1014             offset = currentOffset.GetX() + horizonOffset;
1015             indicatorOffset.SetX(
1016                 std::min(offset, swiperFrameSize.Width() - indicatorFrameSize.Width() - horizonOffset));
1017         } else if (right.has_value()) {
1018             offset = currentOffset.GetX() - horizonOffset;
1019             indicatorOffset.SetX(std::max(offset, horizonOffset));
1020         }
1021     } else {
1022         auto verticleOffset = arrowFrameSize.Height() + indicatorPadding;
1023         auto offset = 0.0;
1024         if (top.has_value()) {
1025             offset = currentOffset.GetY() + verticleOffset;
1026             indicatorOffset.SetY(
1027                 std::min(offset, swiperFrameSize.Height() - indicatorFrameSize.Height() - verticleOffset));
1028         } else if (bottom.has_value()) {
1029             offset = currentOffset.GetY() - verticleOffset;
1030             indicatorOffset.SetY(std::max(offset, verticleOffset));
1031         }
1032     }
1033     return indicatorOffset;
1034 }
1035 
MeasureArrow(const RefPtr<LayoutWrapper> & arrowWrapper,const RefPtr<LayoutProperty> & layoutProperty) const1036 void SwiperLayoutAlgorithm::MeasureArrow(
1037     const RefPtr<LayoutWrapper>& arrowWrapper, const RefPtr<LayoutProperty>& layoutProperty) const
1038 {
1039     CHECK_NULL_VOID(arrowWrapper);
1040     CHECK_NULL_VOID(layoutProperty);
1041     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
1042     CHECK_NULL_VOID(swiperLayoutProperty);
1043     auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
1044     CHECK_NULL_VOID(arrowGeometryNode);
1045 
1046     auto pipelineContext = PipelineBase::GetCurrentContext();
1047     CHECK_NULL_VOID(pipelineContext);
1048     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1049     CHECK_NULL_VOID(swiperIndicatorTheme);
1050 
1051     arrowGeometryNode->SetFrameSize(
1052         SizeF { static_cast<float>(
1053                     swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
1054                         .ConvertToPx()),
1055             static_cast<float>(
1056                 swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
1057                     .ConvertToPx()) });
1058     auto indicatorLayoutConstraint = swiperLayoutProperty->CreateChildConstraint();
1059     arrowWrapper->Measure(indicatorLayoutConstraint);
1060 }
1061 
ArrowLayout(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & arrowWrapper,const PaddingPropertyF padding) const1062 void SwiperLayoutAlgorithm::ArrowLayout(
1063     LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& arrowWrapper, const PaddingPropertyF padding) const
1064 {
1065     CHECK_NULL_VOID(layoutWrapper);
1066     CHECK_NULL_VOID(arrowWrapper);
1067     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
1068     CHECK_NULL_VOID(swiperLayoutProperty);
1069     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1070     auto indicatorType = swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
1071     auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
1072     CHECK_NULL_VOID(arrowGeometryNode);
1073     auto arrowFrameSize = arrowGeometryNode->GetFrameSize();
1074     auto layoutGeometryNode = layoutWrapper->GetGeometryNode();
1075     CHECK_NULL_VOID(layoutGeometryNode);
1076     auto swiperFrameSize = layoutGeometryNode->GetFrameSize();
1077     auto isShowIndicatorArrow =
1078         (!swiperLayoutProperty->GetIsSidebarMiddleValue(false) && swiperLayoutProperty->GetShowIndicatorValue(true));
1079     SizeF indicatorFrameSize;
1080     RectF indicatorFrameRect;
1081     auto normalArrowMargin = 0.0f;
1082     if (isShowIndicatorArrow) {
1083         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
1084         CHECK_NULL_VOID(indicatorWrapper);
1085         auto indicatorGeometry = indicatorWrapper->GetGeometryNode();
1086         CHECK_NULL_VOID(indicatorGeometry);
1087         indicatorFrameSize = indicatorGeometry->GetFrameSize();
1088         indicatorFrameRect = indicatorGeometry->GetFrameRect();
1089         if (indicatorType == SwiperIndicatorType::DOT) {
1090             auto hostNode = layoutWrapper->GetHostNode();
1091             CHECK_NULL_VOID(hostNode);
1092             auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
1093             CHECK_NULL_VOID(swiperPattern);
1094             auto itemCount = swiperPattern->TotalCount();
1095             auto indicatorNode = indicatorWrapper->GetHostNode();
1096             CHECK_NULL_VOID(indicatorNode);
1097             auto pipeline = PipelineBase::GetCurrentContext();
1098             CHECK_NULL_VOID(pipeline);
1099             auto theme = pipeline->GetTheme<SwiperIndicatorTheme>();
1100             CHECK_NULL_VOID(theme);
1101             auto indicatorPaintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
1102             CHECK_NULL_VOID(indicatorPaintProperty);
1103             auto itemWidth =
1104                 static_cast<float>(indicatorPaintProperty->GetItemWidthValue(theme->GetSize()).ConvertToPx());
1105             auto selectedItemWidth =
1106                 static_cast<float>(indicatorPaintProperty->GetSelectedItemWidthValue(theme->GetSize()).ConvertToPx());
1107             auto indicatorPadding = static_cast<float>(theme->GetIndicatorDotPadding().ConvertToPx());
1108             auto allPointDiameterSum = itemWidth * static_cast<float>(itemCount + 1);
1109             if (indicatorPaintProperty->GetIsCustomSizeValue(false)) {
1110                 allPointDiameterSum = itemWidth * static_cast<float>(itemCount - 1) + selectedItemWidth;
1111             }
1112             auto allPointSpaceSum =
1113                 static_cast<float>(theme->GetIndicatorDotItemSpace().ConvertToPx()) * (itemCount - 1);
1114             auto indicatorWidth = indicatorPadding + allPointDiameterSum + allPointSpaceSum + indicatorPadding;
1115             normalArrowMargin = ((axis == Axis::HORIZONTAL ? indicatorFrameSize.Width() : indicatorFrameSize.Height()) -
1116                                     indicatorWidth) * 0.5f;
1117         }
1118     }
1119     auto isLeftArrow = arrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG;
1120     auto pipelineContext = PipelineBase::GetCurrentContext();
1121     CHECK_NULL_VOID(pipelineContext);
1122     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
1123     CHECK_NULL_VOID(swiperIndicatorTheme);
1124     OffsetF arrowOffset(0.0f, 0.0f);
1125     float startPoint = 0.0f;
1126     if (axis == Axis::HORIZONTAL && isShowIndicatorArrow) {
1127         auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
1128                                     ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
1129                                     : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
1130         if (useCustomIndicatorOffset && indicatorType == SwiperIndicatorType::DIGIT) {
1131             startPoint = isLeftArrow ? (indicatorFrameRect.Left() - arrowFrameSize.Width() - indicatorPadding)
1132                                      : (indicatorFrameRect.Right() + indicatorPadding);
1133         } else {
1134             startPoint = isLeftArrow ? (indicatorFrameRect.Left() - arrowFrameSize.Width() -
1135                                         swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding +
1136                                         normalArrowMargin)
1137                                      : (indicatorFrameRect.Right() +
1138                                         swiperIndicatorTheme->GetArrowScale().ConvertToPx() - indicatorPadding -
1139                                         normalArrowMargin);
1140         }
1141         arrowOffset.SetX(startPoint);
1142         if (isLeftArrow && !NonNegative(arrowOffset.GetX() - padding.left.value_or(0.0f))) {
1143             arrowOffset.SetX(padding.left.value_or(0.0f));
1144         }
1145         if (GreatOrEqual(
1146                 arrowOffset.GetX() + arrowFrameSize.Width(), swiperFrameSize.Width() - padding.right.value_or(0.0f))) {
1147             arrowOffset.SetX(swiperFrameSize.Width() - arrowFrameSize.Width() - padding.right.value_or(0.0f));
1148         }
1149         arrowOffset.SetY(indicatorFrameRect.Top() + (indicatorFrameSize.Height() - arrowFrameSize.Height()) * 0.5f);
1150     } else if (axis == Axis::HORIZONTAL && !isShowIndicatorArrow) {
1151         startPoint = isLeftArrow
1152                          ? swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx() + padding.left.value_or(0.0f)
1153                          : (swiperFrameSize.Width() - padding.right.value_or(0.0f) - arrowFrameSize.Width() -
1154                                swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx());
1155         arrowOffset.SetX(startPoint);
1156         arrowOffset.SetY((swiperFrameSize.Height() - padding.top.value_or(0.0f) - padding.bottom.value_or(0.0f) -
1157                              arrowFrameSize.Height()) *
1158                              0.5f +
1159                          padding.top.value_or(0.0f));
1160     } else if (axis != Axis::HORIZONTAL && isShowIndicatorArrow) {
1161         auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
1162                                     ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
1163                                     : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
1164         if (useCustomIndicatorOffset && indicatorType == SwiperIndicatorType::DIGIT) {
1165             startPoint = isLeftArrow
1166                             ? (indicatorFrameRect.Top() - arrowFrameSize.Height() - padding.top.value_or(0.0f) -
1167                                 indicatorPadding)
1168                             : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) + indicatorPadding);
1169         } else {
1170             startPoint =
1171                 isLeftArrow
1172                     ? (indicatorFrameRect.Top() - arrowFrameSize.Height() - padding.top.value_or(0.0f) -
1173                         swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding + normalArrowMargin)
1174                     : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) +
1175                         swiperIndicatorTheme->GetArrowScale().ConvertToPx() - indicatorPadding - normalArrowMargin);
1176         }
1177         arrowOffset.SetX(indicatorFrameRect.Left() + (indicatorFrameSize.Width() - arrowFrameSize.Width()) * 0.5f);
1178         arrowOffset.SetY(startPoint);
1179         if (isLeftArrow && !NonNegative(arrowOffset.GetY() - padding.top.value_or(0.0f))) {
1180             arrowOffset.SetY(padding.top.value_or(0.0f));
1181         }
1182         if (GreatOrEqual(arrowOffset.GetY() + arrowFrameSize.Height(),
1183                 swiperFrameSize.Height() - padding.bottom.value_or(0.0f))) {
1184             arrowOffset.SetY(swiperFrameSize.Height() - arrowFrameSize.Height() - padding.bottom.value_or(0.0f));
1185         }
1186     } else {
1187         startPoint = isLeftArrow
1188                          ? swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx() + padding.top.value_or(0.0f)
1189                          : (swiperFrameSize.Height() - arrowFrameSize.Width() - padding.bottom.value_or(0.0f) -
1190                                swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx());
1191         arrowOffset.SetX(padding.left.value_or(0.0f) + (swiperFrameSize.Width() - padding.left.value_or(0.0f) -
1192                                                            padding.right.value_or(0.0f) - arrowFrameSize.Width()) *
1193                                                            0.5f);
1194         arrowOffset.SetY(startPoint);
1195     }
1196     arrowGeometryNode->SetMarginFrameOffset(arrowOffset);
1197     arrowWrapper->Layout();
1198 }
1199 
ResetOffscreenItemPosition(LayoutWrapper * layoutWrapper,int32_t index,bool isForward,Axis axis) const1200 void SwiperLayoutAlgorithm::ResetOffscreenItemPosition(
1201     LayoutWrapper* layoutWrapper, int32_t index, bool isForward, Axis axis) const
1202 {
1203     auto swiperGeometryNode = layoutWrapper->GetGeometryNode();
1204     CHECK_NULL_VOID(swiperGeometryNode);
1205     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1206     CHECK_NULL_VOID(childWrapper);
1207     auto childGeometryNode = childWrapper->GetGeometryNode();
1208     CHECK_NULL_VOID(childGeometryNode);
1209     auto swiperFrameRect = swiperGeometryNode->GetFrameRect();
1210     auto childFrameRect = childGeometryNode->GetFrameRect();
1211 
1212     OffsetF offset(0.0f, 0.0f);
1213     if (axis == Axis::HORIZONTAL) {
1214         offset.SetX(isForward ? -childFrameRect.Width() : swiperFrameRect.Width());
1215     } else {
1216         offset.SetY(isForward ? -childFrameRect.Height() : swiperFrameRect.Height());
1217     }
1218 
1219     childGeometryNode->SetMarginFrameOffset(offset);
1220     childWrapper->Layout();
1221 }
1222 
1223 } // namespace OHOS::Ace::NG
1224