• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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