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