• 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     // calculate idealSize and set FrameSize
62     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
63 
64     // calculate main size.
65     auto contentConstraint = swiperLayoutProperty->GetContentLayoutConstraint().value();
66     bool hasMinSize = swiperLayoutProperty->GetMinSize().has_value() &&
67                       !LessOrEqual(swiperLayoutProperty->GetMinSizeValue().Value(), 0);
68     bool hasPrevMargin = swiperLayoutProperty->GetPrevMargin().has_value() &&
69                          !LessOrEqual(swiperLayoutProperty->GetPrevMarginValue().ConvertToPx(), 0);
70     bool hasNextMargin = swiperLayoutProperty->GetNextMargin().has_value() &&
71                          !LessOrEqual(swiperLayoutProperty->GetNextMarginValue().ConvertToPx(), 0);
72 
73     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
74         prevMargin_ = static_cast<float>(swiperLayoutProperty->GetPrevMarginValue(0.0_px).ConvertToPx());
75         nextMargin_ = static_cast<float>(swiperLayoutProperty->GetNextMarginValue(0.0_px).ConvertToPx());
76     }
77     auto isSingleCase =
78         !hasMinSize && (!hasPrevMargin && !hasNextMargin) &&
79         ((swiperLayoutProperty->GetDisplayCount().has_value() && swiperLayoutProperty->GetDisplayCountValue() == 1) ||
80             (!swiperLayoutProperty->GetDisplayCount().has_value() && SwiperUtils::IsStretch(swiperLayoutProperty)));
81 
82     OptionalSizeF contentIdealSize;
83     if (isSingleCase) {
84         contentIdealSize = CreateIdealSize(contentConstraint, axis, MeasureType::MATCH_CONTENT);
85         if (mainSizeIsMeasured_) {
86             if (layoutWrapper->IsContraintNoChanged()) {
87                 contentIdealSize.SetMainSize(contentMainSize_, axis);
88             } else {
89                 mainSizeIsMeasured_ = false;
90             }
91         }
92     } else {
93         contentIdealSize = CreateIdealSize(contentConstraint, axis, MeasureType::MATCH_PARENT_MAIN_AXIS);
94     }
95 
96     const auto& padding = swiperLayoutProperty->CreatePaddingAndBorder();
97     paddingBeforeContent_ = axis == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
98     paddingAfterContent_ = axis == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
99     contentMainSize_ = 0.0f;
100     if (!GetMainAxisSize(contentIdealSize, axis) && (!isSingleCase || !mainSizeIsMeasured_)) {
101         if (totalItemCount_ == 0) {
102             contentMainSize_ = 0.0f;
103         } else {
104             // use parent percentReference size first.
105             auto parentPercentReference = contentConstraint.percentReference;
106             contentMainSize_ =
107                 GetMainAxisSize(parentPercentReference, axis) - paddingBeforeContent_ - paddingAfterContent_;
108             mainSizeIsDefined_ = false;
109         }
110     } else {
111         contentMainSize_ = GetMainAxisSize(contentIdealSize.ConvertToSizeT(), axis);
112         mainSizeIsDefined_ = true;
113     }
114     auto hostNode = layoutWrapper->GetHostNode();
115     CHECK_NULL_VOID(hostNode);
116     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
117     CHECK_NULL_VOID(swiperPattern);
118     auto getAutoFill = swiperPattern->IsAutoFill();
119 
120     // calculate child layout constraint.
121     auto childLayoutConstraint =
122         SwiperUtils::CreateChildConstraint(swiperLayoutProperty, contentIdealSize, getAutoFill);
123     auto itemSpace = SwiperUtils::GetItemSpace(swiperLayoutProperty);
124     spaceWidth_ = itemSpace > (contentMainSize_ + paddingBeforeContent_ + paddingAfterContent_) ? 0.0f : itemSpace;
125     if (totalItemCount_ > 0) {
126         currentOffset_ = currentDelta_;
127         startMainPos_ = currentOffset_;
128         if ((Positive(prevMargin_) && NonPositive(swiperLayoutProperty->GetPrevMarginValue(0.0_px).ConvertToPx())) ||
129             (Positive(nextMargin_) && NonPositive(swiperLayoutProperty->GetNextMarginValue(0.0_px).ConvertToPx()))) {
130             prevMargin_ = 0.0f;
131             nextMargin_ = 0.0f;
132             isNeedResetPrevMarginAndNextMargin_ = true;
133         }
134         if (prevMargin_ != 0.0f) {
135             if (nextMargin_ != 0.0f) {
136                 endMainPos_ = currentOffset_ + contentMainSize_ - prevMargin_ - nextMargin_ - 2 * spaceWidth_;
137             } else {
138                 endMainPos_ = currentOffset_ + contentMainSize_ - prevMargin_ - spaceWidth_;
139             }
140         } else {
141             if (nextMargin_ != 0.0f) {
142                 endMainPos_ = currentOffset_ + contentMainSize_ - nextMargin_ - spaceWidth_;
143             } else {
144                 endMainPos_ = currentOffset_ + contentMainSize_;
145             }
146         }
147 
148         MeasureSwiper(layoutWrapper, childLayoutConstraint, axis);
149     } else {
150         itemPosition_.clear();
151         layoutWrapper->RemoveAllChildInRenderTree();
152         LOGI("child size is empty");
153     }
154 
155     auto crossSize = contentIdealSize.CrossSize(axis);
156     if ((crossSize.has_value() && GreaterOrEqualToInfinity(crossSize.value())) || !crossSize.has_value()) {
157         contentCrossSize_ = GetChildMaxSize(layoutWrapper, axis, false) == 0.0f
158                                 ? contentCrossSize_
159                                 : GetChildMaxSize(layoutWrapper, axis, false);
160         contentIdealSize.SetCrossSize(contentCrossSize_, axis);
161     }
162 
163     if (!mainSizeIsDefined_ && isSingleCase) {
164         auto childMaxMainSize = GetChildMaxSize(layoutWrapper, axis, true);
165 
166         if (childMaxMainSize != contentMainSize_) {
167             contentMainSize_ = childMaxMainSize;
168             // CheckInactive
169             SetInactive(layoutWrapper, 0.0f, contentMainSize_, currentTargetIndex_);
170         }
171     }
172 
173     contentIdealSize.SetMainSize(contentMainSize_, axis);
174     AddPaddingToSize(padding, contentIdealSize);
175     layoutWrapper->GetGeometryNode()->SetFrameSize(contentIdealSize.ConvertToSizeT());
176     if (!itemPosition_.empty()) {
177         mainSizeIsMeasured_ = true;
178     }
179 
180     // set swiper cache info.
181     layoutWrapper->SetCacheCount(swiperLayoutProperty->GetCachedCount().value_or(1), childLayoutConstraint);
182     layoutWrapper->SetLongPredictTask();
183 
184     LOGD("new start index is %{public}d, new end index is %{public}d, offset is %{public}f, mainSize is %{public}f",
185         GetStartIndex(), GetEndIndex(), currentOffset_, contentMainSize_);
186 
187     // Measure swiper indicator
188     if (swiperLayoutProperty->GetShowIndicatorValue(true)) {
189         auto hostNode = layoutWrapper->GetHostNode();
190         CHECK_NULL_VOID(hostNode);
191         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
192         CHECK_NULL_VOID(swiperPattern);
193         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
194         if (indicatorWrapper) {
195             auto indicatorLayoutConstraint = swiperLayoutProperty->CreateChildConstraint();
196             indicatorLayoutConstraint.parentIdealSize = contentIdealSize;
197             indicatorWrapper->Measure(indicatorLayoutConstraint);
198         }
199     }
200 
201     if (swiperLayoutProperty->GetDisplayArrowValue(false)) {
202         auto hostNode = layoutWrapper->GetHostNode();
203         CHECK_NULL_VOID(hostNode);
204         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
205         CHECK_NULL_VOID(swiperPattern);
206 
207         if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
208             auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
209             auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
210             CHECK_NULL_VOID(leftArrowWrapper);
211             CHECK_NULL_VOID(rightArrowWrapper);
212             if (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG &&
213                 rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
214                 MeasureArrow(leftArrowWrapper, swiperLayoutProperty);
215                 MeasureArrow(rightArrowWrapper, swiperLayoutProperty);
216             }
217         }
218     }
219 }
220 
GetChildMaxSize(LayoutWrapper * layoutWrapper,Axis axis,bool isMainAxis) const221 float SwiperLayoutAlgorithm::GetChildMaxSize(LayoutWrapper* layoutWrapper, Axis axis, bool isMainAxis) const
222 {
223     if (itemPosition_.empty()) {
224         return 0.0f;
225     }
226     float maxSize = 0.0f;
227     float size = 0.0f;
228     float prevPos = itemPosition_.begin()->second.startPos;
229     for (const auto& pos : itemPosition_) {
230         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(pos.first), false);
231         if (!wrapper) {
232             continue;
233         }
234         auto geometryNode = wrapper->GetGeometryNode();
235         if (!geometryNode) {
236             continue;
237         }
238         size = isMainAxis ? geometryNode->GetMarginFrameSize().MainSize(axis)
239                           : geometryNode->GetMarginFrameSize().CrossSize(axis);
240         prevPos = pos.second.startPos;
241         maxSize = std::max(size, maxSize);
242     }
243     return maxSize;
244 }
245 
MeasureSwiper(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis)246 void SwiperLayoutAlgorithm::MeasureSwiper(
247     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis)
248 {
249     int32_t startIndex = 0;
250     int32_t endIndex = 0;
251     float startPos = 0.0f;
252     float endPos = 0.0f;
253     int32_t startIndexInVisibleWindow = 0;
254     if (!itemPosition_.empty()) {
255         startPos = itemPosition_.begin()->second.startPos;
256         endPos = itemPosition_.rbegin()->second.endPos;
257         for (const auto& item : itemPosition_) {
258             if (GreatNotEqual(
259                 Positive(prevMargin_) ? item.second.endPos + prevMargin_ + spaceWidth_ : item.second.endPos, 0.0f)) {
260                 startIndexInVisibleWindow = item.first;
261                 break;
262             }
263         }
264         if (!isLoop_) {
265             startIndex = std::min(GetLoopIndex(GetStartIndex()), totalItemCount_ - 1);
266             endIndex = std::min(GetLoopIndex(GetEndIndex()), totalItemCount_ - 1);
267             startIndexInVisibleWindow = std::min(GetLoopIndex(startIndexInVisibleWindow), totalItemCount_ - 1);
268             if (targetIndex_.has_value()) {
269                 targetIndex_ = GetLoopIndex(targetIndex_.value());
270             }
271         } else {
272             startIndex = GetStartIndex();
273             endIndex = GetEndIndex();
274         }
275         itemPosition_.clear();
276     }
277     layoutWrapper->RemoveAllChildInRenderTree();
278     if (jumpIndex_) {
279         LOGD("Jump index: %{public}d, offset is %{public}f, startMainPos: %{public}f, endMainPos: %{public}f",
280             jumpIndex_.value(), currentOffset_, startMainPos_, endMainPos_);
281         startPos = (jumpIndex_.value() == 0) && Negative(startMainPos_) ? startMainPos_ : 0;
282         LayoutForward(layoutWrapper, layoutConstraint, axis, jumpIndex_.value(), startPos);
283         auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
284         if ((jumpIndex_.value() > 0 && GreatNotEqual(GetStartPosition(), startMainPos_ - prevMarginMontage)) ||
285             (isLoop_ && Positive(prevMargin_))) {
286             auto prevItemWidth = (Positive(prevMargin_) && NearZero(GetStartIndex()) ? spaceWidth_ : 0.0f);
287             LayoutBackward(
288                 layoutWrapper, layoutConstraint, axis, jumpIndex_.value() - 1, GetStartPosition() - prevItemWidth);
289         }
290         currentIndex_ = jumpIndex_.value();
291     } else if (targetIndex_.has_value()) {
292         if (LessNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
293             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
294             if (GreatNotEqual(GetStartPosition(), startMainPos_)) {
295                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
296             }
297         } else if (GreatNotEqual(startIndexInVisibleWindow, targetIndex_.value())) {
298             int32_t stepsFromCurrentToTarget = endIndex - targetIndex_.value();
299             endIndex -= (stepsFromCurrentToTarget > (totalItemCount_ - 1))
300                 ? (stepsFromCurrentToTarget - totalItemCount_ + 1) : 0;
301             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
302             if (LessNotEqual(GetEndPosition(), endMainPos_)) {
303                 LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
304             }
305         } else {
306             targetIsSameWithStartFlag_ = true;
307             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndexInVisibleWindow, startPos);
308             if (Positive(prevMargin_)) {
309                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
310             }
311         }
312     } else {
313         LOGD("StartIndex index: %{public}d, offset is %{public}f, startMainPos: %{public}f, endMainPos: %{public}f",
314             startIndex, currentOffset_, startMainPos_, endMainPos_);
315         bool overScrollTop = startIndex == 0 && GreatNotEqual(startPos, startMainPos_);
316         if ((!overScrollFeature_ && NonNegative(currentOffset_)) || (overScrollFeature_ && overScrollTop)) {
317             LayoutForward(layoutWrapper, layoutConstraint, axis, startIndex, startPos);
318             if (GetStartIndex() > 0 && GreatNotEqual(GetStartPosition(), startMainPos_)) {
319                 LayoutBackward(layoutWrapper, layoutConstraint, axis, GetStartIndex() - 1, GetStartPosition());
320             }
321         } else {
322             LayoutBackward(layoutWrapper, layoutConstraint, axis, endIndex, endPos);
323             if (GetEndIndex() < (totalItemCount_ - 1) && LessNotEqual(GetEndPosition(), endMainPos_)) {
324                 LayoutForward(layoutWrapper, layoutConstraint, axis, GetEndIndex() + 1, GetEndPosition());
325             }
326         }
327     }
328 }
329 
LayoutForwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t & currentIndex,float startPos,float & endPos)330 bool SwiperLayoutAlgorithm::LayoutForwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
331     Axis axis, int32_t& currentIndex, float startPos, float& endPos)
332 {
333     if ((currentIndex + 1 >= totalItemCount_ && !isLoop_) ||
334         (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_)) {
335         return false;
336     }
337     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(currentIndex + 1));
338     CHECK_NULL_RETURN(wrapper, 0);
339     if (wrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
340         wrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
341         wrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
342         return false;
343     }
344     ++currentIndex;
345     {
346         ACE_SCOPED_TRACE("SwiperLayoutAlgorithm::LayoutForwardItem:%d", currentIndex);
347         wrapper->Measure(layoutConstraint);
348     }
349 
350     float mainLen = GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis);
351     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
352     CHECK_NULL_RETURN(swiperLayoutProperty, 0);
353 
354     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
355         auto layoutProperty = wrapper->GetLayoutProperty();
356         CHECK_NULL_RETURN(layoutProperty, 0);
357         auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
358         if (visibilityValue == VisibleType::INVISIBLE || visibilityValue == VisibleType::GONE) {
359             if (swiperLayoutProperty->GetDisplayCountValue(1) != 0) {
360                 mainLen = (contentMainSize_ - (swiperLayoutProperty->GetDisplayCountValue(1) - 1) * spaceWidth_) /
361                           swiperLayoutProperty->GetDisplayCountValue(1);
362             }
363         }
364     }
365     endPos = startPos + mainLen;
366     itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
367     return true;
368 }
369 
LayoutBackwardItem(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t & currentIndex,float endPos,float & startPos)370 bool SwiperLayoutAlgorithm::LayoutBackwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
371     Axis axis, int32_t& currentIndex, float endPos, float& startPos)
372 {
373     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
374     CHECK_NULL_RETURN(swiperLayoutProperty, 0);
375     int32_t displayCount = swiperLayoutProperty->GetDisplayCount().has_value() ?
376         swiperLayoutProperty->GetDisplayCount().value() : 1;
377     if ((currentIndex - 1 < 0 && !isLoop_) ||
378         static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_ + displayCount - 1) {
379         return false;
380     }
381     auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(currentIndex - 1));
382     CHECK_NULL_RETURN(wrapper, 0);
383     if (wrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
384         wrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
385         wrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
386         return false;
387     }
388     --currentIndex;
389     {
390         ACE_SCOPED_TRACE("SwiperLayoutAlgorithm::MeasureSwiperItem:%d", currentIndex);
391         wrapper->Measure(layoutConstraint);
392     }
393     float mainLen = GetMainAxisSize(wrapper->GetGeometryNode()->GetMarginFrameSize(), axis);
394 
395     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
396         auto layoutProperty = wrapper->GetLayoutProperty();
397         CHECK_NULL_RETURN(layoutProperty, 0);
398         auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
399         if (visibilityValue == VisibleType::INVISIBLE || visibilityValue == VisibleType::GONE) {
400             if (swiperLayoutProperty->GetDisplayCountValue(1) != 0) {
401                 mainLen = (contentMainSize_ - (swiperLayoutProperty->GetDisplayCountValue(1) - 1) * spaceWidth_) /
402                           swiperLayoutProperty->GetDisplayCountValue(1);
403             }
404         }
405     }
406     startPos = endPos - mainLen;
407     itemPosition_[currentIndex] = { startPos, endPos, wrapper->GetHostNode() };
408     return true;
409 }
410 
LayoutForward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t startIndex,float startPos)411 void SwiperLayoutAlgorithm::LayoutForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
412     Axis axis, int32_t startIndex, float startPos)
413 {
414     float currentEndPos = startPos;
415     float currentStartPos = 0.0f;
416     float endMainPos = overScrollFeature_ ? std::max(startPos + contentMainSize_, endMainPos_) : endMainPos_;
417     if (targetIndex_) {
418         endMainPos = Infinity<float>();
419     }
420     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
421     CHECK_NULL_VOID(swiperLayoutProperty);
422 
423     auto currentIndex = startIndex - 1;
424     do {
425         currentStartPos = currentEndPos;
426         auto result =
427             LayoutForwardItem(layoutWrapper, layoutConstraint, axis, currentIndex, currentStartPos, currentEndPos);
428         if (!result) {
429             break;
430         }
431         bool hasMinSize = swiperLayoutProperty->GetMinSize().has_value() &&
432                           !LessOrEqual(swiperLayoutProperty->GetMinSizeValue().Value(), 0);
433         bool hasPrevMargin = swiperLayoutProperty->GetPrevMargin().has_value() &&
434                         !LessOrEqual(swiperLayoutProperty->GetPrevMarginValue().ConvertToPx(), 0);
435         bool hasNextMargin = swiperLayoutProperty->GetNextMargin().has_value() &&
436                         !LessOrEqual(swiperLayoutProperty->GetNextMarginValue().ConvertToPx(), 0);
437         auto isSingleCase =
438             !hasMinSize && (!hasPrevMargin && !hasNextMargin) &&
439             ((swiperLayoutProperty->GetDisplayCount().has_value() &&
440                  swiperLayoutProperty->GetDisplayCountValue() == 1) ||
441                 (!swiperLayoutProperty->GetDisplayCount().has_value() && SwiperUtils::IsStretch(swiperLayoutProperty)));
442         if (isSingleCase && !mainSizeIsDefined_) {
443             endMainPos = startPos + itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
444             endMainPos_ = endMainPos;
445         }
446         if ((currentIndex >= 0 && currentIndex < (totalItemCount_ - 1)) || isLoop_) {
447             currentEndPos += spaceWidth_;
448         }
449         LOGD("LayoutForward: %{public}d current start pos: %{public}f, current end pos: %{public}f", currentIndex,
450             currentStartPos, currentEndPos);
451         // reach the valid target index
452         if (targetIndex_ && GreatOrEqual(currentIndex, targetIndex_.value())) {
453             if (!targetIsSameWithStartFlag_) {
454                 endMainPos = currentStartPos + contentMainSize_;
455                 currentTargetIndex_ = targetIndex_.value();
456                 targetIndex_.reset();
457             } else {
458                 endMainPos = endMainPos_;
459                 currentTargetIndex_ = targetIndex_.value();
460                 targetIndex_.reset();
461             }
462         }
463         if (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_) {
464             break;
465         }
466     } while (LessNotEqual(currentEndPos, nextMargin_ != 0.0f ? endMainPos + nextMargin_ + spaceWidth_ : endMainPos));
467 
468     if (overScrollFeature_ && canOverScroll_) {
469         LOGD("during over scroll, just return in LayoutForward");
470         return;
471     }
472 
473     // adjust offset.
474     if (LessNotEqual(currentEndPos, endMainPos_) && !itemPosition_.empty()) {
475         auto firstItemTop = itemPosition_.begin()->second.startPos;
476         auto itemTotalSize = currentEndPos - firstItemTop;
477         if (LessOrEqual(itemTotalSize, contentMainSize_) && (itemPosition_.begin()->first == 0)) {
478             // all items size is less than swiper.
479             currentOffset_ = firstItemTop;
480             startMainPos_ = currentOffset_;
481             if (!mainSizeIsDefined_) {
482                 // adapt child size.
483                 LOGD("LayoutForward: adapt child total size");
484                 contentMainSize_ = itemTotalSize;
485             }
486         } else {
487             // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
488             if (!canOverScroll_ || jumpIndex_.has_value()) {
489                 auto prevMarginMontage = Positive(prevMargin_) ? prevMargin_ + spaceWidth_ : 0.0f;
490                 auto nextMarginMontage = Positive(nextMargin_) ? nextMargin_ + spaceWidth_ : 0.0f;
491                 currentOffset_ = currentEndPos - contentMainSize_ + prevMarginMontage + nextMarginMontage;
492                 LOGD("LayoutForward: adjust offset to %{public}f", currentOffset_);
493             }
494             startMainPos_ = currentEndPos - contentMainSize_;
495             endMainPos_ = currentEndPos;
496         }
497     }
498 
499     // Mark inactive in wrapper.
500     for (auto pos = itemPosition_.begin(); pos != itemPosition_.end();) {
501         if (GreatNotEqual(
502                 pos->second.endPos, prevMargin_ != 0.0f ? startMainPos_ - prevMargin_ - spaceWidth_ : startMainPos_)) {
503             break;
504         }
505 
506         ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(pos->first), true, axis);
507 
508         layoutWrapper->RemoveChildInRenderTree(GetLoopIndex(pos->first));
509         itemPosition_.erase(pos++);
510     }
511 }
512 
SetInactive(LayoutWrapper * layoutWrapper,float startMainPos,float endMainPos,std::optional<int32_t> targetIndex)513 void SwiperLayoutAlgorithm::SetInactive(
514     LayoutWrapper* layoutWrapper, float startMainPos, float endMainPos, std::optional<int32_t> targetIndex)
515 {
516     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
517     CHECK_NULL_VOID(swiperLayoutProperty);
518     std::list<int32_t> removeIndexes;
519     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
520         if (targetIndex.has_value() && targetIndex.value() == pos->first) {
521             continue;
522         }
523         if (LessOrEqual(
524                 pos->second.endPos, prevMargin_ != 0.0f ? startMainPos - prevMargin_ - spaceWidth_ : startMainPos) ||
525             GreatOrEqual(
526                 pos->second.startPos, nextMargin_ != 0.0f ? endMainPos + nextMargin_ + spaceWidth_ : endMainPos)) {
527             layoutWrapper->RemoveChildInRenderTree(GetLoopIndex(pos->first));
528             removeIndexes.emplace_back(pos->first);
529         }
530     }
531     for (const auto& index : removeIndexes) {
532         itemPosition_.erase(index);
533     }
534 }
535 
LayoutBackward(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint,Axis axis,int32_t endIndex,float endPos)536 void SwiperLayoutAlgorithm::LayoutBackward(
537     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis, int32_t endIndex, float endPos)
538 {
539     float currentStartPos = endPos;
540     float currentEndPos = 0.0f;
541     float startMainPos = overScrollFeature_ ? std::min(endPos - contentMainSize_, startMainPos_) : startMainPos_;
542     if (targetIndex_) {
543         startMainPos = -Infinity<float>();
544     }
545     auto currentIndex = endIndex + 1;
546 
547     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
548     CHECK_NULL_VOID(swiperLayoutProperty);
549     int32_t displayCount = swiperLayoutProperty->GetDisplayCount().has_value() ?
550         swiperLayoutProperty->GetDisplayCount().value() : 1;
551     do {
552         currentEndPos = currentStartPos;
553         auto result =
554             LayoutBackwardItem(layoutWrapper, layoutConstraint, axis, currentIndex, currentEndPos, currentStartPos);
555         if (!result) {
556             break;
557         }
558         if (currentIndex > 0 || isLoop_) {
559             currentStartPos = currentStartPos - spaceWidth_;
560         }
561         LOGD("LayoutBackward: %{public}d current start pos: %{public}f, current end pos: %{public}f", currentIndex,
562             currentStartPos, currentEndPos);
563         // reach the valid target index
564         if (targetIndex_ && LessOrEqual(currentIndex, targetIndex_.value())) {
565             startMainPos = currentStartPos;
566             currentTargetIndex_ = targetIndex_.value();
567             targetIndex_.reset();
568         }
569         if (static_cast<int32_t>(itemPosition_.size()) >= totalItemCount_ + displayCount - 1) {
570             break;
571         }
572     } while (
573         GreatNotEqual(currentStartPos, prevMargin_ != 0.0f ? startMainPos - prevMargin_ - spaceWidth_ : startMainPos));
574 
575     // adjust offset. If edgeEffect is SPRING, jump adjust to allow swiper scroll through boundary
576     if (GreatNotEqual(currentStartPos, startMainPos_)) {
577         if (!canOverScroll_ || jumpIndex_.has_value()) {
578             currentOffset_ = currentStartPos;
579             if (!mainSizeIsDefined_ && GetEndIndex() == totalItemCount_ - 1) {
580                 auto itemTotalSize = GetEndPosition() - currentStartPos;
581                 contentMainSize_ = std::min(contentMainSize_, itemTotalSize);
582             }
583         }
584         endMainPos_ = currentStartPos + contentMainSize_;
585         startMainPos_ = currentStartPos;
586     }
587 
588     if (overScrollFeature_) {
589         LOGD("during over scroll, just return in LayoutBackward");
590         return;
591     }
592 
593     // Mark inactive in wrapper.
594     std::list<int32_t> removeIndexes;
595     for (auto pos = itemPosition_.rbegin(); pos != itemPosition_.rend(); ++pos) {
596         if (LessNotEqual(
597                 pos->second.startPos, nextMargin_ != 0.0f ? endMainPos_ + nextMargin_ + spaceWidth_ : endMainPos_)) {
598             break;
599         }
600 
601         ResetOffscreenItemPosition(layoutWrapper, GetLoopIndex(pos->first), false, axis);
602 
603         layoutWrapper->RemoveChildInRenderTree(GetLoopIndex(pos->first));
604         removeIndexes.emplace_back(pos->first);
605     }
606     for (const auto& index : removeIndexes) {
607         itemPosition_.erase(index);
608     }
609 }
610 
Layout(LayoutWrapper * layoutWrapper)611 void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
612 {
613     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
614     CHECK_NULL_VOID(swiperLayoutProperty);
615     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
616     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
617     auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
618     MinusPaddingToSize(padding, size);
619     auto paddingOffset = padding.Offset();
620 
621     // layout items.
622     for (auto& pos : itemPosition_) {
623         int32_t index = pos.first;
624         auto offset = paddingOffset;
625         auto wrapper = layoutWrapper->GetOrCreateChildByIndex(GetLoopIndex(index));
626         if (!wrapper) {
627             LOGI("wrapper is out of boundary");
628             continue;
629         }
630         if (wrapper->GetHostTag() == V2::SWIPER_INDICATOR_ETS_TAG ||
631             wrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG ||
632             wrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
633             continue;
634         }
635         float crossOffset = 0.0f;
636         pos.second.startPos -= currentOffset_;
637         pos.second.endPos -= currentOffset_;
638 
639         if (axis == Axis::VERTICAL) {
640             offset += OffsetF(crossOffset, pos.second.startPos);
641             if (prevMargin_ != 0.0f) {
642                 offset += OffsetF(0.0f, prevMargin_ + spaceWidth_);
643             }
644         } else {
645             offset += OffsetF(pos.second.startPos, crossOffset);
646             if (prevMargin_ != 0.0f) {
647                 offset += OffsetF(prevMargin_ + spaceWidth_, 0.0f);
648             }
649         }
650         wrapper->GetGeometryNode()->SetMarginFrameOffset(offset);
651         wrapper->Layout();
652     }
653     // Layout swiper indicator
654     if (swiperLayoutProperty->GetShowIndicatorValue(true)) {
655         auto hostNode = layoutWrapper->GetHostNode();
656         CHECK_NULL_VOID(hostNode);
657         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
658         CHECK_NULL_VOID(swiperPattern);
659         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
660         if (indicatorWrapper) {
661             if (swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DIGIT) {
662                 PlaceDigitChild(indicatorWrapper, swiperLayoutProperty);
663             }
664             indicatorWrapper->Layout();
665         }
666     }
667 
668     if (swiperLayoutProperty->GetDisplayArrowValue(false)) {
669         auto hostNode = layoutWrapper->GetHostNode();
670         CHECK_NULL_VOID(hostNode);
671         auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
672         CHECK_NULL_VOID(swiperPattern);
673 
674         if (swiperPattern->HasLeftButtonNode() && swiperPattern->HasRightButtonNode()) {
675             auto leftArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_LEFT_ARROW_ETS_TAG);
676             auto rightArrowWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_RIGHT_ARROW_ETS_TAG);
677             if (leftArrowWrapper && (leftArrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG)) {
678                 ArrowLayout(layoutWrapper, leftArrowWrapper, padding);
679             }
680             if (rightArrowWrapper && (rightArrowWrapper->GetHostTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG)) {
681                 ArrowLayout(layoutWrapper, rightArrowWrapper, padding);
682             }
683         }
684     }
685 }
686 
PlaceDigitChild(const RefPtr<LayoutWrapper> & indicatorWrapper,const RefPtr<LayoutProperty> & layoutProperty)687 void SwiperLayoutAlgorithm::PlaceDigitChild(
688     const RefPtr<LayoutWrapper>& indicatorWrapper, const RefPtr<LayoutProperty>& layoutProperty)
689 {
690     if (indicatorWrapper->GetTotalChildCount() != INDICATOR_HAS_CHILD) {
691         return;
692     }
693     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
694     CHECK_NULL_VOID(swiperLayoutProperty);
695     auto indicatorGeometryNode = indicatorWrapper->GetGeometryNode();
696     CHECK_NULL_VOID(indicatorGeometryNode);
697     auto indicatorWidth = INDICATOR_PADDING.ConvertToPx() * 2.0;
698     auto indicatorHeight = 0.0f;
699     for (auto&& child : indicatorWrapper->GetAllChildrenWithBuild()) {
700         auto textGeometryNode = child->GetGeometryNode();
701         CHECK_NULL_VOID(textGeometryNode);
702         auto textFrameSize = textGeometryNode->GetFrameSize();
703         indicatorWidth += textFrameSize.Width();
704         if (indicatorHeight < textFrameSize.Height()) {
705             indicatorHeight = textFrameSize.Height();
706         }
707     }
708 
709     auto pipelineContext = PipelineBase::GetCurrentContext();
710     CHECK_NULL_VOID_NOLOG(pipelineContext);
711     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
712     CHECK_NULL_VOID_NOLOG(swiperIndicatorTheme);
713     if (LessNotEqual(indicatorHeight, swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx())) {
714         indicatorHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
715     }
716 
717     auto frameNode = indicatorWrapper->GetHostNode();
718     CHECK_NULL_VOID(frameNode);
719     auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
720     CHECK_NULL_VOID(indicatorlayoutProperty);
721 
722     auto currentOffset = SwiperIndicatorUtils::CalcIndicatrFrameOffSet(swiperLayoutProperty,
723                                                                        indicatorlayoutProperty,
724                                                                        indicatorWidth, indicatorHeight);
725 
726     if (swiperLayoutProperty->GetDirectionValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
727         auto top = indicatorlayoutProperty->GetTop();
728         auto bottom = indicatorlayoutProperty->GetBottom();
729         if ((!top.has_value() || NearZero(top.value().Value())) &&
730             (!bottom.has_value() || NearZero(bottom.value().Value()))) {
731             auto dightPadding =
732                 std::abs(swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx() - indicatorHeight) / 2;
733             auto dightVerPadding = swiperIndicatorTheme->GetIndicatorDigitVerticalPadding().ConvertToPx();
734             currentOffset.SetY(currentOffset.GetY() - dightVerPadding + dightPadding);
735         }
736     }
737 
738     indicatorGeometryNode->SetMarginFrameOffset(currentOffset);
739 }
740 
GetNodeLayoutWrapperByTag(LayoutWrapper * layoutWrapper,const std::string & tagName) const741 RefPtr<LayoutWrapper> SwiperLayoutAlgorithm::GetNodeLayoutWrapperByTag(
742     LayoutWrapper* layoutWrapper, const std::string& tagName) const
743 {
744     CHECK_NULL_RETURN(layoutWrapper, nullptr);
745     auto hostNode = layoutWrapper->GetHostNode();
746     CHECK_NULL_RETURN(hostNode, nullptr);
747     auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
748     CHECK_NULL_RETURN(swiperPattern, nullptr);
749     RefPtr<LayoutWrapper> nodeWrapper = nullptr;
750     int32_t totalChildCount = layoutWrapper->GetTotalChildCount();
751     if (totalChildCount == 0) {
752         return nullptr;
753     }
754     int32_t lastChildIndex = totalChildCount - 1;
755     if (swiperPattern->HasIndicatorNode() && !swiperPattern->HasLeftButtonNode() &&
756         !swiperPattern->HasRightButtonNode()) {
757         nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(lastChildIndex);
758         return nodeWrapper;
759     }
760     int32_t endLoopChildIndex = lastChildIndex - SWIPER_HAS_CHILD;
761     for (int32_t index = lastChildIndex; index > endLoopChildIndex && index >= 0; index--) {
762         nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
763         if (nodeWrapper && (nodeWrapper->GetHostTag() == tagName)) {
764             return nodeWrapper;
765         }
766     }
767 
768     return nullptr;
769 }
770 
MeasureArrow(const RefPtr<LayoutWrapper> & arrowWrapper,const RefPtr<LayoutProperty> & layoutProperty) const771 void SwiperLayoutAlgorithm::MeasureArrow(
772     const RefPtr<LayoutWrapper>& arrowWrapper, const RefPtr<LayoutProperty>& layoutProperty) const
773 {
774     CHECK_NULL_VOID(arrowWrapper);
775     CHECK_NULL_VOID(layoutProperty);
776     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutProperty);
777     CHECK_NULL_VOID(swiperLayoutProperty);
778     auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
779     CHECK_NULL_VOID(arrowGeometryNode);
780 
781     auto pipelineContext = PipelineBase::GetCurrentContext();
782     CHECK_NULL_VOID_NOLOG(pipelineContext);
783     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
784     CHECK_NULL_VOID_NOLOG(swiperIndicatorTheme);
785 
786     arrowGeometryNode->SetFrameSize(
787         SizeF { static_cast<float>(
788                     swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
789                         .ConvertToPx()),
790             static_cast<float>(
791                 swiperLayoutProperty->GetBackgroundSizeValue(swiperIndicatorTheme->GetBigArrowBackgroundSize())
792                     .ConvertToPx()) });
793     auto indicatorLayoutConstraint = swiperLayoutProperty->CreateChildConstraint();
794     arrowWrapper->Measure(indicatorLayoutConstraint);
795 }
796 
ArrowLayout(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & arrowWrapper,const PaddingPropertyF padding) const797 void SwiperLayoutAlgorithm::ArrowLayout(
798     LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& arrowWrapper, const PaddingPropertyF padding) const
799 {
800     CHECK_NULL_VOID(layoutWrapper);
801     CHECK_NULL_VOID(arrowWrapper);
802     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(layoutWrapper->GetLayoutProperty());
803     CHECK_NULL_VOID(swiperLayoutProperty);
804     auto axis = swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
805     auto indicatorType = swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
806     auto arrowGeometryNode = arrowWrapper->GetGeometryNode();
807     CHECK_NULL_VOID(arrowGeometryNode);
808     auto arrowFrameSize = arrowGeometryNode->GetFrameSize();
809     auto layoutGeometryNode = layoutWrapper->GetGeometryNode();
810     CHECK_NULL_VOID(layoutGeometryNode);
811     auto swiperFrameSize = layoutGeometryNode->GetFrameSize();
812     auto isShowIndicatorArrow =
813         (!swiperLayoutProperty->GetIsSidebarMiddleValue(false) && swiperLayoutProperty->GetShowIndicatorValue(true));
814     SizeF indicatorFrameSize;
815     RectF indicatorFrameRect;
816     auto normalArrowMargin = 0.0f;
817     if (isShowIndicatorArrow) {
818         auto indicatorWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::SWIPER_INDICATOR_ETS_TAG);
819         CHECK_NULL_VOID(indicatorWrapper);
820         auto indicatorGeometry = indicatorWrapper->GetGeometryNode();
821         CHECK_NULL_VOID(indicatorGeometry);
822         indicatorFrameSize = indicatorGeometry->GetFrameSize();
823         indicatorFrameRect = indicatorGeometry->GetFrameRect();
824         if (indicatorType == SwiperIndicatorType::DOT) {
825             auto hostNode = layoutWrapper->GetHostNode();
826             CHECK_NULL_VOID(hostNode);
827             auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
828             CHECK_NULL_VOID(swiperPattern);
829             auto itemCount = swiperPattern->TotalCount();
830             auto indicatorNode = indicatorWrapper->GetHostNode();
831             CHECK_NULL_VOID(indicatorNode);
832             auto pipeline = PipelineBase::GetCurrentContext();
833             CHECK_NULL_VOID(pipeline);
834             auto theme = pipeline->GetTheme<SwiperIndicatorTheme>();
835             CHECK_NULL_VOID(theme);
836             auto indicatorPaintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
837             CHECK_NULL_VOID(indicatorPaintProperty);
838             auto itemWidth =
839                 static_cast<float>(indicatorPaintProperty->GetItemWidthValue(theme->GetSize()).ConvertToPx());
840             auto selectedItemWidth =
841                 static_cast<float>(indicatorPaintProperty->GetSelectedItemWidthValue(theme->GetSize()).ConvertToPx());
842             auto indicatorPadding = static_cast<float>(theme->GetIndicatorDotPadding().ConvertToPx());
843             auto allPointDiameterSum = itemWidth * static_cast<float>(itemCount + 1);
844             if (indicatorPaintProperty->GetIsCustomSizeValue(false)) {
845                 allPointDiameterSum = itemWidth * static_cast<float>(itemCount - 1) + selectedItemWidth;
846             }
847             auto allPointSpaceSum =
848                 static_cast<float>(theme->GetIndicatorDotItemSpace().ConvertToPx()) * (itemCount - 1);
849             auto indicatorWidth = indicatorPadding + allPointDiameterSum + allPointSpaceSum + indicatorPadding;
850             normalArrowMargin = ((axis == Axis::HORIZONTAL ? indicatorFrameSize.Width() : indicatorFrameSize.Height()) -
851                                     indicatorWidth) * 0.5f;
852         }
853     }
854     auto isLeftArrow = arrowWrapper->GetHostTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG;
855     auto pipelineContext = PipelineBase::GetCurrentContext();
856     CHECK_NULL_VOID(pipelineContext);
857     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
858     CHECK_NULL_VOID(swiperIndicatorTheme);
859     OffsetF arrowOffset(0.0f, 0.0f);
860     float startPoint = 0.0f;
861     if (axis == Axis::HORIZONTAL && isShowIndicatorArrow) {
862         auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
863                                     ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
864                                     : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
865         startPoint = isLeftArrow ? (indicatorFrameRect.Left() - arrowFrameSize.Width() -
866                                        swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding +
867                                        normalArrowMargin)
868                                  : (indicatorFrameRect.Right() + swiperIndicatorTheme->GetArrowScale().ConvertToPx() -
869                                        indicatorPadding - normalArrowMargin);
870         arrowOffset.SetX(startPoint);
871         if (isLeftArrow && !NonNegative(arrowOffset.GetX() - padding.left.value_or(0.0f))) {
872             arrowOffset.SetX(padding.left.value_or(0.0f));
873         }
874         if (GreatOrEqual(
875                 arrowOffset.GetX() + arrowFrameSize.Width(), swiperFrameSize.Width() - padding.right.value_or(0.0f))) {
876             arrowOffset.SetX(swiperFrameSize.Width() - arrowFrameSize.Width() - padding.right.value_or(0.0f));
877         }
878         arrowOffset.SetY(indicatorFrameRect.Top() + (indicatorFrameSize.Height() - arrowFrameSize.Height()) * 0.5f);
879     } else if (axis == Axis::HORIZONTAL && !isShowIndicatorArrow) {
880         startPoint = isLeftArrow
881                          ? swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx() + padding.left.value_or(0.0f)
882                          : (swiperFrameSize.Width() - padding.right.value_or(0.0f) - arrowFrameSize.Width() -
883                                swiperIndicatorTheme->GetArrowHorizontalMargin().ConvertToPx());
884         arrowOffset.SetX(startPoint);
885         arrowOffset.SetY((swiperFrameSize.Height() - padding.top.value_or(0.0f) - padding.bottom.value_or(0.0f) -
886                              arrowFrameSize.Height()) *
887                              0.5f +
888                          padding.top.value_or(0.0f));
889     } else if (axis != Axis::HORIZONTAL && isShowIndicatorArrow) {
890         auto indicatorPadding = indicatorType == SwiperIndicatorType::DIGIT
891                                     ? swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx()
892                                     : swiperIndicatorTheme->GetIndicatorDotPadding().ConvertToPx();
893         startPoint =
894             isLeftArrow
895                 ? (indicatorFrameRect.Top() - arrowFrameSize.Height() - padding.top.value_or(0.0f) -
896                       swiperIndicatorTheme->GetArrowScale().ConvertToPx() + indicatorPadding + normalArrowMargin)
897                 : (indicatorFrameRect.Bottom() + padding.bottom.value_or(0.0f) +
898                       swiperIndicatorTheme->GetArrowScale().ConvertToPx() - indicatorPadding - normalArrowMargin);
899         arrowOffset.SetX(indicatorFrameRect.Left() + (indicatorFrameSize.Width() - arrowFrameSize.Width()) * 0.5f);
900         arrowOffset.SetY(startPoint);
901         if (isLeftArrow && !NonNegative(arrowOffset.GetY() - padding.top.value_or(0.0f))) {
902             arrowOffset.SetY(padding.top.value_or(0.0f));
903         }
904         if (GreatOrEqual(arrowOffset.GetY() + arrowFrameSize.Height(),
905                 swiperFrameSize.Height() - padding.bottom.value_or(0.0f))) {
906             arrowOffset.SetY(swiperFrameSize.Height() - arrowFrameSize.Height() - padding.bottom.value_or(0.0f));
907         }
908     } else {
909         startPoint = isLeftArrow
910                          ? swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx() + padding.top.value_or(0.0f)
911                          : (swiperFrameSize.Height() - arrowFrameSize.Width() - padding.bottom.value_or(0.0f) -
912                                swiperIndicatorTheme->GetArrowVerticalMargin().ConvertToPx());
913         arrowOffset.SetX(padding.left.value_or(0.0f) + (swiperFrameSize.Width() - padding.left.value_or(0.0f) -
914                                                            padding.right.value_or(0.0f) - arrowFrameSize.Width()) *
915                                                            0.5f);
916         arrowOffset.SetY(startPoint);
917     }
918     arrowGeometryNode->SetMarginFrameOffset(arrowOffset);
919     arrowWrapper->Layout();
920 }
921 
ResetOffscreenItemPosition(LayoutWrapper * layoutWrapper,int32_t index,bool isForward,Axis axis) const922 void SwiperLayoutAlgorithm::ResetOffscreenItemPosition(
923     LayoutWrapper* layoutWrapper, int32_t index, bool isForward, Axis axis) const
924 {
925     auto swiperGeometryNode = layoutWrapper->GetGeometryNode();
926     CHECK_NULL_VOID(swiperGeometryNode);
927     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
928     CHECK_NULL_VOID(childWrapper);
929     auto childGeometryNode = childWrapper->GetGeometryNode();
930     CHECK_NULL_VOID(childGeometryNode);
931     auto swiperFrameRect = swiperGeometryNode->GetFrameRect();
932     auto childFrameRect = childGeometryNode->GetFrameRect();
933 
934     OffsetF offset(0.0f, 0.0f);
935     if (axis == Axis::HORIZONTAL) {
936         offset.SetX(isForward ? -childFrameRect.Width() : swiperFrameRect.Width());
937     } else {
938         offset.SetY(isForward ? -childFrameRect.Height() : swiperFrameRect.Height());
939     }
940 
941     childGeometryNode->SetMarginFrameOffset(offset);
942     childWrapper->Layout();
943 }
944 
945 } // namespace OHOS::Ace::NG
946