1 /*
2 * Copyright (c) 2022-2025 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_pattern.h"
17
18 #include <algorithm>
19 #include <cmath>
20 #include <cstdint>
21 #include <optional>
22
23 #include "base/error/error_code.h"
24 #include "base/geometry/axis.h"
25 #include "base/geometry/dimension.h"
26 #include "base/geometry/ng/offset_t.h"
27 #include "base/log/ace_trace.h"
28 #include "base/log/event_report.h"
29 #include "base/log/log_wrapper.h"
30 #include "base/perfmonitor/perf_constants.h"
31 #include "base/perfmonitor/perf_monitor.h"
32 #include "base/ressched/ressched_report.h"
33 #include "base/utils/utils.h"
34 #include "core/animation/curve.h"
35 #include "core/animation/curves.h"
36 #include "core/animation/spring_curve.h"
37 #include "core/common/container_scope.h"
38 #include "core/common/recorder/node_data_cache.h"
39 #include "core/components/common/layout/constants.h"
40 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
41 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
42 #include "core/components_ng/pattern/swiper/swiper_helper.h"
43 #include "core/components_ng/pattern/swiper/swiper_node.h"
44 #include "core/components_ng/pattern/swiper/swiper_paint_method.h"
45 #include "core/components_ng/pattern/swiper/swiper_theme.h"
46 #include "core/components_ng/pattern/swiper_indicator/indicator_common/arc_swiper_indicator_pattern.h"
47 #include "core/components_ng/pattern/swiper_indicator/indicator_common/indicator_pattern.h"
48 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_arrow_pattern.h"
49 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_pattern.h"
50 #include "core/components_ng/pattern/tabs/tab_content_node.h"
51 #include "core/components_ng/pattern/tabs/tab_content_pattern.h"
52 #include "core/components_ng/pattern/tabs/tabs_node.h"
53 #include "core/components_ng/render/adapter/component_snapshot.h"
54 #include "core/components_ng/syntax/for_each_node.h"
55 #include "core/components_ng/syntax/lazy_for_each_node.h"
56 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
57
58 namespace OHOS::Ace::NG {
59 namespace {
60
61 // TODO use theme.
62 constexpr int32_t MAX_DISPLAY_COUNT_MIN = 6;
63 constexpr int32_t MAX_DISPLAY_COUNT_MAX = 9;
64 constexpr int32_t MIN_TURN_PAGE_VELOCITY = 1200;
65 constexpr Dimension INDICATOR_BORDER_RADIUS = 16.0_vp;
66
67 constexpr float PX_EPSILON = 0.01f;
68 constexpr float FADE_DURATION = 500.0f;
69 constexpr float SPRING_DURATION = 600.0f;
70 constexpr float DEFAULT_MINIMUM_AMPLITUDE_PX = 1.0f;
71 constexpr int32_t INDEX_DIFF_TWO = 2;
72 constexpr int32_t FIRST_CAPTURE_DELAY_TIME = 30;
73 const std::string SWIPER_DRAG_SCENE = "swiper_drag_scene";
74 const std::string FADE_PROPERTY_NAME = "fade";
75 const std::string SPRING_PROPERTY_NAME = "spring";
76 const std::string INDICATOR_PROPERTY_NAME = "indicator";
77 const std::string TRANSLATE_PROPERTY_NAME = "translate";
78 constexpr uint16_t CAPTURE_PIXEL_ROUND_VALUE = static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_START) |
79 static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
80 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_END) |
81 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM);
82 constexpr int32_t CAPTURE_COUNT = 2;
83 constexpr char APP_SWIPER_NO_ANIMATION_SWITCH[] = "APP_SWIPER_NO_ANIMATION_SWITCH";
84 constexpr char APP_SWIPER_FRAME_ANIMATION[] = "APP_SWIPER_FRAME_ANIMATION";
85 constexpr char APP_TABS_FLING[] = "APP_TABS_FLING";
86 constexpr char APP_TABS_SCROLL[] = "APP_TABS_SCROLL";
87 constexpr char APP_TABS_NO_ANIMATION_SWITCH[] = "APP_TABS_NO_ANIMATION_SWITCH";
88 constexpr char APP_TABS_FRAME_ANIMATION[] = "APP_TABS_FRAME_ANIMATION";
89
90 constexpr int32_t COMPONENT_SWIPER_FLING = 1;
91 constexpr int32_t PAGE_FLIP_MODE_SIZE = 2;
92 const RefPtr<FrameRateRange> SWIPER_DEFAULT_FRAME_RATE =
93 AceType::MakeRefPtr<FrameRateRange>(0, 0, 0, COMPONENT_SWIPER_FLING);
94
95 constexpr int32_t JUMP_NEAR_VALUE = 3;
96 constexpr int32_t MIN_DUMP_VELOCITY_THRESHOLD = 500;
97 constexpr float MAX_INDICATOR_VELOCITY = 1200.0f;
98 constexpr Dimension DEFAULT_INDICATOR_HEAD_DISTANCE = 14.0_vp;
99 } // namespace
100
SwiperPattern()101 SwiperPattern::SwiperPattern()
102 {
103 swiperController_ = MakeRefPtr<SwiperController>();
104 SwiperHelper::InitSwiperController(swiperController_, WeakClaim(this));
105 }
106
OnAttachToFrameNode()107 void SwiperPattern::OnAttachToFrameNode()
108 {
109 auto host = GetHost();
110 CHECK_NULL_VOID(host);
111 auto renderContext = host->GetRenderContext();
112 CHECK_NULL_VOID(renderContext);
113 renderContext->SetClipToFrame(true);
114 renderContext->SetClipToBounds(true);
115 auto pipeline = host->GetContext();
116 CHECK_NULL_VOID(pipeline);
117 auto indicatorTheme = pipeline->GetTheme<SwiperIndicatorTheme>();
118 CHECK_NULL_VOID(indicatorTheme);
119 renderContext->UpdateClipEdge(indicatorTheme->GetClipEdge());
120 InitSurfaceChangedCallback();
121 }
122
OnDetachFromFrameNode(FrameNode * node)123 void SwiperPattern::OnDetachFromFrameNode(FrameNode* node)
124 {
125 auto pipeline = GetContext();
126 CHECK_NULL_VOID(pipeline);
127 if (HasSurfaceChangedCallback()) {
128 pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
129 }
130 pipeline->RemoveWindowStateChangedCallback(node->GetId());
131 }
132
OnAttachToMainTree()133 void SwiperPattern::OnAttachToMainTree()
134 {
135 if (!isInit_) {
136 SetOnHiddenChangeForParent();
137 }
138 }
139
OnDetachFromMainTree()140 void SwiperPattern::OnDetachFromMainTree()
141 {
142 RemoveOnHiddenChange();
143 }
144
CreateLayoutAlgorithm()145 RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
146 {
147 auto host = GetHost();
148 CHECK_NULL_RETURN(host, nullptr);
149 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
150 CHECK_NULL_RETURN(props, nullptr);
151
152 auto algo = MakeRefPtr<SwiperLayoutAlgorithm>();
153 if (props->GetIsCustomAnimation().value_or(false)) {
154 algo->SetUseCustomAnimation(true);
155 algo->SetCustomAnimationToIndex(customAnimationToIndex_);
156 algo->SetIndexsInAnimation(indexsInAnimation_);
157 algo->SetNeedUnmountIndexs(needUnmountIndexs_);
158 return algo;
159 }
160 if (SupportSwiperCustomAnimation()) {
161 algo->SetNeedUnmountIndexs(needUnmountIndexs_);
162 algo->SetItemsPositionInAnimation(itemPositionInAnimation_);
163 }
164
165 if (jumpIndex_) {
166 algo->SetJumpIndex(jumpIndex_.value());
167 } else if (targetIndex_) {
168 algo->SetTargetIndex(targetIndex_.value());
169 }
170 algo->SetCachedShow(IsCachedShow());
171 algo->SetCurrentIndex(currentIndex_);
172 algo->SetMainSizeIsMeasured(mainSizeIsMeasured_);
173 oldContentMainSize_ = contentMainSize_;
174 algo->SetContentMainSize(contentMainSize_);
175 algo->SetDuringInteraction(isDragging_ || RunningTranslateAnimation());
176 if (!propertyAnimationIsRunning_) {
177 algo->SetCurrentDelta(currentDelta_);
178 }
179 algo->SetItemsPosition(itemPosition_);
180 if (IsOutOfBoundary() && !IsLoop()) {
181 algo->SetOverScrollFeature();
182 }
183 algo->SetTotalItemCount(TotalCount());
184 algo->SetIsLoop(IsLoop());
185 algo->SetSwipeByGroup(IsSwipeByGroup());
186 algo->SetRealTotalCount(RealTotalCount());
187 algo->SetPlaceItemWidth(placeItemWidth_);
188 algo->SetIsFrameAnimation(translateAnimationIsRunning_);
189
190 auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
191 const auto effect = swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
192 algo->SetCanOverScroll(effect == EdgeEffect::SPRING);
193 algo->SetHasCachedCapture(hasCachedCapture_);
194 algo->SetIsCaptureReverse(isCaptureReverse_);
195 algo->SetCachedCount(GetCachedCount());
196 algo->SetIgnoreBlankOffset(ignoreBlankOffset_);
197 return algo;
198 }
199
OnIndexChange(bool isInLayout)200 void SwiperPattern::OnIndexChange(bool isInLayout)
201 {
202 auto totalCount = TotalCount();
203 if (NonPositive(totalCount)) {
204 return;
205 }
206
207 auto oldIndex = GetLoopIndex(oldIndex_);
208 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != totalCount) {
209 oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
210 oldChildrenSize_ = totalCount;
211 }
212
213 auto targetIndex = GetLoopIndex(CurrentIndex());
214 if (oldIndex != targetIndex) {
215 FireChangeEvent(oldIndex, targetIndex, isInLayout);
216 FireSelectedEvent(oldIndex, targetIndex);
217 FireUnselectedEvent(oldIndex, targetIndex);
218 // lazyBuild feature.
219 SetLazyLoadFeature(true);
220 }
221 }
222
StopAndResetSpringAnimation()223 void SwiperPattern::StopAndResetSpringAnimation()
224 {
225 if (springAnimationIsRunning_ && !isTouchDownSpringAnimation_) {
226 StopSpringAnimation();
227 currentDelta_ = 0.0f;
228 itemPosition_.clear();
229 isVoluntarilyClear_ = true;
230 jumpIndex_ = currentIndex_;
231 }
232 }
233
CheckLoopChange()234 void SwiperPattern::CheckLoopChange()
235 {
236 auto props = GetLayoutProperty<SwiperLayoutProperty>();
237 CHECK_NULL_VOID(props);
238 auto currentLoopValue = props->GetLoop().value_or(true);
239 if (!preLoop_.has_value()) {
240 preLoop_ = currentLoopValue;
241 return;
242 }
243
244 if (preLoop_.value() != currentLoopValue) {
245 currentIndex_ =
246 GetLoopIndex(currentIndex_, oldChildrenSize_.has_value() ? oldChildrenSize_.value() : TotalCount());
247 if (props->GetPrevMargin().has_value() || props->GetNextMargin().has_value()) {
248 jumpIndex_ = jumpIndex_.value_or(currentIndex_);
249 }
250 preLoop_ = currentLoopValue;
251 }
252 }
253
AdjustCurrentIndexOnSwipePage(int32_t index)254 void SwiperPattern::AdjustCurrentIndexOnSwipePage(int32_t index)
255 {
256 auto adjustIndex = SwiperUtils::ComputePageIndex(index, GetDisplayCount());
257 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
258 CHECK_NULL_VOID(props);
259 props->UpdateIndexWithoutMeasure(GetLoopIndex(adjustIndex));
260 currentIndex_ = GetLoopIndex(adjustIndex);
261 }
262
InitCapture()263 void SwiperPattern::InitCapture()
264 {
265 auto host = GetHost();
266 CHECK_NULL_VOID(host);
267 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
268 CHECK_NULL_VOID(props);
269 bool hasCachedCapture = SwiperUtils::IsStretch(props) && props->GetLoop().value_or(true) && !IsSwipeByGroup() &&
270 GetDisplayCount() == TotalCount() - 1 &&
271 (Positive(props->GetPrevMarginValue(0.0_px).ConvertToPx()) ||
272 Positive(props->GetNextMarginValue(0.0_px).ConvertToPx()));
273 if (hasCachedCapture) {
274 leftCaptureIndex_ = std::nullopt;
275 rightCaptureIndex_ = std::nullopt;
276 }
277
278 if (!hasCachedCapture_ && hasCachedCapture) {
279 // Screenshot nodes need to be added at the forefront of all special nodes to display at the bottom
280 uint32_t number = static_cast<uint32_t>(indicatorId_.has_value()) + static_cast<uint32_t>(HasLeftButtonNode()) +
281 static_cast<uint32_t>(HasRightButtonNode()) + 1;
282 auto leftCaptureNode = FrameNode::GetOrCreateFrameNode(
283 V2::SWIPER_LEFT_CAPTURE_ETS_TAG, GetLeftCaptureId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
284 auto imageLayoutProperty = leftCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
285 CHECK_NULL_VOID(imageLayoutProperty);
286 imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
287 leftCaptureNode->MarkModifyDone();
288 host->AddChild(leftCaptureNode, -number);
289
290 auto rightCaptureNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_CAPTURE_ETS_TAG, GetRightCaptureId(),
291 []() { return AceType::MakeRefPtr<ImagePattern>(); });
292 imageLayoutProperty = rightCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
293 CHECK_NULL_VOID(imageLayoutProperty);
294 imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
295 rightCaptureNode->MarkModifyDone();
296 host->AddChild(rightCaptureNode, -number);
297 }
298 if (hasCachedCapture_ && !hasCachedCapture) {
299 RemoveAllCaptureNode();
300 }
301 if (SupportSwiperCustomAnimation() && hasCachedCapture) {
302 needUnmountIndexs_.clear();
303 itemPositionInAnimation_.clear();
304 }
305 hasCachedCapture_ = hasCachedCapture;
306 }
307
SetLazyForEachFlag() const308 void SwiperPattern::SetLazyForEachFlag() const
309 {
310 auto host = GetHost();
311 CHECK_NULL_VOID(host);
312 auto targetNode = FindLazyForEachNode(host);
313 if (targetNode.has_value()) {
314 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
315 CHECK_NULL_VOID(lazyForEachNode);
316 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
317 }
318 }
319
ResetOnForceMeasure()320 void SwiperPattern::ResetOnForceMeasure()
321 {
322 resetLayoutTask_.Cancel();
323 StopPropertyTranslateAnimation(isFinishAnimation_, false, true);
324 StopTranslateAnimation();
325 StopSpringAnimationImmediately();
326 StopFadeAnimation();
327 StopIndicatorAnimation(true);
328 currentOffset_ = 0.0f;
329 mainSizeIsMeasured_ = false;
330 currentDelta_ = 0.0f;
331 itemPosition_.clear();
332 isVoluntarilyClear_ = true;
333 jumpIndex_ = jumpIndex_.value_or(currentIndex_);
334 SetLazyForEachFlag();
335 ResetTabBar();
336 MarkDirtyNodeSelf();
337 }
338
ResetTabBar()339 void SwiperPattern::ResetTabBar()
340 {
341 auto host = GetHost();
342 CHECK_NULL_VOID(host);
343 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
344 CHECK_NULL_VOID(tabsNode);
345 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
346 CHECK_NULL_VOID(tabBarNode);
347 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
348 CHECK_NULL_VOID(tabBarPattern);
349 tabBarPattern->ResetOnForceMeasure(jumpIndex_.value_or(currentIndex_));
350 }
351
UpdateTabBarIndicatorCurve()352 void SwiperPattern::UpdateTabBarIndicatorCurve()
353 {
354 CHECK_NULL_VOID(swiperController_);
355 auto updateCubicCurveCallback = [weak = WeakClaim(this)]() {
356 auto swiperPattern = weak.Upgrade();
357 CHECK_NULL_VOID(swiperPattern);
358 auto host = swiperPattern->GetHost();
359 CHECK_NULL_VOID(host);
360 auto props = host->GetPaintProperty<SwiperPaintProperty>();
361 CHECK_NULL_VOID(props);
362 auto curve = MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
363 props->UpdateCurve(curve);
364 };
365 swiperController_->SetUpdateCubicCurveCallback(std::move(updateCubicCurveCallback));
366 }
367
NeedForceMeasure() const368 bool SwiperPattern::NeedForceMeasure() const
369 {
370 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
371 CHECK_NULL_RETURN(props, false);
372
373 return ((props->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
374 (isSwipeByGroup_.has_value() && isSwipeByGroup_.value() != IsSwipeByGroup());
375 }
376
MarkDirtyBindIndicatorNode() const377 void SwiperPattern::MarkDirtyBindIndicatorNode() const
378 {
379 auto indicatorNode = GetIndicatorNode();
380 CHECK_NULL_VOID(indicatorNode);
381 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
382 }
383
OnModifyDone()384 void SwiperPattern::OnModifyDone()
385 {
386 Pattern::OnModifyDone();
387 auto host = GetHost();
388 CHECK_NULL_VOID(host);
389 swiperId_ = host->GetId();
390 auto hub = host->GetEventHub<EventHub>();
391 CHECK_NULL_VOID(hub);
392 auto gestureHub = hub->GetOrCreateGestureEventHub();
393 CHECK_NULL_VOID(gestureHub);
394
395 auto index = CurrentIndex();
396 if (currentIndex_ != index && index >= 0) {
397 AceAsyncTraceBeginCommercial(
398 0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
399 }
400
401 if (!isBindIndicator_) {
402 InitIndicator();
403 } else if (NeedForceMeasure()) {
404 MarkDirtyBindIndicatorNode();
405 }
406 hoverFlag_ = HOVER_NONE;
407 InitArrow();
408 InitCapture();
409 CheckSpecialItemCount();
410 SetLazyLoadIsLoop();
411 RegisterVisibleAreaChange();
412 InitTouchEvent(gestureHub);
413 InitHoverMouseEvent();
414 StopAndResetSpringAnimation();
415
416 if (NeedForceMeasure()) {
417 ResetOnForceMeasure();
418 }
419
420 isSwipeByGroup_ = IsSwipeByGroup();
421
422 bool disableSwipe = IsDisableSwipe();
423 UpdateSwiperPanEvent(disableSwipe);
424
425 auto focusHub = host->GetFocusHub();
426 if (focusHub) {
427 InitOnKeyEvent(focusHub);
428 InitOnFocusInternal(focusHub);
429 }
430 #ifdef SUPPORT_DIGITAL_CROWN
431 InitOnCrownEventInternal(focusHub);
432 #endif
433
434 SetSwiperEventCallback(disableSwipe);
435 UpdateTabBarIndicatorCurve();
436
437 if (IsAutoPlay()) {
438 StartAutoPlay();
439 } else {
440 translateTask_.Cancel();
441 isInAutoPlay_ = false;
442 }
443
444 SetAccessibilityAction();
445 placeItemWidth_.reset();
446
447 if (IsSwipeByGroup()) {
448 needAdjustIndex_ = true;
449 }
450
451 if (isBindIndicator_) {
452 auto refUINode = indicatorNode_.Upgrade();
453 CHECK_NULL_VOID(refUINode);
454 auto frameNode = DynamicCast<NG::FrameNode>(refUINode);
455 CHECK_NULL_VOID(frameNode);
456 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
457 CHECK_NULL_VOID(indicatorPattern);
458 indicatorPattern->InitIndicatorEvent();
459 }
460 }
461
OnAfterModifyDone()462 void SwiperPattern::OnAfterModifyDone()
463 {
464 auto host = GetHost();
465 CHECK_NULL_VOID(host);
466 auto inspectorId = host->GetInspectorId().value_or("");
467 if (!inspectorId.empty()) {
468 Recorder::NodeDataCache::Get().PutInt(host, inspectorId, CurrentIndex());
469 }
470 }
471
CheckUserSetIndex(int32_t index)472 int32_t SwiperPattern::CheckUserSetIndex(int32_t index)
473 {
474 if (!IsAutoLinear()) {
475 return index;
476 }
477
478 if (index < 0 || index >= RealTotalCount()) {
479 index = 0;
480 UpdateCurrentIndex(index);
481 }
482
483 auto childNode = GetCurrentFrameNode(GetLoopIndex(index));
484 CHECK_NULL_RETURN(childNode, index);
485 auto childLayoutProperty = childNode->GetLayoutProperty<LayoutProperty>();
486 CHECK_NULL_RETURN(childLayoutProperty, index);
487 if (childLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
488 return index;
489 }
490
491 return CheckTargetIndex(index + 1);
492 }
493
UpdateIndicatorOnChildChange()494 void SwiperPattern::UpdateIndicatorOnChildChange()
495 {
496 if (HasIndicatorNode()) {
497 StopIndicatorAnimation();
498 auto host = GetHost();
499 CHECK_NULL_VOID(host);
500 auto indicatorNode = GetCommonIndicatorNode();
501 if (indicatorNode && IsIndicator(indicatorNode->GetTag())) {
502 indicatorNode->MarkModifyDone();
503 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
504 }
505 }
506 }
507
UpdateDigitalIndicator()508 void SwiperPattern::UpdateDigitalIndicator()
509 {
510 if (!HasIndicatorNode() || GetIndicatorType() != SwiperIndicatorType::DIGIT) {
511 return;
512 }
513
514 auto host = GetHost();
515 CHECK_NULL_VOID(host);
516 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
517 CHECK_NULL_VOID(indicatorNode);
518
519 if (indicatorNode->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
520 return;
521 }
522
523 indicatorNode->MarkModifyDone();
524 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
525 }
526
BeforeCreateLayoutWrapper()527 void SwiperPattern::BeforeCreateLayoutWrapper()
528 {
529 auto host = GetHost();
530 CHECK_NULL_VOID(host);
531 auto hadCachedCapture = hasCachedCapture_;
532 if (host->GetChildrenUpdated() != -1) {
533 InitCapture();
534 if (NeedAutoPlay() && !translateTask_) {
535 StartAutoPlay();
536 }
537 UpdateCurrentFocus();
538 host->ChildrenUpdatedFrom(-1);
539 }
540
541 CheckLoopChange();
542 auto lastCurrentIndex = currentIndex_;
543 auto userSetCurrentIndex = CurrentIndex();
544 userSetCurrentIndex = CheckUserSetIndex(userSetCurrentIndex);
545 auto oldIndex = GetLoopIndex(lastCurrentIndex);
546 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != TotalCount()) {
547 oldIndex = GetLoopIndex(lastCurrentIndex, oldChildrenSize_.value());
548 UpdateIndicatorOnChildChange();
549 StartAutoPlay();
550 InitArrow();
551 if (IsLoop() && oldIndex != GetLoopIndex(currentIndex_)) {
552 currentIndex_ = oldIndex >= TotalCount() ? 0 : oldIndex;
553 }
554 } else if (oldRealTotalCount_ && oldRealTotalCount_.value() != RealTotalCount()) {
555 UpdateDigitalIndicator();
556 }
557 auto index = CheckIndexRange(userSetCurrentIndex);
558 if (index != userSetCurrentIndex) {
559 UpdateCurrentIndex(index);
560 } else if (oldIndex != userSetCurrentIndex) {
561 currentIndex_ = userSetCurrentIndex;
562 propertyAnimationIndex_ = GetLoopIndex(propertyAnimationIndex_);
563 }
564
565 if (IsSwipeByGroup() && needAdjustIndex_) {
566 AdjustCurrentIndexOnSwipePage(CurrentIndex());
567 needAdjustIndex_ = false;
568 }
569
570 if (lastCurrentIndex != currentIndex_ || (itemPosition_.empty() && !isVoluntarilyClear_)
571 || hadCachedCapture != hasCachedCapture_) {
572 jumpIndex_ = GetLoopIndex(currentIndex_);
573 currentFirstIndex_ = jumpIndex_.value_or(0);
574 turnPageRate_ = 0.0f;
575 SetIndicatorJumpIndex(jumpIndex_);
576 }
577 isVoluntarilyClear_ = false;
578 if (jumpIndex_) {
579 if ((jumpIndex_.value() < 0 || jumpIndex_.value() >= TotalCount()) && !IsLoop()) {
580 jumpIndex_ = 0;
581 }
582 targetIndex_.reset();
583 nextIndex_ = jumpIndex_.value();
584 StopAutoPlay();
585 StopTranslateAnimation();
586 StopFadeAnimation();
587 StopSpringAnimation();
588 if (propertyAnimationIsRunning_) {
589 StopPropertyTranslateAnimation(false, true);
590 StopIndicatorAnimation();
591 }
592 currentDelta_ = 0.0f;
593 }
594 if (isInit_) {
595 FireSelectedEvent(-1, currentIndex_);
596 }
597 if (lastCurrentIndex != currentIndex_ && !isInit_ && !IsUseCustomAnimation()) {
598 FireWillShowEvent(currentIndex_);
599 FireWillHideEvent(lastCurrentIndex);
600 }
601
602 UpdateItemsLatestSwitched();
603 UpdateIgnoreBlankOffsetWithIndex();
604 }
605
UpdateItemsLatestSwitched()606 void SwiperPattern::UpdateItemsLatestSwitched()
607 {
608 if (!hasTabsAncestor_) {
609 return;
610 }
611 auto host = GetHost();
612 CHECK_NULL_VOID(host);
613 auto tabsNode = AceType::DynamicCast<FrameNode>(host->GetParent());
614 CHECK_NULL_VOID(tabsNode);
615 auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
616 CHECK_NULL_VOID(tabsLayoutProperty);
617 auto cachedMaxCount = tabsLayoutProperty->GetCachedMaxCountValue(-1);
618 auto cacheMode = tabsLayoutProperty->GetCacheModeValue(TabsCacheMode::CACHE_BOTH_SIDE);
619 if (cachedMaxCount < 0 || cachedMaxCount >= RealTotalCount() || cacheMode != TabsCacheMode::CACHE_LATEST_SWITCHED) {
620 itemsLatestSwitched_.clear();
621 return;
622 }
623
624 auto props = GetLayoutProperty<SwiperLayoutProperty>();
625 CHECK_NULL_VOID(props);
626 auto currentIndex = props->GetIndexValue(0);
627 auto indexNeedInsert = -1;
628 if (IsUseCustomAnimation()) {
629 indexNeedInsert = customAnimationToIndex_.value_or(currentIndex);
630 } else if (jumpIndex_) {
631 indexNeedInsert = jumpIndex_.value();
632 } else if (targetIndex_) {
633 indexNeedInsert = targetIndex_.value();
634 } else if (itemsLatestSwitched_.empty()) {
635 indexNeedInsert = currentIndex;
636 }
637 if (indexNeedInsert < 0) {
638 return;
639 }
640
641 itemsLatestSwitched_.remove(indexNeedInsert);
642 itemsLatestSwitched_.push_back(indexNeedInsert);
643 if (static_cast<int32_t>(itemsLatestSwitched_.size()) > (cachedMaxCount + 1)) {
644 itemsLatestSwitched_.pop_front();
645 }
646 }
647
HandleTabsCachedMaxCount(int32_t startIndex,int32_t endIndex)648 void SwiperPattern::HandleTabsCachedMaxCount(int32_t startIndex, int32_t endIndex)
649 {
650 if (!hasTabsAncestor_) {
651 return;
652 }
653 itemsNeedClean_.clear();
654 auto host = GetHost();
655 CHECK_NULL_VOID(host);
656 auto tabsNode = AceType::DynamicCast<FrameNode>(host->GetParent());
657 CHECK_NULL_VOID(tabsNode);
658 auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
659 CHECK_NULL_VOID(tabsLayoutProperty);
660 auto realTotalCount = RealTotalCount();
661 auto cachedMaxCount = tabsLayoutProperty->GetCachedMaxCountValue(-1);
662 if (cachedMaxCount < 0 || cachedMaxCount >= realTotalCount) {
663 return;
664 }
665 auto cacheMode = tabsLayoutProperty->GetCacheModeValue(TabsCacheMode::CACHE_BOTH_SIDE);
666 auto useCustomAnimation = IsUseCustomAnimation();
667 for (int32_t index = 0; index < realTotalCount; ++index) {
668 if (cacheMode == TabsCacheMode::CACHE_BOTH_SIDE) {
669 if (useCustomAnimation && ((index >= startIndex - cachedMaxCount && index <= startIndex + cachedMaxCount) ||
670 (index >= endIndex - cachedMaxCount && index <= endIndex + cachedMaxCount))) {
671 continue;
672 } else if (startIndex > endIndex ||
673 (index >= startIndex - cachedMaxCount && index <= endIndex + cachedMaxCount)) {
674 continue;
675 }
676 } else if (cacheMode == TabsCacheMode::CACHE_LATEST_SWITCHED) {
677 if (std::find(itemsLatestSwitched_.begin(), itemsLatestSwitched_.end(), index) !=
678 itemsLatestSwitched_.end()) {
679 continue;
680 }
681 }
682
683 itemsNeedClean_.insert(index);
684 }
685
686 PostIdleTaskToCleanTabContent();
687 }
688
PostIdleTaskToCleanTabContent()689 void SwiperPattern::PostIdleTaskToCleanTabContent()
690 {
691 if (itemsNeedClean_.empty()) {
692 return;
693 }
694 auto pipelineContext = GetContext();
695 CHECK_NULL_VOID(pipelineContext);
696 pipelineContext->AddPredictTask([weak = WeakClaim(this)](int64_t deadline, bool canUseLongPredictTask) {
697 auto pattern = weak.Upgrade();
698 CHECK_NULL_VOID(pattern);
699 auto host = pattern->GetHost();
700 CHECK_NULL_VOID(host);
701
702 std::set<int32_t> itemsHasClean;
703 for (const auto& index : pattern->itemsNeedClean_) {
704 if (GetSysTimestamp() > deadline) {
705 break;
706 }
707 itemsHasClean.insert(index);
708 auto child = AceType::DynamicCast<FrameNode>(host->GetChildByIndex(index));
709 if (!child || child->IsActive()) {
710 continue;
711 }
712 auto tabContentPattern = AceType::DynamicCast<TabContentPattern>(child->GetPattern<TabContentPattern>());
713 if (tabContentPattern) {
714 tabContentPattern->CleanChildren();
715 }
716 }
717 for (const auto& index : itemsHasClean) {
718 pattern->itemsNeedClean_.erase(index);
719 }
720 if (!pattern->itemsNeedClean_.empty()) {
721 pattern->PostIdleTaskToCleanTabContent();
722 }
723 });
724 }
725
UpdateTargetCapture(bool forceUpdate)726 void SwiperPattern::UpdateTargetCapture(bool forceUpdate)
727 {
728 if (itemPosition_.empty()) {
729 return;
730 }
731 auto leftTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
732 auto rightTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
733 if (isCaptureReverse_) {
734 leftTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
735 rightTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
736 }
737 if (forceUpdate || !leftCaptureIndex_.has_value() || leftCaptureIndex_.value() != leftTargetIndex) {
738 CreateCaptureCallback(leftTargetIndex, GetLeftCaptureId(), forceUpdate);
739 leftCaptureIndex_ = leftTargetIndex;
740 }
741 if (forceUpdate || !rightCaptureIndex_.has_value() || rightCaptureIndex_.value() != rightTargetIndex) {
742 CreateCaptureCallback(rightTargetIndex, GetRightCaptureId(), forceUpdate);
743 rightCaptureIndex_ = rightTargetIndex;
744 }
745 }
746
CreateCaptureCallback(int32_t targetIndex,int32_t captureId,bool forceUpdate)747 void SwiperPattern::CreateCaptureCallback(int32_t targetIndex, int32_t captureId, bool forceUpdate)
748 {
749 auto host = GetHost();
750 CHECK_NULL_VOID(host);
751 auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
752 CHECK_NULL_VOID(targetNode);
753 auto callback = [weak = WeakClaim(this), captureId, targetIndex, hostInstanceId = GetHostInstanceId()](
754 std::shared_ptr<Media::PixelMap> pixelMap) {
755 ContainerScope scope(hostInstanceId);
756 auto swiper = weak.Upgrade();
757 CHECK_NULL_VOID(swiper);
758 auto piplineContext = swiper->GetContext();
759 CHECK_NULL_VOID(piplineContext);
760 auto taskExecutor = piplineContext->GetTaskExecutor();
761 CHECK_NULL_VOID(taskExecutor);
762 taskExecutor->PostTask(
763 [weak, pixelMap, captureId, targetIndex]() mutable {
764 auto swiper = weak.Upgrade();
765 CHECK_NULL_VOID(swiper);
766 swiper->UpdateCaptureSource(pixelMap, captureId, targetIndex);
767 },
768 TaskExecutor::TaskType::UI, "ArkUISwiperUpdateCaptureSource");
769 };
770 if (forceUpdate) {
771 // The size changes caused by layout need to wait for rendering before taking a screenshot
772 auto piplineContext = GetContext();
773 CHECK_NULL_VOID(piplineContext);
774 auto taskExecutor = piplineContext->GetTaskExecutor();
775 CHECK_NULL_VOID(taskExecutor);
776 taskExecutor->PostDelayedTask(
777 [weakTarget = WeakClaim(RawPtr(targetNode)), callback]() {
778 auto target = weakTarget.Upgrade();
779 CHECK_NULL_VOID(target);
780 ComponentSnapshot::GetNormalCapture(target, std::move(callback));
781 },
782 TaskExecutor::TaskType::UI, FIRST_CAPTURE_DELAY_TIME, "ArkUISwiperGetNormalCapture");
783 } else {
784 ComponentSnapshot::GetNormalCapture(targetNode, std::move(callback));
785 }
786 }
787
UpdateCaptureSource(std::shared_ptr<Media::PixelMap> pixelMap,int32_t captureId,int32_t targetIndex)788 void SwiperPattern::UpdateCaptureSource(
789 std::shared_ptr<Media::PixelMap> pixelMap, int32_t captureId, int32_t targetIndex)
790 {
791 // Async tasks require verifying if the pixel map is the correct target
792 if (!(captureId == GetLeftCaptureId() && leftCaptureIndex_.has_value() &&
793 targetIndex == leftCaptureIndex_.value()) &&
794 !(captureId == GetRightCaptureId() && rightCaptureIndex_.has_value() &&
795 targetIndex == rightCaptureIndex_.value())) {
796 return;
797 }
798 auto host = GetHost();
799 CHECK_NULL_VOID(host);
800 auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
801 CHECK_NULL_VOID(targetNode);
802 auto targetLayoutProperty = targetNode->GetLayoutProperty<LayoutProperty>();
803 CHECK_NULL_VOID(targetLayoutProperty);
804 auto targetMargin = targetLayoutProperty->CreateMargin();
805 MarginProperty margin;
806 margin.left = CalcLength(targetMargin.left.has_value() ? targetMargin.left.value() : 0.0f);
807 margin.right = CalcLength(targetMargin.right.has_value() ? targetMargin.right.value() : 0.0f);
808 margin.top = CalcLength(targetMargin.top.has_value() ? targetMargin.top.value() : 0.0f);
809 margin.bottom = CalcLength(targetMargin.bottom.has_value() ? targetMargin.bottom.value() : 0.0f);
810
811 auto captureNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(captureId)));
812 CHECK_NULL_VOID(captureNode);
813 auto imageLayoutProperty = captureNode->GetLayoutProperty<ImageLayoutProperty>();
814 CHECK_NULL_VOID(imageLayoutProperty);
815 imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(PixelMap::CreatePixelMap(&pixelMap)));
816 imageLayoutProperty->UpdateMargin(margin);
817 captureNode->MarkModifyDone();
818 captureNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
819 }
820
InitSurfaceChangedCallback()821 void SwiperPattern::InitSurfaceChangedCallback()
822 {
823 auto pipeline = GetContext();
824 CHECK_NULL_VOID(pipeline);
825 if (!HasSurfaceChangedCallback()) {
826 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
827 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
828 WindowSizeChangeReason type) {
829 if (type == WindowSizeChangeReason::UNDEFINED && newWidth == prevWidth && newHeight == prevHeight) {
830 return;
831 }
832 auto swiper = weak.Upgrade();
833 if (!swiper) {
834 return;
835 }
836
837 if (type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::UNDEFINED) {
838 swiper->windowSizeChangeReason_ = type;
839 swiper->StopAutoPlay();
840 }
841 auto currentIndex =
842 swiper->targetIndex_.has_value() ? swiper->targetIndex_.value() : swiper->currentIndex_;
843
844 swiper->needFireCustomAnimationEvent_ = swiper->translateAnimationIsRunning_;
845 if (swiper->SupportSwiperCustomAnimation() && swiper->needFireCustomAnimationEvent_) {
846 swiper->indexsInAnimation_.insert(swiper->GetLoopIndex(currentIndex));
847 }
848
849 swiper->StopPropertyTranslateAnimation(swiper->isFinishAnimation_);
850 swiper->StopTranslateAnimation();
851 swiper->StopSpringAnimationImmediately();
852 swiper->StopFadeAnimation();
853 swiper->StopIndicatorAnimation();
854 const auto& surfaceChangeCallback = swiper->swiperController_->GetSurfaceChangeCallback();
855 if (surfaceChangeCallback) {
856 surfaceChangeCallback();
857 }
858 swiper->currentOffset_ = 0.0f;
859 swiper->itemPosition_.clear();
860 swiper->placeItemWidth_.reset();
861 swiper->isVoluntarilyClear_ = true;
862 swiper->jumpIndex_ = currentIndex;
863 swiper->SetIndicatorJumpIndex(currentIndex);
864 swiper->MarkDirtyNodeSelf();
865 swiper->SetLazyForEachFlag();
866 });
867 UpdateSurfaceChangedCallbackId(callbackId);
868 }
869 }
870
IsFocusNodeInItemPosition(const RefPtr<FocusHub> & targetFocusHub)871 bool SwiperPattern::IsFocusNodeInItemPosition(const RefPtr<FocusHub>& targetFocusHub)
872 {
873 for (const auto& item : itemPosition_) {
874 auto itemNode = GetCurrentFrameNode(item.first);
875 if (!itemNode) {
876 continue;
877 }
878 if (itemNode->GetFirstFocusHubChild() == targetFocusHub) {
879 return true;
880 }
881 }
882 return false;
883 }
884
FlushFocus(const RefPtr<FrameNode> & curShowFrame)885 void SwiperPattern::FlushFocus(const RefPtr<FrameNode>& curShowFrame)
886 {
887 CHECK_NULL_VOID(curShowFrame);
888 auto swiperHost = GetHost();
889 CHECK_NULL_VOID(swiperHost);
890 auto swiperFocusHub = swiperHost->GetFocusHub();
891 CHECK_NULL_VOID(swiperFocusHub);
892 auto showChildFocusHub = curShowFrame->GetFirstFocusHubChild();
893 CHECK_NULL_VOID(showChildFocusHub);
894 int32_t skipCnt = 0;
895 if (IsShowIndicator()) {
896 ++skipCnt;
897 }
898 if (HasLeftButtonNode()) {
899 ++skipCnt;
900 }
901 if (HasRightButtonNode()) {
902 ++skipCnt;
903 }
904 std::list<RefPtr<FocusHub>> focusNodes;
905 swiperFocusHub->FlushChildrenFocusHub(focusNodes);
906 for (auto iter = focusNodes.rbegin(); iter != focusNodes.rend(); ++iter) {
907 const auto& node = *iter;
908 if (skipCnt > 0 || !node) {
909 --skipCnt;
910 continue;
911 }
912 if (IsUseCustomAnimation() && hasTabsAncestor_) {
913 node->SetParentFocusable(node == showChildFocusHub);
914 } else {
915 node->SetParentFocusable(IsFocusNodeInItemPosition(node));
916 }
917 }
918
919 RefPtr<FocusHub> needFocusNode = showChildFocusHub;
920 if (IsShowIndicator() && isLastIndicatorFocused_) {
921 needFocusNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
922 }
923 CHECK_NULL_VOID(needFocusNode);
924 lastWeakShowNode_ = AceType::WeakClaim(AceType::RawPtr(curShowFrame));
925 if (swiperFocusHub->IsCurrentFocus()) {
926 needFocusNode->RequestFocusImmediately();
927 } else {
928 if (swiperFocusHub->AcceptFocusOfPriorityChild()) {
929 return;
930 }
931 swiperFocusHub->SetLastWeakFocusNode(AceType::WeakClaim(AceType::RawPtr(needFocusNode)));
932 }
933 }
GetFocusHubChild(std::string childFrameName)934 RefPtr<FocusHub> SwiperPattern::GetFocusHubChild(std::string childFrameName)
935 {
936 auto swiperHost = GetHost();
937 CHECK_NULL_RETURN(swiperHost, nullptr);
938 auto swiperFocusHub = swiperHost->GetFocusHub();
939 CHECK_NULL_RETURN(swiperFocusHub, nullptr);
940 RefPtr<FocusHub> target;
941 swiperFocusHub->AnyChildFocusHub([&target, childFrameName](const RefPtr<FocusHub>& child) {
942 CHECK_NULL_RETURN(child, true);
943 if (child->GetFrameName() == childFrameName) {
944 target = child;
945 return true;
946 }
947 return false;
948 });
949 return target;
950 }
951
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)952 WeakPtr<FocusHub> SwiperPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
953 {
954 auto curFocusNode = currentFocusNode.Upgrade();
955 CHECK_NULL_RETURN(curFocusNode, nullptr);
956 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::UP) ||
957 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::SHIFT_TAB) ||
958 (GetDirection() == Axis::VERTICAL && step == FocusStep::LEFT)) {
959 return PreviousFocus(curFocusNode);
960 }
961 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
962 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::TAB) ||
963 (GetDirection() == Axis::VERTICAL && step == FocusStep::RIGHT)) {
964 return NextFocus(curFocusNode);
965 }
966 return nullptr;
967 }
968
PreviousFocus(const RefPtr<FocusHub> & curFocusNode)969 WeakPtr<FocusHub> SwiperPattern::PreviousFocus(const RefPtr<FocusHub>& curFocusNode)
970 {
971 CHECK_NULL_RETURN(curFocusNode, nullptr);
972 RefPtr<FocusHub> indicatorNode;
973 RefPtr<FocusHub> leftArrowNode;
974 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
975 CHECK_NULL_RETURN(props, nullptr);
976 if (HasLeftButtonNode()) {
977 leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
978 CHECK_NULL_RETURN(leftArrowNode, nullptr);
979 }
980 if (HasIndicatorNode()) {
981 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
982 CHECK_NULL_RETURN(indicatorNode, nullptr);
983 }
984 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
985 isLastIndicatorFocused_ = false;
986 (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ? curFocusNode->SetParentFocusable(false)
987 : curFocusNode->SetParentFocusable(true);
988 return nullptr;
989 }
990 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
991 if (!HasLeftButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ||
992 props->GetHoverShowValue(false)) {
993 isLastIndicatorFocused_ = true;
994 curFocusNode->SetParentFocusable(true);
995 return nullptr;
996 }
997 isLastIndicatorFocused_ = false;
998 leftArrowNode->SetParentFocusable(true);
999 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
1000 }
1001 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
1002 if (HasIndicatorNode()) {
1003 isLastIndicatorFocused_ = true;
1004 indicatorNode->SetParentFocusable(true);
1005 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
1006 }
1007 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
1008 curFocusNode->SetParentFocusable(true);
1009 return nullptr;
1010 }
1011 isLastIndicatorFocused_ = true;
1012 leftArrowNode->SetParentFocusable(true);
1013 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
1014 }
1015 curFocusNode->SetParentFocusable(true);
1016 return nullptr;
1017 }
1018
NextFocus(const RefPtr<FocusHub> & curFocusNode)1019 WeakPtr<FocusHub> SwiperPattern::NextFocus(const RefPtr<FocusHub>& curFocusNode)
1020 {
1021 CHECK_NULL_RETURN(curFocusNode, nullptr);
1022 RefPtr<FocusHub> indicatorNode;
1023 RefPtr<FocusHub> rightArrowNode;
1024 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
1025 CHECK_NULL_RETURN(props, nullptr);
1026 if (HasIndicatorNode()) {
1027 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
1028 CHECK_NULL_RETURN(indicatorNode, nullptr);
1029 }
1030 if (HasRightButtonNode()) {
1031 rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
1032 CHECK_NULL_RETURN(rightArrowNode, nullptr);
1033 }
1034 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
1035 if (HasIndicatorNode()) {
1036 isLastIndicatorFocused_ = true;
1037 indicatorNode->SetParentFocusable(true);
1038 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
1039 }
1040 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
1041 curFocusNode->SetParentFocusable(true);
1042 return nullptr;
1043 }
1044 isLastIndicatorFocused_ = true;
1045 rightArrowNode->SetParentFocusable(true);
1046 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
1047 }
1048 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
1049 if (!HasRightButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ||
1050 props->GetHoverShowValue(false)) {
1051 isLastIndicatorFocused_ = true;
1052 curFocusNode->SetParentFocusable(true);
1053 return nullptr;
1054 }
1055 isLastIndicatorFocused_ = false;
1056 rightArrowNode->SetParentFocusable(true);
1057 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
1058 }
1059 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
1060 isLastIndicatorFocused_ = false;
1061 (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ? curFocusNode->SetParentFocusable(false)
1062 : curFocusNode->SetParentFocusable(true);
1063 return nullptr;
1064 }
1065 curFocusNode->SetParentFocusable(true);
1066 return nullptr;
1067 }
1068
GetLoopIndex(int32_t originalIndex) const1069 int32_t SwiperPattern::GetLoopIndex(int32_t originalIndex) const
1070 {
1071 auto totalCount = TotalCount();
1072 if (totalCount <= 0) {
1073 return originalIndex;
1074 }
1075 auto loopIndex = originalIndex;
1076 while (loopIndex < 0) {
1077 loopIndex = loopIndex + totalCount;
1078 }
1079 loopIndex %= totalCount;
1080 return loopIndex;
1081 }
1082
AdjustCurrentFocusIndex()1083 void SwiperPattern::AdjustCurrentFocusIndex()
1084 {
1085 if (GetDisplayCount() <= 1) {
1086 currentFocusIndex_ = currentIndex_;
1087 return;
1088 }
1089
1090 if (currentFocusIndex_ >= currentIndex_ && currentFocusIndex_ < currentIndex_ + GetDisplayCount()) {
1091 return;
1092 }
1093
1094 currentFocusIndex_ = currentIndex_;
1095 }
1096
CheckAndFireCustomAnimation()1097 void SwiperPattern::CheckAndFireCustomAnimation()
1098 {
1099 if (!SupportSwiperCustomAnimation() || !needFireCustomAnimationEvent_) {
1100 return;
1101 }
1102
1103 itemPositionInAnimation_.clear();
1104 for (const auto& item : itemPosition_) {
1105 auto index = GetLoopIndex(item.first);
1106 itemPositionInAnimation_[index] = item.second;
1107 }
1108 FireSwiperCustomAnimationEvent();
1109 FireContentDidScrollEvent();
1110 itemPositionInAnimation_.clear();
1111 }
1112
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1113 bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1114 {
1115 if (!isDragging_ || isInit_) {
1116 SetLazyLoadFeature(true);
1117 }
1118 if (!isInit_) {
1119 OnIndexChange(true);
1120 oldIndex_ = currentIndex_;
1121 }
1122
1123 auto isInit = isInit_;
1124 isInit_ = false;
1125
1126 if (!IsAutoPlay() && config.skipMeasure && config.skipLayout) {
1127 return false;
1128 }
1129
1130 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
1131 CHECK_NULL_RETURN(props, false);
1132 auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm();
1133 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
1134 auto algo = DynamicCast<SwiperLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
1135 CHECK_NULL_RETURN(algo, false);
1136
1137 // set tabs invisible item freeze state.
1138 HandleTabsAncestor();
1139
1140 if (props->GetIsCustomAnimation().value_or(false)) {
1141 needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
1142 auto currentIndex = props->GetIndexValue(0);
1143 HandleTabsCachedMaxCount(currentIndex, customAnimationToIndex_.value_or(currentIndex));
1144 return false;
1145 }
1146 if (SupportSwiperCustomAnimation()) {
1147 needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
1148 itemPositionInAnimation_ = algo->GetItemsPositionInAnimation();
1149 FireContentDidScrollEvent();
1150 }
1151 itemPositionWillInvisible_.clear();
1152
1153 UpdateLayoutProperties(algo);
1154 PostIdleTask(GetHost());
1155 HandleTabsCachedMaxCount(startIndex_, endIndex_);
1156
1157 int32_t startIndex = startIndex_;
1158 int32_t endIndex = endIndex_;
1159 if (startIndex != prevStartIndex_ || endIndex != prevEndIndex_) {
1160 auto host = GetHost();
1161 CHECK_NULL_RETURN(host, false);
1162 host->OnAccessibilityEvent(AccessibilityEventType::SCROLLING_EVENT, startIndex, endIndex);
1163 }
1164 prevStartIndex_ = startIndex_;
1165 prevEndIndex_ = endIndex_;
1166
1167 if (!itemPosition_.empty()) {
1168 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
1169 auto firstItem = GetFirstItemInfoInVisibleArea();
1170 auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
1171 if (turnPageRateCallback && isDragging_ && !NearZero(translateLength)) {
1172 turnPageRateCallback(firstItem.first, -firstItem.second.startPos / translateLength);
1173 }
1174
1175 placeItemWidth_ = translateLength;
1176 }
1177 if (hasCachedCapture_) {
1178 isCaptureReverse_ = algo->GetIsCaptureReverse();
1179 UpdateTargetCapture(algo->GetIsNeedUpdateCapture());
1180 }
1181
1182 if (!targetIndex_) {
1183 if (isUserFinish_) {
1184 SetIndicatorJumpIndex(jumpIndex_);
1185 }
1186
1187 CheckMarkDirtyNodeForRenderIndicator();
1188 }
1189
1190 PlayScrollAnimation(currentDelta_, currentIndexOffset_);
1191 if (jumpIndex_) {
1192 ResetAnimationParam();
1193 auto pipeline = GetContext();
1194 if (pipeline) {
1195 pipeline->AddAfterRenderTask([weak = WeakClaim(this)]() {
1196 auto swiper = weak.Upgrade();
1197 CHECK_NULL_VOID(swiper);
1198 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_TAB_SWITCH, true);
1199 AceAsyncTraceEndCommercial(
1200 0, swiper->hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1201 });
1202 }
1203 UpdateCurrentIndex(algo->GetCurrentIndex());
1204 AdjustCurrentFocusIndex();
1205 auto curChild = dirty->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_));
1206 if (curChild && IsContentFocused()) {
1207 auto curChildFrame = curChild->GetHostNode();
1208 CHECK_NULL_RETURN(curChildFrame, false);
1209 FlushFocus(curChildFrame);
1210 }
1211 currentIndexOffset_ = 0.0f;
1212 springOffset_ = 0.0f;
1213 if (!isInit) {
1214 OnIndexChange(true);
1215 }
1216
1217 if (SupportSwiperCustomAnimation() && prevFrameAnimationRunning_) {
1218 for (const auto& item : itemPosition_) {
1219 auto index = GetLoopIndex(item.first);
1220 indexsInAnimation_.insert(index);
1221 }
1222 }
1223
1224 jumpIndex_.reset();
1225 pauseTargetIndex_.reset();
1226 auto delayTime = GetInterval() - GetDuration();
1227 delayTime = std::clamp(delayTime, 0, delayTime);
1228 if (NeedAutoPlay() && isUserFinish_) {
1229 PostTranslateTask(delayTime);
1230 }
1231
1232 CheckAndFireCustomAnimation();
1233 } else if (RunningTranslateAnimation() && !NearEqual(oldContentMainSize_, algo->GetContentMainSize())) {
1234 HandleRunningTranslateAnimation();
1235 } else if (targetIndex_) {
1236 HandleTargetIndex(dirty, algo);
1237 #ifdef SUPPORT_DIGITAL_CROWN
1238 if (IsCrownSpring()) {
1239 SetIsCrownSpring(false);
1240 }
1241 #endif
1242 velocity_.reset();
1243 pauseTargetIndex_ = targetIndex_;
1244 } else if (algo->GetJumpIndex().has_value()) {
1245 // jumpIndex_ is set inside layout algorithm to reset layout, need reset currentIndexOffset_
1246 currentIndexOffset_ = 0.0f;
1247 springOffset_ = 0.0f;
1248 }
1249 mainSizeIsMeasured_ = algo->GetMainSizeIsMeasured();
1250 contentCrossSize_ = algo->GetContentCrossSize();
1251 currentDelta_ = 0.0f;
1252 contentMainSize_ = algo->GetContentMainSize();
1253 oldContentMainSize_ = contentMainSize_;
1254 crossMatchChild_ = algo->IsCrossMatchChild();
1255 ignoreBlankOffset_ = algo->GetIgnoreBlankOffset();
1256 oldIndex_ = currentIndex_;
1257 oldChildrenSize_ = TotalCount();
1258 oldRealTotalCount_ = RealTotalCount();
1259 needFireCustomAnimationEvent_ = true;
1260 prevFrameAnimationRunning_ = false;
1261
1262 if (windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION) {
1263 StartAutoPlay();
1264 windowSizeChangeReason_ = WindowSizeChangeReason::UNDEFINED;
1265 }
1266
1267 if (onContentDidScroll_) {
1268 indexsInAnimation_.clear();
1269 }
1270
1271 const auto& paddingProperty = props->GetPaddingProperty();
1272 jumpOnChange_ = false;
1273 return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
1274 }
1275
HandleRunningTranslateAnimation()1276 void SwiperPattern::HandleRunningTranslateAnimation()
1277 {
1278 auto pipeline = GetContext();
1279 RefPtr<TaskExecutor> taskExecutor = pipeline ? pipeline->GetTaskExecutor() : nullptr;
1280 if (taskExecutor) {
1281 resetLayoutTask_.Cancel();
1282 resetLayoutTask_.Reset([weak = AceType::WeakClaim(this)] {
1283 auto swiper = weak.Upgrade();
1284 CHECK_NULL_VOID(swiper);
1285 if (swiper->RunningTranslateAnimation()) {
1286 swiper->isUserFinish_ = false;
1287 swiper->FinishAnimation();
1288 swiper->currentDelta_ = 0.0f;
1289 swiper->itemPosition_.clear();
1290 swiper->isVoluntarilyClear_ = true;
1291 swiper->jumpIndex_ = swiper->currentIndex_;
1292 swiper->MarkDirtyNodeSelf();
1293 }
1294 });
1295 taskExecutor->PostTask(resetLayoutTask_, TaskExecutor::TaskType::UI, "ArkUISwiperResetLayout");
1296 }
1297 }
1298
HandleTargetIndex(const RefPtr<LayoutWrapper> & dirty,const RefPtr<SwiperLayoutAlgorithm> & algo)1299 void SwiperPattern::HandleTargetIndex(const RefPtr<LayoutWrapper>& dirty, const RefPtr<SwiperLayoutAlgorithm>& algo)
1300 {
1301 auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
1302 auto iter = itemPosition_.find(targetIndexValue);
1303 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1304 CHECK_NULL_VOID(props);
1305
1306 if (iter == itemPosition_.end()) {
1307 HandleTargetItemNotFound(props, targetIndexValue, algo);
1308 return;
1309 }
1310
1311 float targetPos = iter->second.startPos;
1312 bool isNeedForwardTranslate = IsNeedForwardTranslate(props, targetIndexValue);
1313 bool isNeedBackwardTranslate = IsNeedBackwardTranslate(props, targetIndexValue);
1314 bool isNeedPlayTranslateAnimation = translateAnimationIsRunning_ || isNeedForwardTranslate ||
1315 isNeedBackwardTranslate || AutoLinearAnimationNeedReset(targetPos);
1316 auto context = GetContext();
1317 if (context && !isNeedPlayTranslateAnimation && !SupportSwiperCustomAnimation()) {
1318 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1319 bool isNeedOffset = (GetLoopIndex(iter->first) == TotalCount() - 1) && !props->GetDisplayCount().has_value() &&
1320 !IsLoop() &&
1321 LessNotEqual(iter->second.endPos - iter->second.startPos, CalculateVisibleSize());
1322 float offset = isNeedOffset ? CalculateVisibleSize() - iter->second.endPos + iter->second.startPos : 0.0;
1323 targetPos -= offset;
1324 std::optional<float> pixelRoundTargetPos;
1325 #ifdef SUPPORT_DIGITAL_CROWN
1326 // translate property will be pixel rounded in common scenarios.
1327 if (!isNeedOffset && !IsHorizontalAndRightToLeft() && SwiperUtils::CheckIsSingleCase(props) &&
1328 iter->second.node && iter->second.node->GetRenderContext()) {
1329 auto paintRect = iter->second.node->GetRenderContext()->GetPaintRectWithoutTransform();
1330 pixelRoundTargetPos = -(GetDirection() == Axis::HORIZONTAL ? paintRect.GetX() : paintRect.GetY());
1331 }
1332 #endif
1333 if (propertyAnimationIsRunning_ && targetIndex_ == runningTargetIndex_) {
1334 // If property animation is running and the target index is the same as the running target index, the
1335 // animation is not played
1336 return;
1337 }
1338 context->AddAfterLayoutTask([weak = WeakClaim(this), targetPos, pixelRoundTargetPos,
1339 velocity = velocity_.value_or(0.0f), nextIndex = iter->first]() {
1340 auto swiper = weak.Upgrade();
1341 CHECK_NULL_VOID(swiper);
1342 swiper->PlayPropertyTranslateAnimation(-targetPos, nextIndex, velocity, false, pixelRoundTargetPos);
1343 swiper->PlayIndicatorTranslateAnimation(-targetPos, nextIndex);
1344 });
1345 runningTargetIndex_ = targetIndex_;
1346 } else {
1347 PlayTranslateAnimation(
1348 currentOffset_, currentOffset_ - targetPos, iter->first, false, velocity_.value_or(0.0f));
1349 }
1350 }
1351
HandleTargetItemNotFound(const RefPtr<SwiperLayoutProperty> & props,int32_t targetIndexValue,const RefPtr<SwiperLayoutAlgorithm> & algo)1352 void SwiperPattern::HandleTargetItemNotFound(
1353 const RefPtr<SwiperLayoutProperty>& props, int32_t targetIndexValue, const RefPtr<SwiperLayoutAlgorithm>& algo)
1354 {
1355 if (!itemPosition_.empty() && SwiperUtils::IsStretch(props)) {
1356 auto firstItem = GetFirstItemInfoInVisibleArea();
1357 auto targetPos = firstItem.second.startPos +
1358 (targetIndexValue - firstItem.first) * (placeItemWidth_.value_or(0.0f) + GetItemSpace());
1359 PlayTranslateAnimation(
1360 currentOffset_, currentOffset_ - targetPos, targetIndexValue, false, velocity_.value_or(0.0f));
1361 } else {
1362 PlayTranslateAnimation(currentOffset_, currentOffset_ - algo->GetTargetStartPos(), targetIndexValue, false,
1363 velocity_.value_or(0.0f));
1364 }
1365 }
1366
IsNeedForwardTranslate(const RefPtr<SwiperLayoutProperty> & props,int32_t targetIndexValue)1367 bool SwiperPattern::IsNeedForwardTranslate(const RefPtr<SwiperLayoutProperty>& props, int32_t targetIndexValue)
1368 {
1369 if (!IsLoop()) {
1370 return false;
1371 }
1372
1373 auto lastItemIndex = Positive(props->GetCalculatedNextMargin()) ? targetIndexValue + GetDisplayCount()
1374 : targetIndexValue + GetDisplayCount() - 1;
1375 return itemPosition_.find(lastItemIndex) == itemPosition_.end();
1376 }
1377
IsNeedBackwardTranslate(const RefPtr<SwiperLayoutProperty> & props,int32_t targetIndexValue)1378 bool SwiperPattern::IsNeedBackwardTranslate(const RefPtr<SwiperLayoutProperty>& props, int32_t targetIndexValue)
1379 {
1380 if (!IsLoop() || targetIndexValue >= currentIndex_) {
1381 return false;
1382 }
1383
1384 auto firstItemIndex = Positive(props->GetCalculatedPrevMargin()) ? targetIndexValue + TotalCount() - 1
1385 : targetIndexValue + TotalCount();
1386 return itemPosition_.find(firstItemIndex) != itemPosition_.end();
1387 }
1388
HandleTabsAncestor()1389 void SwiperPattern::HandleTabsAncestor()
1390 {
1391 if (hasTabsAncestor_) {
1392 for (int32_t index = 0; index < RealTotalCount(); index++) {
1393 auto childFrameNode = GetCurrentFrameNode(index);
1394 if (childFrameNode) {
1395 auto isActive = childFrameNode->IsActive();
1396 childFrameNode->SetFreeze(!isActive);
1397 }
1398 }
1399 }
1400 }
1401
UpdateLayoutProperties(const RefPtr<SwiperLayoutAlgorithm> & algo)1402 void SwiperPattern::UpdateLayoutProperties(const RefPtr<SwiperLayoutAlgorithm>& algo)
1403 {
1404 autoLinearReachBoundary_ = false;
1405 startMainPos_ = algo->GetStartPosition();
1406 endMainPos_ = algo->GetEndPosition();
1407 startIndex_ = algo->GetStartIndex();
1408 endIndex_ = algo->GetEndIndex();
1409 cachedItems_ = algo->GetCachedItems();
1410 layoutConstraint_ = algo->GetLayoutConstraint();
1411 itemPosition_ = std::move(algo->GetItemPosition());
1412 currentOffset_ -= algo->GetCurrentOffset();
1413 }
1414
AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const1415 float SwiperPattern::AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const
1416 {
1417 if (!NeedEnableIgnoreBlankOffset()) {
1418 return 0.0f;
1419 }
1420 if (isStartOverScroll && NonNegative(ignoreBlankOffset_)) {
1421 return prevMarginIgnoreBlank_ ? GetPrevMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1422 }
1423 if (!isStartOverScroll && NonPositive(ignoreBlankOffset_)) {
1424 return nextMarginIgnoreBlank_ ? -GetNextMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1425 }
1426 return 0.0f;
1427 }
1428
UpdateIgnoreBlankOffsetWithIndex()1429 void SwiperPattern::UpdateIgnoreBlankOffsetWithIndex()
1430 {
1431 if (!NeedEnableIgnoreBlankOffset()) {
1432 auto lastIgnoreBlankOffset = ignoreBlankOffset_;
1433 ignoreBlankOffset_ = 0.0f;
1434 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1435 return;
1436 }
1437
1438 if (targetIndex_.has_value()) {
1439 float lastIgnoreBlankOffset = ignoreBlankOffset_;
1440 if (prevMarginIgnoreBlank_ && targetIndex_.value() == 0) {
1441 ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1442 } else if (nextMarginIgnoreBlank_ && targetIndex_.value() >= (TotalCount() - GetDisplayCount())) {
1443 ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1444 } else {
1445 ignoreBlankOffset_ = 0.0f;
1446 }
1447 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1448 }
1449 }
1450
UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)1451 void SwiperPattern::UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)
1452 {
1453 if (!NeedEnableIgnoreBlankOffset()) {
1454 return;
1455 }
1456 float lastIgnoreBlankOffset = ignoreBlankOffset_;
1457 if (prevMarginIgnoreBlank_ && overScrollDirection) {
1458 ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1459 } else if (nextMarginIgnoreBlank_ && !overScrollDirection) {
1460 ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1461 } else {
1462 ignoreBlankOffset_ = 0.0f;
1463 }
1464
1465 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1466 }
1467
UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)1468 void SwiperPattern::UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)
1469 {
1470 if (NearEqual(ignoreBlankOffset_, lastIgnoreBlankOffset)) {
1471 return;
1472 }
1473
1474 float adjustOffset = ignoreBlankOffset_ - lastIgnoreBlankOffset;
1475 for (auto& item : itemPosition_) {
1476 item.second.startPos -= adjustOffset;
1477 item.second.endPos -= adjustOffset;
1478 }
1479 }
1480
IsAutoLinear() const1481 bool SwiperPattern::IsAutoLinear() const
1482 {
1483 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1484 CHECK_NULL_RETURN(props, false);
1485 return !SwiperUtils::IsStretch(props);
1486 }
1487
AutoLinearAnimationNeedReset(float translate) const1488 bool SwiperPattern::AutoLinearAnimationNeedReset(float translate) const
1489 {
1490 if (!IsAutoLinear()) {
1491 return false;
1492 }
1493
1494 if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
1495 return false;
1496 }
1497
1498 if (NonPositive(translate)) {
1499 return false;
1500 }
1501
1502 auto iter = itemPosition_.rbegin();
1503 auto endPos = iter->second.endPos;
1504 if (endPos - CalculateVisibleSize() < translate) {
1505 return true;
1506 }
1507
1508 return false;
1509 }
1510
OnAnimationTranslateZero(int32_t nextIndex,bool stopAutoPlay)1511 void SwiperPattern::OnAnimationTranslateZero(int32_t nextIndex, bool stopAutoPlay)
1512 {
1513 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
1514
1515 if (!NeedAutoPlay() || !isUserFinish_) {
1516 return;
1517 }
1518
1519 if (stopAutoPlay) {
1520 MarkDirtyNodeSelf();
1521 } else {
1522 auto delayTime = GetInterval() - GetDuration();
1523 delayTime = std::clamp(delayTime, 0, delayTime);
1524 PostTranslateTask(delayTime);
1525 }
1526 }
1527
FireChangeEvent(int32_t preIndex,int32_t currentIndex,bool isInLayout) const1528 void SwiperPattern::FireChangeEvent(int32_t preIndex, int32_t currentIndex, bool isInLayout) const
1529 {
1530 if (jumpOnChange_) {
1531 return;
1532 }
1533 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1534 CHECK_NULL_VOID(swiperEventHub);
1535 swiperEventHub->FireChangeEvent(preIndex, currentIndex, isInLayout);
1536 swiperEventHub->FireIndicatorChangeEvent(currentIndex);
1537 swiperEventHub->FireIndicatorIndexChangeEvent(currentIndex);
1538 swiperEventHub->FireChangeDoneEvent(moveDirection_);
1539 if (swiperController_) {
1540 swiperController_->FireOnChangeEvent(currentIndex);
1541 }
1542
1543 if (jumpIndex_) {
1544 auto host = GetHost();
1545 CHECK_NULL_VOID(host);
1546 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1547 }
1548 }
1549
FireAnimationStartEvent(int32_t currentIndex,int32_t nextIndex,const AnimationCallbackInfo & info) const1550 void SwiperPattern::FireAnimationStartEvent(
1551 int32_t currentIndex, int32_t nextIndex, const AnimationCallbackInfo& info) const
1552 {
1553 TAG_LOGI(AceLogTag::ACE_SWIPER,
1554 "FireAnimationStartEvent, currentIndex: %{public}d, nextIndex: %{public}d, id:%{public}d", currentIndex,
1555 nextIndex, swiperId_);
1556 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1557 CHECK_NULL_VOID(swiperEventHub);
1558 swiperEventHub->FireAnimationStartEvent(currentIndex, nextIndex, info);
1559 auto host = GetHost();
1560 CHECK_NULL_VOID(host);
1561 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
1562 }
1563
FireAnimationEndEvent(int32_t currentIndex,const AnimationCallbackInfo & info,bool isInterrupt) const1564 void SwiperPattern::FireAnimationEndEvent(
1565 int32_t currentIndex, const AnimationCallbackInfo& info, bool isInterrupt) const
1566 {
1567 TAG_LOGI(AceLogTag::ACE_SWIPER,
1568 "FireAnimationEndEvent currentIndex: %{public}d, currentOffset: has_value %{public}d, value %{public}fvp, "
1569 "isForce: %{public}d, id:%{public}d",
1570 currentIndex, info.currentOffset.has_value(), info.currentOffset.value_or(0.0), info.isForceStop, swiperId_);
1571 if (currentIndex == -1) {
1572 return;
1573 }
1574 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1575 CHECK_NULL_VOID(swiperEventHub);
1576 isInterrupt ? swiperEventHub->FireAnimationEndOnForceEvent(currentIndex, info)
1577 : swiperEventHub->FireAnimationEndEvent(currentIndex, info);
1578 auto host = GetHost();
1579 CHECK_NULL_VOID(host);
1580 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1581 }
1582
FireGestureSwipeEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const1583 void SwiperPattern::FireGestureSwipeEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
1584 {
1585 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1586 CHECK_NULL_VOID(swiperEventHub);
1587 swiperEventHub->FireGestureSwipeEvent(currentIndex, info);
1588 }
1589
FireSelectedEvent(int32_t currentIndex,int32_t targetIndex)1590 void SwiperPattern::FireSelectedEvent(int32_t currentIndex, int32_t targetIndex)
1591 {
1592 if (currentIndex == targetIndex) {
1593 return;
1594 }
1595 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1596 CHECK_NULL_VOID(swiperEventHub);
1597 if (selectedIndex_ != GetLoopIndex(targetIndex)) {
1598 selectedIndex_ = GetLoopIndex(targetIndex);
1599 swiperEventHub->FireSelectedEvent(GetLoopIndex(targetIndex));
1600 }
1601 }
1602
FireUnselectedEvent(int32_t currentIndex,int32_t targetIndex)1603 void SwiperPattern::FireUnselectedEvent(int32_t currentIndex, int32_t targetIndex)
1604 {
1605 if (currentIndex == targetIndex || currentIndex != GetLoopIndex(currentIndex)) {
1606 return;
1607 }
1608 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1609 CHECK_NULL_VOID(swiperEventHub);
1610 if (unselectedIndex_ != GetLoopIndex(currentIndex)) {
1611 unselectedIndex_ = GetLoopIndex(currentIndex);
1612 swiperEventHub->FireUnselectedEvent(GetLoopIndex(currentIndex));
1613 }
1614 }
1615
HandleSwiperCustomAnimation(float offset)1616 void SwiperPattern::HandleSwiperCustomAnimation(float offset)
1617 {
1618 if (!SupportSwiperCustomAnimation()) {
1619 return;
1620 }
1621 if (itemPosition_.empty()) {
1622 needUnmountIndexs_.clear();
1623 itemPositionInAnimation_.clear();
1624 return;
1625 }
1626 if (NearZero(offset)) {
1627 return;
1628 }
1629
1630 if (itemPositionInAnimation_.empty()) {
1631 CalculateAndUpdateItemInfo();
1632 }
1633 indexsInAnimation_.clear();
1634 CalculateAndUpdateItemInfo(offset);
1635
1636 std::set<int32_t> unmountIndexs;
1637 for (auto& item : itemPositionInAnimation_) {
1638 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end() &&
1639 needUnmountIndexs_.find(item.first) == needUnmountIndexs_.end()) {
1640 indexsInAnimation_.insert(item.first);
1641 needUnmountIndexs_.insert(item.first);
1642 item.second.startPos += offset;
1643 item.second.endPos += offset;
1644 unmountIndexs.insert(item.first);
1645 }
1646 }
1647 for (const auto& index : unmountIndexs) {
1648 auto iter = itemPositionInAnimation_.find(index);
1649 if (iter == itemPositionInAnimation_.end()) {
1650 continue;
1651 }
1652
1653 OnSwiperCustomAnimationFinish(iter->second.task, index, iter->second.isFinishAnimation);
1654 }
1655
1656 FireSwiperCustomAnimationEvent();
1657 }
1658
CalculateAndUpdateItemInfo(float offset)1659 void SwiperPattern::CalculateAndUpdateItemInfo(float offset)
1660 {
1661 auto prevMargin = GetPrevMargin();
1662 auto nextMargin = GetNextMargin();
1663 auto visibleSize = CalculateVisibleSize();
1664 auto itemSpace = GetItemSpace();
1665 auto isLoop = IsLoop();
1666 auto displayCount = GetDisplayCount();
1667 auto swipeByGroup = IsSwipeByGroup();
1668
1669 for (auto& item : itemPosition_) {
1670 auto index = item.first;
1671 auto startPos = item.second.startPos + offset;
1672 auto endPos = item.second.endPos + offset;
1673 auto itemPosDiff = endPos - startPos + itemSpace;
1674 auto pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index, displayCount) : index;
1675 auto pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index, displayCount) : index;
1676 auto pageStartPos = swipeByGroup ? startPos - itemPosDiff * (index - pageStartIndex) : startPos;
1677 auto pageEndPos = swipeByGroup ? endPos + itemPosDiff * (pageEndIndex - index) : endPos;
1678
1679 if (LessOrEqual(pageEndPos, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace) ||
1680 GreatOrEqual(pageStartPos, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace)) {
1681 continue;
1682 }
1683
1684 if (GreatNotEqual(startPos - itemSpace, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace) &&
1685 itemPosition_.find(index - 1) == itemPosition_.end() && (isLoop || index > 0)) {
1686 if (!targetIndex_.has_value() || index < targetIndex_.value() || index - 1 >= targetIndex_.value()) {
1687 pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index - 1, displayCount) : index - 1;
1688 }
1689 }
1690 if (LessNotEqual(
1691 endPos + itemSpace, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace) &&
1692 itemPosition_.find(index + 1) == itemPosition_.end() && (isLoop || index < RealTotalCount() - 1)) {
1693 if (!targetIndex_.has_value() || index > targetIndex_.value() || index + 1 <= targetIndex_.value()) {
1694 pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index + 1, displayCount) : index + 1;
1695 }
1696 }
1697 auto currentIndex = index - 1;
1698 while (currentIndex >= pageStartIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1699 UpdateItemInfoInCustomAnimation(currentIndex, startPos - itemPosDiff * (index - currentIndex),
1700 endPos - itemPosDiff * (index - currentIndex));
1701 currentIndex--;
1702 }
1703 currentIndex = index + 1;
1704 while (currentIndex <= pageEndIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1705 UpdateItemInfoInCustomAnimation(currentIndex, startPos + itemPosDiff * (currentIndex - index),
1706 endPos + itemPosDiff * (currentIndex - index));
1707 currentIndex++;
1708 }
1709 UpdateItemInfoInCustomAnimation(index, startPos, endPos);
1710 }
1711 }
1712
UpdateItemInfoInCustomAnimation(int32_t index,float startPos,float endPos)1713 void SwiperPattern::UpdateItemInfoInCustomAnimation(int32_t index, float startPos, float endPos)
1714 {
1715 index = GetLoopIndex(index);
1716 if (IsSwipeByGroup() && index >= RealTotalCount()) {
1717 return;
1718 }
1719 indexsInAnimation_.insert(index);
1720 needUnmountIndexs_.erase(index);
1721 auto itemInAnimation = itemPositionInAnimation_.find(index);
1722 if (itemInAnimation == itemPositionInAnimation_.end()) {
1723 itemPositionInAnimation_[index] = { startPos, endPos, nullptr };
1724 } else {
1725 itemInAnimation->second.startPos = startPos;
1726 itemInAnimation->second.endPos = endPos;
1727 if (itemInAnimation->second.task) {
1728 itemInAnimation->second.task.Cancel();
1729 }
1730 }
1731 }
1732
FireSwiperCustomAnimationEvent()1733 void SwiperPattern::FireSwiperCustomAnimationEvent()
1734 {
1735 CHECK_NULL_VOID(onSwiperCustomContentTransition_);
1736 auto transition = onSwiperCustomContentTransition_->transition;
1737 CHECK_NULL_VOID(transition);
1738
1739 auto selectedIndex = GetCurrentIndex();
1740 for (auto& item : itemPositionInAnimation_) {
1741 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1742 continue;
1743 }
1744 auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1745 if (IsHorizontalAndRightToLeft()) {
1746 offset = Dimension(-item.second.startPos, DimensionUnit::PX).ConvertToVp();
1747 }
1748 auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1749 if (NonPositive(mainAxisLength)) {
1750 continue;
1751 }
1752 auto position = offset / mainAxisLength;
1753 auto proxy = AceType::MakeRefPtr<SwiperContentTransitionProxy>();
1754 proxy->SetSelectedIndex(selectedIndex);
1755 proxy->SetIndex(item.first);
1756 proxy->SetPosition(position);
1757 proxy->SetMainAxisLength(mainAxisLength);
1758 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), index = item.first]() {
1759 auto swiper = weak.Upgrade();
1760 CHECK_NULL_VOID(swiper);
1761 auto item = swiper->itemPositionInAnimation_.find(index);
1762 if (item == swiper->itemPositionInAnimation_.end()) {
1763 return;
1764 }
1765 item->second.isFinishAnimation = true;
1766 swiper->OnSwiperCustomAnimationFinish(item->second.task, index, true);
1767 });
1768 transition(proxy);
1769 }
1770 }
1771
FireContentDidScrollEvent()1772 void SwiperPattern::FireContentDidScrollEvent()
1773 {
1774 if (indexsInAnimation_.empty() || itemPositionInAnimation_.empty()) {
1775 return;
1776 }
1777
1778 CHECK_NULL_VOID(onContentDidScroll_);
1779 auto event = *onContentDidScroll_;
1780 CHECK_NULL_VOID(event);
1781 auto selectedIndex = GetCurrentIndex();
1782
1783 SwiperLayoutAlgorithm::PositionMap mergeMap;
1784 mergeMap.insert(itemPositionInAnimation_.begin(), itemPositionInAnimation_.end());
1785 mergeMap.insert(itemPositionWillInvisible_.begin(), itemPositionWillInvisible_.end());
1786 for (auto& item : mergeMap) {
1787 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1788 continue;
1789 }
1790 auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1791 auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1792 if (NonPositive(mainAxisLength)) {
1793 continue;
1794 }
1795 auto position = offset / mainAxisLength;
1796 event(selectedIndex, item.first, position, mainAxisLength);
1797 }
1798 }
1799
OnSwiperCustomAnimationFinish(CancelableCallback<void ()> & task,int32_t index,bool isFinishAnimation)1800 void SwiperPattern::OnSwiperCustomAnimationFinish(
1801 CancelableCallback<void()>& task, int32_t index, bool isFinishAnimation)
1802 {
1803 if (needUnmountIndexs_.find(index) == needUnmountIndexs_.end()) {
1804 return;
1805 }
1806 auto pipeline = GetContext();
1807 CHECK_NULL_VOID(pipeline);
1808 auto taskExecutor = pipeline->GetTaskExecutor();
1809 CHECK_NULL_VOID(taskExecutor);
1810 if (task) {
1811 task.Cancel();
1812 }
1813
1814 int32_t timeout = 0;
1815 if (onSwiperCustomContentTransition_ && !isFinishAnimation) {
1816 timeout = onSwiperCustomContentTransition_->timeout;
1817 }
1818
1819 if (timeout == 0) {
1820 auto item = itemPositionInAnimation_.find(index);
1821 if (item != itemPositionInAnimation_.end()) {
1822 itemPositionWillInvisible_[index] = item->second;
1823 }
1824 needUnmountIndexs_.erase(index);
1825 itemPositionInAnimation_.erase(index);
1826 MarkDirtyNodeSelf();
1827 return;
1828 }
1829
1830 task.Reset([weak = AceType::WeakClaim(this), index] {
1831 auto swiper = weak.Upgrade();
1832 CHECK_NULL_VOID(swiper);
1833 swiper->needUnmountIndexs_.erase(index);
1834 swiper->itemPositionInAnimation_.erase(index);
1835 swiper->MarkDirtyNodeSelf();
1836 });
1837 taskExecutor->PostDelayedTask(task, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperDelayedCustomAnimation");
1838 }
1839
SwipeToWithoutAnimation(int32_t index)1840 void SwiperPattern::SwipeToWithoutAnimation(int32_t index)
1841 {
1842 if (currentIndex_ != index) {
1843 FireWillShowEvent(index);
1844 FireWillHideEvent(currentIndex_);
1845 }
1846 if (IsVisibleChildrenSizeLessThanSwiper()) {
1847 return;
1848 }
1849
1850 if (propertyAnimationIsRunning_) {
1851 StopPropertyTranslateAnimation(isFinishAnimation_);
1852 }
1853
1854 StopTranslateAnimation();
1855 StopFadeAnimation();
1856 StopSpringAnimationImmediately();
1857 StopIndicatorAnimation(true);
1858 jumpIndex_ = index;
1859 AceAsyncTraceBeginCommercial(0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1860 uiCastJumpIndex_ = index;
1861 MarkDirtyNodeSelf();
1862 FireAndCleanScrollingListener();
1863 }
1864
StopSpringAnimationAndFlushImmediately()1865 void SwiperPattern::StopSpringAnimationAndFlushImmediately()
1866 {
1867 if (springAnimationIsRunning_) {
1868 StopSpringAnimationImmediately();
1869 currentDelta_ = 0.0f;
1870 itemPosition_.clear();
1871 isVoluntarilyClear_ = true;
1872 jumpIndex_ = currentIndex_;
1873 MarkDirtyNodeSelf();
1874 auto pipeline = GetContext();
1875 CHECK_NULL_VOID(pipeline);
1876 pipeline->FlushUITasks();
1877 }
1878 }
1879
IsUseCustomAnimation() const1880 bool SwiperPattern::IsUseCustomAnimation() const
1881 {
1882 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1883 CHECK_NULL_RETURN(props, false);
1884 return props->GetIsCustomAnimation().value_or(false);
1885 }
1886
NeedFastAnimation() const1887 bool SwiperPattern::NeedFastAnimation() const
1888 {
1889 return tabAnimationMode_ == TabAnimateMode::CONTENT_FIRST_WITH_JUMP ||
1890 tabAnimationMode_ == TabAnimateMode::ACTION_FIRST_WITH_JUMP;
1891 }
1892
SwipeTo(int32_t index)1893 void SwiperPattern::SwipeTo(int32_t index)
1894 {
1895 auto targetIndex = IsLoop() ? index : (index < 0 || index > (TotalCount() - 1)) ? 0 : index;
1896 targetIndex = IsLoop() ? targetIndex : std::clamp(targetIndex, 0, TotalCount() - GetDisplayCount());
1897 if (!ContentWillChange(targetIndex)) {
1898 return;
1899 }
1900
1901 if (IsUseCustomAnimation()) {
1902 OnCustomContentTransition(targetIndex);
1903 MarkDirtyNodeSelf();
1904 return;
1905 }
1906
1907 if (IsVisibleChildrenSizeLessThanSwiper()) {
1908 return;
1909 }
1910
1911 // If targetIndex_ has a value, means animation is still running, stop it before play new animation.
1912 if (currentIndex_ == targetIndex && !targetIndex_.has_value()) {
1913 return;
1914 }
1915 StopFadeAnimation();
1916 if (springAnimationIsRunning_) {
1917 StopSpringAnimationImmediately();
1918 jumpIndex_ = currentIndex_;
1919 MarkDirtyNodeSelf();
1920 auto pipeline = GetContext();
1921 CHECK_NULL_VOID(pipeline);
1922 pipeline->FlushUITasks();
1923 }
1924 StopAutoPlay();
1925 StopTranslateAnimation();
1926
1927 StopIndicatorAnimation();
1928 if (propertyAnimationIsRunning_) {
1929 StopPropertyTranslateAnimation(isFinishAnimation_);
1930 }
1931
1932 if (hasTabsAncestor_ && NeedFastAnimation()) {
1933 FastAnimation(targetIndex);
1934 }
1935
1936 targetIndex_ = targetIndex;
1937
1938 UpdateTabBarAnimationDuration(index);
1939 if (GetDuration() == 0 || !isVisible_) {
1940 SwipeToWithoutAnimation(index);
1941 return;
1942 }
1943
1944 if (currentIndex_ != targetIndex_.value_or(0)) {
1945 FireWillShowEvent(targetIndex_.value_or(0));
1946 FireWillHideEvent(currentIndex_);
1947 }
1948 MarkDirtyNodeSelf();
1949 }
1950
UpdateTabBarAnimationDuration(int32_t index)1951 void SwiperPattern::UpdateTabBarAnimationDuration(int32_t index)
1952 {
1953 auto host = GetHost();
1954 CHECK_NULL_VOID(host);
1955 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1956 CHECK_NULL_VOID(tabsNode);
1957 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
1958 CHECK_NULL_VOID(tabBarNode);
1959 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
1960 CHECK_NULL_VOID(tabBarPattern);
1961 tabBarPattern->UpdateAnimationDuration();
1962 }
1963
CheckTargetIndex(int32_t targetIndex,bool isForceBackward)1964 int32_t SwiperPattern::CheckTargetIndex(int32_t targetIndex, bool isForceBackward)
1965 {
1966 if (!IsAutoLinear()) {
1967 return targetIndex;
1968 }
1969 while (GetLoopIndex(targetIndex) != GetLoopIndex(currentIndex_)) {
1970 auto currentFrameNode = GetCurrentFrameNode(GetLoopIndex(targetIndex));
1971 CHECK_NULL_RETURN(currentFrameNode, targetIndex);
1972 auto props = currentFrameNode->GetLayoutProperty<LayoutProperty>();
1973 CHECK_NULL_RETURN(props, targetIndex);
1974 if (props->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
1975 return targetIndex;
1976 }
1977 if (isForceBackward || currentIndex_ < targetIndex) {
1978 ++targetIndex;
1979 } else {
1980 --targetIndex;
1981 }
1982 if (!IsLoop() && (targetIndex < 0 || targetIndex >= TotalCount())) {
1983 return currentIndex_;
1984 }
1985 }
1986 return targetIndex;
1987 }
1988
ShowNext(bool needCheckWillScroll)1989 void SwiperPattern::ShowNext(bool needCheckWillScroll)
1990 {
1991 if (IsVisibleChildrenSizeLessThanSwiper()) {
1992 return;
1993 }
1994 indicatorDoingAnimation_ = false;
1995 auto childrenSize = TotalCount();
1996 auto displayCount = GetDisplayCount();
1997 if (childrenSize <= 0 || displayCount == 0) {
1998 return;
1999 }
2000
2001 auto stepItems = IsSwipeByGroup() ? displayCount : 1;
2002 auto fromIndex = targetIndex_.value_or(currentIndex_);
2003 auto nextIndex = fromIndex + stepItems;
2004 if (fromIndex >= childrenSize - displayCount && !IsLoop()) {
2005 return;
2006 }
2007
2008 StopAutoPlay();
2009 StopSpringAnimationAndFlushImmediately();
2010 StopFadeAnimation();
2011 StopIndicatorAnimation();
2012 if (propertyAnimationIsRunning_ || translateAnimationIsRunning_) {
2013 isUserFinish_ = false;
2014 FinishAnimation();
2015 if (!ContentWillChange(currentIndex_ + 1)) {
2016 return;
2017 }
2018 }
2019
2020 if (needCheckWillScroll && HasOnContentWillScroll()) {
2021 auto offset = CalcWillScrollOffset(nextIndex);
2022 if (!ContentWillScroll(currentIndex_, nextIndex, -offset)) {
2023 return;
2024 }
2025 }
2026
2027 moveDirection_ = true;
2028
2029 if (isVisibleArea_) {
2030 targetIndex_ = CheckTargetIndex(nextIndex);
2031 MarkDirtyNodeSelf();
2032 auto pipeline = GetContext();
2033 CHECK_NULL_VOID(pipeline);
2034 pipeline->FlushUITasks();
2035 } else {
2036 SwipeToWithoutAnimation(nextIndex);
2037 }
2038 auto swiperEventHub = GetEventHub<SwiperEventHub>();
2039 CHECK_NULL_VOID(swiperEventHub);
2040 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
2041 }
2042
ShowPrevious(bool needCheckWillScroll)2043 void SwiperPattern::ShowPrevious(bool needCheckWillScroll)
2044 {
2045 if (IsVisibleChildrenSizeLessThanSwiper()) {
2046 return;
2047 }
2048
2049 if (IsAutoLinear() && static_cast<int32_t>(itemPosition_.size()) == TotalCount() && !autoLinearReachBoundary_) {
2050 return;
2051 }
2052
2053 indicatorDoingAnimation_ = false;
2054 auto childrenSize = TotalCount();
2055 auto displayCount = GetDisplayCount();
2056 if (childrenSize <= 0 || displayCount == 0) {
2057 return;
2058 }
2059
2060 auto stepItems = IsSwipeByGroup() ? displayCount : 1;
2061 auto fromIndex = targetIndex_.value_or(currentIndex_);
2062 auto prevIndex = fromIndex - stepItems;
2063 if (fromIndex <= 0 && !IsLoop()) {
2064 return;
2065 }
2066
2067 StopAutoPlay();
2068 StopSpringAnimationAndFlushImmediately();
2069 StopFadeAnimation();
2070 StopIndicatorAnimation();
2071
2072 if (propertyAnimationIsRunning_ || translateAnimationIsRunning_) {
2073 isUserFinish_ = false;
2074 FinishAnimation();
2075 if (!ContentWillChange(currentIndex_ - 1)) {
2076 return;
2077 }
2078 }
2079
2080 if (needCheckWillScroll && HasOnContentWillScroll()) {
2081 auto offset = CalcWillScrollOffset(prevIndex);
2082 if (!ContentWillScroll(currentIndex_, prevIndex, offset)) {
2083 return;
2084 }
2085 }
2086
2087 moveDirection_ = false;
2088
2089 if (isVisibleArea_) {
2090 targetIndex_ = CheckTargetIndex(prevIndex);
2091 MarkDirtyNodeSelf();
2092 auto pipeline = GetContext();
2093 CHECK_NULL_VOID(pipeline);
2094 pipeline->FlushUITasks();
2095 } else {
2096 SwipeToWithoutAnimation(prevIndex);
2097 }
2098 auto swiperEventHub = GetEventHub<SwiperEventHub>();
2099 CHECK_NULL_VOID(swiperEventHub);
2100 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
2101 }
2102
FastAnimation(int32_t targetIndex)2103 void SwiperPattern::FastAnimation(int32_t targetIndex)
2104 {
2105 fastCurrentIndex_.reset();
2106 if (abs(currentIndex_ - targetIndex) > JUMP_NEAR_VALUE) {
2107 jumpOnChange_ = true;
2108 auto tempIndex = targetIndex - ((currentIndex_ < targetIndex) ? JUMP_NEAR_VALUE : -JUMP_NEAR_VALUE);
2109 fastCurrentIndex_ = currentIndex_;
2110 jumpIndex_ = tempIndex;
2111 auto host = GetHost();
2112 CHECK_NULL_VOID(host);
2113 MarkDirtyNodeSelf();
2114 auto pipeline = GetContext();
2115 CHECK_NULL_VOID(pipeline);
2116 pipeline->FlushUITaskWithSingleDirtyNode(host);
2117 pipeline->FlushSyncGeometryNodeTasks();
2118 }
2119 }
2120
GetCurrentIndex(bool original)2121 int32_t SwiperPattern::GetCurrentIndex(bool original)
2122 {
2123 if (!original || !targetIndex_.has_value() || !fastCurrentIndex_.has_value()) {
2124 return GetLoopIndex(currentIndex_);
2125 }
2126 if (targetIndex_.value_or(0) != GetLoopIndex(currentIndex_)) {
2127 auto currentIndex = GetLoopIndex(fastCurrentIndex_.value_or(0));
2128 fastCurrentIndex_.reset();
2129 return currentIndex;
2130 }
2131 return GetLoopIndex(currentIndex_);
2132 }
2133
IsInFastAnimation() const2134 bool SwiperPattern::IsInFastAnimation() const
2135 {
2136 if (!NeedFastAnimation()) {
2137 return false;
2138 }
2139 if (targetIndex_) {
2140 return true;
2141 }
2142 return propertyAnimationIsRunning_;
2143 }
2144
ChangeIndex(int32_t index,SwiperAnimationMode mode)2145 void SwiperPattern::ChangeIndex(int32_t index, SwiperAnimationMode mode)
2146 {
2147 int32_t targetIndex = 0;
2148 if (!ComputeTargetIndex(index, targetIndex)) {
2149 return;
2150 }
2151
2152 fastCurrentIndex_.reset();
2153 targetIndex = CheckTargetIndex(targetIndex);
2154 if (mode == SwiperAnimationMode::NO_ANIMATION) {
2155 needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
2156
2157 if (GetMaxDisplayCount() > 0) {
2158 SetIndicatorChangeIndexStatus(false);
2159 }
2160
2161 SwipeToWithoutAnimation(GetLoopIndex(targetIndex));
2162 } else if (mode == SwiperAnimationMode::DEFAULT_ANIMATION) {
2163 if (GetMaxDisplayCount() > 0) {
2164 SetIndicatorChangeIndexStatus(true);
2165 }
2166 SwipeTo(targetIndex);
2167 } else if (mode == SwiperAnimationMode::FAST_ANIMATION) {
2168 // skip to the tab near 3 to target
2169 FastAnimation(targetIndex);
2170 if (GetMaxDisplayCount() > 0) {
2171 SetIndicatorChangeIndexStatus(true);
2172 }
2173 SwipeTo(targetIndex);
2174 }
2175 }
2176
ComputeTargetIndex(int32_t index,int32_t & targetIndex) const2177 bool SwiperPattern::ComputeTargetIndex(int32_t index, int32_t& targetIndex) const
2178 {
2179 index = CheckIndexRange(index);
2180 auto itemCount = TotalCount();
2181 auto displayCount = GetDisplayCount();
2182 auto loopCount = itemCount == 0 ? 0 : std::abs(currentIndex_ / itemCount);
2183 targetIndex = currentIndex_ >= 0 ? loopCount * itemCount + index : -(loopCount + 1) * itemCount + index;
2184 targetIndex = IsSwipeByGroup() ? SwiperUtils::ComputePageIndex(targetIndex, displayCount) : targetIndex;
2185 if (targetIndex_.has_value() && targetIndex_.value() == targetIndex) {
2186 return false;
2187 }
2188 return true;
2189 }
2190
ChangeIndex(int32_t index,bool useAnimation)2191 void SwiperPattern::ChangeIndex(int32_t index, bool useAnimation)
2192 {
2193 int32_t targetIndex = 0;
2194 if (!ComputeTargetIndex(index, targetIndex)) {
2195 return;
2196 }
2197
2198 fastCurrentIndex_.reset();
2199 targetIndex = CheckTargetIndex(targetIndex);
2200 if (useAnimation) {
2201 if (GetMaxDisplayCount() > 0) {
2202 SetIndicatorChangeIndexStatus(true);
2203 }
2204
2205 SwipeTo(targetIndex);
2206 } else {
2207 needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
2208
2209 if (GetMaxDisplayCount() > 0) {
2210 SetIndicatorChangeIndexStatus(false);
2211 }
2212
2213 SwipeToWithoutAnimation(GetLoopIndex(targetIndex));
2214 }
2215 }
2216
FinishAnimation()2217 void SwiperPattern::FinishAnimation()
2218 {
2219 if (translateAnimationIsRunning_) {
2220 isFinishAnimation_ = true;
2221 StopTranslateAnimation();
2222 }
2223 StopSpringAnimation();
2224 StopFadeAnimation();
2225 StopIndicatorAnimation(true);
2226 if (propertyAnimationIsRunning_) {
2227 isFinishAnimation_ = true;
2228 StopPropertyTranslateAnimation(isFinishAnimation_);
2229 }
2230 if (isUserFinish_) {
2231 if (swiperController_ && swiperController_->GetFinishCallback()) {
2232 auto finishCallback = swiperController_->GetFinishCallback();
2233 finishCallback();
2234 swiperController_->SetFinishCallback(nullptr);
2235 }
2236 } else {
2237 isUserFinish_ = true;
2238 }
2239 }
2240
PreloadItems(const std::set<int32_t> & indexSet)2241 void SwiperPattern::PreloadItems(const std::set<int32_t>& indexSet)
2242 {
2243 std::set<int32_t> validIndexSet;
2244 auto childrenSize = RealTotalCount();
2245 for (const auto& index : indexSet) {
2246 if (index < 0 || index >= childrenSize) {
2247 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
2248 "BusinessError 401: Parameter error. Each value in indices must be valid index value of child.");
2249 return;
2250 }
2251 validIndexSet.emplace(index);
2252 }
2253
2254 if (validIndexSet.empty()) {
2255 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
2256 "BusinessError 401: Parameter error. The parameter indices must be a non-empty array.");
2257 return;
2258 }
2259
2260 auto preloadTask = [weak = WeakClaim(this), id = GetHostInstanceId(), indexSet]() {
2261 ContainerScope scope(id);
2262 auto swiperPattern = weak.Upgrade();
2263 CHECK_NULL_VOID(swiperPattern);
2264 auto host = swiperPattern->GetHost();
2265 CHECK_NULL_VOID(host);
2266 auto parent = host->GetParent();
2267 if (AceType::InstanceOf<TabsNode>(parent)) {
2268 swiperPattern->DoTabsPreloadItems(indexSet);
2269 } else {
2270 swiperPattern->DoSwiperPreloadItems(indexSet);
2271 }
2272
2273 swiperPattern->FirePreloadFinishEvent(ERROR_CODE_NO_ERROR);
2274 };
2275
2276 auto pipeline = GetContext();
2277 CHECK_NULL_VOID(pipeline);
2278 auto taskExecutor = pipeline->GetTaskExecutor();
2279 CHECK_NULL_VOID(taskExecutor);
2280 taskExecutor->PostTask(preloadTask, TaskExecutor::TaskType::UI, "ArkUIFirePreloadFinish");
2281 }
2282
FirePreloadFinishEvent(int32_t errorCode,std::string message)2283 void SwiperPattern::FirePreloadFinishEvent(int32_t errorCode, std::string message)
2284 {
2285 if (swiperController_ && swiperController_->GetPreloadFinishCallback()) {
2286 auto preloadFinishCallback = swiperController_->GetPreloadFinishCallback();
2287 swiperController_->SetPreloadFinishCallback(nullptr);
2288 preloadFinishCallback(errorCode, message);
2289 }
2290 }
2291
DoTabsPreloadItems(const std::set<int32_t> & indexSet)2292 void SwiperPattern::DoTabsPreloadItems(const std::set<int32_t>& indexSet)
2293 {
2294 auto host = GetHost();
2295 CHECK_NULL_VOID(host);
2296 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
2297 CHECK_NULL_VOID(props);
2298 auto geometryNode = host->GetGeometryNode();
2299 CHECK_NULL_VOID(geometryNode);
2300 auto contentConstraint = props->GetContentLayoutConstraint();
2301 auto frameSize = OptionalSizeF(geometryNode->GetPaddingSize());
2302 auto childConstraint = SwiperUtils::CreateChildConstraint(props, frameSize, false);
2303 for (auto index : indexSet) {
2304 auto tabContent = GetCurrentFrameNode(index);
2305 if (!tabContent) {
2306 continue;
2307 }
2308 if (!tabContent->GetChildren().empty()) {
2309 continue;
2310 }
2311 auto tabContentPattern = tabContent->GetPattern<TabContentPattern>();
2312 if (!tabContentPattern) {
2313 continue;
2314 }
2315 tabContentPattern->BeforeCreateLayoutWrapper();
2316
2317 for (const auto& child : tabContent->GetChildren()) {
2318 child->Build(nullptr);
2319 }
2320 if (contentConstraint.has_value() && tabContent->GetGeometryNode()) {
2321 tabContent->GetGeometryNode()->SetParentLayoutConstraint(childConstraint);
2322 FrameNode::ProcessOffscreenNode(tabContent);
2323 }
2324 }
2325 }
2326
BuildForEachChild(const std::set<int32_t> & indexSet,const RefPtr<UINode> & child)2327 void SwiperPattern::BuildForEachChild(const std::set<int32_t>& indexSet, const RefPtr<UINode>& child)
2328 {
2329 auto childNode = FindForEachNode(child);
2330 if (!childNode) {
2331 return;
2332 }
2333
2334 auto forEachNode = AceType::DynamicCast<ForEachNode>(childNode.value());
2335 auto repeatNode = AceType::DynamicCast<RepeatVirtualScrollNode>(childNode.value());
2336 for (auto index : indexSet) {
2337 if (forEachNode && forEachNode->GetChildAtIndex(index)) {
2338 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper preload item index: %{public}d, id:%{public}d", index, swiperId_);
2339 forEachNode->GetChildAtIndex(index)->Build(nullptr);
2340 continue;
2341 }
2342
2343 if (repeatNode) {
2344 repeatNode->GetFrameChildByIndex(index, true);
2345 }
2346 }
2347 }
2348
DoSwiperPreloadItems(const std::set<int32_t> & indexSet)2349 void SwiperPattern::DoSwiperPreloadItems(const std::set<int32_t>& indexSet)
2350 {
2351 auto host = GetHost();
2352 CHECK_NULL_VOID(host);
2353 auto targetNode = FindLazyForEachNode(host);
2354 if (targetNode.has_value()) {
2355 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
2356 for (auto index : indexSet) {
2357 if (lazyForEachNode) {
2358 lazyForEachNode->GetFrameChildByIndex(index, true);
2359 }
2360 }
2361 }
2362 const auto& children = host->GetChildren();
2363 for (const auto& child : children) {
2364 BuildForEachChild(indexSet, child);
2365 }
2366 }
2367
OnTranslateAnimationFinish()2368 void SwiperPattern::OnTranslateAnimationFinish()
2369 {
2370 if (!translateAnimationIsRunning_) {
2371 return;
2372 }
2373 translateAnimationIsRunning_ = false;
2374 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
2375 }
2376
StopTranslateAnimation()2377 void SwiperPattern::StopTranslateAnimation()
2378 {
2379 if (translateAnimationIsRunning_) {
2380 auto host = GetHost();
2381 CHECK_NULL_VOID(host);
2382 translateAnimationIsRunning_ = false;
2383 prevFrameAnimationRunning_ = true;
2384
2385 if (NearZero(translateAnimationEndPos_ - currentOffset_)) {
2386 AnimationUtils::StopAnimation(translateAnimation_);
2387 fastCurrentIndex_.reset();
2388 targetIndex_.reset();
2389 } else {
2390 AnimationOption option;
2391 option.SetCurve(Curves::LINEAR);
2392 option.SetDuration(0);
2393 translateAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
2394 auto swiper = weak.Upgrade();
2395 CHECK_NULL_VOID(swiper);
2396 auto host = swiper->GetHost();
2397 CHECK_NULL_VOID(host);
2398 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, swiper->currentOffset_);
2399 });
2400 }
2401
2402 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_, true);
2403 }
2404 }
2405
StopSpringAnimationImmediately()2406 void SwiperPattern::StopSpringAnimationImmediately()
2407 {
2408 if (!springAnimationIsRunning_) {
2409 return;
2410 }
2411 AnimationOption option;
2412 option.SetCurve(Curves::LINEAR);
2413 option.SetDuration(0);
2414 springAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
2415 auto swiper = weak.Upgrade();
2416 CHECK_NULL_VOID(swiper);
2417 auto host = swiper->GetHost();
2418 CHECK_NULL_VOID(host);
2419 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, swiper->currentIndexOffset_);
2420 });
2421 OnSpringAnimationFinish();
2422 }
2423
StopSpringAnimation()2424 void SwiperPattern::StopSpringAnimation()
2425 {
2426 if (springAnimationIsRunning_) {
2427 AnimationUtils::StopAnimation(springAnimation_);
2428 }
2429 }
2430
StopFadeAnimation()2431 void SwiperPattern::StopFadeAnimation()
2432 {
2433 AnimationUtils::StopAnimation(fadeAnimation_);
2434 if (fadeAnimationIsRunning_) {
2435 fadeAnimationIsRunning_ = false;
2436 }
2437 }
2438
SaveIndicatorProperty(const RefPtr<FrameNode> & indicatorNode,SwiperIndicatorType swiperIndicatorType)2439 void SwiperPattern::SaveIndicatorProperty(
2440 const RefPtr<FrameNode>& indicatorNode, SwiperIndicatorType swiperIndicatorType)
2441 {
2442 if (swiperIndicatorType == SwiperIndicatorType::DOT) {
2443 SwiperHelper::SaveDotIndicatorProperty(indicatorNode, *this);
2444 } else if (swiperIndicatorType == SwiperIndicatorType::ARC_DOT) {
2445 SaveCircleDotIndicatorProperty(indicatorNode);
2446 } else {
2447 SwiperHelper::SaveDigitIndicatorProperty(indicatorNode, *this);
2448 }
2449 }
2450
InitIndicator()2451 void SwiperPattern::InitIndicator()
2452 {
2453 auto swiperNode = GetHost();
2454 CHECK_NULL_VOID(swiperNode);
2455 RefPtr<FrameNode> indicatorNode;
2456 auto indicatorType = GetIndicatorType();
2457 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2458 CHECK_NULL_VOID(layoutProperty);
2459 if (!HasIndicatorNode()) {
2460 if (!IsShowIndicator()) {
2461 return;
2462 }
2463 if (layoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::ARC_DOT) {
2464 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, CreateIndicatorId(),
2465 []() { return AceType::MakeRefPtr<ArcSwiperIndicatorPattern>(); });
2466 } else {
2467 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, CreateIndicatorId(),
2468 [indicatorType]() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(indicatorType); });
2469 }
2470 swiperNode->UINode::AddChild(indicatorNode);
2471 } else {
2472 indicatorNode =
2473 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetIndicatorId())));
2474 CHECK_NULL_VOID(indicatorNode);
2475 if (!IsShowIndicator()) {
2476 RemoveIndicatorNode();
2477 return;
2478 }
2479 if ((indicatorType == SwiperIndicatorType::DIGIT && lastSwiperIndicatorType_ == SwiperIndicatorType::DOT) ||
2480 (indicatorType == SwiperIndicatorType::DOT && lastSwiperIndicatorType_ == SwiperIndicatorType::DIGIT)) {
2481 RemoveIndicatorNode();
2482 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, CreateIndicatorId(),
2483 [indicatorType]() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(indicatorType); });
2484 swiperNode->UINode::AddChild(indicatorNode);
2485 }
2486 }
2487 lastSwiperIndicatorType_ = indicatorType;
2488 CHECK_NULL_VOID(indicatorNode);
2489 SaveIndicatorProperty(indicatorNode, layoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT));
2490
2491 auto renderContext = indicatorNode->GetRenderContext();
2492 CHECK_NULL_VOID(renderContext);
2493 BorderRadiusProperty radius;
2494 radius.SetRadius(INDICATOR_BORDER_RADIUS);
2495 renderContext->UpdateBorderRadius(radius);
2496
2497 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
2498 indicatorPattern->SetIndicatorInteractive(isIndicatorInteractive_);
2499
2500 indicatorNode->MarkModifyDone();
2501 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2502 }
2503
InitArrow()2504 void SwiperPattern::InitArrow()
2505 {
2506 auto swiperNode = GetHost();
2507 CHECK_NULL_VOID(swiperNode);
2508 RefPtr<FrameNode> leftArrow;
2509 RefPtr<FrameNode> rightArrow;
2510 if (!HasLeftButtonNode() && !HasRightButtonNode()) {
2511 if (!IsShowArrow()) {
2512 return;
2513 }
2514 leftArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_LEFT_ARROW_ETS_TAG, GetLeftButtonId(),
2515 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2516 swiperNode->AddChild(leftArrow);
2517 rightArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_ARROW_ETS_TAG, GetRightButtonId(),
2518 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2519 swiperNode->AddChild(rightArrow);
2520 } else {
2521 leftArrow =
2522 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
2523 CHECK_NULL_VOID(leftArrow);
2524 rightArrow =
2525 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
2526 CHECK_NULL_VOID(rightArrow);
2527 if (!IsShowArrow()) {
2528 RemoveLeftButtonNode();
2529 RemoveRightButtonNode();
2530 return;
2531 }
2532 }
2533
2534 SaveArrowProperty(leftArrow);
2535 SaveArrowProperty(rightArrow);
2536
2537 leftArrow->MarkModifyDone();
2538 rightArrow->MarkModifyDone();
2539 }
2540
CheckAndReportEvent()2541 void SwiperPattern::CheckAndReportEvent()
2542 {
2543 if (gestureStatus_ == GestureStatus::INIT || gestureStatus_ == GestureStatus::END) {
2544 gestureStatus_ = GestureStatus::START;
2545 return;
2546 }
2547
2548 EventReport::ReportScrollableErrorEvent(
2549 "Swiper", ScrollableErrorType::GESTURE_MISMATCH, "Swiper previous pan event lost end.");
2550 }
2551
ActionStartTask()2552 SwiperPattern::PanEventFunction SwiperPattern::ActionStartTask()
2553 {
2554 return [weak = WeakClaim(this)](const GestureEvent& info) {
2555 auto pattern = weak.Upgrade();
2556 CHECK_NULL_VOID(pattern);
2557 pattern->CheckAndReportEvent();
2558 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag start. SourceTool: %{public}d, id:%{public}d",
2559 info.GetSourceTool(), pattern->swiperId_);
2560 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2561 pattern->isFirstAxisAction_ = true;
2562 return;
2563 }
2564 pattern->FireAndCleanScrollingListener();
2565 pattern->HandleDragStart(info);
2566 // notify scrollStart upwards
2567 pattern->NotifyParentScrollStart(weak, pattern->direction_ == Axis::HORIZONTAL
2568 ? info.GetGlobalLocation().GetX()
2569 : info.GetGlobalLocation().GetY());
2570 };
2571 }
2572
ActionUpdateTask()2573 SwiperPattern::PanEventFunction SwiperPattern::ActionUpdateTask()
2574 {
2575 return [weak = WeakClaim(this)](const GestureEvent& info) {
2576 auto pattern = weak.Upgrade();
2577 CHECK_NULL_VOID(pattern);
2578 auto infoChecked = info;
2579 // Reverse velocity and delta when receiving.
2580 if (pattern->IsHorizontalAndRightToLeft()) {
2581 infoChecked.SetMainVelocity(-info.GetMainVelocity());
2582 infoChecked.SetMainDelta(-info.GetMainDelta());
2583 }
2584 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2585 if (pattern->isFirstAxisAction_) {
2586 pattern->isFirstAxisAction_ = false;
2587 } else if (pattern->pageFlipMode_ == PageFlipMode::SINGLE &&
2588 (pattern->propertyAnimationIsRunning_ || pattern->translateAnimationIsRunning_)) {
2589 return;
2590 }
2591 if (!pattern->CheckSwiperPanEvent(infoChecked.GetMainDelta())) {
2592 return;
2593 }
2594 if (GreatNotEqual(infoChecked.GetMainDelta(), 0.0)) {
2595 pattern->ShowPrevious(true);
2596 } else if (LessNotEqual(infoChecked.GetMainDelta(), 0.0)) {
2597 pattern->ShowNext(true);
2598 }
2599 } else {
2600 pattern->HandleDragUpdate(infoChecked);
2601 }
2602 };
2603 }
2604
ActionEndTask()2605 SwiperPattern::PanEventFunction SwiperPattern::ActionEndTask()
2606 {
2607 return [weak = WeakClaim(this)](const GestureEvent& info) {
2608 auto pattern = weak.Upgrade();
2609 CHECK_NULL_VOID(pattern);
2610 pattern->SetGestureStatus(GestureStatus::END);
2611 TAG_LOGI(AceLogTag::ACE_SWIPER,
2612 "Swiper drag end. Velocity: %{public}f px/s, SourceTool: %{public}d id:%{public}d", info.GetMainVelocity(),
2613 info.GetSourceTool(), pattern->swiperId_);
2614 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2615 pattern->InitIndexCanChangeMap();
2616 return;
2617 }
2618 bool isUsingTouchPad =
2619 (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD);
2620 auto velocity =
2621 isUsingTouchPad ? info.GetMainVelocity() * pattern->GetVelocityCoefficient() : info.GetMainVelocity();
2622 // Reverse velocity when receiving.
2623 velocity = pattern->IsHorizontalAndRightToLeft() ? -velocity : velocity;
2624 auto mainDelta = pattern->IsHorizontalAndRightToLeft() ? -info.GetMainDelta() : info.GetMainDelta();
2625 pattern->HandleDragEnd(velocity, mainDelta);
2626 pattern->InitIndexCanChangeMap();
2627 if (LessOrEqual(std::abs(velocity), pattern->newMinTurnPageVelocity_) &&
2628 std::abs(velocity) > MIN_DUMP_VELOCITY_THRESHOLD) {
2629 auto host = pattern->GetHost();
2630 CHECK_NULL_VOID(host);
2631 auto eventHub = host->GetEventHub<EventHub>();
2632 CHECK_NULL_VOID(eventHub);
2633 auto gestureEventHub = eventHub->GetOrCreateGestureEventHub();
2634 CHECK_NULL_VOID(gestureEventHub);
2635 gestureEventHub->DumpVelocityInfoFroPanEvent(info.GetPointerId());
2636 }
2637 };
2638 }
2639
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)2640 void SwiperPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
2641 {
2642 if (direction_ == GetDirection() && panEvent_) {
2643 return;
2644 }
2645 // fade offset need to be reset when is still dragging
2646 if (direction_ != GetDirection()) {
2647 fadeOffset_ = 0.f;
2648 }
2649 direction_ = GetDirection();
2650
2651 auto actionCancelTask = [weak = WeakClaim(this)]() {
2652 auto pattern = weak.Upgrade();
2653 if (pattern) {
2654 pattern->SetGestureStatus(GestureStatus::END);
2655 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag cancel id:%{public}d", pattern->swiperId_);
2656 pattern->HandleDragEnd(0.0);
2657 pattern->InitIndexCanChangeMap();
2658 }
2659 };
2660
2661 AddPanEvent(gestureHub, ActionStartTask(), ActionUpdateTask(), ActionEndTask(), std::move(actionCancelTask));
2662 }
2663
AddPanEvent(const RefPtr<GestureEventHub> & gestureHub,GestureEventFunc && actionStart,GestureEventFunc && actionUpdate,GestureEventFunc && actionEnd,GestureEventNoParameter && actionCancel)2664 void SwiperPattern::AddPanEvent(const RefPtr<GestureEventHub>& gestureHub, GestureEventFunc&& actionStart,
2665 GestureEventFunc&& actionUpdate, GestureEventFunc&& actionEnd, GestureEventNoParameter&& actionCancel)
2666 {
2667 if (GetDirection() == Axis::VERTICAL) {
2668 panDirection_.type = PanDirection::VERTICAL;
2669 } else {
2670 panDirection_.type = PanDirection::HORIZONTAL;
2671 }
2672 if (panEvent_) {
2673 gestureHub->RemovePanEvent(panEvent_);
2674 }
2675
2676 panEvent_ = MakeRefPtr<PanEvent>(
2677 std::move(actionStart), std::move(actionUpdate), std::move(actionEnd), std::move(actionCancel));
2678 gestureHub->AddPanEvent(panEvent_, panDirection_, 1, DEFAULT_PAN_DISTANCE);
2679 }
2680
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)2681 void SwiperPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
2682 {
2683 if (touchEvent_) {
2684 return;
2685 }
2686
2687 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2688 auto pattern = weak.Upgrade();
2689 if (pattern) {
2690 pattern->HandleTouchEvent(info);
2691 }
2692 };
2693
2694 if (touchEvent_) {
2695 gestureHub->RemoveTouchEvent(touchEvent_);
2696 }
2697 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2698 gestureHub->AddTouchEvent(touchEvent_);
2699 }
2700
InitOnFocusInternal(const RefPtr<FocusHub> & focusHub)2701 void SwiperPattern::InitOnFocusInternal(const RefPtr<FocusHub>& focusHub)
2702 {
2703 auto focusTask = [weak = WeakClaim(this)]() {
2704 auto pattern = weak.Upgrade();
2705 if (pattern) {
2706 pattern->HandleFocusInternal();
2707 }
2708 };
2709 focusHub->SetOnFocusInternal(std::move(focusTask));
2710 }
2711
HandleFocusInternal()2712 void SwiperPattern::HandleFocusInternal()
2713 {
2714 currentFocusIndex_ = currentIndex_;
2715
2716 auto host = GetHost();
2717 CHECK_NULL_VOID(host);
2718 auto focusHub = host->GetFocusHub();
2719 CHECK_NULL_VOID(focusHub);
2720 auto lastFocusNode = focusHub->GetLastWeakFocusNode().Upgrade();
2721 CHECK_NULL_VOID(lastFocusNode);
2722 for (const auto& item : itemPosition_) {
2723 auto itemNode = GetCurrentFrameNode(item.first);
2724 if (!itemNode) {
2725 continue;
2726 }
2727 if (itemNode->GetFirstFocusHubChild() == lastFocusNode) {
2728 currentFocusIndex_ = item.first;
2729 return;
2730 }
2731 }
2732 }
2733
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)2734 void SwiperPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
2735 {
2736 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
2737 auto pattern = wp.Upgrade();
2738 if (pattern) {
2739 return pattern->OnKeyEvent(event);
2740 }
2741 return false;
2742 };
2743 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
2744 }
2745
IsContentFocused()2746 bool SwiperPattern::IsContentFocused()
2747 {
2748 auto swiperHost = GetHost();
2749 CHECK_NULL_RETURN(swiperHost, true);
2750 auto swiperFocusHub = swiperHost->GetFocusHub();
2751 CHECK_NULL_RETURN(swiperFocusHub, true);
2752 bool ret = true;
2753 swiperFocusHub->AnyChildFocusHub([&ret](const RefPtr<FocusHub>& child) {
2754 if (!child || !child->IsCurrentFocus()) {
2755 return false;
2756 }
2757 auto frameName = child->GetFrameName();
2758 if (frameName == V2::SWIPER_INDICATOR_ETS_TAG || frameName == V2::SWIPER_RIGHT_ARROW_ETS_TAG ||
2759 frameName == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
2760 ret = false;
2761 }
2762 return true;
2763 });
2764 return ret;
2765 }
2766
OnKeyEvent(const KeyEvent & event)2767 bool SwiperPattern::OnKeyEvent(const KeyEvent& event)
2768 {
2769 if (event.action != KeyAction::DOWN) {
2770 return false;
2771 }
2772 if ((GetDirection() == Axis::HORIZONTAL && event.code == (IsHorizontalAndRightToLeft() ? KeyCode::KEY_DPAD_RIGHT :
2773 KeyCode::KEY_DPAD_LEFT)) || (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
2774 auto onlyFlushFocus = IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ > currentIndex_;
2775 if (onlyFlushFocus) {
2776 currentFocusIndex_ =
2777 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2778 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2779 } else {
2780 ShowPrevious(true);
2781 currentFocusIndex_ =
2782 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2783 }
2784
2785 return true;
2786 }
2787 if ((GetDirection() == Axis::HORIZONTAL && event.code == (IsHorizontalAndRightToLeft() ? KeyCode::KEY_DPAD_LEFT :
2788 KeyCode::KEY_DPAD_RIGHT)) || (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
2789 auto onlyFlushFocus =
2790 IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ < currentIndex_ + GetDisplayCount() - 1;
2791 if (onlyFlushFocus) {
2792 currentFocusIndex_ =
2793 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2794 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2795 } else {
2796 ShowNext(true);
2797 currentFocusIndex_ =
2798 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2799 }
2800
2801 return true;
2802 }
2803 return false;
2804 }
2805
StopAutoPlay()2806 void SwiperPattern::StopAutoPlay()
2807 {
2808 if (IsAutoPlay()) {
2809 isInAutoPlay_ = false;
2810 translateTask_.Cancel();
2811 }
2812 }
2813
StartAutoPlay()2814 void SwiperPattern::StartAutoPlay()
2815 {
2816 if (NeedAutoPlay() && !translateAnimationIsRunning_ && !propertyAnimationIsRunning_) {
2817 PostTranslateTask(GetInterval());
2818 }
2819 }
2820
OnVisibleChange(bool isVisible)2821 void SwiperPattern::OnVisibleChange(bool isVisible)
2822 {
2823 isVisible_ = isVisible;
2824 if (isInit_) {
2825 return;
2826 }
2827
2828 if (!isVisible_) {
2829 StopAutoPlay();
2830 return;
2831 }
2832
2833 if (NeedStartAutoPlay()) {
2834 StartAutoPlay();
2835 }
2836 }
2837
UpdateCurrentOffset(float offset)2838 void SwiperPattern::UpdateCurrentOffset(float offset)
2839 {
2840 if (itemPosition_.empty()) {
2841 MarkDirtyNodeSelf();
2842 return;
2843 }
2844 if (!IsLoop() && (isDragging_ || childScrolling_)) {
2845 // handle edge effects
2846 if (CheckOverScroll(offset)) {
2847 ResetCurrentFrameNodeAnimation();
2848 return;
2849 }
2850 }
2851 if (!IsLoop() && GetEdgeEffect() != EdgeEffect::SPRING && IsOutOfBoundary(offset)) {
2852 offset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2853 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2854 }
2855 currentDelta_ -= offset;
2856 currentIndexOffset_ += offset;
2857 if (isDragging_ || childScrolling_) {
2858 AnimationCallbackInfo callbackInfo;
2859 callbackInfo.currentOffset =
2860 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2861 if (IsHorizontalAndRightToLeft()) {
2862 callbackInfo.currentOffset =
2863 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2864 }
2865 bool skipGestureSwipe = TotalCount() == 1 && GetEdgeEffect() == EdgeEffect::NONE;
2866 if (!skipGestureSwipe) {
2867 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
2868 }
2869 }
2870 HandleSwiperCustomAnimation(-currentDelta_);
2871 MarkDirtyNodeSelf();
2872 }
2873
CheckOverScroll(float offset)2874 bool SwiperPattern::CheckOverScroll(float offset)
2875 {
2876 switch (GetEdgeEffect()) {
2877 case EdgeEffect::SPRING:
2878 if (SpringOverScroll(offset)) {
2879 return true;
2880 }
2881 break;
2882 case EdgeEffect::FADE:
2883 if (FadeOverScroll(offset)) {
2884 return true;
2885 }
2886 break;
2887 case EdgeEffect::NONE:
2888 if (IsOutOfBoundary(offset)) {
2889 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2890 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2891 currentDelta_ -= realOffset;
2892 HandleSwiperCustomAnimation(realOffset);
2893 MarkDirtyNodeSelf();
2894 return true;
2895 }
2896 break;
2897 }
2898 return false;
2899 }
2900
SpringOverScroll(float offset)2901 bool SwiperPattern::SpringOverScroll(float offset)
2902 {
2903 bool outOfBounds = IsOutOfBoundary(offset);
2904 if (!outOfBounds) {
2905 springOffset_ = 0.0f;
2906 return false;
2907 }
2908
2909 ResetParentNodeColor();
2910 auto visibleSize = CalculateVisibleSize();
2911 if (LessOrEqual(visibleSize, 0.0)) {
2912 return true;
2913 }
2914 auto currentRealOffset = springOffset_ * SwiperHelper::CalculateFriction(std::abs(springOffset_ / visibleSize));
2915 auto delta = 0.0f;
2916 if (IsOutOfBoundary()) {
2917 springOffset_ += offset;
2918 } else {
2919 if (offset > 0) {
2920 springOffset_ = itemPosition_.begin()->second.startPos + offset + AdjustIgnoreBlankOverScrollOffSet(true);
2921 } else {
2922 springOffset_ =
2923 itemPosition_.rbegin()->second.endPos + offset - visibleSize + AdjustIgnoreBlankOverScrollOffSet(false);
2924 }
2925 delta = offset - springOffset_;
2926 }
2927 if (std::abs(springOffset_) > visibleSize) {
2928 springOffset_ = springOffset_ > 0 ? visibleSize : -visibleSize;
2929 }
2930 auto realOffset = springOffset_ * SwiperHelper::CalculateFriction(std::abs(springOffset_ / visibleSize));
2931 delta += (realOffset - currentRealOffset);
2932 currentDelta_ -= delta;
2933 currentIndexOffset_ += delta;
2934 AnimationCallbackInfo callbackInfo;
2935 callbackInfo.currentOffset =
2936 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2937 if (IsHorizontalAndRightToLeft()) {
2938 callbackInfo.currentOffset =
2939 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2940 }
2941
2942 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
2943 HandleSwiperCustomAnimation(delta);
2944 MarkDirtyNodeSelf();
2945 return true;
2946 }
2947
FadeOverScroll(float offset)2948 bool SwiperPattern::FadeOverScroll(float offset)
2949 {
2950 if (IsOutOfBoundary(fadeOffset_ + offset)) {
2951 if (!IsVisibleChildrenSizeLessThanSwiper() && NearZero(fadeOffset_)) {
2952 UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart(offset));
2953 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2954 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2955 currentDelta_ -= realOffset;
2956 offset -= realOffset;
2957 HandleSwiperCustomAnimation(realOffset);
2958 }
2959 fadeOffset_ += offset;
2960 auto host = GetHost();
2961 CHECK_NULL_RETURN(host, false);
2962 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2963 MarkDirtyNodeSelf();
2964 return true;
2965 }
2966 fadeOffset_ = 0.0f;
2967 return false;
2968 }
2969
IsHorizontalAndRightToLeft() const2970 bool SwiperPattern::IsHorizontalAndRightToLeft() const
2971 {
2972 auto host = GetHost();
2973 if (hasTabsAncestor_ && host) {
2974 host = AceType::DynamicCast<FrameNode>(host->GetParent());
2975 }
2976 CHECK_NULL_RETURN(host, false);
2977 CHECK_NULL_RETURN(host->GetLayoutProperty(), false);
2978 return GetDirection() == Axis::HORIZONTAL &&
2979 host->GetLayoutProperty()->GetNonAutoLayoutDirection() == TextDirection::RTL;
2980 }
2981
GetNonAutoLayoutDirection() const2982 TextDirection SwiperPattern::GetNonAutoLayoutDirection() const
2983 {
2984 auto host = GetHost();
2985 CHECK_NULL_RETURN(host, TextDirection::LTR);
2986 CHECK_NULL_RETURN(host->GetLayoutProperty(), TextDirection::LTR);
2987 return host->GetLayoutProperty()->GetNonAutoLayoutDirection();
2988 }
2989
UpdateNextValidIndex()2990 void SwiperPattern::UpdateNextValidIndex()
2991 {
2992 // item may be invalid in auto linear scene, mark next valid item
2993 if (IsAutoLinear()) {
2994 currentFirstIndex_ = CheckTargetIndex(currentFirstIndex_, true);
2995 nextValidIndex_ = GetLoopIndex(CheckTargetIndex(currentFirstIndex_ + 1, true));
2996 } else {
2997 nextValidIndex_ = -1;
2998 }
2999 }
3000
CheckMarkDirtyNodeForRenderIndicator(float additionalOffset,std::optional<int32_t> nextIndex)3001 void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset, std::optional<int32_t> nextIndex)
3002 {
3003 additionalOffset = IsHorizontalAndRightToLeft() ? -additionalOffset : additionalOffset;
3004 if (!HasIndicatorNode()) {
3005 return;
3006 }
3007 auto child = GetCommonIndicatorNode();
3008 CHECK_NULL_VOID(child);
3009
3010 if (!IsIndicator(child->GetTag())) {
3011 return;
3012 }
3013
3014 int32_t preFirstIndex = currentFirstIndex_;
3015 auto currentPageStatus = (IsHorizontalAndRightToLeft() && GetMaxDisplayCount() > 0)
3016 ? CalcCurrentPageStatusOnRTL(additionalOffset)
3017 : CalcCurrentPageStatus(additionalOffset);
3018 float currentTurnPageRate = currentPageStatus.first;
3019 currentFirstIndex_ = currentPageStatus.second;
3020
3021 groupTurnPageRate_ =
3022 (IsSwipeByGroup() && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) ?
3023 CalculateGroupTurnPageRate(additionalOffset) : 0.0f);
3024 currentFirstIndex_ = nextIndex.value_or(currentFirstIndex_);
3025 UpdateNextValidIndex();
3026 currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
3027 auto isRtl = IsHorizontalAndRightToLeft() && GetMaxDisplayCount() <= 0;
3028 isRtl ? CalculateGestureStateOnRTL(additionalOffset, currentTurnPageRate, preFirstIndex)
3029 : CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
3030 turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
3031 turnPageRate_ = isRtl ? std::abs(turnPageRate_) - 1.0f : turnPageRate_;
3032 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
3033 CheckMarkForIndicatorBoundary();
3034 isRtl ? HandleTouchBottomLoopOnRTL() : HandleTouchBottomLoop();
3035
3036 if (IsVisibleChildrenSizeLessThanSwiper()) {
3037 turnPageRate_ = 0.0f;
3038 groupTurnPageRate_ = 0.0f;
3039 gestureState_ = GestureState::GESTURE_STATE_NONE;
3040 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
3041 }
3042
3043 if (!indicatorDoingAnimation_) {
3044 child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3045 }
3046 if (GetLoopIndex(currentIndex_) != currentFirstIndex_) {
3047 auto swiperEventHub = GetEventHub<SwiperEventHub>();
3048 CHECK_NULL_VOID(swiperEventHub);
3049 swiperEventHub->FireIndicatorChangeEvent(currentFirstIndex_);
3050 }
3051 }
3052
CheckMarkForIndicatorBoundary()3053 void SwiperPattern::CheckMarkForIndicatorBoundary()
3054 {
3055 bool isRtl = IsHorizontalAndRightToLeft();
3056
3057 auto startIndex = isRtl ? TotalCount() - 1 : 0;
3058 auto endIndex = isRtl ? 0 : TotalCount() - 1;
3059 if (!IsLoop() && ((currentFirstIndex_ == startIndex && GreatNotEqualCustomPrecision(turnPageRate_, 0.0f)) ||
3060 (currentFirstIndex_ == endIndex && LessNotEqualCustomPrecision(turnPageRate_, 0.0f)))) {
3061 return;
3062 }
3063 }
3064
CalculateGroupTurnPageRate(float additionalOffset)3065 float SwiperPattern::CalculateGroupTurnPageRate(float additionalOffset)
3066 {
3067 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3068 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3069 auto firstItemIndex = firstItemInfoInVisibleArea.first;
3070 auto displayCount = GetDisplayCount();
3071 auto itemSpace = GetItemSpace();
3072 auto swiperWidth = CalculateVisibleSize();
3073 auto totalCount = TotalCount();
3074 float groupTurnPageRate = FLT_MAX;
3075 float currentStartPos = 0.0f;
3076
3077 if (swiperWidth == 0 || displayCount == 0 || totalCount == 0) {
3078 return 0.0f;
3079 }
3080 if (itemPosition_.empty() || itemPosition_.find(firstItemIndex) == itemPosition_.end()) {
3081 return 0.0f;
3082 }
3083 if (firstItemIndex >= currentIndex_) {
3084 currentStartPos = itemPosition_[firstItemIndex].startPos -
3085 (itemSpace + firstItemLength) * (firstItemIndex - currentIndex_);
3086
3087 if (currentStartPos > 0) {
3088 return 0.0f;
3089 }
3090 if (!IsLoop() && firstItemIndex % totalCount >= totalCount - displayCount) {
3091 return 0.0f;
3092 }
3093
3094 groupTurnPageRate = NearZero(swiperWidth) ? 0 : (currentStartPos + additionalOffset) / swiperWidth;
3095 } else if (firstItemIndex < currentIndex_) {
3096 currentStartPos = itemPosition_[firstItemIndex].startPos - (itemSpace + firstItemLength) *
3097 (displayCount - ((currentIndex_ - firstItemIndex) - 1) % displayCount - 1);
3098
3099 if (currentStartPos > 0) {
3100 return 0.0f;
3101 }
3102
3103 groupTurnPageRate = NearZero(swiperWidth) ? 0 :(currentStartPos + additionalOffset) / swiperWidth;
3104 } else {
3105 groupTurnPageRate = 0.0f;
3106 }
3107
3108 if (IsHorizontalAndRightToLeft()) {
3109 groupTurnPageRate = std::abs(groupTurnPageRate) <= 1.0f ? std::abs(groupTurnPageRate) - 1.0f : 0.0f;
3110 }
3111
3112 return (groupTurnPageRate == FLT_MAX ? groupTurnPageRate_ : groupTurnPageRate);
3113 }
3114
CalculateStepAndItemCount() const3115 std::pair<int32_t, int32_t> SwiperPattern::CalculateStepAndItemCount() const
3116 {
3117 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
3118 return { RealTotalCount(), 1 };
3119 }
3120
3121 auto displaycount = GetDisplayCount();
3122
3123 int32_t itemCount = (IsSwipeByGroup() ? TotalCount() : DisplayIndicatorTotalCount());
3124 int32_t step = (IsSwipeByGroup() ? displaycount : 1);
3125
3126 return { itemCount, step };
3127 }
3128
UpdateAnimationProperty(float velocity)3129 void SwiperPattern::UpdateAnimationProperty(float velocity)
3130 {
3131 if (isDragging_ || childScrolling_) {
3132 targetIndex_ = CheckTargetIndex(ComputeNextIndexByVelocity(velocity));
3133 velocity_ = velocity;
3134 } else {
3135 targetIndex_ = pauseTargetIndex_;
3136 velocity_ = velocity;
3137 }
3138
3139 MarkDirtyNodeSelf();
3140 moveDirection_ = velocity <= 0;
3141 }
3142
HandleTouchEvent(const TouchEventInfo & info)3143 void SwiperPattern::HandleTouchEvent(const TouchEventInfo& info)
3144 {
3145 if (info.GetTouches().empty()) {
3146 return;
3147 }
3148 auto locationInfo = info.GetTouches().front();
3149 auto touchType = locationInfo.GetTouchType();
3150 if (touchType == TouchType::DOWN) {
3151 HandleTouchDown(locationInfo);
3152 } else if (touchType == TouchType::UP) {
3153 HandleTouchUp();
3154 } else if (touchType == TouchType::CANCEL) {
3155 HandleTouchUp();
3156 }
3157 }
3158
InsideIndicatorRegion(const TouchLocationInfo & locationInfo)3159 bool SwiperPattern::InsideIndicatorRegion(const TouchLocationInfo& locationInfo)
3160 {
3161 auto host = GetHost();
3162 CHECK_NULL_RETURN(host, false);
3163 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
3164 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
3165 return false;
3166 }
3167 auto geometryNode = indicatorNode->GetGeometryNode();
3168 CHECK_NULL_RETURN(geometryNode, false);
3169 auto hotRegion = geometryNode->GetFrameRect();
3170 auto touchPoint = PointF(static_cast<float>(locationInfo.GetLocalLocation().GetX()),
3171 static_cast<float>(locationInfo.GetLocalLocation().GetY()));
3172 return hotRegion.IsInRegion(touchPoint);
3173 }
3174
UpdateOverlongForceStopPageRate(float forceStopPageRate)3175 void SwiperPattern::UpdateOverlongForceStopPageRate(float forceStopPageRate)
3176 {
3177 CHECK_NULL_VOID(updateOverlongForceStopPageRateFunc_);
3178 updateOverlongForceStopPageRateFunc_(forceStopPageRate);
3179 }
3180
HandleTouchDown(const TouchLocationInfo & locationInfo)3181 void SwiperPattern::HandleTouchDown(const TouchLocationInfo& locationInfo)
3182 {
3183 ACE_SCOPED_TRACE("Swiper HandleTouchDown");
3184 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchDown id: %{public}d", swiperId_);
3185 isTouchDown_ = true;
3186 isTouchDownOnOverlong_ = true;
3187 if (InsideIndicatorRegion(locationInfo)) {
3188 return;
3189 }
3190
3191 if (childScrolling_) {
3192 // Even if the child fails to notify scrollEnd, we reset childScrolling_ flag on TouchDown to ensure its
3193 // value is correct.
3194 childScrolling_ = false;
3195 }
3196
3197 if (!stopWhenTouched_) {
3198 return;
3199 }
3200 auto isOverlongIndicator = GetMaxDisplayCount() > 0;
3201 if (!isOverlongIndicator) {
3202 StopIndicatorAnimation(true);
3203 }
3204
3205 if (propertyAnimationIsRunning_) {
3206 StopPropertyTranslateAnimation(isFinishAnimation_);
3207 }
3208
3209 if (isOverlongIndicator) {
3210 UpdateOverlongForceStopPageRate(CalcCurrentTurnPageRate());
3211 StopIndicatorAnimation(true);
3212 }
3213
3214 indicatorDoingAnimation_ = false;
3215 // Stop translate animation when touch down.
3216 if (translateAnimationIsRunning_) {
3217 StopTranslateAnimation();
3218 }
3219
3220 if (springAnimationIsRunning_) {
3221 AnimationUtils::PauseAnimation(springAnimation_);
3222 isTouchDownSpringAnimation_ = true;
3223 }
3224
3225 AnimationUtils::PauseAnimation(fadeAnimation_);
3226 if (fadeAnimationIsRunning_) {
3227 isTouchDownFadeAnimation_ = true;
3228 }
3229
3230 // Stop auto play when touch down.
3231 StopAutoPlay();
3232 }
3233
HandleTouchUp()3234 void SwiperPattern::HandleTouchUp()
3235 {
3236 ACE_SCOPED_TRACE("Swiper HandleTouchUp");
3237 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchUp id: %{public}d", swiperId_);
3238 isTouchDown_ = false;
3239 isTouchDownOnOverlong_ = false;
3240 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3241 if (!isDragging_ && !childScrolling_ && !NearZero(firstItemInfoInVisibleArea.second.startPos) &&
3242 !springAnimationIsRunning_) {
3243 UpdateAnimationProperty(0.0);
3244 }
3245
3246 if (springAnimationIsRunning_ && isTouchDownSpringAnimation_) {
3247 isTouchDownSpringAnimation_ = false;
3248 AnimationUtils::ResumeAnimation(springAnimation_);
3249 }
3250
3251 if (fadeAnimationIsRunning_ && isTouchDownFadeAnimation_) {
3252 isTouchDownFadeAnimation_ = false;
3253 AnimationUtils::ResumeAnimation(fadeAnimation_);
3254 }
3255
3256 if (!isDragging_) {
3257 StartAutoPlay();
3258 }
3259
3260 if (GetMaxDisplayCount() > 0) {
3261 UpdateOverlongForceStopPageRate(FLT_MAX);
3262 }
3263 }
3264
HandleDragStart(const GestureEvent & info)3265 void SwiperPattern::HandleDragStart(const GestureEvent& info)
3266 {
3267 if (!hasTabsAncestor_) {
3268 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_SWIPER_SCROLL,
3269 PerfActionType::FIRST_MOVE, "");
3270 } else {
3271 AceAsyncTraceBeginCommercial(0, APP_TABS_SCROLL);
3272 }
3273 UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::START);
3274 StopAnimationOnScrollStart(
3275 info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD, true);
3276 StopAutoPlay();
3277
3278 const auto& tabBarFinishCallback = swiperController_->GetTabBarFinishCallback();
3279 if (tabBarFinishCallback) {
3280 tabBarFinishCallback();
3281 }
3282
3283 const auto& removeEventCallback = swiperController_->GetRemoveTabBarEventCallback();
3284 if (removeEventCallback) {
3285 removeEventCallback();
3286 }
3287
3288 gestureSwipeIndex_ = currentIndex_;
3289 isDragging_ = true;
3290 isTouchDown_ = true;
3291 isTouchDownOnOverlong_ = true;
3292 mainDeltaSum_ = 0.0f;
3293 ResetAnimationParam();
3294 // in drag process, close lazy feature.
3295 SetLazyLoadFeature(false);
3296 }
3297
StopAnimationOnScrollStart(bool flushImmediately,bool stopLongPointAnimation)3298 void SwiperPattern::StopAnimationOnScrollStart(bool flushImmediately, bool stopLongPointAnimation)
3299 {
3300 if (propertyAnimationIsRunning_) {
3301 StopPropertyTranslateAnimation(isFinishAnimation_);
3302 }
3303 StopIndicatorAnimation(stopLongPointAnimation);
3304 StopTranslateAnimation();
3305 StopFadeAnimation();
3306 if (flushImmediately) {
3307 StopSpringAnimationAndFlushImmediately();
3308 } else {
3309 StopSpringAnimationImmediately();
3310 }
3311 }
3312
HandleDragUpdate(const GestureEvent & info)3313 void SwiperPattern::HandleDragUpdate(const GestureEvent& info)
3314 {
3315 isTouchDownOnOverlong_ = true;
3316 auto velocity = info.GetMainVelocity();
3317 UpdateDragFRCSceneInfo(velocity, SceneStatus::RUNNING);
3318 UpdateNodeRate();
3319 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD) {
3320 isTouchPad_ = true;
3321 }
3322
3323 PointF dragPoint(
3324 static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
3325 NGGestureRecognizer::Transform(dragPoint, GetHost(), true, info.GetIsPostEventResult(), info.GetPostEventNodeId());
3326 if (IsOutOfHotRegion(dragPoint)) {
3327 isTouchPad_ = false;
3328 return;
3329 }
3330
3331 auto mainDelta = static_cast<float>(info.GetMainDelta());
3332 ProcessDelta(mainDelta, contentMainSize_, mainDeltaSum_);
3333 mainDeltaSum_ += mainDelta;
3334
3335 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(static_cast<float>(mainDelta))) {
3336 return;
3337 }
3338
3339 if (propertyAnimationIsRunning_) {
3340 return;
3341 }
3342
3343 HandleScroll(static_cast<float>(mainDelta), SCROLL_FROM_UPDATE, NestedState::GESTURE, velocity);
3344 UpdateItemRenderGroup(true);
3345 isTouchPad_ = false;
3346 }
3347
TriggerAddTabBarEvent() const3348 void SwiperPattern::TriggerAddTabBarEvent() const
3349 {
3350 const auto& addEventCallback = swiperController_->GetAddTabBarEventCallback();
3351 if (addEventCallback) {
3352 addEventCallback();
3353 }
3354 }
3355
HandleDragEnd(double dragVelocity,float mainDelta)3356 void SwiperPattern::HandleDragEnd(double dragVelocity, float mainDelta)
3357 {
3358 if (!hasTabsAncestor_) {
3359 PerfMonitor::GetPerfMonitor()->EndCommercial(PerfConstants::APP_SWIPER_SCROLL, false);
3360 } else {
3361 AceAsyncTraceEndCommercial(0, APP_TABS_SCROLL);
3362 }
3363 isTouchDown_ = false;
3364 isTouchDownOnOverlong_ = false;
3365 if (!CheckSwiperPanEvent(dragVelocity) || !CheckContentWillScroll(dragVelocity, mainDelta)) {
3366 dragVelocity = 0.0;
3367 }
3368 if (!childScrolling_) {
3369 UpdateDragFRCSceneInfo(dragVelocity, SceneStatus::END);
3370 }
3371
3372 TriggerAddTabBarEvent();
3373
3374 auto pipeline = GetContext();
3375 CHECK_NULL_VOID(pipeline);
3376 pipeline->FlushUITasks();
3377 if (itemPosition_.empty()) {
3378 EventReport::ReportScrollableErrorEvent(
3379 "Swiper", ScrollableErrorType::INTERNAL_ERROR, "Swiper item position is empty.");
3380 return;
3381 }
3382
3383 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(0.0f)) {
3384 return;
3385 }
3386
3387 if (CheckDragOutOfBoundary(dragVelocity)) {
3388 return;
3389 }
3390
3391 UpdateAnimationProperty(static_cast<float>(dragVelocity));
3392 // nested and reached end (but not out of bounds), need to pass velocity to parent scrollable
3393 auto parent = GetNestedScrollParent();
3394 if (NearZero(GetDistanceToEdge())) {
3395 ResetCurrentFrameNodeAnimation();
3396 }
3397 if (!IsLoop() && parent && NearZero(GetDistanceToEdge())) {
3398 parent->HandleScrollVelocity(dragVelocity);
3399 StartAutoPlay();
3400 } else {
3401 NotifyParentScrollEnd();
3402 }
3403 if (pipeline) {
3404 pipeline->FlushUITasks();
3405 pipeline->FlushMessages();
3406 }
3407
3408 isDragging_ = false;
3409
3410 if (currentIndex_ != pauseTargetIndex_.value_or(0)) {
3411 FireWillShowEvent(pauseTargetIndex_.value_or(0));
3412 FireWillHideEvent(currentIndex_);
3413 }
3414 }
3415
UpdateCurrentIndex(int32_t index)3416 void SwiperPattern::UpdateCurrentIndex(int32_t index)
3417 {
3418 currentIndex_ = index;
3419 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
3420 CHECK_NULL_VOID(props);
3421 props->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
3422 }
3423
ComputeSwipePageNextIndex(float velocity,bool onlyDistance) const3424 int32_t SwiperPattern::ComputeSwipePageNextIndex(float velocity, bool onlyDistance) const
3425 {
3426 auto swiperWidth = CalculateVisibleSize();
3427 if (LessOrEqual(swiperWidth, 0)) {
3428 return currentIndex_;
3429 }
3430
3431 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3432 auto firstIndex = firstItemInfoInVisibleArea.first;
3433 auto displayCount = GetDisplayCount();
3434 auto endIndex = SwiperUtils::ComputePageEndIndex(firstIndex, displayCount);
3435 auto iter = itemPosition_.find(endIndex);
3436 if (iter == itemPosition_.end()) {
3437 return currentIndex_;
3438 }
3439
3440 auto currentEndIndex = SwiperUtils::ComputePageEndIndex(currentIndex_, displayCount);
3441 auto dragDistance = iter->second.endPos;
3442 auto dragForward = currentIndex_ > firstIndex;
3443 auto dragThresholdFlag = dragForward ? dragDistance > swiperWidth / swiperProportion_ :
3444 (dragDistance < swiperWidth / swiperProportion_) | (currentEndIndex < firstIndex);
3445 auto nextIndex = currentIndex_;
3446 if (dragThresholdFlag) {
3447 nextIndex = dragForward ? currentIndex_ - displayCount : currentIndex_ + displayCount;
3448 }
3449
3450 if (!onlyDistance && std::abs(velocity) > newMinTurnPageVelocity_ && velocity != 0.0f) {
3451 auto direction = GreatNotEqual(velocity, 0.0f);
3452 if (dragForward != direction || !dragThresholdFlag) {
3453 nextIndex = velocity > 0.0f ? nextIndex - displayCount : nextIndex + displayCount;
3454 }
3455 }
3456
3457 if (!IsAutoLinear() && nextIndex > currentIndex_ + displayCount) {
3458 nextIndex = currentIndex_ + displayCount;
3459 }
3460
3461 if (!IsLoop()) {
3462 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - displayCount));
3463 }
3464
3465 return nextIndex;
3466 }
3467
GetVelocityCoefficient()3468 float SwiperPattern::GetVelocityCoefficient()
3469 {
3470 auto pipelineContext = GetContext();
3471 CHECK_NULL_RETURN(pipelineContext, 1);
3472 auto swiperTheme = pipelineContext->GetTheme<SwiperTheme>();
3473 CHECK_NULL_RETURN(swiperTheme, 1);
3474 auto velocityCoefficient = swiperTheme->GetTouchPadVelocityCoefficient();
3475 return velocityCoefficient;
3476 }
3477
ComputeNextIndexInSinglePage(float velocity,bool onlyDistance) const3478 int32_t SwiperPattern::ComputeNextIndexInSinglePage(float velocity, bool onlyDistance) const
3479 {
3480 auto firstItemInfo = GetFirstItemInfoInVisibleArea();
3481 auto swiperWidthHalf = (firstItemInfo.second.endPos - firstItemInfo.second.startPos) / swiperProportion_;
3482 if (LessOrEqual(swiperWidthHalf, 0)) {
3483 return currentIndex_;
3484 }
3485 // if direction is true, expected index to decrease by 1
3486 bool direction = Positive(velocity);
3487
3488 bool overTurnPageVelocity =
3489 !onlyDistance && (std::abs(velocity) > (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
3490 ? newMinTurnPageVelocity_
3491 : MIN_TURN_PAGE_VELOCITY));
3492
3493 auto firstIndex = firstItemInfo.first;
3494 auto baseIndex = -firstItemInfo.second.startPos < swiperWidthHalf ? firstIndex : firstIndex + 1;
3495 if (overTurnPageVelocity) {
3496 return direction ? baseIndex - 1 : baseIndex + 1;
3497 }
3498 return baseIndex;
3499 }
3500
ComputeNextIndexByVelocity(float velocity,bool onlyDistance) const3501 int32_t SwiperPattern::ComputeNextIndexByVelocity(float velocity, bool onlyDistance) const
3502 {
3503 #ifdef SUPPORT_DIGITAL_CROWN
3504 if (IsCrownSpring() && velocity == 0.0f) {
3505 return currentIndex_;
3506 }
3507 #endif
3508 if (IsSwipeByGroup()) {
3509 return ComputeSwipePageNextIndex(velocity, onlyDistance);
3510 }
3511
3512 auto nextIndex = currentIndex_;
3513 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3514 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3515 if (LessOrEqual(firstItemLength, 0)) {
3516 return nextIndex;
3517 }
3518
3519 auto firstIndex = firstItemInfoInVisibleArea.first;
3520 auto dragDistance = firstItemInfoInVisibleArea.second.endPos;
3521 if (firstIndex == currentIndex_ && firstItemInfoInVisibleArea.second.startPos > 0) {
3522 firstIndex--;
3523 dragDistance = firstItemInfoInVisibleArea.second.startPos;
3524 }
3525 auto direction = GreatNotEqual(velocity, 0.0);
3526 auto dragThresholdFlag =
3527 direction ? dragDistance > firstItemLength / swiperProportion_ :
3528 firstItemInfoInVisibleArea.second.endPos < firstItemLength / swiperProportion_;
3529 auto turnVelocity = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? newMinTurnPageVelocity_
3530 : MIN_TURN_PAGE_VELOCITY;
3531 if ((!onlyDistance && std::abs(velocity) > turnVelocity) || dragThresholdFlag) {
3532 nextIndex = direction ? firstIndex : firstItemInfoInVisibleArea.first + 1;
3533 } else {
3534 nextIndex = direction ? firstIndex + 1 : firstItemInfoInVisibleArea.first;
3535 }
3536
3537 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3538 // don't run this in nested scroll. Parallel nested scroll can deviate > 1 page from currentIndex_
3539 if (!childScrolling_ && SwiperUtils::IsStretch(props) && GetDisplayCount() == 1) {
3540 nextIndex =
3541 std::clamp(ComputeNextIndexInSinglePage(velocity, onlyDistance), currentIndex_ - 1, currentIndex_ + 1);
3542 }
3543
3544 if (!IsAutoLinear() && nextIndex > currentIndex_ + GetDisplayCount()) {
3545 nextIndex = currentIndex_ + GetDisplayCount();
3546 }
3547
3548 if (!IsLoop()) {
3549 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - GetDisplayCount()));
3550 }
3551 return nextIndex;
3552 }
3553
NeedStartNewAnimation(const OffsetF & offset) const3554 bool SwiperPattern::NeedStartNewAnimation(const OffsetF& offset) const
3555 {
3556 if (itemPositionInAnimation_.empty()) {
3557 return true;
3558 }
3559
3560 for (const auto& animationItem : itemPositionInAnimation_) {
3561 auto iter = itemPosition_.find(animationItem.first);
3562 if (iter == itemPosition_.end()) {
3563 return true;
3564 }
3565 if ((animationItem.second.node && animationItem.second.finalOffset != offset) ||
3566 !NearEqual(animationItem.second.startPos, iter->second.startPos) ||
3567 !NearEqual(animationItem.second.endPos, iter->second.endPos)) {
3568 return true;
3569 }
3570 }
3571
3572 return false;
3573 }
3574
UpdateCurrentFocus()3575 void SwiperPattern::UpdateCurrentFocus()
3576 {
3577 do {
3578 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
3579 if (!curChildFrame) {
3580 break;
3581 }
3582 FlushFocus(curChildFrame);
3583 currentFocusIndex_ = currentIndex_;
3584 } while (0);
3585 }
3586
CheckDragOutOfBoundary(double dragVelocity)3587 bool SwiperPattern::CheckDragOutOfBoundary(double dragVelocity)
3588 {
3589 if (IsLoop()) {
3590 return false;
3591 }
3592
3593 auto edgeEffect = GetEdgeEffect();
3594 // edge effect is NONE and reached boundary
3595 const bool noneOutOfBoundary =
3596 (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) &&
3597 NearZero(GetDistanceToEdge()) && edgeEffect == EdgeEffect::NONE;
3598 if (IsOutOfBoundary() || !NearZero(fadeOffset_) || noneOutOfBoundary) {
3599 isDragging_ = false;
3600
3601 if (edgeEffect == EdgeEffect::SPRING) {
3602 PlaySpringAnimation(dragVelocity);
3603 return true;
3604 }
3605
3606 if (edgeEffect == EdgeEffect::FADE) {
3607 PlayFadeAnimation();
3608 return true;
3609 }
3610
3611 auto nextIndex = ComputeNextIndexByVelocity(static_cast<float>(dragVelocity), true);
3612 if (currentIndex_ != nextIndex) {
3613 FireWillShowEvent(nextIndex_);
3614 FireWillHideEvent(currentIndex_);
3615
3616 UpdateCurrentIndex(nextIndex);
3617 UpdateCurrentFocus();
3618 OnIndexChange();
3619 oldIndex_ = currentIndex_;
3620 }
3621
3622 if (edgeEffect == EdgeEffect::NONE) {
3623 auto parent = GetNestedScrollParent();
3624 const bool isForward = NonPositive(dragVelocity);
3625 if (parent && GetNestedScroll().NeedParent(isForward)) {
3626 parent->HandleScrollVelocity(dragVelocity);
3627 }
3628 StartAutoPlay();
3629 UpdateItemRenderGroup(false);
3630 return true;
3631 }
3632 }
3633
3634 return false;
3635 }
3636
UpdateTranslateForCaptureNode(const OffsetF & offset,bool cancel)3637 void SwiperPattern::UpdateTranslateForCaptureNode(const OffsetF& offset, bool cancel)
3638 {
3639 CHECK_NULL_VOID(hasCachedCapture_);
3640 auto leftCaptureNode = GetLeftCaptureNode();
3641 CHECK_NULL_VOID(leftCaptureNode);
3642 auto rightCaptureNode = GetRightCaptureNode();
3643 CHECK_NULL_VOID(rightCaptureNode);
3644 auto leftRenderContext = leftCaptureNode->GetRenderContext();
3645 CHECK_NULL_VOID(leftRenderContext);
3646 auto rightRenderContext = rightCaptureNode->GetRenderContext();
3647 CHECK_NULL_VOID(rightRenderContext);
3648 if (cancel) {
3649 leftRenderContext->CancelTranslateXYAnimation();
3650 rightRenderContext->CancelTranslateXYAnimation();
3651 } else {
3652 leftRenderContext->UpdateTranslateInXY(offset);
3653 rightRenderContext->UpdateTranslateInXY(offset);
3654 captureFinalOffset_ = offset;
3655 }
3656 }
3657
UpdateFinalTranslateForSwiperItem(const SwiperLayoutAlgorithm::PositionMap & itemPosition)3658 void SwiperPattern::UpdateFinalTranslateForSwiperItem(const SwiperLayoutAlgorithm::PositionMap& itemPosition)
3659 {
3660 for (const auto& item : itemPosition) {
3661 auto frameNode = item.second.node;
3662 if (!frameNode) {
3663 continue;
3664 }
3665 auto renderContext = frameNode->GetRenderContext();
3666 if (!renderContext) {
3667 continue;
3668 }
3669 renderContext->UpdateTranslateInXY(item.second.finalOffset);
3670 }
3671 }
3672
UpdateTranslateForSwiperItem(SwiperLayoutAlgorithm::PositionMap & itemPosition,const OffsetF & offset,bool cancel)3673 void SwiperPattern::UpdateTranslateForSwiperItem(SwiperLayoutAlgorithm::PositionMap& itemPosition,
3674 const OffsetF& offset, bool cancel)
3675 {
3676 for (auto& item : itemPosition) {
3677 auto frameNode = item.second.node;
3678 if (!frameNode) {
3679 continue;
3680 }
3681 auto renderContext = frameNode->GetRenderContext();
3682 if (!renderContext) {
3683 continue;
3684 }
3685 if (cancel) {
3686 renderContext->CancelTranslateXYAnimation();
3687 } else {
3688 renderContext->UpdateTranslateInXY(offset);
3689 item.second.finalOffset = offset;
3690 }
3691 }
3692 }
3693
PlayPropertyTranslateAnimation(float translate,int32_t nextIndex,float velocity,bool stopAutoPlay,std::optional<float> pixelRoundTargetPos)3694 void SwiperPattern::PlayPropertyTranslateAnimation(
3695 float translate, int32_t nextIndex, float velocity, bool stopAutoPlay, std::optional<float> pixelRoundTargetPos)
3696 {
3697 if (NearZero(translate)) {
3698 SetIndicatorChangeIndexStatus(false, GetLoopIndex(currentIndex_));
3699 OnAnimationTranslateZero(nextIndex, stopAutoPlay);
3700 return;
3701 }
3702
3703 AnimationOption option;
3704 option.SetDuration(GetDuration());
3705 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
3706 if (iter != frameRateRange_.end()) {
3707 TAG_LOGI(AceLogTag::ACE_SWIPER,
3708 "Property translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}, "
3709 "id: %{public}d",
3710 iter->second->min_, iter->second->max_, iter->second->preferred_, swiperId_);
3711 iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
3712 option.SetFrameRateRange(iter->second);
3713 } else {
3714 option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
3715 }
3716 motionVelocity_ = velocity / translate;
3717 auto curve = GetCurveIncludeMotion();
3718 auto minimumAmplitudeRatio = DEFAULT_MINIMUM_AMPLITUDE_PX / translate;
3719 if (InstanceOf<InterpolatingSpring>(curve) &&
3720 LessNotEqualCustomPrecision(
3721 minimumAmplitudeRatio, InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO)) {
3722 auto interpolatingSpring = AceType::DynamicCast<InterpolatingSpring>(curve);
3723 interpolatingSpring->UpdateMinimumAmplitudeRatio(minimumAmplitudeRatio);
3724 }
3725 option.SetCurve(curve);
3726 option.SetFinishCallbackType(GetFinishCallbackType());
3727 OffsetF offset;
3728 if (GetDirection() == Axis::HORIZONTAL) {
3729 offset.AddX(translate);
3730 } else {
3731 offset.AddY(translate);
3732 }
3733 if (propertyAnimationIsRunning_) {
3734 if (!NeedStartNewAnimation(offset)) {
3735 stopIndicatorAnimation_ = false;
3736 return;
3737 }
3738 std::optional<int32_t> targetIndex;
3739 if (targetIndex_) {
3740 targetIndex = targetIndex_;
3741 }
3742 StopPropertyTranslateAnimation(isFinishAnimation_);
3743 StopIndicatorAnimation();
3744
3745 if (targetIndex) {
3746 targetIndex_ = targetIndex;
3747 MarkDirtyNodeSelf();
3748 return;
3749 }
3750 }
3751 auto finishCallback = [weak = WeakClaim(this), offset]() {
3752 auto swiper = weak.Upgrade();
3753 CHECK_NULL_VOID(swiper);
3754 #ifdef OHOS_PLATFORM
3755 if (swiper->isInAutoPlay_) {
3756 ResSchedReport::GetInstance().ResSchedDataReport("auto_play_off");
3757 }
3758 #endif
3759 if (!swiper->hasTabsAncestor_) {
3760 PerfMonitor::GetPerfMonitor()->EndCommercial(PerfConstants::APP_SWIPER_FLING, true);
3761 } else {
3762 AceAsyncTraceEndCommercial(0, APP_TABS_FLING);
3763 }
3764 swiper->OnPropertyTranslateAnimationFinish(offset);
3765 };
3766 // initial translate info use final offset
3767 UpdateFinalTranslateForSwiperItem(itemPosition_);
3768 UpdateTranslateForCaptureNode(captureFinalOffset_);
3769 auto adOffset = offset;
3770 if (IsHorizontalAndRightToLeft()) {
3771 if (GetDirection() == Axis::HORIZONTAL) {
3772 adOffset.SetX(-adOffset.GetX());
3773 } else {
3774 adOffset.SetY(-adOffset.GetY());
3775 }
3776 }
3777 #ifdef SUPPORT_DIGITAL_CROWN
3778 if (pixelRoundTargetPos.has_value()) {
3779 if (GetDirection() == Axis::HORIZONTAL) {
3780 adOffset.SetX(pixelRoundTargetPos.value());
3781 } else {
3782 adOffset.SetY(pixelRoundTargetPos.value());
3783 }
3784 }
3785 #endif
3786 // property callback will call immediately.
3787 auto propertyUpdateCallback = [swiper = WeakClaim(this), offset = adOffset]() {
3788 auto swiperPattern = swiper.Upgrade();
3789 CHECK_NULL_VOID(swiperPattern);
3790 #ifdef OHOS_PLATFORM
3791 if (swiperPattern->isInAutoPlay_) {
3792 ResSchedReport::GetInstance().ResSchedDataReport("auto_play_on");
3793 }
3794 #endif
3795 if (!swiperPattern->hasTabsAncestor_) {
3796 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_SWIPER_FLING,
3797 PerfActionType::LAST_UP, "");
3798 } else {
3799 AceAsyncTraceBeginCommercial(0, APP_TABS_FLING);
3800 }
3801 TAG_LOGI(AceLogTag::ACE_SWIPER,
3802 "Swiper start property animation with offsetX: %{public}f, offsetY: %{public}f, id: %{public}d",
3803 offset.GetX(), offset.GetY(), swiperPattern->swiperId_);
3804 ACE_SCOPED_TRACE_COMMERCIAL("%s start property animation, X: %f, Y: %f",
3805 swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, offset.GetX(), offset.GetY());
3806 swiperPattern->UpdateTranslateForSwiperItem(swiperPattern->itemPosition_, offset);
3807 swiperPattern->itemPositionInAnimation_ = swiperPattern->itemPosition_;
3808 swiperPattern->UpdateTranslateForCaptureNode(offset);
3809 };
3810 propertyAnimationIsRunning_ = true;
3811 propertyAnimationIndex_ = nextIndex;
3812 FireSelectedEvent(currentIndex_, nextIndex);
3813 FireUnselectedEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex));
3814 ElementRegister::GetInstance()->ReSyncGeometryTransition(GetHost(), option);
3815 AnimationUtils::Animate(option, propertyUpdateCallback, finishCallback);
3816 AnimationCallbackInfo info;
3817 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3818 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3819 info.targetOffset = GetCustomPropertyTargetOffset() - Dimension(translate, DimensionUnit::PX).ConvertToVp();
3820 if (IsHorizontalAndRightToLeft()) {
3821 info.currentOffset =
3822 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3823 info.targetOffset = GetCustomPropertyTargetOffset() - Dimension(-translate, DimensionUnit::PX).ConvertToVp();
3824 }
3825
3826 auto pipeline = GetContext();
3827 CHECK_NULL_VOID(pipeline);
3828 if (GetDuration() == 0) {
3829 // if the duration is 0, the animation will be end immediately, so the start event should be triggered
3830 // after Layout Task to ensure the timing of events.
3831 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3832 auto swiper = weak.Upgrade();
3833 CHECK_NULL_VOID(swiper);
3834 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
3835 swiper->FireAndCleanScrollingListener();
3836 });
3837 } else {
3838 pipeline->AddAfterRenderTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3839 auto swiper = weak.Upgrade();
3840 CHECK_NULL_VOID(swiper);
3841 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
3842 swiper->FireAndCleanScrollingListener();
3843 });
3844 }
3845
3846 // enable lazy load feature.
3847 SetLazyLoadFeature(true);
3848 UpdateItemRenderGroup(true);
3849 }
3850
UpdateOffsetAfterPropertyAnimation(float offset)3851 void SwiperPattern::UpdateOffsetAfterPropertyAnimation(float offset)
3852 {
3853 UpdateCurrentOffset(offset);
3854 auto host = GetHost();
3855 CHECK_NULL_VOID(host);
3856 host->SetLayoutDirtyMarked(true);
3857 auto context = host->GetContext();
3858 if (context) {
3859 context->FlushUITaskWithSingleDirtyNode(host);
3860 context->FlushSyncGeometryNodeTasks();
3861 }
3862 }
3863
OnPropertyTranslateAnimationFinish(const OffsetF & offset)3864 void SwiperPattern::OnPropertyTranslateAnimationFinish(const OffsetF& offset)
3865 {
3866 if (!propertyAnimationIsRunning_) {
3867 // force stop.
3868 return;
3869 }
3870 OffsetF finalOffset =
3871 itemPositionInAnimation_.empty() ? OffsetF()
3872 : itemPositionInAnimation_.begin()->second.node
3873 ? itemPositionInAnimation_.begin()->second.node->GetRenderContext()->GetTranslateXYProperty()
3874 : OffsetF();
3875 TAG_LOGI(AceLogTag::ACE_SWIPER,
3876 "Swiper finish property animation with offsetX: %{public}f, offsetY: %{public}f isVerifiedSuc %{public}d, id: "
3877 "%{public}d",
3878 finalOffset.GetX(), finalOffset.GetY(), !IsItemOverlay(), swiperId_);
3879 ACE_SCOPED_TRACE_COMMERCIAL("%s finish property animation, X: %f, Y: %f isVerifiedSuc %d",
3880 hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, finalOffset.GetX(), finalOffset.GetY(),
3881 !IsItemOverlay());
3882 propertyAnimationIsRunning_ = false;
3883 syncCancelAniIsFailed_ = false;
3884 fastCurrentIndex_.reset();
3885 targetIndex_.reset();
3886 // reset translate.
3887 UpdateTranslateForSwiperItem(itemPositionInAnimation_, OffsetF());
3888 itemPositionInAnimation_.clear();
3889 UpdateTranslateForCaptureNode(OffsetF());
3890 // update postion info.
3891 UpdateOffsetAfterPropertyAnimation(offset.GetMainOffset(GetDirection()));
3892 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
3893 }
3894
PropertyCancelAnimationFinish(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper,bool isInterrupt)3895 void SwiperPattern::PropertyCancelAnimationFinish(
3896 bool isFinishAnimation, bool isBeforeCreateLayoutWrapper, bool isInterrupt)
3897 {
3898 fastCurrentIndex_.reset();
3899 targetIndex_.reset();
3900 OffsetF currentOffset;
3901 for (auto iter = itemPositionInAnimation_.rbegin(); iter != itemPositionInAnimation_.rend(); ++iter) {
3902 auto frameNode = iter->second.node;
3903 auto renderContext = frameNode ? frameNode->GetRenderContext() : nullptr;
3904 if (renderContext) {
3905 currentOffset = renderContext->GetTranslateXYProperty();
3906 break;
3907 }
3908 }
3909 if (IsHorizontalAndRightToLeft()) {
3910 if (GetDirection() == Axis::HORIZONTAL) {
3911 currentOffset.SetX(-currentOffset.GetX());
3912 } else {
3913 currentOffset.SetY(-currentOffset.GetY());
3914 }
3915 }
3916 ACE_SCOPED_TRACE("Swiper stop propertyAni offset %f", currentOffset.GetMainOffset(GetDirection()));
3917 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper stop propertyAni offset %{public}f, id: %{public}d",
3918 currentOffset.GetMainOffset(GetDirection()), swiperId_);
3919 UpdateTranslateForSwiperItem(itemPositionInAnimation_, OffsetF());
3920 itemPositionInAnimation_.clear();
3921 UpdateTranslateForCaptureNode(OffsetF());
3922 if (!isBeforeCreateLayoutWrapper) {
3923 UpdateOffsetAfterPropertyAnimation(currentOffset.GetMainOffset(GetDirection()));
3924 }
3925 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation, true, isInterrupt);
3926 }
3927
StopPropertyTranslateAnimation(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper,bool isInterrupt)3928 void SwiperPattern::StopPropertyTranslateAnimation(
3929 bool isFinishAnimation, bool isBeforeCreateLayoutWrapper, bool isInterrupt)
3930 {
3931 if (!propertyAnimationIsRunning_ || syncCancelAniIsFailed_) {
3932 return;
3933 }
3934 propertyAnimationIsRunning_ = false;
3935 AnimationOption option;
3936 option.SetDuration(0);
3937 option.SetCurve(Curves::LINEAR);
3938 auto propertyUpdateCallback = [weak = WeakClaim(this)]() {
3939 auto swiper = weak.Upgrade();
3940 CHECK_NULL_VOID(swiper);
3941 // cancel translate for swiper item and capture node
3942 swiper->UpdateTranslateForSwiperItem(swiper->itemPositionInAnimation_, OffsetF(), true);
3943 swiper->UpdateTranslateForCaptureNode(OffsetF(), true);
3944 };
3945 AnimationUtils::OpenImplicitAnimation(option, Curves::LINEAR, nullptr);
3946 propertyUpdateCallback();
3947 bool isSyncSuc = AnimationUtils::CloseImplicitCancelAnimation();
3948 if (!isSyncSuc) {
3949 EventReport::ReportScrollableErrorEvent(
3950 "Swiper", ScrollableErrorType::STOP_ANIMATION_TIMEOUT, "Swiper stop propertyAni sync failed");
3951 ACE_SCOPED_TRACE("Swiper stop propertyAni sync failed");
3952 TAG_LOGW(AceLogTag::ACE_SWIPER, "Swiper stop propertyAni sync failed");
3953 // sync cancel animation failed, need to wait for the animation to finish completely
3954 syncCancelAniIsFailed_ = true;
3955 propertyAnimationIsRunning_ = true;
3956 return;
3957 }
3958 PropertyCancelAnimationFinish(isFinishAnimation, isBeforeCreateLayoutWrapper, isInterrupt);
3959 }
3960
InitAnimationCurve()3961 void SwiperPattern::InitAnimationCurve()
3962 {
3963 auto pipelineContext = GetContext();
3964 CHECK_NULL_VOID(pipelineContext);
3965 auto swiperTheme = pipelineContext->GetTheme<SwiperTheme>();
3966 CHECK_NULL_VOID(swiperTheme);
3967 animationCurveStiffness_ = swiperTheme->GetAnimationCurveStiffness();
3968 animationCurveDamping_ = swiperTheme->GetAnimationCurveDamping();
3969 }
3970
GetCurveIncludeMotion()3971 RefPtr<Curve> SwiperPattern::GetCurveIncludeMotion()
3972 {
3973 auto curve = GetCurve();
3974 auto container = Container::Current();
3975 bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
3976 if (isLauncherFeature) {
3977 finishCallbackType_ = FinishCallbackType::LOGICALLY;
3978 }
3979
3980 if (curve) {
3981 if (InstanceOf<SpringCurve>(curve)) {
3982 auto springCurve = DynamicCast<SpringCurve>(curve);
3983 // check velocity to judge if this current velocity.
3984 if (springCurve->GetCurrentVelocity() < 0) {
3985 return AceType::MakeRefPtr<SpringCurve>(
3986 motionVelocity_, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
3987 }
3988 }
3989 if (InstanceOf<InterpolatingSpring>(curve)) {
3990 auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
3991 // check velocity to judge if this current velocity.
3992 if (interpolatingSpring->GetVelocity() < 0) {
3993 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, interpolatingSpring->GetMass(),
3994 interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
3995 }
3996 }
3997 return curve;
3998 }
3999 #ifdef SUPPORT_DIGITAL_CROWN
4000 if (IsCrownSpring()) {
4001 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, 1.0f, 228.0f, 30.0f);
4002 }
4003 #endif
4004 // use spring motion feature.
4005 // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
4006 InitAnimationCurve();
4007 return AceType::MakeRefPtr<InterpolatingSpring>(
4008 motionVelocity_, SWIPER_CURVE_MASS, animationCurveStiffness_, animationCurveDamping_);
4009 }
4010
GetIndicatorHeadCurve()4011 RefPtr<Curve> SwiperPattern::GetIndicatorHeadCurve()
4012 {
4013 auto curve = GetCurve();
4014 auto maxMotionVelocity = static_cast<float>(MAX_INDICATOR_VELOCITY / DEFAULT_INDICATOR_HEAD_DISTANCE.ConvertToPx());
4015 auto motionVelocity = std::min(motionVelocity_, maxMotionVelocity);
4016 if (!curve) {
4017 InitAnimationCurve();
4018 return AceType::MakeRefPtr<InterpolatingSpring>(
4019 motionVelocity, SWIPER_CURVE_MASS, animationCurveStiffness_, animationCurveDamping_);
4020 }
4021
4022 if (InstanceOf<SpringCurve>(curve)) {
4023 auto springCurve = DynamicCast<SpringCurve>(curve);
4024 if (springCurve->GetCurrentVelocity() < 0) {
4025 return AceType::MakeRefPtr<SpringCurve>(
4026 motionVelocity, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
4027 }
4028 }
4029
4030 if (InstanceOf<InterpolatingSpring>(curve)) {
4031 auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
4032 if (interpolatingSpring->GetVelocity() < 0) {
4033 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity, interpolatingSpring->GetMass(),
4034 interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
4035 }
4036 }
4037
4038 return curve;
4039 }
4040
PlayIndicatorTranslateAnimation(float translate,std::optional<int32_t> nextIndex)4041 void SwiperPattern::PlayIndicatorTranslateAnimation(float translate, std::optional<int32_t> nextIndex)
4042 {
4043 if (!stopIndicatorAnimation_) {
4044 stopIndicatorAnimation_ = true;
4045 return;
4046 }
4047 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
4048 if (!HasIndicatorNode() && !turnPageRateCallback) {
4049 return;
4050 }
4051 CheckMarkDirtyNodeForRenderIndicator(translate, nextIndex);
4052 AnimationUtils::StopAnimation(indicatorAnimation_);
4053 indicatorAnimationIsRunning_ = false;
4054 if (itemPosition_.empty()) {
4055 return;
4056 }
4057
4058 auto host = GetHost();
4059 CHECK_NULL_VOID(host);
4060 auto weak = AceType::WeakClaim(this);
4061 host->CreateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0, [weak](float value) {
4062 auto swiper = weak.Upgrade();
4063 CHECK_NULL_VOID(swiper);
4064 const auto& turnPageRateCallback = swiper->swiperController_->GetTurnPageRateCallback();
4065 auto firstItem = swiper->GetFirstItemInfoInVisibleArea();
4066 auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
4067 if (turnPageRateCallback && !NearZero(translateLength)) {
4068 turnPageRateCallback(firstItem.first, (-firstItem.second.startPos - value) / translateLength);
4069 }
4070 });
4071
4072 AnimationOption option;
4073 option.SetDuration(GetDuration());
4074 option.SetCurve(Curves::LINEAR);
4075
4076 host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0);
4077 indicatorAnimationIsRunning_ = true;
4078 indicatorAnimation_ = AnimationUtils::StartAnimation(
4079 option,
4080 [weakHost = WeakClaim(RawPtr(host)), translate]() {
4081 auto host = weakHost.Upgrade();
4082 CHECK_NULL_VOID(host);
4083 host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, translate);
4084 },
4085 [weak]() {
4086 auto swiperPattern = weak.Upgrade();
4087 CHECK_NULL_VOID(swiperPattern);
4088 swiperPattern->indicatorAnimationIsRunning_ = false;
4089 });
4090 }
4091
PlayTranslateAnimation(float startPos,float endPos,int32_t nextIndex,bool restartAutoPlay,float velocity)4092 void SwiperPattern::PlayTranslateAnimation(
4093 float startPos, float endPos, int32_t nextIndex, bool restartAutoPlay, float velocity)
4094 {
4095 if (translateAnimationIsRunning_) {
4096 return;
4097 }
4098 if (NearZero(endPos - startPos)) {
4099 OnAnimationTranslateZero(nextIndex, restartAutoPlay);
4100 return;
4101 }
4102
4103 if (HasIndicatorNode()) {
4104 CheckMarkDirtyNodeForRenderIndicator(endPos - startPos, nextIndex);
4105 }
4106
4107 auto host = GetHost();
4108 CHECK_NULL_VOID(host);
4109 auto weak = AceType::WeakClaim(this);
4110 host->CreateAnimatablePropertyFloat(
4111 TRANSLATE_PROPERTY_NAME, 0,
4112 [weak](float value) {
4113 auto swiper = weak.Upgrade();
4114 CHECK_NULL_VOID(swiper);
4115 // currentDelta_ needs to be adjusted when the previous frame has not been processed.
4116 value += swiper->currentDelta_;
4117 swiper->UpdateCurrentOffset(static_cast<float>(value - swiper->currentOffset_));
4118 },
4119 PropertyUnit::PIXEL_POSITION);
4120
4121 AnimationOption option;
4122 auto duration = GetDuration();
4123 bool finishAnimation = (duration == 0);
4124 motionVelocity_ = velocity / (endPos - startPos);
4125 option.SetCurve(GetCurveIncludeMotion());
4126 option.SetDuration(duration);
4127 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
4128 if (iter != frameRateRange_.end()) {
4129 TAG_LOGI(AceLogTag::ACE_SWIPER,
4130 "Translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}",
4131 iter->second->min_, iter->second->max_, iter->second->preferred_);
4132 iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
4133 option.SetFrameRateRange(iter->second);
4134 } else {
4135 option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
4136 }
4137 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, startPos);
4138 translateAnimationIsRunning_ = true;
4139 propertyAnimationIndex_ = nextIndex;
4140 translateAnimationEndPos_ = endPos;
4141 translateAnimation_ = AnimationUtils::StartAnimation(
4142 option,
4143 [weak, startPos, endPos, nextIndex, velocity]() {
4144 auto swiper = weak.Upgrade();
4145 CHECK_NULL_VOID(swiper);
4146 auto host = swiper->GetHost();
4147 CHECK_NULL_VOID(host);
4148 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, endPos);
4149 AceAsyncTraceBeginCommercial(
4150 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
4151 AnimationCallbackInfo info;
4152 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
4153 info.currentOffset = swiper->GetCustomPropertyOffset() +
4154 Dimension(swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4155 info.targetOffset =
4156 swiper->GetCustomPropertyTargetOffset() + Dimension(startPos - endPos, DimensionUnit::PX).ConvertToVp();
4157 if (swiper->IsHorizontalAndRightToLeft()) {
4158 info.currentOffset = swiper->GetCustomPropertyOffset() +
4159 Dimension(-swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4160 }
4161 swiper->FireSelectedEvent(
4162 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex));
4163 swiper->FireUnselectedEvent(
4164 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex));
4165 swiper->FireAnimationStartEvent(
4166 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex), info);
4167 swiper->FireAndCleanScrollingListener();
4168 },
4169 [weak, finishAnimation]() {
4170 auto swiper = weak.Upgrade();
4171 CHECK_NULL_VOID(swiper);
4172 AceAsyncTraceEndCommercial(
4173 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
4174 if (finishAnimation && swiper->translateAnimationIsRunning_) {
4175 swiper->isFinishAnimation_ = true;
4176 }
4177 swiper->fastCurrentIndex_.reset();
4178 swiper->targetIndex_.reset();
4179 swiper->OnTranslateAnimationFinish();
4180 });
4181
4182 SetLazyLoadFeature(true);
4183 UpdateItemRenderGroup(true);
4184 }
4185
OnSpringAnimationStart(float velocity)4186 void SwiperPattern::OnSpringAnimationStart(float velocity)
4187 {
4188 AnimationCallbackInfo info;
4189 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
4190 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4191 if (IsHorizontalAndRightToLeft()) {
4192 info.currentOffset =
4193 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4194 }
4195
4196 nextIndex_ = ComputeNextIndexByVelocity(velocity, true);
4197 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
4198 info.targetOffset = info.currentOffset;
4199 } else {
4200 FireWillShowEvent(nextIndex_);
4201 FireWillHideEvent(currentIndex_);
4202 auto iter = itemPosition_.find(nextIndex_);
4203 auto nextOffset = iter != itemPosition_.end() ? iter->second.startPos : 0.0f;
4204 info.targetOffset = GetCustomPropertyTargetOffset() + Dimension(nextOffset, DimensionUnit::PX).ConvertToVp();
4205 }
4206
4207 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
4208 }
4209
OnSpringAnimationFinish()4210 void SwiperPattern::OnSpringAnimationFinish()
4211 {
4212 if (!springAnimationIsRunning_) {
4213 return;
4214 }
4215 PerfMonitor::GetPerfMonitor()->EndCommercial(PerfConstants::APP_LIST_FLING, false);
4216 AceAsyncTraceEndCommercial(0, TRAILING_ANIMATION);
4217 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper finish spring animation offset %{public}f, id: %{public}d",
4218 currentIndexOffset_, swiperId_);
4219 ACE_SCOPED_TRACE_COMMERCIAL("%s finish spring animation, offset: %f",
4220 hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, currentIndexOffset_);
4221 springAnimationIsRunning_ = false;
4222 isTouchDownSpringAnimation_ = false;
4223 OnSpringAndFadeAnimationFinish();
4224 }
4225
EstimateSpringOffset(float realOffset)4226 float SwiperPattern::EstimateSpringOffset(float realOffset)
4227 {
4228 float springOffset = 0.0f;
4229 if (GetEdgeEffect() != EdgeEffect::SPRING || !IsOutOfBoundary() || NearEqual(realOffset, 0.0f)) {
4230 return springOffset;
4231 }
4232 auto visibleSize = CalculateVisibleSize();
4233 if (LessOrEqual(visibleSize, 0.0f)) {
4234 return springOffset;
4235 }
4236 constexpr float MIN_FRICTION = 0.419f;
4237 auto absRealOffset = std::abs(realOffset);
4238 auto start = absRealOffset;
4239 auto end = std::min(visibleSize, absRealOffset / MIN_FRICTION);
4240 while (LessNotEqual(start, end)) {
4241 constexpr float factor = 0.5f;
4242 springOffset = (start + end) * factor;
4243 auto estimate = springOffset * SwiperHelper::CalculateFriction(springOffset / visibleSize);
4244 if (NearEqual(estimate, absRealOffset)) {
4245 break;
4246 }
4247 if (estimate < absRealOffset) {
4248 start = springOffset;
4249 } else {
4250 end = springOffset;
4251 }
4252 }
4253 if (springOffset > 0 && realOffset < 0) {
4254 springOffset = -springOffset;
4255 }
4256 if (NearZero(springOffset)) {
4257 springOffset = 0.0f;
4258 }
4259 return springOffset;
4260 }
4261
OnSpringAndFadeAnimationFinish()4262 void SwiperPattern::OnSpringAndFadeAnimationFinish()
4263 {
4264 auto itemInfoInVisibleArea = std::make_pair(0, SwiperItemInfo {});
4265 if (!itemPosition_.empty()) {
4266 auto item = itemPosition_.find(nextIndex_);
4267 itemInfoInVisibleArea =
4268 std::make_pair(item->first, SwiperItemInfo { item->second.startPos, item->second.endPos });
4269 }
4270 if (GetLoopIndex(currentIndex_) != GetLoopIndex(nextIndex_)) {
4271 UpdateCurrentIndex(nextIndex_);
4272 UpdateCurrentFocus();
4273 OnIndexChange();
4274 oldIndex_ = currentIndex_;
4275 }
4276 AnimationCallbackInfo info;
4277 auto indexStartPos = itemInfoInVisibleArea.second.startPos;
4278 info.currentOffset = GetCustomPropertyOffset() + Dimension(indexStartPos, DimensionUnit::PX).ConvertToVp();
4279 if (IsHorizontalAndRightToLeft()) {
4280 info.currentOffset = GetCustomPropertyOffset() + Dimension(-indexStartPos, DimensionUnit::PX).ConvertToVp();
4281 }
4282 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
4283 currentIndexOffset_ = indexStartPos;
4284 springOffset_ = EstimateSpringOffset(currentIndexOffset_);
4285 UpdateItemRenderGroup(false);
4286 NotifyParentScrollEnd();
4287
4288 if (!isTouchDown_) {
4289 StartAutoPlay();
4290 }
4291
4292 fadeAnimationIsRunning_ = false;
4293 isTouchDownFadeAnimation_ = false;
4294 }
4295
OnFadeAnimationStart()4296 void SwiperPattern::OnFadeAnimationStart()
4297 {
4298 AnimationCallbackInfo info;
4299 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4300 if (IsHorizontalAndRightToLeft()) {
4301 info.currentOffset =
4302 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4303 }
4304 nextIndex_ = ComputeNextIndexByVelocity(0.0);
4305 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
4306 info.targetOffset = info.currentOffset;
4307 } else {
4308 FireWillShowEvent(nextIndex_);
4309 FireWillHideEvent(currentIndex_);
4310 info.targetOffset = GetCustomPropertyTargetOffset();
4311 }
4312
4313 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
4314 fadeAnimationIsRunning_ = true;
4315 }
4316
PlayFadeAnimation()4317 void SwiperPattern::PlayFadeAnimation()
4318 {
4319 if (NearZero(fadeOffset_)) {
4320 fadeAnimationIsRunning_ = false;
4321 return;
4322 }
4323
4324 auto host = GetHost();
4325 CHECK_NULL_VOID(host);
4326 auto weak = AceType::WeakClaim(this);
4327 host->CreateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0, Animation<double>::ValueCallback([weak](float value) {
4328 auto swiper = weak.Upgrade();
4329 if (swiper && swiper->GetHost() && !swiper->isTouchDown_) {
4330 swiper->fadeOffset_ = value;
4331 swiper->GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4332 }
4333 }));
4334
4335 AnimationOption option;
4336 option.SetDuration(FADE_DURATION);
4337 option.SetCurve(Curves::LINEAR);
4338
4339 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, fadeOffset_);
4340 nextIndex_ = currentIndex_;
4341 fadeAnimation_ = AnimationUtils::StartAnimation(
4342 option,
4343 [weak]() {
4344 auto swiperPattern = weak.Upgrade();
4345 CHECK_NULL_VOID(swiperPattern);
4346 swiperPattern->OnFadeAnimationStart();
4347 auto host = swiperPattern->GetHost();
4348 CHECK_NULL_VOID(host);
4349 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0.f);
4350 },
4351 [weak]() {
4352 auto swiperPattern = weak.Upgrade();
4353 CHECK_NULL_VOID(swiperPattern);
4354 swiperPattern->OnSpringAndFadeAnimationFinish();
4355 });
4356 }
4357
CreateSpringProperty()4358 void SwiperPattern::CreateSpringProperty()
4359 {
4360 auto host = GetHost();
4361 CHECK_NULL_VOID(host);
4362 host->CreateAnimatablePropertyFloat(
4363 SPRING_PROPERTY_NAME, 0,
4364 [weak = AceType::WeakClaim(this)](float position) {
4365 auto swiper = weak.Upgrade();
4366 CHECK_NULL_VOID(swiper);
4367 auto positionDelta = static_cast<float>(position) - swiper->currentIndexOffset_;
4368 swiper->UpdateCurrentOffset(positionDelta);
4369 if (LessNotEqual(std::abs(positionDelta), 1) && !NearZero(positionDelta)) {
4370 AceAsyncTraceBeginCommercial(0, TRAILING_ANIMATION);
4371 }
4372 },
4373 PropertyUnit::PIXEL_POSITION);
4374 }
4375
PlaySpringAnimation(double dragVelocity)4376 void SwiperPattern::PlaySpringAnimation(double dragVelocity)
4377 {
4378 UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart());
4379 if (RunningTranslateAnimation()) {
4380 return;
4381 }
4382 auto host = GetHost();
4383 CHECK_NULL_VOID(host);
4384 auto mainSize = CalculateVisibleSize();
4385 if (LessOrEqual(mainSize, 0) || itemPosition_.empty()) {
4386 return;
4387 }
4388 childScrolling_ = false;
4389 auto leading = currentIndexOffset_ + mainSize - itemPosition_.rbegin()->second.endPos;
4390 auto trailing = currentIndexOffset_ - itemPosition_.begin()->second.startPos;
4391 ExtentPair extentPair = ExtentPair(leading, trailing);
4392 CreateSpringProperty();
4393 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, currentIndexOffset_);
4394 auto delta = currentIndexOffset_ < 0.0f ? extentPair.Leading() : extentPair.Trailing();
4395 if (IsVisibleChildrenSizeLessThanSwiper()) {
4396 delta = extentPair.Trailing();
4397 }
4398 // spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
4399 auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
4400 AnimationOption option;
4401 option.SetCurve(springCurve);
4402 option.SetDuration(SPRING_DURATION);
4403 nextIndex_ = currentIndex_;
4404 springAnimation_ = AnimationUtils::StartAnimation(
4405 option,
4406 [weak = AceType::WeakClaim(this), delta]() {
4407 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_LIST_FLING,
4408 PerfActionType::FIRST_MOVE, "");
4409 auto swiperPattern = weak.Upgrade();
4410 CHECK_NULL_VOID(swiperPattern);
4411 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper start spring animation with offset:%{public}f, id:%{public}d",
4412 delta, swiperPattern->swiperId_);
4413 ACE_SCOPED_TRACE_COMMERCIAL(
4414 "%s start spring animation", swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG);
4415 auto host = swiperPattern->GetHost();
4416 CHECK_NULL_VOID(host);
4417 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, delta);
4418 },
4419 [weak = AceType::WeakClaim(this)]() {
4420 auto swiperPattern = weak.Upgrade();
4421 CHECK_NULL_VOID(swiperPattern);
4422 swiperPattern->OnSpringAnimationFinish();
4423 });
4424 OnSpringAnimationStart(static_cast<float>(dragVelocity));
4425 springAnimationIsRunning_ = true;
4426 }
4427
IsOutOfBoundary(float mainOffset) const4428 bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
4429 {
4430 if (IsLoop() || itemPosition_.empty()) {
4431 return false;
4432 }
4433
4434 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
4435 startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
4436 auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
4437 auto visibleWindowSize = CalculateVisibleSize();
4438 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
4439 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
4440 auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
4441 return isOutOfStart || isOutOfEnd;
4442 }
4443
IsOutOfStart(float mainOffset) const4444 bool SwiperPattern::IsOutOfStart(float mainOffset) const
4445 {
4446 if (IsLoop() || itemPosition_.empty()) {
4447 return false;
4448 }
4449
4450 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
4451 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
4452 return itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.f);
4453 }
4454
IsOutOfEnd(float mainOffset) const4455 bool SwiperPattern::IsOutOfEnd(float mainOffset) const
4456 {
4457 if (IsLoop() || itemPosition_.empty()) {
4458 return false;
4459 }
4460
4461 auto visibleWindowSize = CalculateVisibleSize();
4462 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
4463 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
4464 return itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
4465 }
4466
IsAtStart() const4467 bool SwiperPattern::IsAtStart() const
4468 {
4469 if (IsLoop() || itemPosition_.empty()) {
4470 return false;
4471 }
4472
4473 auto startPos = itemPosition_.begin()->second.startPos;
4474 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
4475 return itemPosition_.begin()->first == 0 && GreatOrEqual(startPos, 0.f);
4476 }
4477
IsAtEnd() const4478 bool SwiperPattern::IsAtEnd() const
4479 {
4480 if (IsLoop() || itemPosition_.empty()) {
4481 return false;
4482 }
4483
4484 auto visibleWindowSize = CalculateVisibleSize();
4485 auto endPos = itemPosition_.rbegin()->second.endPos;
4486 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
4487 return itemPosition_.rbegin()->first == TotalCount() - 1 && LessOrEqual(endPos, visibleWindowSize);
4488 }
4489
AutoLinearIsOutOfBoundary(float mainOffset) const4490 bool SwiperPattern::AutoLinearIsOutOfBoundary(float mainOffset) const
4491 {
4492 // Check the scenario where all child nodes are within the window but isloop is true。
4493 if (!IsLoop() || itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
4494 return false;
4495 }
4496
4497 auto startPos = itemPosition_.begin()->second.startPos;
4498 auto isOutOfStart = GreatNotEqual(startPos + mainOffset, 0.0);
4499
4500 auto visibleWindowSize = CalculateVisibleSize();
4501 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
4502 auto isOutOfEnd = LessNotEqual(endPos, visibleWindowSize);
4503
4504 return isOutOfStart || isOutOfEnd;
4505 }
4506
GetDistanceToEdge() const4507 float SwiperPattern::GetDistanceToEdge() const
4508 {
4509 if (IsLoop() || itemPosition_.empty()) {
4510 return 0.0f;
4511 }
4512 if (itemPosition_.begin()->first == 0) {
4513 return -itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
4514 }
4515 auto visibleWindowSize = CalculateVisibleSize();
4516 return itemPosition_.rbegin()->second.endPos - visibleWindowSize + AdjustIgnoreBlankOverScrollOffSet(false);
4517 }
4518
MainSize() const4519 float SwiperPattern::MainSize() const
4520 {
4521 auto host = GetHost();
4522 CHECK_NULL_RETURN(host, 0.0);
4523 auto geometryNode = host->GetGeometryNode();
4524 CHECK_NULL_RETURN(geometryNode, 0.0);
4525 return geometryNode->GetFrameSize().MainSize(GetDirection());
4526 }
4527
GetMainContentSize() const4528 float SwiperPattern::GetMainContentSize() const
4529 {
4530 auto host = GetHost();
4531 CHECK_NULL_RETURN(host, 0.0);
4532 auto geometryNode = host->GetGeometryNode();
4533 CHECK_NULL_RETURN(geometryNode, 0.0);
4534 return geometryNode->GetPaddingSize().Width();
4535 }
4536
GetItemSpace() const4537 float SwiperPattern::GetItemSpace() const
4538 {
4539 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4540 CHECK_NULL_RETURN(props, 0.0f);
4541 if (props->IgnoreItemSpace()) {
4542 return 0.0f;
4543 }
4544 auto itemSpace = props->GetItemSpace().value_or(0.0_vp).ConvertToPx();
4545 auto host = GetHost();
4546 CHECK_NULL_RETURN(host, 0.0f);
4547 auto geometryNode = host->GetGeometryNode();
4548 CHECK_NULL_RETURN(geometryNode, 0.0f);
4549 auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
4550 if (itemSpace > mainSize) {
4551 itemSpace = 0.0f;
4552 }
4553 return itemSpace;
4554 }
4555
IsCachedShow() const4556 bool SwiperPattern::IsCachedShow() const
4557 {
4558 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4559 CHECK_NULL_RETURN(props, false);
4560 return props->GetCachedIsShown().value_or(false);
4561 }
4562
GetPrevMargin() const4563 float SwiperPattern::GetPrevMargin() const
4564 {
4565 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4566 CHECK_NULL_RETURN(props, 0.0f);
4567 return props->GetCalculatedPrevMargin();
4568 }
4569
GetNextMargin() const4570 float SwiperPattern::GetNextMargin() const
4571 {
4572 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4573 CHECK_NULL_RETURN(props, 0.0f);
4574 return props->GetCalculatedNextMargin();
4575 }
4576
GetDirection() const4577 Axis SwiperPattern::GetDirection() const
4578 {
4579 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4580 CHECK_NULL_RETURN(props, Axis::HORIZONTAL);
4581 return props->GetDirection().value_or(Axis::HORIZONTAL);
4582 }
4583
CurrentIndex() const4584 int32_t SwiperPattern::CurrentIndex() const
4585 {
4586 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4587 CHECK_NULL_RETURN(props, 0);
4588 return props->GetIndex().value_or(0);
4589 }
4590
GetDisplayCount() const4591 int32_t SwiperPattern::GetDisplayCount() const
4592 {
4593 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4594 CHECK_NULL_RETURN(props, 1);
4595 auto displayCount = CalculateDisplayCount();
4596 return displayCount;
4597 }
4598
CalculateDisplayCount() const4599 int32_t SwiperPattern::CalculateDisplayCount() const
4600 {
4601 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4602 CHECK_NULL_RETURN(props, 1);
4603 bool isAutoFill = IsAutoFill();
4604 if (isAutoFill) {
4605 auto minSize = props->GetMinSize()->ConvertToPx();
4606 float contentWidth = GetMainContentSize();
4607 auto displayCount =
4608 CalculateCount(contentWidth, minSize, SWIPER_MARGIN.ConvertToPx(), SWIPER_GUTTER.ConvertToPx());
4609 if (LessOrEqual(minSize, 0)) {
4610 displayCount = 1;
4611 }
4612
4613 displayCount = displayCount > 0 ? displayCount : 1;
4614 auto totalCount = TotalCount();
4615 displayCount = displayCount > totalCount ? totalCount : displayCount;
4616 auto displayCountProperty = props->GetDisplayCount().value_or(1);
4617 if (displayCountProperty != displayCount) {
4618 props->UpdateDisplayCount(displayCount);
4619 auto host = GetHost();
4620 CHECK_NULL_RETURN(host, 1);
4621 host->MarkDirtyNode(
4622 (crossMatchChild_ ? PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD : PROPERTY_UPDATE_MEASURE_SELF) |
4623 PROPERTY_UPDATE_RENDER);
4624 }
4625 return displayCount;
4626 } else {
4627 return props->GetDisplayCount().value_or(1);
4628 }
4629 }
4630
CalculateCount(float contentWidth,float minSize,float margin,float gutter,float swiperPadding) const4631 int32_t SwiperPattern::CalculateCount(
4632 float contentWidth, float minSize, float margin, float gutter, float swiperPadding) const
4633 {
4634 return static_cast<int32_t>(floor((contentWidth - 2 * margin + gutter - 2 * swiperPadding) / (minSize + gutter)));
4635 }
4636
IsAutoFill() const4637 bool SwiperPattern::IsAutoFill() const
4638 {
4639 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4640 CHECK_NULL_RETURN(props, false);
4641 return props->GetMinSize().has_value();
4642 }
4643
IsAutoPlay() const4644 bool SwiperPattern::IsAutoPlay() const
4645 {
4646 auto props = GetPaintProperty<SwiperPaintProperty>();
4647 CHECK_NULL_RETURN(props, false);
4648 return props->GetAutoPlay().value_or(false);
4649 }
4650
GetDuration() const4651 int32_t SwiperPattern::GetDuration() const
4652 {
4653 const int32_t DEFAULT_DURATION = 400;
4654 auto props = GetPaintProperty<SwiperPaintProperty>();
4655 CHECK_NULL_RETURN(props, DEFAULT_DURATION);
4656 return props->GetDuration().value_or(DEFAULT_DURATION);
4657 }
4658
GetInterval() const4659 int32_t SwiperPattern::GetInterval() const
4660 {
4661 const int32_t DEFAULT_INTERVAL = 3000;
4662 auto props = GetPaintProperty<SwiperPaintProperty>();
4663 CHECK_NULL_RETURN(props, DEFAULT_INTERVAL);
4664 return props->GetAutoPlayInterval().value_or(DEFAULT_INTERVAL);
4665 }
4666
GetCurve() const4667 RefPtr<Curve> SwiperPattern::GetCurve() const
4668 {
4669 auto props = GetPaintProperty<SwiperPaintProperty>();
4670 CHECK_NULL_RETURN(props, nullptr);
4671 return props->GetCurve().value_or(nullptr);
4672 }
4673
IsLoop() const4674 bool SwiperPattern::IsLoop() const
4675 {
4676 if (hasCachedCapture_) {
4677 return true;
4678 }
4679 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4680 CHECK_NULL_RETURN(props, true);
4681 if (TotalDisPlayCount() > TotalCount() ||
4682 (TotalDisPlayCount() == TotalCount() && SwiperUtils::IsStretch(props) &&
4683 (NonPositive(props->GetCalculatedPrevMargin()) || NonPositive(props->GetCalculatedNextMargin())))) {
4684 return false;
4685 }
4686 return props->GetLoop().value_or(true);
4687 }
4688
IsEnabled() const4689 bool SwiperPattern::IsEnabled() const
4690 {
4691 auto props = GetPaintProperty<SwiperPaintProperty>();
4692 CHECK_NULL_RETURN(props, true);
4693 return props->GetEnabled().value_or(true);
4694 }
4695
GetEdgeEffect() const4696 EdgeEffect SwiperPattern::GetEdgeEffect() const
4697 {
4698 auto props = GetPaintProperty<SwiperPaintProperty>();
4699 CHECK_NULL_RETURN(props, EdgeEffect::SPRING);
4700 return props->GetEdgeEffect().value_or(EdgeEffect::SPRING);
4701 }
4702
IsDisableSwipe() const4703 bool SwiperPattern::IsDisableSwipe() const
4704 {
4705 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4706 CHECK_NULL_RETURN(props, false);
4707 return props->GetDisableSwipe().value_or(false);
4708 }
4709
IsShowIndicator() const4710 bool SwiperPattern::IsShowIndicator() const
4711 {
4712 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4713 CHECK_NULL_RETURN(props, true);
4714 return props->GetShowIndicatorValue(true);
4715 }
4716
IsShowArrow() const4717 bool SwiperPattern::IsShowArrow() const
4718 {
4719 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4720 CHECK_NULL_RETURN(props, true);
4721 return props->GetDisplayArrowValue(false);
4722 }
4723
GetIndicatorType() const4724 SwiperIndicatorType SwiperPattern::GetIndicatorType() const
4725 {
4726 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4727 CHECK_NULL_RETURN(props, SwiperIndicatorType::DOT);
4728 return props->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
4729 }
4730
GetSwiperParameters() const4731 std::shared_ptr<SwiperParameters> SwiperPattern::GetSwiperParameters() const
4732 {
4733 if (swiperParameters_ == nullptr) {
4734 swiperParameters_ = std::make_shared<SwiperParameters>();
4735 auto pipelineContext = PipelineBase::GetCurrentContext();
4736 CHECK_NULL_RETURN(pipelineContext, swiperParameters_);
4737 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4738 CHECK_NULL_RETURN(swiperIndicatorTheme, swiperParameters_);
4739 swiperParameters_->itemWidth = swiperIndicatorTheme->GetSize();
4740 swiperParameters_->itemHeight = swiperIndicatorTheme->GetSize();
4741 swiperParameters_->selectedItemWidth = swiperIndicatorTheme->GetSize();
4742 swiperParameters_->selectedItemHeight = swiperIndicatorTheme->GetSize();
4743 swiperParameters_->maskValue = false;
4744 swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
4745 swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
4746 swiperParameters_->maxDisplayCountVal = 0;
4747 swiperParameters_->dimSpace = swiperIndicatorTheme->GetIndicatorDotItemSpace();
4748 swiperParameters_->ignoreSizeValue = false;
4749 swiperParameters_->setIgnoreSizeValue = false;
4750 }
4751 return swiperParameters_;
4752 }
4753
GetSwiperDigitalParameters() const4754 std::shared_ptr<SwiperDigitalParameters> SwiperPattern::GetSwiperDigitalParameters() const
4755 {
4756 if (swiperDigitalParameters_ == nullptr) {
4757 swiperDigitalParameters_ = std::make_shared<SwiperDigitalParameters>();
4758 auto pipelineContext = PipelineBase::GetCurrentContext();
4759 CHECK_NULL_RETURN(pipelineContext, swiperDigitalParameters_);
4760 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4761 swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
4762 swiperDigitalParameters_->selectedFontColor =
4763 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
4764 swiperDigitalParameters_->fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
4765 swiperDigitalParameters_->selectedFontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
4766 swiperDigitalParameters_->fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
4767 swiperDigitalParameters_->selectedFontWeight =
4768 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
4769 swiperDigitalParameters_->ignoreSizeValue = false;
4770 swiperDigitalParameters_->setIgnoreSizeValue = false;
4771 }
4772 return swiperDigitalParameters_;
4773 }
4774
TotalCount() const4775 int32_t SwiperPattern::TotalCount() const
4776 {
4777 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4778 CHECK_NULL_RETURN(props, 1);
4779 auto displayCount = props->GetDisplayCount().value_or(1);
4780 auto totalCount = RealTotalCount();
4781 if (IsSwipeByGroup() && displayCount != 0) {
4782 totalCount =
4783 static_cast<int32_t>(std::ceil(static_cast<float>(totalCount) / static_cast<float>(displayCount))) *
4784 displayCount;
4785 }
4786
4787 return totalCount;
4788 }
4789
RealTotalCount() const4790 int32_t SwiperPattern::RealTotalCount() const
4791 {
4792 auto host = GetHost();
4793 CHECK_NULL_RETURN(host, 0);
4794 // last child is swiper indicator
4795 int num = 0;
4796 if (!isBindIndicator_ && IsShowIndicator() && HasIndicatorNode()) {
4797 num += 1;
4798 }
4799 if (HasLeftButtonNode()) {
4800 num += 1;
4801 }
4802 if (HasRightButtonNode()) {
4803 num += 1;
4804 }
4805 if (hasCachedCapture_ && leftCaptureId_.has_value() && rightCaptureId_.has_value()) {
4806 num += CAPTURE_COUNT;
4807 }
4808 return host->TotalChildCount() - num;
4809 }
4810
DisplayIndicatorTotalCount() const4811 int32_t SwiperPattern::DisplayIndicatorTotalCount() const
4812 {
4813 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
4814 return RealTotalCount();
4815 }
4816
4817 auto displayCount = GetDisplayCount();
4818 auto realTotalCount = RealTotalCount();
4819 if (realTotalCount <= 0) {
4820 return 0;
4821 }
4822 if (realTotalCount <= displayCount) {
4823 return 1;
4824 }
4825 if (IsSwipeByGroup() && displayCount != 0) {
4826 int32_t totalPages = 0;
4827 totalPages = realTotalCount / displayCount;
4828
4829 if (realTotalCount % displayCount) {
4830 totalPages++;
4831 }
4832
4833 return totalPages;
4834 } else {
4835 if (IsLoop()) {
4836 return realTotalCount;
4837 } else {
4838 return realTotalCount - displayCount + 1;
4839 }
4840 }
4841 }
4842
GetFirstItemInfoInVisibleArea() const4843 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetFirstItemInfoInVisibleArea() const
4844 {
4845 if (itemPosition_.empty()) {
4846 return std::make_pair(0, SwiperItemInfo {});
4847 }
4848 for (const auto& item : itemPosition_) {
4849 if (item.second.startPos < 0 && item.second.endPos < 0) {
4850 continue;
4851 }
4852 if (item.second.startPos <= 0 && item.second.endPos > 0) {
4853 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
4854 }
4855 if (item.second.startPos > 0 && item.second.endPos > 0) {
4856 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
4857 }
4858 }
4859 return std::make_pair(itemPosition_.begin()->first,
4860 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
4861 }
4862
GetFirstIndexInVisibleArea() const4863 int32_t SwiperPattern::GetFirstIndexInVisibleArea() const
4864 {
4865 if (itemPosition_.empty()) {
4866 return 0;
4867 }
4868 for (const auto& item : itemPosition_) {
4869 if (Negative(item.second.startPos) && Negative(item.second.endPos)) {
4870 continue;
4871 }
4872 if (Positive(item.second.endPos)) {
4873 return item.first;
4874 }
4875 }
4876 return itemPosition_.begin()->first;
4877 }
4878
GetLastItemInfoInVisibleArea() const4879 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetLastItemInfoInVisibleArea() const
4880 {
4881 if (itemPosition_.empty()) {
4882 return std::make_pair(0, SwiperItemInfo {});
4883 }
4884 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4885 auto lastItemIndex = firstItemInfoInVisibleArea.first + GetDisplayCount() - 1;
4886 auto iter = itemPosition_.find(lastItemIndex);
4887 if (iter != itemPosition_.end()) {
4888 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
4889 }
4890 return std::make_pair(itemPosition_.rbegin()->first,
4891 SwiperItemInfo { itemPosition_.rbegin()->second.startPos, itemPosition_.rbegin()->second.endPos });
4892 }
4893
GetSecondItemInfoInVisibleArea() const4894 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetSecondItemInfoInVisibleArea() const
4895 {
4896 if (itemPosition_.empty()) {
4897 return std::make_pair(0, SwiperItemInfo {});
4898 }
4899 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4900 auto secondItemIndex = firstItemInfoInVisibleArea.first + 1;
4901 auto iter = itemPosition_.find(secondItemIndex);
4902 if (iter != itemPosition_.end()) {
4903 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
4904 }
4905 return std::make_pair(itemPosition_.begin()->first,
4906 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
4907 }
4908
IsOutOfHotRegion(const PointF & dragPoint) const4909 bool SwiperPattern::IsOutOfHotRegion(const PointF& dragPoint) const
4910 {
4911 auto host = GetHost();
4912 CHECK_NULL_RETURN(host, true);
4913 auto context = host->GetRenderContext();
4914 CHECK_NULL_RETURN(context, true);
4915
4916 auto hotRegion = context->GetPaintRectWithoutTransform();
4917 return !hotRegion.IsInRegion(dragPoint + OffsetF(hotRegion.GetX(), hotRegion.GetY()));
4918 }
4919
UpdatePaintProperty(const RefPtr<FrameNode> & indicatorNode)4920 void SwiperPattern::UpdatePaintProperty(const RefPtr<FrameNode>& indicatorNode)
4921 {
4922 CHECK_NULL_VOID(indicatorNode);
4923 auto paintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
4924 CHECK_NULL_VOID(paintProperty);
4925 auto pipelineContext = PipelineBase::GetCurrentContext();
4926 CHECK_NULL_VOID(pipelineContext);
4927 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4928 CHECK_NULL_VOID(swiperIndicatorTheme);
4929 auto swiperParameters = GetSwiperParameters();
4930 CHECK_NULL_VOID(swiperParameters);
4931 paintProperty->UpdateItemWidth(swiperParameters->itemWidth.value_or(swiperIndicatorTheme->GetSize()));
4932 paintProperty->UpdateItemHeight(swiperParameters->itemHeight.value_or(swiperIndicatorTheme->GetSize()));
4933 paintProperty->UpdateSelectedItemWidth(
4934 swiperParameters->selectedItemWidth.value_or(swiperIndicatorTheme->GetSize()));
4935 paintProperty->UpdateSelectedItemHeight(
4936 swiperParameters->selectedItemHeight.value_or(swiperIndicatorTheme->GetSize()));
4937 paintProperty->UpdateIndicatorMask(swiperParameters->maskValue.value_or(false));
4938 paintProperty->UpdateColor(swiperParameters->colorVal.value_or(swiperIndicatorTheme->GetColor()));
4939 paintProperty->UpdateSelectedColor(
4940 swiperParameters->selectedColorVal.value_or(swiperIndicatorTheme->GetSelectedColor()));
4941 paintProperty->UpdateIsCustomSize(isCustomSize_);
4942 paintProperty->UpdateSpace(swiperParameters->dimSpace.value_or(swiperIndicatorTheme->GetIndicatorDotItemSpace()));
4943 paintProperty->UpdateIgnoreSize(swiperParameters->ignoreSizeValue.value_or(false));
4944 MarkDirtyNodeSelf();
4945 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4946 }
4947
SetDigitStartAndEndProperty(const RefPtr<FrameNode> & indicatorNode)4948 void SwiperPattern::SetDigitStartAndEndProperty(const RefPtr<FrameNode>& indicatorNode)
4949 {
4950 CHECK_NULL_VOID(indicatorNode);
4951 auto indicatorProps = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
4952 CHECK_NULL_VOID(indicatorProps);
4953 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4954 CHECK_NULL_VOID(props);
4955 const auto digitalParams = GetSwiperDigitalParameters();
4956 CHECK_NULL_VOID(digitalParams);
4957 bool isRtl = GetNonAutoLayoutDirection() == TextDirection::RTL;
4958 if (digitalParams->dimStart.has_value()) {
4959 auto dimValue = digitalParams->dimStart.value().Value() >= 0.0 ? digitalParams->dimStart.value()
4960 : Dimension(0.0, DimensionUnit::VP);
4961 isRtl ? indicatorProps->UpdateRight(dimValue) : indicatorProps->UpdateLeft(dimValue);
4962 isRtl ? props->UpdateRight(dimValue) : props->UpdateLeft(digitalParams->dimLeft.value_or(0.0_vp));
4963 ;
4964 } else if (digitalParams->dimEnd.has_value()) {
4965 auto dimValue = digitalParams->dimEnd.value().Value() >= 0.0 ? digitalParams->dimEnd.value()
4966 : Dimension(0.0, DimensionUnit::VP);
4967 isRtl ? indicatorProps->UpdateLeft(dimValue) : indicatorProps->UpdateRight(dimValue);
4968 isRtl ? props->UpdateLeft(dimValue) : props->UpdateRight(digitalParams->dimRight.value_or(0.0_vp));
4969 }
4970 }
4971
PostTranslateTask(uint32_t delayTime)4972 void SwiperPattern::PostTranslateTask(uint32_t delayTime)
4973 {
4974 auto pipeline = GetContext();
4975 CHECK_NULL_VOID(pipeline);
4976 auto taskExecutor = pipeline->GetTaskExecutor();
4977 CHECK_NULL_VOID(taskExecutor);
4978
4979 if (translateTask_) {
4980 translateTask_.Cancel();
4981 }
4982
4983 auto weak = AceType::WeakClaim(this);
4984 translateTask_.Reset([weak, delayTime] {
4985 auto swiper = weak.Upgrade();
4986 if (swiper) {
4987 swiper->isInAutoPlay_ = true;
4988 auto childrenSize = swiper->TotalCount();
4989 auto displayCount = swiper->GetDisplayCount();
4990 if (childrenSize <= 0 || displayCount <= 0 || swiper->itemPosition_.empty()) {
4991 return;
4992 }
4993 if (!swiper->IsLoop() && swiper->GetLoopIndex(swiper->currentIndex_) + 1 > (childrenSize - displayCount)) {
4994 return;
4995 }
4996 auto stepItems = swiper->IsSwipeByGroup() ? displayCount : 1;
4997 swiper->targetIndex_ = swiper->CheckTargetIndex(swiper->currentIndex_ + stepItems);
4998 ACE_SCOPED_TRACE("Swiper autoPlay delayTime %d targetIndex %d isVisibleArea_ %d isWindowShow_ %d",
4999 delayTime, swiper->targetIndex_.value(), swiper->isVisibleArea_, swiper->isWindowShow_);
5000 swiper->MarkDirtyNodeSelf();
5001 }
5002 });
5003
5004 taskExecutor->PostDelayedTask(translateTask_, TaskExecutor::TaskType::UI, delayTime, "ArkUISwiperTranslate");
5005 }
5006
HandleVisibleChange(bool visible)5007 void SwiperPattern::HandleVisibleChange(bool visible)
5008 {
5009 isVisibleArea_ = visible;
5010 if (!visible) {
5011 translateTask_.Cancel();
5012 isInAutoPlay_ = false;
5013 return;
5014 }
5015
5016 if (NeedStartAutoPlay()) {
5017 StartAutoPlay();
5018 }
5019 }
5020
RegisterVisibleAreaChange()5021 void SwiperPattern::RegisterVisibleAreaChange()
5022 {
5023 auto host = GetHost();
5024 CHECK_NULL_VOID(host);
5025 auto pipeline = GetContext();
5026 CHECK_NULL_VOID(pipeline);
5027 pipeline->AddWindowStateChangedCallback(host->GetId());
5028
5029 if (hasVisibleChangeRegistered_) {
5030 return;
5031 }
5032
5033 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
5034 auto swiperPattern = weak.Upgrade();
5035 CHECK_NULL_VOID(swiperPattern);
5036 swiperPattern->HandleVisibleChange(visible);
5037 };
5038 pipeline->RemoveVisibleAreaChangeNode(host->GetId());
5039 std::vector<double> ratioList = { 0.0 };
5040 pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, true);
5041 hasVisibleChangeRegistered_ = true;
5042
5043 auto isFormRender = pipeline->IsFormRender();
5044 auto formMgr = pipeline->GetFormVisibleManager();
5045 if (!isFormRender || !formMgr) {
5046 return;
5047 }
5048 formMgr->RemoveFormVisibleChangeNode(host->GetId());
5049 auto formCallback = [weak = WeakClaim(this)](bool visible) {
5050 auto swiperPattern = weak.Upgrade();
5051 CHECK_NULL_VOID(swiperPattern);
5052 swiperPattern->HandleVisibleChange(visible);
5053 };
5054 formMgr->AddFormVisibleChangeNode(host, formCallback);
5055 }
5056
NeedAutoPlay() const5057 bool SwiperPattern::NeedAutoPlay() const
5058 {
5059 bool reachEnd = GetLoopIndex(CurrentIndex()) >= TotalCount() - 1 && !IsLoop();
5060 return IsAutoPlay() && !reachEnd && NeedStartAutoPlay() && !isIndicatorLongPress_;
5061 }
5062
TriggerAnimationEndOnSwipeToLeft()5063 void SwiperPattern::TriggerAnimationEndOnSwipeToLeft()
5064 {
5065 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5066 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
5067 auto firstIndexStartPos = firstItemInfoInVisibleArea.second.startPos;
5068 if (std::abs(firstIndexStartPos) < (firstItemLength / swiperProportion_)) {
5069 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
5070 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
5071 } else {
5072 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
5073 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
5074 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
5075 }
5076 }
5077
TriggerAnimationEndOnSwipeToRight()5078 void SwiperPattern::TriggerAnimationEndOnSwipeToRight()
5079 {
5080 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5081 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
5082 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
5083 auto secondIndexStartPos = secondItemInfoInVisibleArea.second.startPos;
5084 if (std::abs(secondIndexStartPos) < (firstItemLength / swiperProportion_)) {
5085 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
5086 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
5087 } else {
5088 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
5089 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
5090 }
5091 }
5092
UpdateIndexOnAnimationStop()5093 void SwiperPattern::UpdateIndexOnAnimationStop()
5094 {
5095 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5096 if (currentIndex_ == firstItemInfoInVisibleArea.first) {
5097 // swipe to left
5098 TriggerAnimationEndOnSwipeToLeft();
5099 } else {
5100 // swipe to right
5101 TriggerAnimationEndOnSwipeToRight();
5102 }
5103 }
5104
UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)5105 void SwiperPattern::UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)
5106 {
5107 auto iter = itemPosition_.find(currentIndex_);
5108 if (iter == itemPosition_.end()) {
5109 UpdateCurrentIndex(pauseTargetIndex);
5110 if (itemPosition_.find(pauseTargetIndex) != itemPosition_.end()) {
5111 currentIndexOffset_ = itemPosition_.find(pauseTargetIndex)->second.startPos;
5112 }
5113 return;
5114 }
5115
5116 auto swiperWidth = MainSize();
5117 auto currentOffset = iter->second.startPos;
5118 if (std::abs(currentOffset) < (swiperWidth / swiperProportion_)) {
5119 return;
5120 }
5121
5122 if (currentOffset < 0.0f) {
5123 auto nextPageIndex = currentIndex_ + GetDisplayCount();
5124 auto nextIter = itemPosition_.find(nextPageIndex);
5125 if (nextIter == itemPosition_.end()) {
5126 return;
5127 }
5128
5129 auto nextPageOffset = nextIter->second.startPos;
5130 currentIndexOffset_ = nextPageOffset;
5131 UpdateCurrentIndex(nextPageIndex);
5132 } else {
5133 auto prevPageIndex = currentIndex_ - GetDisplayCount();
5134 auto prevIter = itemPosition_.find(prevPageIndex);
5135 if (prevIter == itemPosition_.end()) {
5136 return;
5137 }
5138
5139 auto prevPageOffset = prevIter->second.startPos;
5140 currentIndexOffset_ = prevPageOffset;
5141 UpdateCurrentIndex(prevPageIndex);
5142 }
5143 }
5144
TriggerAnimationEndOnForceStop(bool isInterrupt)5145 void SwiperPattern::TriggerAnimationEndOnForceStop(bool isInterrupt)
5146 {
5147 auto pauseTargetIndex = pauseTargetIndex_.has_value() ? pauseTargetIndex_.value() : currentIndex_;
5148 if (currentIndex_ != pauseTargetIndex) {
5149 if (IsSwipeByGroup()) {
5150 UpdateIndexOnSwipePageStop(pauseTargetIndex);
5151 } else {
5152 UpdateIndexOnAnimationStop();
5153 }
5154
5155 UpdateCurrentFocus();
5156 OnIndexChange();
5157 oldIndex_ = currentIndex_;
5158 }
5159 AnimationCallbackInfo info;
5160 info.isForceStop = true;
5161 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
5162 if (IsHorizontalAndRightToLeft()) {
5163 info.currentOffset =
5164 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
5165 }
5166 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info, isInterrupt);
5167 UpdateItemRenderGroup(false);
5168 }
5169
TriggerEventOnFinish(int32_t nextIndex)5170 void SwiperPattern::TriggerEventOnFinish(int32_t nextIndex)
5171 {
5172 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
5173
5174 AnimationCallbackInfo info;
5175 info.isForceStop = false;
5176 info.currentOffset = GetCustomPropertyOffset();
5177 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
5178 }
5179
GetCachedCount() const5180 int32_t SwiperPattern::GetCachedCount() const
5181 {
5182 auto host = GetHost();
5183 CHECK_NULL_RETURN(host, 1);
5184 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
5185 CHECK_NULL_RETURN(props, 1);
5186 auto cachedCount = props->GetCachedCount().value_or(1);
5187
5188 if (IsSwipeByGroup()) {
5189 cachedCount *= GetDisplayCount();
5190 }
5191
5192 return cachedCount;
5193 }
5194
SetLazyLoadFeature(bool useLazyLoad)5195 void SwiperPattern::SetLazyLoadFeature(bool useLazyLoad)
5196 {
5197 requestLongPredict_ = useLazyLoad;
5198 SetLazyForEachLongPredict(useLazyLoad);
5199
5200 if (!useLazyLoad) {
5201 return;
5202 }
5203 auto cacheCount = std::min(GetCachedCount(), RealTotalCount());
5204 std::set<int32_t> forEachIndexSet;
5205 for (auto count = 1; count <= cacheCount; count++) {
5206 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ + count));
5207 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ - count));
5208 }
5209 if (forEachIndexSet.empty()) {
5210 return;
5211 }
5212
5213 auto host = GetHost();
5214 CHECK_NULL_VOID(host);
5215 const auto& children = host->GetChildren();
5216 for (const auto& child : children) {
5217 if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
5218 continue;
5219 }
5220 auto pipeline = GetContext();
5221 CHECK_NULL_VOID(pipeline);
5222 auto taskExecutor = pipeline->GetTaskExecutor();
5223 CHECK_NULL_VOID(taskExecutor);
5224 taskExecutor->PostTask(
5225 [weak = WeakClaim(RawPtr(child)), id = host->GetInstanceId(), forEachIndexSet]() {
5226 ContainerScope scope(id);
5227 auto node = weak.Upgrade();
5228 CHECK_NULL_VOID(node);
5229 auto forEachNode = AceType::DynamicCast<ForEachNode>(node);
5230 CHECK_NULL_VOID(forEachNode);
5231 for (auto index : forEachIndexSet) {
5232 auto childNode = forEachNode->GetChildAtIndex(index);
5233 CHECK_NULL_VOID(childNode);
5234 childNode->Build(nullptr);
5235 }
5236 },
5237 TaskExecutor::TaskType::UI, "ArkUISwiperSetLazyLoadFeature");
5238 }
5239 }
5240
SetLazyForEachLongPredict(bool useLazyLoad) const5241 void SwiperPattern::SetLazyForEachLongPredict(bool useLazyLoad) const
5242 {
5243 // lazyBuild feature.
5244 auto host = GetHost();
5245 CHECK_NULL_VOID(host);
5246 auto targetNode = FindLazyForEachNode(host);
5247 if (targetNode.has_value()) {
5248 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
5249 CHECK_NULL_VOID(lazyForEachNode);
5250 lazyForEachNode->SetRequestLongPredict(useLazyLoad);
5251 }
5252 }
5253
SetLazyLoadIsLoop() const5254 void SwiperPattern::SetLazyLoadIsLoop() const
5255 {
5256 auto host = GetHost();
5257 CHECK_NULL_VOID(host);
5258 auto targetNode = FindLazyForEachNode(host);
5259 if (targetNode.has_value()) {
5260 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
5261 if (lazyForEachNode) {
5262 lazyForEachNode->SetIsLoop(IsLoop());
5263 }
5264 auto repeatVirtualNode = AceType::DynamicCast<RepeatVirtualScrollNode>(targetNode.value());
5265 if (repeatVirtualNode) {
5266 repeatVirtualNode->SetIsLoop(IsLoop());
5267 }
5268 }
5269 }
5270
PostIdleTask(const RefPtr<FrameNode> & frameNode)5271 void SwiperPattern::PostIdleTask(const RefPtr<FrameNode>& frameNode)
5272 {
5273 if (cachedItems_.empty()) {
5274 return;
5275 }
5276 auto pipelineContext = GetContext();
5277 CHECK_NULL_VOID(pipelineContext);
5278 pipelineContext->AddPredictTask(
5279 [weak = WeakClaim(RawPtr(frameNode))](int64_t deadline, bool canUseLongPredictTask) {
5280 auto frameNode = weak.Upgrade();
5281 CHECK_NULL_VOID(frameNode);
5282 auto pattern = frameNode->GetPattern<SwiperPattern>();
5283 CHECK_NULL_VOID(pattern);
5284 if (!canUseLongPredictTask || !pattern->GetRequestLongPredict()) {
5285 pattern->PostIdleTask(frameNode);
5286 return;
5287 }
5288 auto cachedItems = pattern->GetCachedItems();
5289 for (auto it = cachedItems.begin(); it != cachedItems.end();) {
5290 if (GetSysTimestamp() > deadline) {
5291 break;
5292 }
5293 ACE_SCOPED_TRACE("Swiper cached self index: %d", *it);
5294 auto wrapper = frameNode->GetOrCreateChildByIndex(*it, false, true);
5295 if (!wrapper) {
5296 it = cachedItems.erase(it);
5297 continue;
5298 }
5299 auto childNode = wrapper->GetHostNode();
5300 if (childNode && childNode->GetGeometryNode()) {
5301 childNode->GetGeometryNode()->SetParentLayoutConstraint(pattern->GetLayoutConstraint());
5302 FrameNode::ProcessOffscreenNode(childNode);
5303 }
5304 it = cachedItems.erase(it);
5305 }
5306 pattern->SetCachedItems(cachedItems);
5307 if (!cachedItems.empty()) {
5308 pattern->PostIdleTask(frameNode);
5309 }
5310 });
5311 }
5312
IsVisibleChildrenSizeLessThanSwiper() const5313 bool SwiperPattern::IsVisibleChildrenSizeLessThanSwiper() const
5314 {
5315 if (itemPosition_.empty() || GetDisplayCount() > TotalCount()) {
5316 return true;
5317 }
5318 const auto firstItem = GetFirstItemInfoInVisibleArea();
5319 const auto lastItem = GetLastItemInfoInVisibleArea();
5320 const int32_t visibleItemCnt = lastItem.first - firstItem.first + 1;
5321 if (TotalCount() != visibleItemCnt) {
5322 return false;
5323 }
5324 const float childrenLength = lastItem.second.endPos - firstItem.second.startPos;
5325 if (NonPositive(childrenLength)) {
5326 return true;
5327 }
5328 return LessOrEqual(childrenLength, CalculateVisibleSize());
5329 }
5330
UpdateItemRenderGroup(bool itemRenderGroup)5331 void SwiperPattern::UpdateItemRenderGroup(bool itemRenderGroup)
5332 {
5333 for (auto& item : itemPosition_) {
5334 if (auto frameNode = item.second.node) {
5335 groupedItems_.insert(frameNode);
5336 }
5337 }
5338 auto host = GetHost();
5339 CHECK_NULL_VOID(host);
5340 for (auto child : host->GetChildren()) {
5341 auto frameNode = DynamicCast<FrameNode>(child);
5342 if (!frameNode || child->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
5343 continue;
5344 }
5345 groupedItems_.insert(frameNode);
5346 }
5347 for (auto iter = groupedItems_.begin(); iter != groupedItems_.end();) {
5348 if (auto node = iter->Upgrade()) {
5349 auto context = node->GetRenderContext();
5350 CHECK_NULL_VOID(context);
5351 context->UpdateSuggestedRenderGroup(itemRenderGroup);
5352 ++iter;
5353 } else {
5354 iter = groupedItems_.erase(iter);
5355 }
5356 }
5357 }
5358
OnTranslateFinish(int32_t nextIndex,bool restartAutoPlay,bool isFinishAnimation,bool forceStop,bool isInterrupt)5359 void SwiperPattern::OnTranslateFinish(
5360 int32_t nextIndex, bool restartAutoPlay, bool isFinishAnimation, bool forceStop, bool isInterrupt)
5361 {
5362 runningTargetIndex_.reset();
5363 if (forceStop && !isFinishAnimation) {
5364 TriggerAnimationEndOnForceStop(isInterrupt);
5365 } else {
5366 TriggerEventOnFinish(nextIndex);
5367 }
5368
5369 auto host = GetHost();
5370 CHECK_NULL_VOID(host);
5371 if (HasIndicatorNode()) {
5372 auto indicatorNode = GetCommonIndicatorNode();
5373 CHECK_NULL_VOID(indicatorNode);
5374 if (IsIndicator(indicatorNode->GetTag())) {
5375 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5376 MarkDirtyNodeSelf();
5377 }
5378 }
5379
5380 auto delayTime = GetInterval() - GetDuration();
5381 delayTime = std::clamp(delayTime, 0, delayTime);
5382 if (NeedAutoPlay() && isUserFinish_ && !forceStop) {
5383 PostTranslateTask(delayTime);
5384 }
5385 UpdateItemRenderGroup(false);
5386 }
5387
OnWindowShow()5388 void SwiperPattern::OnWindowShow()
5389 {
5390 if (!isParentHiddenChange_) {
5391 FireWillShowEvent(currentIndex_);
5392 }
5393 isWindowShow_ = true;
5394 if (NeedStartAutoPlay()) {
5395 StartAutoPlay();
5396 }
5397 }
5398
OnWindowHide()5399 void SwiperPattern::OnWindowHide()
5400 {
5401 if (!isParentHiddenChange_) {
5402 FireWillHideEvent(currentIndex_);
5403 }
5404 isWindowShow_ = false;
5405 StopAutoPlay();
5406
5407 if (isDragging_) {
5408 HandleDragEnd(0.0);
5409 }
5410
5411 StopSpringAnimationAndFlushImmediately();
5412 }
5413
ArrowHover(bool isHover,SwiperHoverFlag flag)5414 void SwiperPattern::ArrowHover(bool isHover, SwiperHoverFlag flag)
5415 {
5416 if (isHover) {
5417 hoverFlag_ |= flag;
5418 } else {
5419 hoverFlag_ &= (~flag);
5420 }
5421 if (HasLeftButtonNode() && HasRightButtonNode()) {
5422 auto swiperNode = GetHost();
5423 CHECK_NULL_VOID(swiperNode);
5424 auto leftArrowNode =
5425 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
5426 CHECK_NULL_VOID(leftArrowNode);
5427 auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
5428 CHECK_NULL_VOID(leftArrowPattern);
5429 leftArrowPattern->SetButtonVisible(hoverFlag_ != HOVER_NONE);
5430 auto rightArrowNode =
5431 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
5432 CHECK_NULL_VOID(rightArrowNode);
5433 auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
5434 CHECK_NULL_VOID(rightArrowPattern);
5435 rightArrowPattern->SetButtonVisible(hoverFlag_ != HOVER_NONE);
5436 }
5437 }
5438
SaveArrowProperty(const RefPtr<FrameNode> & arrowNode)5439 void SwiperPattern::SaveArrowProperty(const RefPtr<FrameNode>& arrowNode)
5440 {
5441 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5442 CHECK_NULL_VOID(props);
5443 const auto paintProps = GetPaintProperty<SwiperPaintProperty>();
5444 CHECK_NULL_VOID(props);
5445 const auto arrowProps = arrowNode->GetLayoutProperty<SwiperArrowLayoutProperty>();
5446 CHECK_NULL_VOID(arrowProps);
5447 arrowProps->UpdateDirection(props->GetDirection().value_or(Axis::HORIZONTAL));
5448 arrowProps->UpdateIndex(props->GetIndex().value_or(0));
5449 arrowProps->UpdateLoop(props->GetLoop().value_or(true));
5450 arrowProps->UpdateEnabled(paintProps->GetEnabled().value_or(true));
5451 arrowProps->UpdateDisplayArrow(props->GetDisplayArrowValue());
5452 arrowProps->UpdateHoverShow(props->GetHoverShowValue());
5453 arrowProps->UpdateIsShowBackground(props->GetIsShowBackgroundValue());
5454 arrowProps->UpdateBackgroundSize(props->GetBackgroundSizeValue());
5455 arrowProps->UpdateBackgroundColor(props->GetBackgroundColorValue());
5456 arrowProps->UpdateArrowSize(props->GetArrowSizeValue());
5457 arrowProps->UpdateArrowColor(props->GetArrowColorValue());
5458 arrowProps->UpdateIsSidebarMiddle(props->GetIsSidebarMiddleValue());
5459 }
5460
SetAccessibilityAction()5461 void SwiperPattern::SetAccessibilityAction()
5462 {
5463 auto host = GetHost();
5464 CHECK_NULL_VOID(host);
5465 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
5466 CHECK_NULL_VOID(accessibilityProperty);
5467 accessibilityProperty->SetActionScrollForward(
5468 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
5469 const auto& pattern = weakPtr.Upgrade();
5470 CHECK_NULL_VOID(pattern);
5471 const auto& accessibilityProperty = accessibility.Upgrade();
5472 CHECK_NULL_VOID(accessibilityProperty);
5473 if (!accessibilityProperty->IsScrollable()) {
5474 return;
5475 }
5476 pattern->ShowNext(true);
5477 });
5478
5479 accessibilityProperty->SetActionScrollBackward(
5480 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
5481 const auto& pattern = weakPtr.Upgrade();
5482 CHECK_NULL_VOID(pattern);
5483 const auto& accessibilityProperty = accessibility.Upgrade();
5484 CHECK_NULL_VOID(accessibilityProperty);
5485 if (!accessibilityProperty->IsScrollable()) {
5486 return;
5487 }
5488 pattern->ShowPrevious(true);
5489 });
5490 }
5491
NeedStartAutoPlay() const5492 bool SwiperPattern::NeedStartAutoPlay() const
5493 {
5494 return isWindowShow_ && isVisibleArea_;
5495 }
5496
ProvideRestoreInfo()5497 std::string SwiperPattern::ProvideRestoreInfo()
5498 {
5499 auto jsonObj = JsonUtil::Create(true);
5500 CHECK_NULL_RETURN(jsonObj, "");
5501 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5502 CHECK_NULL_RETURN(props, "");
5503 jsonObj->Put("Index", props->GetIndex().value_or(0));
5504 return jsonObj->ToString();
5505 }
5506
OnRestoreInfo(const std::string & restoreInfo)5507 void SwiperPattern::OnRestoreInfo(const std::string& restoreInfo)
5508 {
5509 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5510 CHECK_NULL_VOID(props);
5511 auto info = JsonUtil::ParseJsonString(restoreInfo);
5512 if (!info || !info->IsValid() || !info->IsObject()) {
5513 return;
5514 }
5515 auto jsonIsOn = info->GetValue("Index");
5516 props->UpdateIndex(jsonIsOn->GetInt());
5517 OnModifyDone();
5518 }
5519
InitHoverMouseEvent()5520 void SwiperPattern::InitHoverMouseEvent()
5521 {
5522 auto host = GetHost();
5523 CHECK_NULL_VOID(host);
5524 auto eventHub = host->GetEventHub<EventHub>();
5525 CHECK_NULL_VOID(eventHub);
5526 auto inputHub = eventHub->GetOrCreateInputEventHub();
5527 CHECK_NULL_VOID(inputHub);
5528
5529 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
5530 auto pattern = weak.Upgrade();
5531 CHECK_NULL_VOID(pattern);
5532 if (!pattern->IsShowIndicator()) {
5533 pattern->ArrowHover(isHover, HOVER_SWIPER);
5534 }
5535 };
5536
5537 if (!hoverEvent_) {
5538 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
5539 inputHub->AddOnHoverEvent(hoverEvent_);
5540 }
5541
5542 auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
5543 auto pattern = weak.Upgrade();
5544 if (pattern) {
5545 pattern->HandleMouseEvent(info);
5546 }
5547 };
5548 if (mouseEvent_) {
5549 inputHub->RemoveOnMouseEvent(mouseEvent_);
5550 }
5551 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
5552 inputHub->AddOnMouseEvent(mouseEvent_);
5553 }
5554
HandleMouseEvent(const MouseInfo & info)5555 void SwiperPattern::HandleMouseEvent(const MouseInfo& info)
5556 {
5557 auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
5558 auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
5559 auto mousePoint = PointF(mouseOffsetX, mouseOffsetY);
5560 if (IsShowIndicator()) {
5561 CheckAndSetArrowHoverState(mousePoint);
5562 }
5563 }
5564
CheckAndSetArrowHoverState(const PointF & mousePoint)5565 void SwiperPattern::CheckAndSetArrowHoverState(const PointF& mousePoint)
5566 {
5567 if (!HasLeftButtonNode() || !HasRightButtonNode() || !HasIndicatorNode()) {
5568 return;
5569 }
5570
5571 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5572 CHECK_NULL_VOID(props);
5573 if (props->GetIsSidebarMiddleValue(false)) {
5574 return;
5575 }
5576
5577 RectF leftNodeRect;
5578 RectF rightNodeRect;
5579
5580 leftNodeRect = GetArrowFrameRect(GetLeftButtonId());
5581 rightNodeRect = GetArrowFrameRect(GetRightButtonId());
5582
5583 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
5584 leftNodeRect = GetArrowFrameRect(GetIndicatorId());
5585 }
5586
5587 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
5588 rightNodeRect = GetArrowFrameRect(GetIndicatorId());
5589 }
5590 RectF newNodeRect;
5591 if (GetDirection() == Axis::HORIZONTAL) {
5592 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(), rightNodeRect.Right() - leftNodeRect.Left(),
5593 std::min(rightNodeRect.Height(), leftNodeRect.Height()));
5594 } else {
5595 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(),
5596 std::min(rightNodeRect.Width(), leftNodeRect.Width()), rightNodeRect.Bottom() - leftNodeRect.Top());
5597 }
5598
5599 isAtHotRegion_ = newNodeRect.IsInRegion(mousePoint);
5600 ArrowHover(isAtHotRegion_, HOVER_SWIPER);
5601 }
5602
GetArrowFrameRect(const int32_t index) const5603 RectF SwiperPattern::GetArrowFrameRect(const int32_t index) const
5604 {
5605 auto swiperNode = GetHost();
5606 CHECK_NULL_RETURN(swiperNode, RectF(0, 0, 0, 0));
5607 auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(index)));
5608 CHECK_NULL_RETURN(arrowNode, RectF(0, 0, 0, 0));
5609 auto arrowGeometryNode = arrowNode->GetGeometryNode();
5610 CHECK_NULL_RETURN(arrowGeometryNode, RectF(0, 0, 0, 0));
5611 return arrowGeometryNode->GetFrameRect();
5612 }
5613
GetCustomPropertyOffset() const5614 float SwiperPattern::GetCustomPropertyOffset() const
5615 {
5616 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5617 CHECK_NULL_RETURN(props, 0.0);
5618 auto paddingAndBorder = props->CreatePaddingAndBorder();
5619 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
5620 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
5621 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
5622 return Dimension(paddingAndBorderValue + GetPrevMarginWithItemSpace(), DimensionUnit::PX).ConvertToVp();
5623 }
5624
GetCustomPropertyTargetOffset() const5625 float SwiperPattern::GetCustomPropertyTargetOffset() const
5626 {
5627 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5628 CHECK_NULL_RETURN(props, 0.0);
5629 auto paddingAndBorder = props->CreatePaddingAndBorder();
5630 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
5631 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
5632 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
5633
5634 auto preMarginPX = GetPrevMarginWithItemSpace();
5635 if (IsHorizontalAndRightToLeft()) {
5636 return Dimension(paddingAndBorderValue - preMarginPX, DimensionUnit::PX).ConvertToVp();
5637 }
5638 return Dimension(paddingAndBorderValue + preMarginPX, DimensionUnit::PX).ConvertToVp();
5639 }
5640
TotalDisPlayCount() const5641 int32_t SwiperPattern::TotalDisPlayCount() const
5642 {
5643 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5644 CHECK_NULL_RETURN(props, 1);
5645 auto displayCount = GetDisplayCount();
5646 if (SwiperUtils::IsStretch(props)) {
5647 if (Positive(props->GetCalculatedPrevMargin())) {
5648 displayCount++;
5649 }
5650 if (Positive(props->GetCalculatedNextMargin())) {
5651 displayCount++;
5652 }
5653 }
5654 return displayCount;
5655 }
5656
MarkDirtyNodeSelf()5657 void SwiperPattern::MarkDirtyNodeSelf()
5658 {
5659 auto host = GetHost();
5660 CHECK_NULL_VOID(host);
5661 if (!crossMatchChild_) {
5662 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5663 } else {
5664 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5665 }
5666 }
5667
ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)5668 void SwiperPattern::ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)
5669 {
5670 auto pipeline = GetContext();
5671 CHECK_NULL_VOID(pipeline);
5672
5673 fastCurrentIndex_.reset();
5674 targetIndex_.reset();
5675
5676 if (isFinishAnimation_) {
5677 currentDelta_ = 0.0f;
5678 itemPosition_.clear();
5679 isVoluntarilyClear_ = true;
5680 jumpIndex_ = nextIndex;
5681 MarkDirtyNodeSelf();
5682 pipeline->FlushUITasks();
5683 isFinishAnimation_ = false;
5684 } else if (currentIndex_ != nextIndex) {
5685 UpdateCurrentIndex(nextIndex);
5686 if (currentFocusIndex_ < currentIndex_ || currentFocusIndex_ >= currentIndex_ + GetDisplayCount()) {
5687 currentFocusIndex_ = currentIndex_;
5688 }
5689 auto host = GetHost();
5690 CHECK_NULL_VOID(host);
5691 do {
5692 auto curChildFrame =
5693 DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_)));
5694 if (!curChildFrame || !IsContentFocused()) {
5695 break;
5696 }
5697 FlushFocus(curChildFrame);
5698 } while (0);
5699 auto tempOldIndex = oldIndex_;
5700 oldIndex_ = nextIndex;
5701 currentFirstIndex_ = GetLoopIndex(nextIndex);
5702 turnPageRate_ = 0.0f;
5703 currentIndexOffset_ = 0.0f;
5704 if (pipeline->IsLayouting()) {
5705 pipeline->FlushUITaskWithSingleDirtyNode(host);
5706 pipeline->FlushSyncGeometryNodeTasks();
5707 } else {
5708 pipeline->FlushUITasks();
5709 pipeline->FlushMessages();
5710 }
5711 FireSelectedEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5712 FireUnselectedEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5713 FireChangeEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5714 // lazyBuild feature.
5715 SetLazyLoadFeature(true);
5716 }
5717 }
5718
OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child,float position,float)5719 void SwiperPattern::OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child, float position, float /* velocity */)
5720 {
5721 SetIsNestedInterrupt(false);
5722 if (IsDisableSwipe()) {
5723 return;
5724 }
5725 childScrolling_ = true;
5726 gestureSwipeIndex_ = currentIndex_;
5727 StopAnimationOnScrollStart(false);
5728 NotifyParentScrollStart(child, position);
5729 }
5730
NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child,float position)5731 void SwiperPattern::NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child, float position)
5732 {
5733 if (!GetIsFixedNestedScrollMode()) {
5734 SetParentScrollable();
5735 }
5736 auto parent = GetNestedScrollParent();
5737 CHECK_NULL_VOID(parent);
5738 const auto& nestedScroll = GetNestedScroll();
5739 if (parent && nestedScroll.NeedParent()) {
5740 parent->OnScrollStartRecursive(child, position);
5741 }
5742 }
5743
OnScrollEndRecursive(const std::optional<float> & velocity)5744 void SwiperPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
5745 {
5746 if (IsDisableSwipe()) {
5747 return;
5748 }
5749 // in case child didn't call swiper's HandleScrollVelocity
5750 if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
5751 HandleDragEnd(velocity.value_or(0.0f));
5752 }
5753 SetIsNestedInterrupt(false);
5754 childScrolling_ = false;
5755 InitIndexCanChangeMap();
5756 }
5757
OnScrollDragEndRecursive()5758 void SwiperPattern::OnScrollDragEndRecursive()
5759 {
5760 NestableScrollContainer::OnScrollDragEndRecursive();
5761 if (IsDisableSwipe()) {
5762 return;
5763 }
5764 // Swiper and child handle drag end event together.
5765 if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
5766 HandleDragEnd(0.0f);
5767 }
5768 }
5769
NotifyParentScrollEnd()5770 void SwiperPattern::NotifyParentScrollEnd()
5771 {
5772 auto parent = GetNestedScrollParent();
5773 const auto& nestedScroll = GetNestedScroll();
5774 if (parent && (nestedScroll.NeedParent() || GetIsNestedInterrupt())) {
5775 parent->OnScrollEndRecursive(std::nullopt);
5776 }
5777 }
5778
DuringTranslateAnimation() const5779 inline bool SwiperPattern::DuringTranslateAnimation() const
5780 {
5781 return (springAnimation_ && springAnimationIsRunning_ && !isTouchDownSpringAnimation_) || targetIndex_ ||
5782 propertyAnimationIsRunning_ || translateAnimationIsRunning_;
5783 }
5784
RunningTranslateAnimation() const5785 inline bool SwiperPattern::RunningTranslateAnimation() const
5786 {
5787 return springAnimationIsRunning_ || propertyAnimationIsRunning_ || translateAnimationIsRunning_;
5788 }
5789
DuringFadeAnimation() const5790 inline bool SwiperPattern::DuringFadeAnimation() const
5791 {
5792 return fadeAnimation_ && fadeAnimationIsRunning_ && !isTouchDownFadeAnimation_;
5793 }
5794
HandleScrollVelocity(float velocity,const RefPtr<NestableScrollContainer> & child)5795 bool SwiperPattern::HandleScrollVelocity(float velocity, const RefPtr<NestableScrollContainer>& child)
5796 {
5797 if (IsDisableSwipe()) {
5798 return false;
5799 }
5800 DestructSetter<bool> scope(childScrolling_, false);
5801 // haven't reached edge
5802 if (GetDistanceToEdge() > 0.0f || IsLoop()) {
5803 HandleDragEnd(velocity);
5804 return true;
5805 }
5806
5807 auto parent = GetNestedScrollParent();
5808 const auto nestedScroll = GetNestedScroll();
5809 if (parent && nestedScroll.NeedParent(NonPositive(velocity))) {
5810 // after reach end, parent handle velocity first
5811 if (parent->HandleScrollVelocity(velocity)) {
5812 return true;
5813 }
5814 }
5815 HandleDragEnd(velocity);
5816 // after reached end, NONE doesn't consume velocity, other edge effects do
5817 return GetEdgeEffect() != EdgeEffect::NONE;
5818 }
5819
HandleOutBoundarySelf(float offset,float & selfOffset,float & remainOffset)5820 void SwiperPattern::HandleOutBoundarySelf(float offset, float& selfOffset, float& remainOffset)
5821 {
5822 if (IsLoop()) {
5823 return;
5824 }
5825 if (GetEdgeEffect() == EdgeEffect::FADE && !NearZero(fadeOffset_)) {
5826 if ((Negative(offset) && Positive(fadeOffset_)) || (Positive(offset) && Negative(fadeOffset_))) {
5827 if (GreatNotEqual(std::abs(fadeOffset_), std::abs(offset))) {
5828 remainOffset = 0.0f;
5829 selfOffset = offset;
5830 } else {
5831 remainOffset += fadeOffset_;
5832 selfOffset = -fadeOffset_;
5833 }
5834 }
5835 }
5836 if (GetEdgeEffect() == EdgeEffect::SPRING && !itemPosition_.empty()) {
5837 if (Negative(offset) && itemPosition_.begin()->first == 0) {
5838 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
5839 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
5840 if (Positive(startPos)) {
5841 selfOffset = -std::min(startPos, -offset);
5842 remainOffset -= selfOffset;
5843 }
5844 } else if (Positive(offset) && itemPosition_.rbegin()->first == TotalCount() - 1) {
5845 auto visibleWindowSize = CalculateVisibleSize();
5846 auto endPos = itemPosition_.rbegin()->second.endPos + AdjustIgnoreBlankOverScrollOffSet(false);
5847 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
5848 if (LessNotEqual(endPos, visibleWindowSize)) {
5849 selfOffset = std::min(visibleWindowSize - endPos, offset);
5850 remainOffset -= selfOffset;
5851 }
5852 }
5853 }
5854 }
5855
HandleOutBoundary(float offset,int32_t source,float velocity)5856 ScrollResult SwiperPattern::HandleOutBoundary(float offset, int32_t source, float velocity)
5857 {
5858 float selfOffset = 0.0f;
5859 float remainOffset = offset;
5860 HandleOutBoundarySelf(offset, selfOffset, remainOffset);
5861 auto parent = GetNestedScrollParent();
5862 if (!NearZero(remainOffset) && parent) {
5863 auto res = parent->HandleScroll(remainOffset, source, NestedState::CHILD_CHECK_OVER_SCROLL, velocity);
5864 remainOffset = res.remain;
5865 }
5866 if (!NearZero(selfOffset)) {
5867 UpdateCurrentOffset(selfOffset);
5868 }
5869 return { remainOffset, true };
5870 }
5871
HandleScroll(float offset,int32_t source,NestedState state,float velocity)5872 ScrollResult SwiperPattern::HandleScroll(float offset, int32_t source, NestedState state, float velocity)
5873 {
5874 if (state == NestedState::CHILD_CHECK_OVER_SCROLL) {
5875 return HandleOutBoundary(offset, source, velocity);
5876 }
5877 if (IsDisableSwipe() || (source == SCROLL_FROM_ANIMATION && DuringTranslateAnimation()) ||
5878 !CheckSwiperPanEvent(offset) || !CheckContentWillScroll(offset, offset)) {
5879 // deny conflicting animation from child
5880 return { offset, true };
5881 }
5882 if (state != NestedState::GESTURE) {
5883 // handle situations when multiple children are notifying scrollStart / scrollEnd
5884 // reset flag and animations to correct states when scroll happens
5885 childScrolling_ = true;
5886 if (DuringTranslateAnimation()) {
5887 StopAnimationOnScrollStart(false);
5888 }
5889 }
5890 // mouse scroll triggers showNext / showPrev instead of updating offset
5891 if (source == SCROLL_FROM_AXIS) {
5892 auto targetBfr = targetIndex_;
5893 (offset > 0) ? ShowPrevious() : ShowNext();
5894 if (targetBfr == targetIndex_) {
5895 // unchanged targetIndex_ implies Swiper has reached the edge and the mouse scroll isn't consumed.
5896 return { offset, true };
5897 }
5898 return { 0.0f, false };
5899 }
5900 auto parent = GetNestedScrollParent();
5901 auto nestedScroll = GetNestedScroll();
5902 if (!parent || !nestedScroll.NeedParent()) {
5903 if (IsOutOfBoundary(offset) && ChildFirst(state)) {
5904 CloseTheGap(offset);
5905 return { offset, true };
5906 }
5907 UpdateCurrentOffset(offset);
5908 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5909 }
5910 ScrollResult result = { 0.f, !IsLoop() && GetDistanceToEdge() <= 0.f };
5911 if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::PARENT_FIRST) ||
5912 (Positive(offset) && nestedScroll.backward == NestedScrollMode::PARENT_FIRST))) {
5913 result = HandleScrollParentFirst(offset, source, state, velocity);
5914 } else if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::SELF_FIRST) ||
5915 (Positive(offset) && nestedScroll.backward == NestedScrollMode::SELF_FIRST))) {
5916 result = HandleScrollSelfFirst(offset, source, state, velocity);
5917 }
5918 return result;
5919 }
5920
HandleScrollParentFirst(float offset,int32_t source,NestedState state,float velocity)5921 ScrollResult SwiperPattern::HandleScrollParentFirst(float offset, int32_t source, NestedState state, float velocity)
5922 {
5923 // priority: parent scroll > self scroll > self overScroll > parent overScroll
5924 auto parent = GetNestedScrollParent();
5925 if (!parent) {
5926 return { 0.0f, true };
5927 }
5928 // skip CHECK_NULL, already checked in HandleScroll
5929 auto result = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
5930 offset = result.remain;
5931 if (IsOutOfBoundary(offset)) {
5932 if (NearZero(offset)) {
5933 return { 0.f, true };
5934 }
5935 CloseTheGap(offset);
5936 if (ChildFirst(state)) {
5937 if (result.reachEdge) {
5938 result = parent->HandleScroll(offset, source, NestedState::CHILD_OVER_SCROLL, velocity);
5939 }
5940 return { result.remain, true };
5941 }
5942 }
5943 // self Scroll && self overScroll
5944 UpdateCurrentOffset(offset);
5945 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5946 }
5947
HandleScrollSelfFirst(float offset,int32_t source,NestedState state,float velocity)5948 ScrollResult SwiperPattern::HandleScrollSelfFirst(float offset, int32_t source, NestedState state, float velocity)
5949 {
5950 // priority: self scroll > parent scroll > parent overScroll > self overScroll
5951 if ((IsOutOfStart(offset) && Positive(offset)) || (IsOutOfEnd(offset) && Negative(offset))) {
5952 CloseTheGap(offset);
5953 // skip CHECK_NULL, already checked in HandleScroll
5954 auto parent = GetNestedScrollParent();
5955 if (!parent) {
5956 return { 0.0f, true };
5957 }
5958
5959 // reached edge, pass offset to parent
5960 auto res = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
5961 if (res.remain == 0.0f) {
5962 return { 0.0f, true };
5963 }
5964 // parent handle overScroll first
5965 if (res.reachEdge) {
5966 res = parent->HandleScroll(res.remain, source, NestedState::CHILD_OVER_SCROLL, velocity);
5967 }
5968 if (ChildFirst(state)) {
5969 return { res.remain, true };
5970 }
5971 if (res.remain != 0.0f) {
5972 // self overScroll
5973 UpdateCurrentOffset(res.remain);
5974 }
5975 } else {
5976 // regular scroll
5977 UpdateCurrentOffset(offset);
5978 }
5979 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5980 }
5981
CloseTheGap(float & offset)5982 void SwiperPattern::CloseTheGap(float& offset)
5983 {
5984 float distanceToEdge = GetDistanceToEdge();
5985 if (Positive(distanceToEdge)) {
5986 if (GreatOrEqual(std::abs(offset), distanceToEdge)) {
5987 UpdateCurrentOffset(Positive(offset) ? distanceToEdge : -distanceToEdge);
5988 offset = Positive(offset) ? offset - distanceToEdge : offset + distanceToEdge;
5989 }
5990 }
5991 }
5992
ChildFirst(NestedState state)5993 inline bool SwiperPattern::ChildFirst(NestedState state)
5994 {
5995 // SELF/CHILD priority: self scroll > child scroll > self overScroll > child overScroll
5996 return state == NestedState::CHILD_SCROLL // child hasn't reach edge
5997 || GetEdgeEffect() == EdgeEffect::NONE;
5998 }
5999
UpdateDragFRCSceneInfo(float speed,SceneStatus sceneStatus)6000 void SwiperPattern::UpdateDragFRCSceneInfo(float speed, SceneStatus sceneStatus)
6001 {
6002 auto host = GetHost();
6003 CHECK_NULL_VOID(host);
6004 host->AddFRCSceneInfo(SWIPER_DRAG_SCENE, speed, sceneStatus);
6005 }
6006
GetLoopIndex(int32_t index,int32_t childrenSize) const6007 int32_t SwiperPattern::GetLoopIndex(int32_t index, int32_t childrenSize) const
6008 {
6009 if (childrenSize <= 0) {
6010 return index;
6011 }
6012 auto loopIndex = index;
6013 while (loopIndex < 0) {
6014 loopIndex = loopIndex + childrenSize;
6015 }
6016 loopIndex %= childrenSize;
6017 return loopIndex;
6018 }
6019
DumpAdvanceInfo()6020 void SwiperPattern::DumpAdvanceInfo()
6021 {
6022 SwiperHelper::DumpAdvanceInfo(*this);
6023 }
6024
RegisterScrollingListener(const RefPtr<ScrollingListener> listener)6025 void SwiperPattern::RegisterScrollingListener(const RefPtr<ScrollingListener> listener)
6026 {
6027 CHECK_NULL_VOID(listener);
6028 scrollingListener_.emplace_back(listener);
6029 }
6030
FireAndCleanScrollingListener()6031 void SwiperPattern::FireAndCleanScrollingListener()
6032 {
6033 for (auto listener : scrollingListener_) {
6034 CHECK_NULL_VOID(listener);
6035 listener->NotifyScrollingEvent();
6036 }
6037 scrollingListener_.clear();
6038 }
6039
CleanScrollingListener()6040 void SwiperPattern::CleanScrollingListener()
6041 {
6042 scrollingListener_.clear();
6043 }
6044
IsSwipeByGroup() const6045 bool SwiperPattern::IsSwipeByGroup() const
6046 {
6047 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
6048 CHECK_NULL_RETURN(props, false);
6049 return props->GetSwipeByGroup().value_or(false);
6050 }
6051
GetCurrentFrameNode(int32_t currentIndex) const6052 RefPtr<FrameNode> SwiperPattern::GetCurrentFrameNode(int32_t currentIndex) const
6053 {
6054 auto host = GetHost();
6055 CHECK_NULL_RETURN(host, nullptr);
6056 auto currentLayoutWrapper = host->GetChildByIndex(GetLoopIndex(currentIndex), true);
6057 CHECK_NULL_RETURN(currentLayoutWrapper, nullptr);
6058 return currentLayoutWrapper->GetHostNode();
6059 }
6060
OnCustomContentTransition(int32_t toIndex)6061 void SwiperPattern::OnCustomContentTransition(int32_t toIndex)
6062 {
6063 if (!currentProxyInAnimation_ && toIndex == CurrentIndex()) {
6064 return;
6065 }
6066
6067 customAnimationToIndex_ = toIndex;
6068 indexsInAnimation_.insert(toIndex);
6069 auto fromIndex = CurrentIndex();
6070 if (currentProxyInAnimation_) {
6071 fromIndex = currentProxyInAnimation_->GetToIndex();
6072
6073 FireChangeEvent(CurrentIndex(), fromIndex);
6074
6075 UpdateCurrentIndex(fromIndex);
6076 oldIndex_ = fromIndex;
6077
6078 AnimationCallbackInfo info;
6079 info.currentOffset = GetCustomPropertyOffset();
6080 FireAnimationEndEvent(fromIndex, info);
6081
6082 currentProxyInAnimation_->SetHasOnChanged(true);
6083 }
6084 if (fromIndex != toIndex) {
6085 FireWillShowEvent(toIndex);
6086 FireWillHideEvent(fromIndex);
6087 }
6088 auto pipelineContext = GetContext();
6089 CHECK_NULL_VOID(pipelineContext);
6090 pipelineContext->AddAfterLayoutTask([weak = WeakClaim(this), fromIndex, toIndex]() {
6091 auto swiperPattern = weak.Upgrade();
6092 CHECK_NULL_VOID(swiperPattern);
6093 swiperPattern->TriggerCustomContentTransitionEvent(fromIndex, toIndex);
6094 });
6095
6096 MarkDirtyNodeSelf();
6097 }
6098
TriggerCustomContentTransitionEvent(int32_t fromIndex,int32_t toIndex)6099 void SwiperPattern::TriggerCustomContentTransitionEvent(int32_t fromIndex, int32_t toIndex)
6100 {
6101 if (customAnimationToIndex_.value_or(toIndex) != toIndex) {
6102 TAG_LOGW(AceLogTag::ACE_SWIPER,
6103 "Swiper TriggerCustomContentTransitionEvent, fromIndex:%{public}d, toIndex:%{public}d", fromIndex, toIndex);
6104 needUnmountIndexs_.insert(toIndex);
6105 indexsInAnimation_.erase(toIndex);
6106 MarkDirtyNodeSelf();
6107 return;
6108 }
6109 CHECK_NULL_VOID(onTabsCustomContentTransition_);
6110
6111 auto tabContentAnimatedTransition = (*onTabsCustomContentTransition_)(fromIndex, toIndex);
6112 auto transition = tabContentAnimatedTransition.transition;
6113
6114 if (!transition) {
6115 OnCustomAnimationFinish(fromIndex, toIndex, false);
6116 return;
6117 }
6118
6119 auto proxy = AceType::MakeRefPtr<TabContentTransitionProxy>();
6120 proxy->SetFromIndex(fromIndex);
6121 proxy->SetToIndex(toIndex);
6122 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), fromIndex, toIndex](bool hasOnChanged) {
6123 auto swiperPattern = weak.Upgrade();
6124 CHECK_NULL_VOID(swiperPattern);
6125 swiperPattern->OnCustomAnimationFinish(fromIndex, toIndex, hasOnChanged);
6126 });
6127
6128 transition(proxy);
6129 currentProxyInAnimation_ = proxy;
6130
6131 AnimationCallbackInfo info;
6132 info.currentOffset = GetCustomPropertyOffset();
6133 info.targetOffset = GetCustomPropertyTargetOffset();
6134 FireSelectedEvent(fromIndex, toIndex);
6135 FireUnselectedEvent(fromIndex, toIndex);
6136 FireAnimationStartEvent(fromIndex, toIndex, info);
6137
6138 auto pipeline = GetContext();
6139 CHECK_NULL_VOID(pipeline);
6140 auto taskExecutor = pipeline->GetTaskExecutor();
6141 CHECK_NULL_VOID(taskExecutor);
6142
6143 auto timeout = tabContentAnimatedTransition.timeout;
6144 auto timeoutTask = [weak = AceType::WeakClaim(AceType::RawPtr(proxy))] {
6145 auto transitionProxy = weak.Upgrade();
6146 CHECK_NULL_VOID(transitionProxy);
6147 transitionProxy->FinishTransition();
6148 };
6149
6150 taskExecutor->PostDelayedTask(timeoutTask, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperFinishTransition");
6151 }
6152
OnCustomAnimationFinish(int32_t fromIndex,int32_t toIndex,bool hasOnChanged)6153 void SwiperPattern::OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged)
6154 {
6155 customAnimationToIndex_.reset();
6156 needUnmountIndexs_.insert(fromIndex);
6157 indexsInAnimation_.erase(toIndex);
6158
6159 if (!hasOnChanged) {
6160 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
6161 CHECK_NULL_VOID(props);
6162 props->UpdateIndexWithoutMeasure(GetLoopIndex(toIndex));
6163 oldIndex_ = fromIndex;
6164
6165 AnimationCallbackInfo info;
6166 info.currentOffset = GetCustomPropertyOffset();
6167 FireAnimationEndEvent(toIndex, info);
6168 }
6169
6170 if (indexsInAnimation_.empty()) {
6171 currentProxyInAnimation_ = nullptr;
6172 }
6173 auto curChildFrame = GetCurrentFrameNode(toIndex);
6174 if (curChildFrame) {
6175 FlushFocus(curChildFrame);
6176 }
6177 auto host = GetHost();
6178 CHECK_NULL_VOID(host);
6179 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
6180 auto pipeline = GetContext();
6181 CHECK_NULL_VOID(pipeline);
6182 pipeline->FlushUITasks();
6183 pipeline->FlushMessages();
6184 }
6185
SetSwiperEventCallback(bool disableSwipe)6186 void SwiperPattern::SetSwiperEventCallback(bool disableSwipe)
6187 {
6188 CHECK_NULL_VOID(swiperController_);
6189 auto removeSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
6190 auto swiperPattern = weak.Upgrade();
6191 CHECK_NULL_VOID(swiperPattern);
6192 auto host = swiperPattern->GetHost();
6193 CHECK_NULL_VOID(host);
6194 auto hub = host->GetEventHub<EventHub>();
6195 CHECK_NULL_VOID(hub);
6196 auto gestureHub = hub->GetOrCreateGestureEventHub();
6197 CHECK_NULL_VOID(gestureHub);
6198 gestureHub->RemoveTouchEvent(swiperPattern->touchEvent_);
6199 if (!disableSwipe) {
6200 gestureHub->RemovePanEvent(swiperPattern->panEvent_);
6201 }
6202 };
6203 swiperController_->SetRemoveSwiperEventCallback(std::move(removeSwiperEventCallback));
6204
6205 auto addSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
6206 auto swiperPattern = weak.Upgrade();
6207 CHECK_NULL_VOID(swiperPattern);
6208 auto host = swiperPattern->GetHost();
6209 CHECK_NULL_VOID(host);
6210 auto hub = host->GetEventHub<EventHub>();
6211 CHECK_NULL_VOID(hub);
6212 auto gestureHub = hub->GetOrCreateGestureEventHub();
6213 CHECK_NULL_VOID(gestureHub);
6214 gestureHub->AddTouchEvent(swiperPattern->touchEvent_);
6215 if (!disableSwipe) {
6216 gestureHub->AddPanEvent(swiperPattern->panEvent_, swiperPattern->panDirection_, 1, DEFAULT_PAN_DISTANCE);
6217 }
6218 };
6219 swiperController_->SetAddSwiperEventCallback(std::move(addSwiperEventCallback));
6220 }
6221
UpdateSwiperPanEvent(bool disableSwipe)6222 void SwiperPattern::UpdateSwiperPanEvent(bool disableSwipe)
6223 {
6224 auto host = GetHost();
6225 CHECK_NULL_VOID(host);
6226 auto hub = host->GetEventHub<EventHub>();
6227 CHECK_NULL_VOID(hub);
6228 auto gestureHub = hub->GetOrCreateGestureEventHub();
6229 CHECK_NULL_VOID(gestureHub);
6230
6231 if (!disableSwipe) {
6232 InitPanEvent(gestureHub);
6233 } else if (panEvent_) {
6234 TAG_LOGI(AceLogTag::ACE_SWIPER, "Remove pan event when disable swipe. id:%{public}d", swiperId_);
6235 gestureHub->RemovePanEvent(panEvent_);
6236 panEvent_.Reset();
6237 if (isDragging_) {
6238 HandleDragEnd(0.0);
6239 }
6240 }
6241 }
6242
ProcessDelta(float & delta,float mainSize,float deltaSum)6243 void SwiperPattern::ProcessDelta(float& delta, float mainSize, float deltaSum)
6244 {
6245 if (std::abs(delta) > mainSize) {
6246 delta = delta > 0 ? mainSize : -mainSize;
6247 }
6248
6249 if ((std::abs(deltaSum + delta)) > mainSize) {
6250 delta = GreatNotEqual((deltaSum + delta), 0) ? (mainSize - deltaSum) : (-deltaSum - mainSize);
6251 }
6252 }
6253
ContentWillChange(int32_t comingIndex)6254 bool SwiperPattern::ContentWillChange(int32_t comingIndex)
6255 {
6256 return ContentWillChange(GetCurrentIndex(), comingIndex);
6257 }
6258
ContentWillChange(int32_t currentIndex,int32_t comingIndex)6259 bool SwiperPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
6260 {
6261 auto host = GetHost();
6262 CHECK_NULL_RETURN(host, true);
6263 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
6264 CHECK_NULL_RETURN(tabsNode, true);
6265 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
6266 CHECK_NULL_RETURN(tabsPattern, true);
6267 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
6268 CHECK_NULL_RETURN(tabBarNode, true);
6269 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
6270 CHECK_NULL_RETURN(tabBarPattern, true);
6271 if (!tabBarPattern->GetTabContentWillChangeFlag() && tabsPattern->GetInterceptStatus() &&
6272 currentIndex != comingIndex) {
6273 tabBarPattern->ResetTabContentWillChangeFlag();
6274 auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
6275 return ret.has_value() ? ret.value() : true;
6276 }
6277 tabBarPattern->ResetTabContentWillChangeFlag();
6278 return true;
6279 }
6280
CheckSwiperPanEvent(float mainDeltaOrVelocity)6281 bool SwiperPattern::CheckSwiperPanEvent(float mainDeltaOrVelocity)
6282 {
6283 int32_t currentIndex = GetCurrentIndex();
6284 int32_t comingIndex = currentIndex;
6285 if (GreatNotEqual(mainDeltaOrVelocity, 0.0)) {
6286 comingIndex = comingIndex < 1 ? 0 : comingIndex - 1;
6287 } else if (LessNotEqual(mainDeltaOrVelocity, 0.0)) {
6288 comingIndex = comingIndex > TotalCount() - INDEX_DIFF_TWO ? TotalCount() - 1 : comingIndex + 1;
6289 }
6290
6291 auto iter = indexCanChangeMap_.find(comingIndex);
6292 if (iter != indexCanChangeMap_.end()) {
6293 return iter->second;
6294 }
6295 bool ret = ContentWillChange(currentIndex, comingIndex);
6296 indexCanChangeMap_.emplace(comingIndex, ret);
6297 return ret;
6298 }
6299
CalcFirstItemWithoutItemSpace() const6300 std::pair<int32_t, SwiperItemInfo> SwiperPattern::CalcFirstItemWithoutItemSpace() const
6301 {
6302 if (itemPosition_.empty()) {
6303 return std::make_pair(0, SwiperItemInfo {});
6304 }
6305 for (const auto& item : itemPosition_) {
6306 auto startPos = item.second.startPos;
6307 auto endPos = item.second.endPos;
6308 auto itemSpace = GetItemSpace();
6309 startPos -= itemSpace;
6310 if (startPos < 0 && endPos < 0) {
6311 continue;
6312 }
6313 if (startPos <= 0 && endPos > 0) {
6314 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, endPos });
6315 }
6316 if (startPos > 0 && endPos > 0) {
6317 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, endPos });
6318 }
6319 }
6320 return std::make_pair(itemPosition_.begin()->first,
6321 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
6322 }
6323
CalcComingIndex(float mainDelta) const6324 int32_t SwiperPattern::CalcComingIndex(float mainDelta) const
6325 {
6326 auto firstItemInfoInVisibleArea = CalcFirstItemWithoutItemSpace();
6327 auto firstStartPos = firstItemInfoInVisibleArea.second.startPos;
6328 auto firstEndPos = firstItemInfoInVisibleArea.second.endPos;
6329 auto firstItemLength = firstEndPos - firstStartPos;
6330 if (LessOrEqual(firstItemLength, 0)) {
6331 return true;
6332 }
6333
6334 auto firstIndex = firstItemInfoInVisibleArea.first;
6335 auto step = 0;
6336 auto displayCount = GetDisplayCount();
6337 if (GreatNotEqual(mainDelta, 0.0)) {
6338 if (IsSwipeByGroup()) {
6339 step = -displayCount;
6340 } else if (firstIndex >= currentIndex_) {
6341 step = -1;
6342 } else {
6343 step = firstEndPos > firstItemLength ? firstIndex - currentIndex_ - 1 : firstIndex - currentIndex_;
6344 }
6345 } else if (LessNotEqual(mainDelta, 0.0)) {
6346 if (IsSwipeByGroup()) {
6347 step = displayCount;
6348 } else if (firstIndex <= currentIndex_) {
6349 step = 1;
6350 } else {
6351 step = firstIndex - currentIndex_;
6352 step += static_cast<int32_t>(std::ceil(std::abs(firstStartPos) / firstItemLength));
6353 }
6354 }
6355
6356 auto comingIndex = IsLoop() ? GetLoopIndex(currentIndex_ + step)
6357 : std::clamp(GetLoopIndex(currentIndex_) + step, 0, RealTotalCount() - 1);
6358 return comingIndex;
6359 }
6360
CalcWillScrollOffset(int32_t comingIndex)6361 float SwiperPattern::CalcWillScrollOffset(int32_t comingIndex)
6362 {
6363 if (itemPosition_.empty()) {
6364 return 0.0f;
6365 }
6366
6367 auto itemMainSize = CalculateVisibleSize();
6368 if (GetDisplayCount() > 1 && !IsSwipeByGroup()) {
6369 itemMainSize /= GetDisplayCount();
6370 }
6371
6372 if (NeedEnableIgnoreBlankOffset()) {
6373 auto currentIndex = GetLoopIndex(currentIndex_);
6374 comingIndex = GetLoopIndex(comingIndex);
6375 auto realLastIndex = RealTotalCount() - 1;
6376 auto secondIndex = 1;
6377 auto lastIndex = realLastIndex;
6378 auto penultimateIndex = realLastIndex - 1;
6379 if (IsSwipeByGroup()) {
6380 auto displayCount = GetDisplayCount();
6381 secondIndex = displayCount;
6382 lastIndex = SwiperUtils::ComputePageIndex(realLastIndex, displayCount);
6383 penultimateIndex = GetLoopIndex(lastIndex - displayCount);
6384 }
6385
6386 if (((currentIndex == 0 && comingIndex == secondIndex) || (currentIndex == secondIndex && comingIndex == 0)) &&
6387 prevMarginIgnoreBlank_) {
6388 auto offset = itemMainSize - GetPrevMargin();
6389 return offset;
6390 }
6391
6392 if (((currentIndex == penultimateIndex && comingIndex == lastIndex) ||
6393 (currentIndex == lastIndex && comingIndex == penultimateIndex)) &&
6394 nextMarginIgnoreBlank_) {
6395 auto offset = itemMainSize - GetNextMargin();
6396 return offset;
6397 }
6398 }
6399
6400 auto offset = itemMainSize + GetItemSpace();
6401 return offset;
6402 }
6403
CheckContentWillScroll(float checkValue,float mainDelta)6404 bool SwiperPattern::CheckContentWillScroll(float checkValue, float mainDelta)
6405 {
6406 if (itemPosition_.empty()) {
6407 return true;
6408 }
6409
6410 if (!HasOnContentWillScroll()) {
6411 return true;
6412 }
6413
6414 auto comingIndex = CalcComingIndex(checkValue);
6415 bool willScroll = ContentWillScroll(GetLoopIndex(currentIndex_), comingIndex, mainDelta);
6416 return willScroll;
6417 }
6418
ContentWillScroll(int32_t currentIndex,int32_t comingIndex,float offset)6419 bool SwiperPattern::ContentWillScroll(int32_t currentIndex, int32_t comingIndex, float offset)
6420 {
6421 currentIndex = GetLoopIndex(currentIndex);
6422 comingIndex = GetLoopIndex(comingIndex);
6423 auto result = OnContentWillScroll(currentIndex, comingIndex, offset);
6424 if (result && !result.value()) {
6425 return false;
6426 }
6427
6428 return true;
6429 }
6430
OnContentWillScroll(int32_t currentIndex,int32_t comingIndex,float offset) const6431 std::optional<bool> SwiperPattern::OnContentWillScroll(int32_t currentIndex, int32_t comingIndex, float offset) const
6432 {
6433 std::optional<bool> ret;
6434 if (!HasOnContentWillScroll()) {
6435 return ret;
6436 }
6437
6438 if (currentIndex != comingIndex) {
6439 auto event = *onContentWillScroll_;
6440 SwiperContentWillScrollResult result;
6441 result.currentIndex = currentIndex;
6442 result.comingIndex = comingIndex;
6443 result.offset = offset;
6444 ret = event(result);
6445 }
6446 return ret;
6447 }
6448
HandleTouchBottomLoopOnRTL()6449 void SwiperPattern::HandleTouchBottomLoopOnRTL()
6450 {
6451 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6452 auto currentIndex = GetLoopIndex(currentIndex_);
6453 auto totalCount = TotalCount();
6454 auto displayCount = GetDisplayCount();
6455 bool commTouchBottom = (currentFirstIndex == totalCount - 1);
6456 bool releaseLeftTouchBottomStart = (currentIndex == totalCount - 1);
6457 bool releaseLeftTouchBottomEnd = (currentFirstIndex == 0);
6458 bool releaseRightTouchBottom = (currentFirstIndex == totalCount - 1);
6459 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && IsSwipeByGroup()) {
6460 commTouchBottom = (currentFirstIndex >= totalCount - displayCount);
6461 releaseLeftTouchBottomStart = (currentIndex == totalCount - displayCount);
6462 releaseRightTouchBottom = (currentFirstIndex >= totalCount - displayCount);
6463 releaseLeftTouchBottomEnd = (currentFirstIndex < displayCount);
6464 }
6465 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
6466 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
6467 if (followTouchBottom) {
6468 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
6469 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6470 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
6471 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6472 }
6473 return;
6474 }
6475
6476 if (releaseLeftTouchBottomEnd && releaseLeftTouchBottomStart &&
6477 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT) {
6478 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6479 return;
6480 }
6481
6482 if (releaseRightTouchBottom && currentIndex == 0 &&
6483 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
6484 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6485 return;
6486 }
6487 }
6488
HandleTouchBottomLoop()6489 void SwiperPattern::HandleTouchBottomLoop()
6490 {
6491 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6492 auto currentIndex = GetLoopIndex(currentIndex_);
6493 if (IsHorizontalAndRightToLeft()) {
6494 currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
6495 currentIndex = TotalCount() - 1 - currentIndex;
6496 }
6497
6498 bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
6499 bool releaseTouchBottom = (currentIndex == TotalCount() - 1);
6500 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && IsSwipeByGroup()) {
6501 commTouchBottom = currentFirstIndex >= TotalCount() - GetDisplayCount();
6502 releaseTouchBottom = currentIndex >= TotalCount() - GetDisplayCount();
6503 }
6504 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
6505 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
6506 if (followTouchBottom) {
6507 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
6508 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6509 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
6510 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6511 }
6512 return;
6513 }
6514
6515 bool leftReleaseTouchBottom =
6516 (commTouchBottom && (currentIndex == 0 && gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT));
6517 bool rightReleaseTouchBottom = ((currentFirstIndex == 0) && (releaseTouchBottom) &&
6518 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT);
6519 if (leftReleaseTouchBottom || rightReleaseTouchBottom) {
6520 if (currentIndex == 0) {
6521 // left bottom
6522 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6523 } else if (releaseTouchBottom) {
6524 // right bottom
6525 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6526 }
6527 }
6528 return;
6529 }
6530
CalculateGestureStateOnRTL(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)6531 void SwiperPattern::CalculateGestureStateOnRTL(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
6532 {
6533 if (GreatNotEqual(additionalOffset, 0.0f)) {
6534 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
6535 needTurn_ = false;
6536 return;
6537 }
6538
6539 if (LessNotEqual(additionalOffset, 0.0f)) {
6540 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
6541 needTurn_ = false;
6542 return;
6543 }
6544
6545 auto currentIndex = GetLoopIndex(currentIndex_);
6546 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6547 if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
6548 needTurn_ = true;
6549 if (isTouchDown_ && GreatOrEqual(mainDeltaSum_, 0.0f)) {
6550 needTurn_ = false;
6551 }
6552 } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
6553 needTurn_ = true;
6554 if (isTouchDown_ && (LessOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
6555 needTurn_ = false;
6556 }
6557 }
6558
6559 if (!IsLoop()) {
6560 needTurn_ = false;
6561 }
6562
6563 if (currentFirstIndex >= currentIndex) {
6564 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
6565 return;
6566 }
6567
6568 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
6569 }
6570
CalculateGestureState(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)6571 void SwiperPattern::CalculateGestureState(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
6572 {
6573 auto currentIndex = GetLoopIndex(currentIndex_);
6574 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6575 if (IsHorizontalAndRightToLeft()) {
6576 preFirstIndex = TotalCount() - 1 - preFirstIndex;
6577 currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
6578 currentIndex = TotalCount() - 1 - currentIndex;
6579 }
6580
6581 // Keep follow hand
6582 if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
6583 needTurn_ = true;
6584 if (isTouchDown_ && LessOrEqual(mainDeltaSum_, 0.0f) && !childScrolling_) {
6585 needTurn_ = false;
6586 }
6587 } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
6588 needTurn_ = true;
6589 if (isTouchDown_ && (GreatOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
6590 needTurn_ = false;
6591 }
6592 }
6593
6594 if (GreatNotEqual(additionalOffset, 0.0f)) {
6595 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
6596 needTurn_ = false;
6597 } else if (LessNotEqual(additionalOffset, 0.0f)) {
6598 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
6599 needTurn_ = false;
6600 } else if (currentFirstIndex >= currentIndex) {
6601 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
6602
6603 if (!IsLoop() && currentFirstIndex == 0 && GreatOrEqual(mainDeltaSum_, 0.0f)) {
6604 gestureState_ = GestureState::GESTURE_STATE_FOLLOW_LEFT;
6605 needTurn_ = false;
6606 }
6607
6608 if (!IsLoop() && currentFirstIndex == TotalCount() - 1 && LessOrEqual(mainDeltaSum_, 0.0f)) {
6609 gestureState_ = GestureState::GESTURE_STATE_FOLLOW_RIGHT;
6610 needTurn_ = false;
6611 }
6612 } else if (currentFirstIndex < currentIndex) {
6613 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
6614 }
6615 return;
6616 }
6617
CalcCurrentPageStatusOnRTL(float additionalOffset,bool isTouchBottom) const6618 std::pair<float, float> SwiperPattern::CalcCurrentPageStatusOnRTL(float additionalOffset, bool isTouchBottom) const
6619 {
6620 float currentTurnPageRate = FLT_MAX;
6621 auto firstIndex = currentFirstIndex_;
6622 auto itemMainSize = CalculateVisibleSize();
6623 auto itemSpace = GetItemSpace();
6624 for (auto iter = itemPosition_.rbegin(); iter != itemPosition_.rend(); iter++) {
6625 auto startPos = itemMainSize - iter->second.endPos;
6626 auto endPos = itemMainSize - iter->second.startPos;
6627 if (isTouchBottom && Positive(itemSpace)) {
6628 startPos += itemSpace;
6629 endPos += itemSpace;
6630 }
6631
6632 if (LessNotEqual((startPos + additionalOffset), 0) && LessNotEqual((endPos + additionalOffset), 0)) {
6633 continue;
6634 }
6635 if (GreatOrEqual((startPos + additionalOffset), 0) && GreatNotEqual((endPos + additionalOffset), 0)) {
6636 firstIndex = iter->first;
6637 currentTurnPageRate = 0.0f;
6638 break;
6639 }
6640 if (GreatNotEqual((endPos + additionalOffset), 0)) {
6641 firstIndex = iter->first;
6642 currentTurnPageRate =
6643 (NearEqual(endPos, startPos) ? 0 : ((startPos + additionalOffset) / (endPos - startPos)));
6644 break;
6645 }
6646 }
6647
6648 return std::make_pair(currentTurnPageRate, firstIndex);
6649 }
6650
CalcCurrentTurnPageRate(bool isTouchBottom) const6651 float SwiperPattern::CalcCurrentTurnPageRate(bool isTouchBottom) const
6652 {
6653 if (IsHorizontalAndRightToLeft()) {
6654 return CalcCurrentPageStatusOnRTL(0.0f, isTouchBottom).first;
6655 }
6656
6657 return CalcCurrentPageStatus(0.0f).first;
6658 }
6659
CalcCurrentPageStatus(float additionalOffset) const6660 std::pair<float, float> SwiperPattern::CalcCurrentPageStatus(float additionalOffset) const
6661 {
6662 float currentTurnPageRate = FLT_MAX;
6663 auto firstIndex = currentFirstIndex_;
6664 for (const auto& iter : itemPosition_) {
6665 if (LessNotEqual((iter.second.startPos + additionalOffset), 0) &&
6666 LessNotEqual((iter.second.endPos + additionalOffset), 0)) {
6667 continue;
6668 }
6669 if (GreatOrEqual((iter.second.startPos + additionalOffset), 0) &&
6670 GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
6671 firstIndex = iter.first;
6672 currentTurnPageRate = 0.0f;
6673 break;
6674 }
6675 if (GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
6676 firstIndex = iter.first;
6677 currentTurnPageRate =
6678 (NearEqual(iter.second.endPos, iter.second.startPos)
6679 ? 0
6680 : ((iter.second.startPos + additionalOffset) / (iter.second.endPos - iter.second.startPos)));
6681 break;
6682 }
6683 }
6684
6685 return std::make_pair(currentTurnPageRate, firstIndex);
6686 }
6687
StopIndicatorAnimation(bool ifImmediately)6688 void SwiperPattern::StopIndicatorAnimation(bool ifImmediately)
6689 {
6690 AnimationUtils::StopAnimation(indicatorAnimation_);
6691
6692 if (stopIndicatorAnimationFunc_) {
6693 stopIndicatorAnimationFunc_(ifImmediately);
6694 }
6695 }
6696
FireWillHideEvent(int32_t willHideIndex) const6697 void SwiperPattern::FireWillHideEvent(int32_t willHideIndex) const
6698 {
6699 if (!hasTabsAncestor_) {
6700 return;
6701 }
6702 auto host = GetHost();
6703 CHECK_NULL_VOID(host);
6704 auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willHideIndex));
6705 CHECK_NULL_VOID(tabContentNode);
6706 auto tabContentEventHub = tabContentNode->GetEventHub<TabContentEventHub>();
6707 CHECK_NULL_VOID(tabContentEventHub);
6708 tabContentEventHub->FireWillHideEvent();
6709 }
6710
FireWillShowEvent(int32_t willShowIndex) const6711 void SwiperPattern::FireWillShowEvent(int32_t willShowIndex) const
6712 {
6713 if (!hasTabsAncestor_) {
6714 return;
6715 }
6716 auto host = GetHost();
6717 CHECK_NULL_VOID(host);
6718 auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willShowIndex));
6719 CHECK_NULL_VOID(tabContentNode);
6720 auto tabContentEventHub = tabContentNode->GetEventHub<TabContentEventHub>();
6721 CHECK_NULL_VOID(tabContentEventHub);
6722 tabContentEventHub->FireWillShowEvent();
6723 }
6724
SetOnHiddenChangeForParent()6725 void SwiperPattern::SetOnHiddenChangeForParent()
6726 {
6727 auto host = GetHost();
6728 CHECK_NULL_VOID(host);
6729 auto parent = host->GetAncestorNodeOfFrame(false);
6730 CHECK_NULL_VOID(parent);
6731 while (parent) {
6732 if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6733 break;
6734 }
6735 parent = parent->GetAncestorNodeOfFrame(false);
6736 }
6737 auto onHiddenChange = [weak = WeakClaim(this)](bool isShow) {
6738 auto swiperPattern = weak.Upgrade();
6739 CHECK_NULL_VOID(swiperPattern);
6740 auto index = swiperPattern->GetCurrentIndex();
6741
6742 if (isShow) {
6743 swiperPattern->FireWillShowEvent(index);
6744 } else {
6745 swiperPattern->FireWillHideEvent(index);
6746 }
6747 swiperPattern->isParentHiddenChange_ = true;
6748 };
6749 CHECK_NULL_VOID(parent);
6750 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
6751 auto pagePattern = parent->GetPattern<PagePattern>();
6752 CHECK_NULL_VOID(pagePattern);
6753 pagePattern->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
6754 }
6755
6756 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6757 auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
6758 CHECK_NULL_VOID(navDestinationePattern);
6759 auto navDestinationEventHub = navDestinationePattern->GetEventHub<NavDestinationEventHub>();
6760 CHECK_NULL_VOID(navDestinationEventHub);
6761 navDestinationEventHub->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
6762 }
6763 }
6764
RemoveOnHiddenChange()6765 void SwiperPattern::RemoveOnHiddenChange()
6766 {
6767 auto host = GetHost();
6768 CHECK_NULL_VOID(host);
6769 auto parent = host->GetAncestorNodeOfFrame(false);
6770 CHECK_NULL_VOID(parent);
6771 while (parent) {
6772 if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6773 break;
6774 }
6775 parent = parent->GetAncestorNodeOfFrame(false);
6776 }
6777 CHECK_NULL_VOID(parent);
6778 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
6779 auto pagePattern = parent->GetPattern<PagePattern>();
6780 CHECK_NULL_VOID(pagePattern);
6781 pagePattern->RemoveOnHiddenChange(host->GetId());
6782 }
6783 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6784 auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
6785 CHECK_NULL_VOID(navDestinationePattern);
6786 auto navDestinationEventHub = navDestinationePattern->GetEventHub<NavDestinationEventHub>();
6787 CHECK_NULL_VOID(navDestinationEventHub);
6788 navDestinationEventHub->RemoveOnHiddenChange(host->GetId());
6789 }
6790 }
6791
FindLazyForEachNode(RefPtr<UINode> baseNode,bool isSelfNode) const6792 std::optional<RefPtr<UINode>> SwiperPattern::FindLazyForEachNode(RefPtr<UINode> baseNode, bool isSelfNode) const
6793 {
6794 if (AceType::DynamicCast<LazyForEachNode>(baseNode)) {
6795 return baseNode;
6796 }
6797 if (AceType::DynamicCast<RepeatVirtualScrollNode>(baseNode)) {
6798 return baseNode;
6799 }
6800 if (!isSelfNode && AceType::DynamicCast<FrameNode>(baseNode)) {
6801 return std::nullopt;
6802 }
6803 for (const auto& child : baseNode->GetChildren()) {
6804 auto targetNode = FindLazyForEachNode(child, false);
6805 if (targetNode.has_value()) {
6806 return targetNode;
6807 }
6808 }
6809 return std::nullopt;
6810 }
6811
FindForEachNode(const RefPtr<UINode> & baseNode,bool isSelfNode) const6812 std::optional<RefPtr<UINode>> SwiperPattern::FindForEachNode(const RefPtr<UINode>& baseNode, bool isSelfNode) const
6813 {
6814 if (AceType::DynamicCast<ForEachNode>(baseNode)) {
6815 return baseNode;
6816 }
6817
6818 if (AceType::DynamicCast<RepeatVirtualScrollNode>(baseNode)) {
6819 return baseNode;
6820 }
6821
6822 if (!isSelfNode && AceType::DynamicCast<FrameNode>(baseNode)) {
6823 return std::nullopt;
6824 }
6825
6826 for (const auto& child : baseNode->GetChildren()) {
6827 auto targetNode = FindForEachNode(child, false);
6828 if (targetNode.has_value()) {
6829 return targetNode;
6830 }
6831 }
6832
6833 return std::nullopt;
6834 }
6835
CreateNodePaintMethod()6836 RefPtr<NodePaintMethod> SwiperPattern::CreateNodePaintMethod()
6837 {
6838 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
6839 CHECK_NULL_RETURN(props, nullptr);
6840 const auto& paddingProperty = props->GetPaddingProperty();
6841 bool needClipPadding = paddingProperty != nullptr;
6842 bool needPaintFade = !IsLoop() && GetEdgeEffect() == EdgeEffect::FADE && !NearZero(fadeOffset_);
6843 auto paintMethod =
6844 MakeRefPtr<SwiperPaintMethod>(GetDirection(), IsHorizontalAndRightToLeft() ? -fadeOffset_ : fadeOffset_);
6845 paintMethod->SetNeedPaintFade(needPaintFade);
6846 paintMethod->SetNeedClipPadding(needClipPadding);
6847 return paintMethod;
6848 }
6849
UpdateNodeRate()6850 void SwiperPattern::UpdateNodeRate()
6851 {
6852 auto host = GetHost();
6853 CHECK_NULL_VOID(host);
6854 auto pipelineContext = GetContext();
6855 CHECK_NULL_VOID(pipelineContext);
6856 auto frameRateManager = pipelineContext->GetFrameRateManager();
6857 CHECK_NULL_VOID(frameRateManager);
6858 auto nodeId = host->GetId();
6859 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::GESTURE);
6860 if (iter != frameRateRange_.end() && iter->second->IsValid()) {
6861 auto expectedRate = iter->second->preferred_;
6862 TAG_LOGI(AceLogTag::ACE_SWIPER, "Expected gesture frame rate is: %{public}d", expectedRate);
6863 frameRateManager->UpdateNodeRate(nodeId, expectedRate);
6864 }
6865 }
6866
GetBindIndicatorParameters() const6867 std::shared_ptr<SwiperParameters> SwiperPattern::GetBindIndicatorParameters() const
6868 {
6869 auto bindIndicatorNode = GetIndicatorNode();
6870 CHECK_NULL_RETURN(bindIndicatorNode, nullptr);
6871 auto indicatorPattern = bindIndicatorNode->GetPattern<IndicatorPattern>();
6872 CHECK_NULL_RETURN(indicatorPattern, nullptr);
6873 return indicatorPattern->GetIndicatorParameters();
6874 }
6875
GetMaxDisplayCount() const6876 int32_t SwiperPattern::GetMaxDisplayCount() const
6877 {
6878 auto indicatorParameters = isBindIndicator_ ? GetBindIndicatorParameters() : swiperParameters_;
6879 if (!indicatorParameters || !indicatorParameters->maxDisplayCountVal.has_value()) {
6880 return 0;
6881 }
6882
6883 auto maxDisplayCount = indicatorParameters->maxDisplayCountVal.value();
6884 if (maxDisplayCount < MAX_DISPLAY_COUNT_MIN || maxDisplayCount > MAX_DISPLAY_COUNT_MAX) {
6885 return 0;
6886 }
6887
6888 auto childrenSize = RealTotalCount();
6889 if (childrenSize <= maxDisplayCount) {
6890 return 0;
6891 }
6892
6893 return maxDisplayCount;
6894 }
6895
SetIndicatorChangeIndexStatus(bool withAnimation,std::optional<int32_t> startIndex)6896 void SwiperPattern::SetIndicatorChangeIndexStatus(bool withAnimation, std::optional<int32_t> startIndex)
6897 {
6898 auto indicatorNode = GetCommonIndicatorNode();
6899 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
6900 return;
6901 }
6902
6903 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
6904 CHECK_NULL_VOID(indicatorPattern);
6905
6906 indicatorPattern->SetChangeIndexWithAnimation(withAnimation);
6907 indicatorPattern->SetStartIndex(startIndex);
6908 }
6909
SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)6910 void SwiperPattern::SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)
6911 {
6912 if (GetMaxDisplayCount() <= 0) {
6913 return;
6914 }
6915 auto indicatorNode = GetCommonIndicatorNode();
6916 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
6917 return;
6918 }
6919
6920 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
6921 CHECK_NULL_VOID(indicatorPattern);
6922
6923 indicatorPattern->SetJumpIndex(jumpIndex);
6924 }
6925
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const6926 void SwiperPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
6927 {
6928 CHECK_NULL_VOID(json);
6929 Pattern::ToJsonValue(json, filter);
6930 /* no fixed attr below, just return */
6931 if (filter.IsFastFilter()) {
6932 return;
6933 }
6934
6935 auto nestedScroll = GetNestedScroll().forward;
6936 json->PutExtAttr("nestedScroll",
6937 nestedScroll == NestedScrollMode::SELF_ONLY ? "SwiperNestedScrollMode.SELF_ONLY"
6938 : "SwiperNestedScrollMode.SELF_FIRST",
6939 filter);
6940 json->PutExtAttr("stopWhenTouched", IsStopWhenTouched() ? "true" : "false", filter);
6941 json->PutExtAttr("currentIndex", currentIndex_, filter);
6942 json->PutExtAttr("currentOffset", currentOffset_, filter);
6943 json->PutExtAttr("uiCastJumpIndex", uiCastJumpIndex_.value_or(-1), filter);
6944
6945 if (indicatorIsBoolean_) {
6946 return;
6947 }
6948
6949 auto indicatorType = GetIndicatorType();
6950 const char* indicator = "indicator";
6951 if (indicatorType == SwiperIndicatorType::DOT) {
6952 json->PutExtAttr(indicator, SwiperHelper::GetDotIndicatorStyle(GetSwiperParameters()).c_str(), filter);
6953 } else if (indicatorType == SwiperIndicatorType::ARC_DOT) {
6954 json->PutExtAttr(indicator, GetArcDotIndicatorStyle().c_str(), filter);
6955 } else {
6956 json->PutExtAttr(
6957 indicator, SwiperHelper::GetDigitIndicatorStyle(GetSwiperDigitalParameters()).c_str(), filter);
6958 }
6959 }
6960
FromJson(const std::unique_ptr<JsonValue> & json)6961 void SwiperPattern::FromJson(const std::unique_ptr<JsonValue>& json)
6962 {
6963 CHECK_NULL_VOID(json);
6964 currentIndex_ = json->GetInt("currentIndex");
6965 auto currentOffset = json->GetDouble("currentOffset");
6966 auto jumpIndex = json->GetInt("uiCastJumpIndex");
6967 if (currentOffset != currentOffset_) {
6968 auto delta = currentOffset - currentOffset_;
6969 UpdateCurrentOffset(delta);
6970 } else if (jumpIndex >= 0) {
6971 jumpIndex_ = jumpIndex;
6972 MarkDirtyNodeSelf();
6973 }
6974 Pattern::FromJson(json);
6975 }
6976
GetGestureState()6977 GestureState SwiperPattern::GetGestureState()
6978 {
6979 auto gestureState = gestureState_;
6980 if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
6981 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
6982 gestureState_ = GestureState::GESTURE_STATE_NONE;
6983 }
6984
6985 return gestureState;
6986 }
6987
SetSwiperController(const RefPtr<SwiperController> & controller)6988 void SwiperPattern::SetSwiperController(const RefPtr<SwiperController>& controller)
6989 {
6990 CHECK_NULL_VOID(controller);
6991 swiperController_ = controller;
6992 SwiperHelper::InitSwiperController(controller, WeakClaim(this));
6993 }
6994
SetPropertyAnimationIsRunning(bool propertyAnimationIsRunning)6995 void SwiperPattern::SetPropertyAnimationIsRunning(bool propertyAnimationIsRunning)
6996 {
6997 propertyAnimationIsRunning_ = propertyAnimationIsRunning;
6998 }
6999
GetPropertyAnimationIsRunning()7000 bool SwiperPattern::GetPropertyAnimationIsRunning()
7001 {
7002 return propertyAnimationIsRunning_;
7003 }
7004
IsItemOverlay() const7005 bool SwiperPattern::IsItemOverlay() const
7006 {
7007 if (itemPosition_.empty()) {
7008 return false;
7009 }
7010 float lastItemEndPos = 0.0f;
7011 for (auto& item : itemPosition_) {
7012 auto frameNode = item.second.node;
7013 if (!frameNode) {
7014 continue;
7015 }
7016 auto renderContext = frameNode->GetRenderContext();
7017 if (!renderContext) {
7018 continue;
7019 }
7020 RectF rect = renderContext->GetPaintRectWithoutTransform();
7021 if (item.first == itemPosition_.begin()->first) {
7022 lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
7023 continue;
7024 }
7025 float currentItemStartPos = direction_ == Axis::HORIZONTAL ? rect.Left() : rect.Top();
7026 if (GreatNotEqual(lastItemEndPos, currentItemStartPos)) {
7027 return true;
7028 }
7029 lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
7030 }
7031 return false;
7032 }
7033
CheckSpecialItemCount() const7034 void SwiperPattern::CheckSpecialItemCount() const
7035 {
7036 auto swiperNode = AceType::DynamicCast<SwiperNode>(GetHost());
7037 CHECK_NULL_VOID(swiperNode);
7038 swiperNode->SetSpecialItemCount(indicatorId_.has_value() + leftButtonId_.has_value() + rightButtonId_.has_value() +
7039 leftCaptureId_.has_value() + rightCaptureId_.has_value());
7040 }
7041
CheckIndexRange(int32_t index) const7042 int32_t SwiperPattern::CheckIndexRange(int32_t index) const
7043 {
7044 auto itemCount = TotalCount();
7045 auto displayCount = GetDisplayCount();
7046 if (index < 0 || index >= itemCount || displayCount >= itemCount) {
7047 index = 0;
7048 } else if (!IsLoop() && index > itemCount - displayCount) {
7049 index = itemCount - displayCount;
7050 }
7051 return index;
7052 }
7053
DumpAdvanceInfo(std::unique_ptr<JsonValue> & json)7054 void SwiperPattern::DumpAdvanceInfo(std::unique_ptr<JsonValue>& json)
7055 {
7056 json->Put("isLastIndicatorFocused", isLastIndicatorFocused_);
7057 json->Put("moveDirection", moveDirection_);
7058 json->Put("indicatorDoingAnimation", indicatorDoingAnimation_);
7059 json->Put("hasVisibleChangeRegistered", hasVisibleChangeRegistered_);
7060 json->Put("isVisible", isVisible_);
7061 json->Put("isVisibleArea", isVisibleArea_);
7062 json->Put("isWindowShow", isWindowShow_);
7063 json->Put("IsCustomSize", isCustomSize_);
7064 json->Put("indicatorIsBoolean", indicatorIsBoolean_);
7065 json->Put("isAtHotRegion", isAtHotRegion_);
7066 json->Put("isDragging", isDragging_);
7067 json->Put("isTouchDown", isTouchDown_);
7068 json->Put("preLoop", preLoop_.has_value() ? std::to_string(preLoop_.value()).c_str() : "null");
7069 json->Put("indicatorId", indicatorId_.has_value() ? std::to_string(indicatorId_.value()).c_str() : "null");
7070 json->Put("leftButtonId", leftButtonId_.has_value() ? std::to_string(leftButtonId_.value()).c_str() : "null");
7071 json->Put("rightButtonId", rightButtonId_.has_value() ? std::to_string(rightButtonId_.value()).c_str() : "null");
7072 json->Put("crossMatchChild", crossMatchChild_);
7073 json->Put(
7074 "uiCastJumpIndex", uiCastJumpIndex_.has_value() ? std::to_string(uiCastJumpIndex_.value()).c_str() : "null");
7075 json->Put("jumpIndex", jumpIndex_.has_value() ? std::to_string(jumpIndex_.value()).c_str() : "null");
7076 json->Put("targetIndex", targetIndex_.has_value() ? std::to_string(targetIndex_.value()).c_str() : "null");
7077 json->Put(
7078 "pauseTargetIndex", pauseTargetIndex_.has_value() ? std::to_string(pauseTargetIndex_.value()).c_str() : "null");
7079 json->Put("velocity", velocity_.has_value() ? std::to_string(velocity_.value()).c_str() : "null");
7080 json->Put("curve", GetCurveIncludeMotion() ? GetCurveIncludeMotion()->ToString().c_str() : "null");
7081 json->Put("isFinishAnimation", isFinishAnimation_);
7082 json->Put("mainSizeIsMeasured", mainSizeIsMeasured_);
7083 json->Put("usePropertyAnimation", propertyAnimationIsRunning_);
7084 json->Put("isUserFinish", isUserFinish_);
7085 json->Put("isVoluntarilyClear", isVoluntarilyClear_);
7086 json->Put("isIndicatorLongPress", isIndicatorLongPress_);
7087 json->Put("stopIndicatorAnimation", stopIndicatorAnimation_);
7088 json->Put("isTouchPad", isTouchPad_);
7089 json->Put("surfaceChangedCallbackId",
7090 surfaceChangedCallbackId_.has_value() ? std::to_string(surfaceChangedCallbackId_.value()).c_str() : "null");
7091 json->Put("currentIndex", currentIndex_);
7092 json->Put("oldIndex", oldIndex_);
7093 BuildOffsetInfo(json);
7094 BuildIndicatorTypeInfo(json);
7095 BuildItemPositionInfo(json);
7096 BuildPanDirectionInfo(json);
7097 BuildAxisInfo(json);
7098 }
7099
BuildOffsetInfo(std::unique_ptr<JsonValue> & json)7100 void SwiperPattern::BuildOffsetInfo(std::unique_ptr<JsonValue>& json)
7101 {
7102 json->Put("currentOffset", std::to_string(currentOffset_).c_str());
7103 json->Put("fadeOffset", std::to_string(fadeOffset_).c_str());
7104 json->Put("touchBottomRate", std::to_string(touchBottomRate_).c_str());
7105 json->Put("currentIndexOffset", std::to_string(currentIndexOffset_).c_str());
7106 json->Put("gestureSwipeIndex", gestureSwipeIndex_);
7107 json->Put("currentFirstIndex", currentFirstIndex_);
7108 json->Put("startMainPos", startMainPos_);
7109 json->Put("endMainPos", endMainPos_);
7110 json->Put("contentMainSize", contentMainSize_);
7111 json->Put("contentCrossSize", contentCrossSize_);
7112 json->Put("propertyAnimationIndex", propertyAnimationIndex_);
7113 json->Put("mainDeltaSum", mainDeltaSum_);
7114 }
7115
BuildAxisInfo(std::unique_ptr<JsonValue> & json)7116 void SwiperPattern::BuildAxisInfo(std::unique_ptr<JsonValue>& json)
7117 {
7118 switch (direction_) {
7119 case Axis::NONE: {
7120 json->Put("Axis", "NONE");
7121 break;
7122 }
7123 case Axis::HORIZONTAL: {
7124 json->Put("Axis", "HORIZONTAL");
7125 break;
7126 }
7127 case Axis::FREE: {
7128 json->Put("Axis", "FREE");
7129 break;
7130 }
7131 case Axis::VERTICAL: {
7132 json->Put("Axis", "VERTICAL");
7133 break;
7134 }
7135 default: {
7136 break;
7137 }
7138 }
7139 }
7140
BuildItemPositionInfo(std::unique_ptr<JsonValue> & json)7141 void SwiperPattern::BuildItemPositionInfo(std::unique_ptr<JsonValue>& json)
7142 {
7143 if (!itemPosition_.empty()) {
7144 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
7145 for (auto item : itemPosition_) {
7146 std::unique_ptr<JsonValue> child = JsonUtil::CreateArray(true);
7147 child->Put("id", item.first);
7148 child->Put("startPos", std::to_string(item.second.startPos).c_str());
7149 child->Put("endPos", std::to_string(item.second.endPos).c_str());
7150 children->Put(child);
7151 }
7152 json->Put("itemPosition", children);
7153 }
7154 if (!itemPositionInAnimation_.empty()) {
7155 std::unique_ptr<JsonValue> children = JsonUtil::CreateArray(true);
7156 for (auto item : itemPositionInAnimation_) {
7157 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
7158 child->Put("id", item.first);
7159 child->Put("startPos", std::to_string(item.second.startPos).c_str());
7160 child->Put("endPos", std::to_string(item.second.endPos).c_str());
7161 children->Put(child);
7162 }
7163 json->Put("itemPositionInAnimation", children);
7164 }
7165 }
7166
BuildIndicatorTypeInfo(std::unique_ptr<JsonValue> & json)7167 void SwiperPattern::BuildIndicatorTypeInfo(std::unique_ptr<JsonValue>& json)
7168 {
7169 if (lastSwiperIndicatorType_.has_value()) {
7170 switch (lastSwiperIndicatorType_.value()) {
7171 case SwiperIndicatorType::DOT: {
7172 json->Put("SwiperIndicatorType", "DOT");
7173 break;
7174 }
7175 case SwiperIndicatorType::DIGIT: {
7176 json->Put("SwiperIndicatorType", "DIGIT");
7177 break;
7178 }
7179 default: {
7180 break;
7181 }
7182 }
7183 } else {
7184 json->Put("lastSwiperIndicatorType", "null");
7185 }
7186 }
7187
BuildPanDirectionInfo(std::unique_ptr<JsonValue> & json)7188 void SwiperPattern::BuildPanDirectionInfo(std::unique_ptr<JsonValue>& json)
7189 {
7190 switch (panDirection_.type) {
7191 case PanDirection::NONE: {
7192 json->Put("PanDirection", "NONE");
7193 break;
7194 }
7195 case PanDirection::LEFT: {
7196 json->Put("PanDirection", "LEFT");
7197 break;
7198 }
7199 case PanDirection::RIGHT: {
7200 json->Put("PanDirection", "RIGHT");
7201 break;
7202 }
7203 case PanDirection::HORIZONTAL: {
7204 json->Put("PanDirection", "HORIZONTAL");
7205 break;
7206 }
7207 case PanDirection::UP: {
7208 json->Put("PanDirection", "UP");
7209 break;
7210 }
7211 case PanDirection::DOWN: {
7212 json->Put("PanDirection", "DOWN");
7213 break;
7214 }
7215 case PanDirection::VERTICAL: {
7216 json->Put("PanDirection", "VERTICAL");
7217 break;
7218 }
7219 case PanDirection::ALL: {
7220 json->Put("PanDirection", "ALL");
7221 break;
7222 }
7223 default: {
7224 break;
7225 }
7226 }
7227 }
7228
SetPageFlipMode(int32_t pageFlipMode)7229 void SwiperPattern::SetPageFlipMode(int32_t pageFlipMode)
7230 {
7231 if (pageFlipMode < 0 || pageFlipMode > PAGE_FLIP_MODE_SIZE - 1) {
7232 pageFlipMode_ = PageFlipMode::CONTINUOUS;
7233 return;
7234 }
7235 pageFlipMode_ = static_cast<PageFlipMode>(pageFlipMode);
7236 }
7237
GetCommonIndicatorNode()7238 RefPtr<FrameNode> SwiperPattern::GetCommonIndicatorNode()
7239 {
7240 if (isBindIndicator_) {
7241 return GetIndicatorNode();
7242 } else {
7243 CHECK_NULL_RETURN(indicatorId_.has_value(), nullptr);
7244 auto host = GetHost();
7245 CHECK_NULL_RETURN(host, nullptr);
7246 return DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
7247 }
7248 }
7249
SetIndicatorNode(const WeakPtr<NG::UINode> & indicatorNode)7250 void SwiperPattern::SetIndicatorNode(const WeakPtr<NG::UINode>& indicatorNode)
7251 {
7252 if (isBindIndicator_) {
7253 indicatorNode_ = indicatorNode;
7254 auto host = GetHost();
7255 CHECK_NULL_VOID(host);
7256 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7257
7258 auto frameIndicatorNode = GetIndicatorNode();
7259 CHECK_NULL_VOID(frameIndicatorNode);
7260 frameIndicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7261 }
7262 }
7263 } // namespace OHOS::Ace::NG
7264