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