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