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