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