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