• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/geometry/axis.h"
24 #include "base/geometry/dimension.h"
25 #include "base/geometry/ng/offset_t.h"
26 #include "base/log/ace_trace.h"
27 #include "base/log/log_wrapper.h"
28 #include "base/perfmonitor/perf_constants.h"
29 #include "base/perfmonitor/perf_monitor.h"
30 #include "base/ressched/ressched_report.h"
31 #include "base/utils/utils.h"
32 #include "core/animation/curve.h"
33 #include "core/animation/curves.h"
34 #include "core/animation/spring_curve.h"
35 #include "core/common/container_scope.h"
36 #include "core/common/recorder/node_data_cache.h"
37 #include "core/components/common/layout/constants.h"
38 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
39 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
40 #include "core/components_ng/pattern/stage/page_pattern.h"
41 #include "core/components_ng/pattern/swiper/swiper_helper.h"
42 #include "core/components_ng/pattern/swiper/swiper_layout_algorithm.h"
43 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
44 #include "core/components_ng/pattern/swiper/swiper_model.h"
45 #include "core/components_ng/pattern/swiper/swiper_node.h"
46 #include "core/components_ng/pattern/swiper/swiper_paint_method.h"
47 #include "core/components_ng/pattern/swiper/swiper_paint_property.h"
48 #include "core/components_ng/pattern/swiper/swiper_utils.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/pattern/tabs/tabs_pattern.h"
55 #include "core/components_ng/property/measure_utils.h"
56 #include "core/components_ng/property/property.h"
57 #include "core/components_ng/render/adapter/component_snapshot.h"
58 #include "core/components_ng/syntax/for_each_node.h"
59 #include "core/components_ng/syntax/lazy_for_each_node.h"
60 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
61 #include "core/components_v2/inspector/inspector_constants.h"
62 #include "core/event/ace_events.h"
63 #include "core/event/touch_event.h"
64 #include "core/pipeline_ng/pipeline_context.h"
65 
66 namespace OHOS::Ace::NG {
67 namespace {
68 
69 // TODO use theme.
70 constexpr int32_t MAX_DISPLAY_COUNT_MIN = 6;
71 constexpr int32_t MAX_DISPLAY_COUNT_MAX = 9;
72 constexpr int32_t MIN_TURN_PAGE_VELOCITY = 1200;
73 constexpr int32_t NEW_MIN_TURN_PAGE_VELOCITY = 780;
74 constexpr int32_t ERROR_CODE_NO_ERROR = 0;
75 constexpr int32_t ERROR_CODE_PARAM_INVALID = 401;
76 constexpr Dimension INDICATOR_BORDER_RADIUS = 16.0_vp;
77 
78 constexpr float PX_EPSILON = 0.01f;
79 constexpr float FADE_DURATION = 500.0f;
80 constexpr float SPRING_DURATION = 600.0f;
81 constexpr float DEFAULT_MINIMUM_AMPLITUDE_PX = 1.0f;
82 constexpr int32_t INDEX_DIFF_TWO = 2;
83 constexpr int32_t FIRST_CAPTURE_DELAY_TIME = 30;
84 const std::string SWIPER_DRAG_SCENE = "swiper_drag_scene";
85 const std::string FADE_PROPERTY_NAME = "fade";
86 const std::string SPRING_PROPERTY_NAME = "spring";
87 const std::string INDICATOR_PROPERTY_NAME = "indicator";
88 const std::string TRANSLATE_PROPERTY_NAME = "translate";
89 constexpr uint8_t CAPTURE_PIXEL_ROUND_VALUE = static_cast<uint8_t>(PixelRoundPolicy::FORCE_FLOOR_START) |
90                                               static_cast<uint8_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
91                                               static_cast<uint8_t>(PixelRoundPolicy::FORCE_CEIL_END) |
92                                               static_cast<uint8_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM);
93 constexpr int32_t SWIPER_HALF = 2;
94 constexpr int32_t CAPTURE_COUNT = 2;
95 constexpr char APP_SWIPER_NO_ANIMATION_SWITCH[] = "APP_SWIPER_NO_ANIMATION_SWITCH";
96 constexpr char APP_SWIPER_FRAME_ANIMATION[] = "APP_SWIPER_FRAME_ANIMATION";
97 constexpr char APP_TABS_FLING[] = "APP_TABS_FLING";
98 constexpr char APP_TABS_SCROLL[] = "APP_TABS_SCROLL";
99 constexpr char APP_TABS_NO_ANIMATION_SWITCH[] = "APP_TABS_NO_ANIMATION_SWITCH";
100 constexpr char APP_TABS_FRAME_ANIMATION[] = "APP_TABS_FRAME_ANIMATION";
101 
102 // TODO define as common method
CalculateFriction(float gamma)103 float CalculateFriction(float gamma)
104 {
105     constexpr float SCROLL_RATIO = 0.72f;
106     if (GreatOrEqual(gamma, 1.0)) {
107         gamma = 1.0;
108     }
109     return SCROLL_RATIO * static_cast<float>(std::pow(1.0 - gamma, SQUARE));
110 }
111 
112 constexpr int32_t COMPONENT_SWIPER_FLING = 1;
113 const RefPtr<FrameRateRange> SWIPER_DEFAULT_FRAME_RATE =
114     AceType::MakeRefPtr<FrameRateRange>(0, 0, 0, COMPONENT_SWIPER_FLING);
115 
116 } // namespace
117 
SwiperPattern()118 SwiperPattern::SwiperPattern()
119 {
120     swiperController_ = MakeRefPtr<SwiperController>();
121     SwiperHelper::InitSwiperController(swiperController_, WeakClaim(this));
122 }
123 
OnAttachToFrameNode()124 void SwiperPattern::OnAttachToFrameNode()
125 {
126     auto host = GetHost();
127     CHECK_NULL_VOID(host);
128     host->GetRenderContext()->SetClipToFrame(true);
129     host->GetRenderContext()->SetClipToBounds(true);
130     host->GetRenderContext()->UpdateClipEdge(true);
131     InitSurfaceChangedCallback();
132 }
133 
OnDetachFromFrameNode(FrameNode * node)134 void SwiperPattern::OnDetachFromFrameNode(FrameNode* node)
135 {
136     auto pipeline = PipelineContext::GetCurrentContextSafely();
137     CHECK_NULL_VOID(pipeline);
138     if (HasSurfaceChangedCallback()) {
139         pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
140     }
141     pipeline->RemoveWindowStateChangedCallback(node->GetId());
142 }
143 
OnAttachToMainTree()144 void SwiperPattern::OnAttachToMainTree()
145 {
146     if (!isInit_) {
147         SetOnHiddenChangeForParent();
148     }
149 }
150 
OnDetachFromMainTree()151 void SwiperPattern::OnDetachFromMainTree()
152 {
153     RemoveOnHiddenChange();
154 }
155 
CreateLayoutAlgorithm()156 RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
157 {
158     auto host = GetHost();
159     CHECK_NULL_RETURN(host, nullptr);
160     auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
161     CHECK_NULL_RETURN(props, nullptr);
162 
163     auto algo = MakeRefPtr<SwiperLayoutAlgorithm>();
164     if (props->GetIsCustomAnimation().value_or(false)) {
165         algo->SetUseCustomAnimation(true);
166         algo->SetCustomAnimationToIndex(customAnimationToIndex_);
167         algo->SetIndexsInAnimation(indexsInAnimation_);
168         algo->SetNeedUnmountIndexs(needUnmountIndexs_);
169         return algo;
170     }
171     if (SupportSwiperCustomAnimation()) {
172         algo->SetNeedUnmountIndexs(needUnmountIndexs_);
173         algo->SetItemsPositionInAnimation(itemPositionInAnimation_);
174     }
175 
176     if (jumpIndex_) {
177         algo->SetJumpIndex(jumpIndex_.value());
178     } else if (targetIndex_) {
179         algo->SetTargetIndex(targetIndex_.value());
180     }
181     algo->SetCurrentIndex(currentIndex_);
182     algo->SetContentCrossSize(contentCrossSize_);
183     algo->SetMainSizeIsMeasured(mainSizeIsMeasured_);
184     oldContentMainSize_ = contentMainSize_;
185     algo->SetContentMainSize(contentMainSize_);
186     algo->SetCurrentDelta(currentDelta_);
187     algo->SetDuringInteraction(isDragging_ || RunningTranslateAnimation());
188     algo->SetItemsPosition(itemPosition_);
189     if (IsOutOfBoundary() && !IsLoop()) {
190         algo->SetOverScrollFeature();
191     }
192     algo->SetTotalItemCount(TotalCount());
193     algo->SetIsLoop(IsLoop());
194     algo->SetSwipeByGroup(IsSwipeByGroup());
195     algo->SetRealTotalCount(RealTotalCount());
196     algo->SetPlaceItemWidth(placeItemWidth_);
197     algo->SetIsFrameAnimation(translateAnimationIsRunning_);
198 
199     auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
200     const auto effect = swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
201     algo->SetCanOverScroll(effect == EdgeEffect::SPRING);
202     algo->SetHasCachedCapture(hasCachedCapture_);
203     algo->SetIsCaptureReverse(isCaptureReverse_);
204     algo->SetCachedCount(GetCachedCount());
205     algo->SetNextMarginIgnoreBlank(nextMarginIgnoreBlank_);
206     algo->SetIgnoreBlankOffset(ignoreBlankOffset_);
207     return algo;
208 }
209 
OnIndexChange()210 void SwiperPattern::OnIndexChange()
211 {
212     auto totalCount = TotalCount();
213     if (NonPositive(totalCount)) {
214         return;
215     }
216 
217     auto oldIndex = GetLoopIndex(oldIndex_);
218     if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != totalCount) {
219         oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
220         oldChildrenSize_ = totalCount;
221     }
222 
223     auto targetIndex = GetLoopIndex(CurrentIndex());
224     if (oldIndex != targetIndex) {
225         FireChangeEvent(oldIndex, targetIndex);
226         // lazyBuild feature.
227         SetLazyLoadFeature(true);
228     }
229 }
230 
StopAndResetSpringAnimation()231 void SwiperPattern::StopAndResetSpringAnimation()
232 {
233     if (springAnimationIsRunning_ && !isTouchDownSpringAnimation_) {
234         StopSpringAnimation();
235         currentDelta_ = 0.0f;
236         itemPosition_.clear();
237         isVoluntarilyClear_ = true;
238         jumpIndex_ = currentIndex_;
239         TAG_LOGI(AceLogTag::ACE_SWIPER, "jump index has been changed to %{public}d by spring animation reset",
240             jumpIndex_.value_or(-1));
241     }
242     UpdateItemRenderGroup(false);
243 }
244 
OnLoopChange()245 void SwiperPattern::OnLoopChange()
246 {
247     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
248     CHECK_NULL_VOID(props);
249 
250     if (!preLoop_.has_value()) {
251         preLoop_ = props->GetLoop().value_or(true);
252         return;
253     }
254 
255     if (preLoop_.value() && !props->GetLoop().value_or(true)) {
256         needResetCurrentIndex_ = true;
257     }
258 
259     if (preLoop_.value() != props->GetLoop().value_or(true) &&
260         (props->GetPrevMargin().has_value() || props->GetNextMargin().has_value())) {
261         jumpIndex_ = GetLoopIndex(currentIndex_);
262     }
263     preLoop_ = props->GetLoop().value_or(true);
264 }
265 
AdjustCurrentIndexOnSwipePage(int32_t index)266 void SwiperPattern::AdjustCurrentIndexOnSwipePage(int32_t index)
267 {
268     auto adjustIndex = SwiperUtils::ComputePageIndex(index, GetDisplayCount());
269     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
270     CHECK_NULL_VOID(props);
271     props->UpdateIndexWithoutMeasure(GetLoopIndex(adjustIndex));
272     currentIndex_ = GetLoopIndex(adjustIndex);
273 }
274 
InitCapture()275 void SwiperPattern::InitCapture()
276 {
277     auto host = GetHost();
278     CHECK_NULL_VOID(host);
279     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
280     CHECK_NULL_VOID(props);
281     bool hasCachedCapture = SwiperUtils::IsStretch(props) && props->GetLoop().value_or(true) && !IsSwipeByGroup() &&
282                             GetDisplayCount() == TotalCount() - 1 &&
283                             (Positive(props->GetPrevMarginValue(0.0_px).ConvertToPx()) ||
284                                 Positive(props->GetNextMarginValue(0.0_px).ConvertToPx()));
285     if (hasCachedCapture) {
286         leftCaptureIndex_ = std::nullopt;
287         rightCaptureIndex_ = std::nullopt;
288     }
289 
290     if (!hasCachedCapture_ && hasCachedCapture) {
291         // Screenshot nodes need to be added at the forefront of all special nodes to display at the bottom
292         uint32_t number = static_cast<uint32_t>(HasIndicatorNode()) + static_cast<uint32_t>(HasLeftButtonNode()) +
293                           static_cast<uint32_t>(HasRightButtonNode()) + 1;
294         auto leftCaptureNode = FrameNode::GetOrCreateFrameNode(
295             V2::SWIPER_LEFT_CAPTURE_ETS_TAG, GetLeftCaptureId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
296         auto imageLayoutProperty = leftCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
297         CHECK_NULL_VOID(imageLayoutProperty);
298         imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
299         leftCaptureNode->MarkModifyDone();
300         host->AddChild(leftCaptureNode, -number);
301 
302         auto rightCaptureNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_CAPTURE_ETS_TAG, GetRightCaptureId(),
303             []() { return AceType::MakeRefPtr<ImagePattern>(); });
304         imageLayoutProperty = rightCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
305         CHECK_NULL_VOID(imageLayoutProperty);
306         imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
307         rightCaptureNode->MarkModifyDone();
308         host->AddChild(rightCaptureNode, -number);
309     }
310     if (hasCachedCapture_ && !hasCachedCapture) {
311         RemoveAllCaptureNode();
312     }
313     if (SupportSwiperCustomAnimation() && hasCachedCapture) {
314         needUnmountIndexs_.clear();
315         itemPositionInAnimation_.clear();
316     }
317     hasCachedCapture_ = hasCachedCapture;
318 }
319 
ResetOnForceMeasure()320 void SwiperPattern::ResetOnForceMeasure()
321 {
322     resetLayoutTask_.Cancel();
323     StopPropertyTranslateAnimation(isFinishAnimation_, false, true);
324     StopTranslateAnimation();
325     StopSpringAnimationImmediately();
326     StopFadeAnimation();
327     StopIndicatorAnimation(true);
328     currentOffset_ = 0.0f;
329     mainSizeIsMeasured_ = false;
330     currentDelta_ = 0.0f;
331     itemPosition_.clear();
332     isVoluntarilyClear_ = true;
333     jumpIndex_ = currentIndex_;
334 
335     auto host = GetHost();
336     CHECK_NULL_VOID(host);
337     auto targetNode = FindLazyForEachNode(host);
338     if (targetNode.has_value()) {
339         auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
340         CHECK_NULL_VOID(lazyForEachNode);
341         lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
342     }
343 }
344 
UpdateTabBarIndicatorCurve()345 void SwiperPattern::UpdateTabBarIndicatorCurve()
346 {
347     auto updateCubicCurveCallback = [weak = WeakClaim(this)]() {
348         auto swiperPattern = weak.Upgrade();
349         CHECK_NULL_VOID(swiperPattern);
350         auto host = swiperPattern->GetHost();
351         CHECK_NULL_VOID(host);
352         auto props = host->GetPaintProperty<SwiperPaintProperty>();
353         CHECK_NULL_VOID(props);
354         auto curve = MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
355         props->UpdateCurve(curve);
356     };
357     swiperController_->SetUpdateCubicCurveCallback(std::move(updateCubicCurveCallback));
358 }
359 
NeedForceMeasure() const360 bool SwiperPattern::NeedForceMeasure() const
361 {
362     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
363     CHECK_NULL_RETURN(props, false);
364 
365     return ((props->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
366            (isSwipeByGroup_.has_value() && isSwipeByGroup_.value() != IsSwipeByGroup());
367 }
368 
OnModifyDone()369 void SwiperPattern::OnModifyDone()
370 {
371     Pattern::OnModifyDone();
372     auto host = GetHost();
373     CHECK_NULL_VOID(host);
374     auto hub = host->GetEventHub<EventHub>();
375     CHECK_NULL_VOID(hub);
376     auto gestureHub = hub->GetOrCreateGestureEventHub();
377     CHECK_NULL_VOID(gestureHub);
378 
379     auto index = CurrentIndex();
380     if (currentIndex_ != index && index >= 0) {
381         AceAsyncTraceBeginCommercial(
382             0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
383     }
384 
385     InitIndicator();
386     InitArrow();
387     InitCapture();
388     CheckSpecialItemCount();
389     SetLazyLoadIsLoop();
390     RegisterVisibleAreaChange();
391     InitTouchEvent(gestureHub);
392     InitHoverMouseEvent();
393     StopAndResetSpringAnimation();
394     OnLoopChange();
395 
396     if (NeedForceMeasure()) {
397         ResetOnForceMeasure();
398     }
399 
400     isSwipeByGroup_ = IsSwipeByGroup();
401 
402     bool disableSwipe = IsDisableSwipe();
403     UpdateSwiperPanEvent(disableSwipe);
404 
405     auto focusHub = host->GetFocusHub();
406     if (focusHub) {
407         InitOnKeyEvent(focusHub);
408         InitOnFocusInternal(focusHub);
409     }
410 
411     SetSwiperEventCallback(disableSwipe);
412     UpdateTabBarIndicatorCurve();
413 
414     if (IsAutoPlay()) {
415         StartAutoPlay();
416     } else {
417         translateTask_.Cancel();
418         isInAutoPlay_ = false;
419     }
420 
421     SetAccessibilityAction();
422     placeItemWidth_.reset();
423 
424     if (IsSwipeByGroup()) {
425         needAdjustIndex_ = true;
426     }
427 }
428 
OnAfterModifyDone()429 void SwiperPattern::OnAfterModifyDone()
430 {
431     auto host = GetHost();
432     CHECK_NULL_VOID(host);
433     auto inspectorId = host->GetInspectorId().value_or("");
434     if (!inspectorId.empty()) {
435         Recorder::NodeDataCache::Get().PutInt(host, inspectorId, CurrentIndex());
436     }
437 }
438 
CheckUserSetIndex(int32_t index)439 int32_t SwiperPattern::CheckUserSetIndex(int32_t index)
440 {
441     if (!IsAutoLinear()) {
442         return index;
443     }
444 
445     if (index < 0 || index >= RealTotalCount()) {
446         index = 0;
447     }
448 
449     auto childNode = GetCurrentFrameNode(GetLoopIndex(index));
450     CHECK_NULL_RETURN(childNode, index);
451     auto childLayoutProperty = childNode->GetLayoutProperty<LayoutProperty>();
452     CHECK_NULL_RETURN(childLayoutProperty, index);
453     if (childLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
454         return index;
455     }
456 
457     return CheckTargetIndex(index + 1);
458 }
459 
UpdateIndicatorOnChildChange()460 void SwiperPattern::UpdateIndicatorOnChildChange()
461 {
462     if (HasIndicatorNode()) {
463         StopIndicatorAnimation();
464         auto host = GetHost();
465         CHECK_NULL_VOID(host);
466         auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
467         if (indicatorNode && indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
468             indicatorNode->MarkModifyDone();
469             indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
470         }
471     }
472 }
473 
BeforeCreateLayoutWrapper()474 void SwiperPattern::BeforeCreateLayoutWrapper()
475 {
476     auto host = GetHost();
477     CHECK_NULL_VOID(host);
478     if (host->GetChildrenUpdated() != -1) {
479         InitCapture();
480         if (NeedAutoPlay() && !translateTask_) {
481             StartAutoPlay();
482         }
483         UpdateCurrentFocus();
484         host->ChildrenUpdatedFrom(-1);
485     }
486 
487     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
488     CHECK_NULL_VOID(props);
489     oldIndex_ = currentIndex_;
490     auto userSetCurrentIndex = CurrentIndex();
491     userSetCurrentIndex = CheckUserSetIndex(userSetCurrentIndex);
492     auto oldIndex = GetLoopIndex(oldIndex_);
493     if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != TotalCount()) {
494         oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
495         UpdateIndicatorOnChildChange();
496         StartAutoPlay();
497         InitArrow();
498         if (IsLoop() && oldIndex != GetLoopIndex(currentIndex_)) {
499             currentIndex_ = oldIndex >= TotalCount() ? 0 : oldIndex;
500         }
501     }
502     int32_t maxValidIndex = IsLoop() ? RealTotalCount() : TotalCount() - GetDisplayCount() + 1;
503     if (userSetCurrentIndex < 0 || userSetCurrentIndex >= maxValidIndex || GetDisplayCount() >= RealTotalCount()) {
504         currentIndex_ = 0;
505         props->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
506     } else {
507         if (oldIndex != userSetCurrentIndex) {
508             currentIndex_ = userSetCurrentIndex;
509             propertyAnimationIndex_ = GetLoopIndex(propertyAnimationIndex_);
510         }
511     }
512 
513     if (IsSwipeByGroup() && needAdjustIndex_) {
514         AdjustCurrentIndexOnSwipePage(CurrentIndex());
515         needAdjustIndex_ = false;
516     }
517 
518     if (oldIndex_ != currentIndex_ || (itemPosition_.empty() && !isVoluntarilyClear_)) {
519         jumpIndex_ = GetLoopIndex(currentIndex_);
520         currentFirstIndex_ = jumpIndex_.value_or(0);
521         turnPageRate_ = 0.0f;
522         SetIndicatorJumpIndex(jumpIndex_);
523     }
524     isVoluntarilyClear_ = false;
525     if (jumpIndex_) {
526         if ((jumpIndex_.value() < 0 || jumpIndex_.value() >= TotalCount()) && !IsLoop()) {
527             jumpIndex_ = 0;
528         }
529         targetIndex_.reset();
530         nextIndex_ = jumpIndex_.value();
531         StopAutoPlay();
532         StopTranslateAnimation();
533         StopFadeAnimation();
534         StopSpringAnimation();
535         if (usePropertyAnimation_) {
536             StopPropertyTranslateAnimation(false, true);
537             StopIndicatorAnimation();
538         }
539         currentDelta_ = 0.0f;
540     }
541     if (oldIndex_ != currentIndex_ && !isInit_ && !IsUseCustomAnimation()) {
542         FireWillShowEvent(currentIndex_);
543         FireWillHideEvent(oldIndex_);
544     }
545 
546     if (needResetCurrentIndex_) {
547         needResetCurrentIndex_ = false;
548         currentIndex_ = GetLoopIndex(currentIndex_);
549         props->UpdateIndexWithoutMeasure(currentIndex_);
550     }
551     UpdateIgnoreBlankOffsetWithIndex();
552 }
553 
UpdateTargetCapture(bool forceUpdate)554 void SwiperPattern::UpdateTargetCapture(bool forceUpdate)
555 {
556     if (itemPosition_.empty()) {
557         return;
558     }
559     auto leftTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
560     auto rightTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
561     if (isCaptureReverse_) {
562         leftTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
563         rightTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
564     }
565     if (forceUpdate || !leftCaptureIndex_.has_value() || leftCaptureIndex_.value() != leftTargetIndex) {
566         CreateCaptureCallback(leftTargetIndex, GetLeftCaptureId(), forceUpdate);
567         leftCaptureIndex_ = leftTargetIndex;
568     }
569     if (forceUpdate || !rightCaptureIndex_.has_value() || rightCaptureIndex_.value() != rightTargetIndex) {
570         CreateCaptureCallback(rightTargetIndex, GetRightCaptureId(), forceUpdate);
571         rightCaptureIndex_ = rightTargetIndex;
572     }
573 }
574 
CreateCaptureCallback(int32_t targetIndex,int32_t captureId,bool forceUpdate)575 void SwiperPattern::CreateCaptureCallback(int32_t targetIndex, int32_t captureId, bool forceUpdate)
576 {
577     auto host = GetHost();
578     CHECK_NULL_VOID(host);
579     auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
580     CHECK_NULL_VOID(targetNode);
581     auto callback = [weak = WeakClaim(this), captureId, targetIndex, hostInstanceId = GetHostInstanceId()](
582                         std::shared_ptr<Media::PixelMap> pixelMap) {
583         ContainerScope scope(hostInstanceId);
584         auto piplineContext = PipelineContext::GetCurrentContext();
585         CHECK_NULL_VOID(piplineContext);
586         auto taskExecutor = piplineContext->GetTaskExecutor();
587         CHECK_NULL_VOID(taskExecutor);
588         taskExecutor->PostTask(
589             [weak, pixelMap, captureId, targetIndex]() mutable {
590                 auto swiper = weak.Upgrade();
591                 CHECK_NULL_VOID(swiper);
592                 swiper->UpdateCaptureSource(pixelMap, captureId, targetIndex);
593             },
594             TaskExecutor::TaskType::UI, "ArkUISwiperUpdateCaptureSource");
595     };
596     if (forceUpdate) {
597         // The size changes caused by layout need to wait for rendering before taking a screenshot
598         auto piplineContext = PipelineContext::GetCurrentContext();
599         CHECK_NULL_VOID(piplineContext);
600         auto taskExecutor = piplineContext->GetTaskExecutor();
601         CHECK_NULL_VOID(taskExecutor);
602         taskExecutor->PostDelayedTask(
603             [targetNode, callback]() { ComponentSnapshot::GetNormalCapture(targetNode, std::move(callback)); },
604             TaskExecutor::TaskType::UI, FIRST_CAPTURE_DELAY_TIME, "ArkUISwiperGetNormalCapture");
605     } else {
606         ComponentSnapshot::GetNormalCapture(targetNode, std::move(callback));
607     }
608 }
609 
UpdateCaptureSource(std::shared_ptr<Media::PixelMap> pixelMap,int32_t captureId,int32_t targetIndex)610 void SwiperPattern::UpdateCaptureSource(
611     std::shared_ptr<Media::PixelMap> pixelMap, int32_t captureId, int32_t targetIndex)
612 {
613     // Async tasks require verifying if the pixel map is the correct target
614     if (!(captureId == GetLeftCaptureId() && leftCaptureIndex_.has_value() &&
615             targetIndex == leftCaptureIndex_.value()) &&
616         !(captureId == GetRightCaptureId() && rightCaptureIndex_.has_value() &&
617             targetIndex == rightCaptureIndex_.value())) {
618         return;
619     }
620     auto host = GetHost();
621     CHECK_NULL_VOID(host);
622     auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
623     CHECK_NULL_VOID(targetNode);
624     auto targetLayoutProperty = targetNode->GetLayoutProperty<LayoutProperty>();
625     CHECK_NULL_VOID(targetLayoutProperty);
626     auto targetMargin = targetLayoutProperty->CreateMargin();
627     MarginProperty margin;
628     margin.left = CalcLength(targetMargin.left.has_value() ? targetMargin.left.value() : 0.0f);
629     margin.right = CalcLength(targetMargin.right.has_value() ? targetMargin.right.value() : 0.0f);
630     margin.top = CalcLength(targetMargin.top.has_value() ? targetMargin.top.value() : 0.0f);
631     margin.bottom = CalcLength(targetMargin.bottom.has_value() ? targetMargin.bottom.value() : 0.0f);
632 
633     auto captureNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(captureId)));
634     CHECK_NULL_VOID(captureNode);
635     auto imageLayoutProperty = captureNode->GetLayoutProperty<ImageLayoutProperty>();
636     CHECK_NULL_VOID(imageLayoutProperty);
637     imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(PixelMap::CreatePixelMap(&pixelMap)));
638     imageLayoutProperty->UpdateMargin(margin);
639     captureNode->MarkModifyDone();
640     captureNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
641 }
642 
InitSurfaceChangedCallback()643 void SwiperPattern::InitSurfaceChangedCallback()
644 {
645     auto host = GetHost();
646     CHECK_NULL_VOID(host);
647     auto pipeline = host->GetContextRefPtr();
648     CHECK_NULL_VOID(pipeline);
649     if (!HasSurfaceChangedCallback()) {
650         auto callbackId = pipeline->RegisterSurfaceChangedCallback(
651             [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
652                 WindowSizeChangeReason type) {
653                 if (type == WindowSizeChangeReason::UNDEFINED && newWidth == prevWidth && newHeight == prevHeight) {
654                     return;
655                 }
656                 auto swiper = weak.Upgrade();
657                 if (!swiper) {
658                     return;
659                 }
660 
661                 if (type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::UNDEFINED) {
662                     swiper->windowSizeChangeReason_ = type;
663                     swiper->StopAutoPlay();
664                 }
665                 auto currentIndex =
666                     swiper->targetIndex_.has_value() ? swiper->targetIndex_.value() : swiper->currentIndex_;
667 
668                 swiper->needFireCustomAnimationEvent_ = swiper->translateAnimationIsRunning_;
669                 swiper->StopPropertyTranslateAnimation(swiper->isFinishAnimation_);
670                 swiper->StopTranslateAnimation();
671                 swiper->StopSpringAnimationImmediately();
672                 swiper->StopFadeAnimation();
673                 swiper->StopIndicatorAnimation();
674                 const auto& surfaceChangeCallback = swiper->swiperController_->GetSurfaceChangeCallback();
675                 if (surfaceChangeCallback) {
676                     surfaceChangeCallback();
677                 }
678                 swiper->currentOffset_ = 0.0f;
679                 swiper->itemPosition_.clear();
680                 swiper->placeItemWidth_.reset();
681                 swiper->isVoluntarilyClear_ = true;
682                 swiper->jumpIndex_ = currentIndex;
683                 swiper->SetIndicatorJumpIndex(currentIndex);
684                 swiper->MarkDirtyNodeSelf();
685                 auto swiperNode = swiper->GetHost();
686                 CHECK_NULL_VOID(swiperNode);
687                 auto targetNode = swiper->FindLazyForEachNode(swiperNode);
688                 if (targetNode.has_value()) {
689                     auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
690                     CHECK_NULL_VOID(lazyForEachNode);
691                     lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
692                 }
693             });
694         UpdateSurfaceChangedCallbackId(callbackId);
695     }
696 }
697 
IsFocusNodeInItemPosition(const RefPtr<FocusHub> & targetFocusHub)698 bool SwiperPattern::IsFocusNodeInItemPosition(const RefPtr<FocusHub>& targetFocusHub)
699 {
700     for (const auto& item : itemPosition_) {
701         auto itemNode = GetCurrentFrameNode(item.first);
702         if (!itemNode) {
703             continue;
704         }
705         if (itemNode->GetFirstFocusHubChild() == targetFocusHub) {
706             return true;
707         }
708     }
709     return false;
710 }
711 
FlushFocus(const RefPtr<FrameNode> & curShowFrame)712 void SwiperPattern::FlushFocus(const RefPtr<FrameNode>& curShowFrame)
713 {
714     CHECK_NULL_VOID(curShowFrame);
715     auto swiperHost = GetHost();
716     CHECK_NULL_VOID(swiperHost);
717     auto swiperFocusHub = swiperHost->GetFocusHub();
718     CHECK_NULL_VOID(swiperFocusHub);
719     auto showChildFocusHub = curShowFrame->GetFirstFocusHubChild();
720     CHECK_NULL_VOID(showChildFocusHub);
721     auto focusChildren = swiperFocusHub->GetChildren();
722     CHECK_NULL_VOID(!focusChildren.empty());
723     auto iter = focusChildren.rbegin();
724     if (IsShowIndicator()) {
725         ++iter;
726     }
727     if (HasLeftButtonNode()) {
728         ++iter;
729     }
730     if (HasRightButtonNode()) {
731         ++iter;
732     }
733     while (iter != focusChildren.rend()) {
734         auto child = *iter;
735         if (!child) {
736             ++iter;
737             continue;
738         }
739         if (IsUseCustomAnimation() && hasTabsAncestor_) {
740             child->SetParentFocusable(child == showChildFocusHub);
741         } else {
742             child->SetParentFocusable(IsFocusNodeInItemPosition(child));
743         }
744         ++iter;
745     }
746 
747     RefPtr<FocusHub> needFocusNode = showChildFocusHub;
748     if (IsShowIndicator() && isLastIndicatorFocused_) {
749         needFocusNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
750     }
751     CHECK_NULL_VOID(needFocusNode);
752     lastWeakShowNode_ = AceType::WeakClaim(AceType::RawPtr(curShowFrame));
753     if (swiperFocusHub->IsCurrentFocus()) {
754         needFocusNode->RequestFocusImmediately();
755     } else {
756         if (swiperFocusHub->AcceptFocusOfPriorityChild()) {
757             return;
758         }
759         swiperFocusHub->SetLastWeakFocusNode(AceType::WeakClaim(AceType::RawPtr(needFocusNode)));
760     }
761 }
GetFocusHubChild(std::string childFrameName)762 RefPtr<FocusHub> SwiperPattern::GetFocusHubChild(std::string childFrameName)
763 {
764     auto swiperHost = GetHost();
765     CHECK_NULL_RETURN(swiperHost, nullptr);
766     auto swiperFocusHub = swiperHost->GetFocusHub();
767     CHECK_NULL_RETURN(swiperFocusHub, nullptr);
768     auto focusChildren = swiperFocusHub->GetChildren();
769     CHECK_NULL_RETURN(!focusChildren.empty(), nullptr);
770     for (const auto& child : focusChildren) {
771         CHECK_NULL_RETURN(child, nullptr);
772         if (child->GetFrameName() == childFrameName) {
773             return child;
774         }
775     }
776     return nullptr;
777 }
778 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)779 WeakPtr<FocusHub> SwiperPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
780 {
781     auto curFocusNode = currentFocusNode.Upgrade();
782     CHECK_NULL_RETURN(curFocusNode, nullptr);
783     if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::UP) ||
784         (GetDirection() == Axis::HORIZONTAL && step == FocusStep::SHIFT_TAB) ||
785         (GetDirection() == Axis::VERTICAL && step == FocusStep::LEFT)) {
786         return PreviousFocus(curFocusNode);
787     }
788     if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
789         (GetDirection() == Axis::HORIZONTAL && step == FocusStep::TAB) ||
790         (GetDirection() == Axis::VERTICAL && step == FocusStep::RIGHT)) {
791         return NextFocus(curFocusNode);
792     }
793     return nullptr;
794 }
795 
PreviousFocus(const RefPtr<FocusHub> & curFocusNode)796 WeakPtr<FocusHub> SwiperPattern::PreviousFocus(const RefPtr<FocusHub>& curFocusNode)
797 {
798     CHECK_NULL_RETURN(curFocusNode, nullptr);
799     RefPtr<FocusHub> indicatorNode;
800     RefPtr<FocusHub> leftArrowNode;
801     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
802     CHECK_NULL_RETURN(props, nullptr);
803     if (HasLeftButtonNode()) {
804         leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
805         CHECK_NULL_RETURN(leftArrowNode, nullptr);
806     }
807     if (HasIndicatorNode()) {
808         indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
809         CHECK_NULL_RETURN(indicatorNode, nullptr);
810     }
811     if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
812         isLastIndicatorFocused_ = false;
813         (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ? curFocusNode->SetParentFocusable(false)
814                                                         : curFocusNode->SetParentFocusable(true);
815         return nullptr;
816     }
817     if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
818         if (!HasLeftButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ||
819             props->GetHoverShowValue(false)) {
820             isLastIndicatorFocused_ = true;
821             curFocusNode->SetParentFocusable(true);
822             return nullptr;
823         }
824         isLastIndicatorFocused_ = false;
825         leftArrowNode->SetParentFocusable(true);
826         return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
827     }
828     if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
829         if (HasIndicatorNode()) {
830             isLastIndicatorFocused_ = true;
831             indicatorNode->SetParentFocusable(true);
832             return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
833         }
834         if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
835             curFocusNode->SetParentFocusable(true);
836             return nullptr;
837         }
838         isLastIndicatorFocused_ = true;
839         leftArrowNode->SetParentFocusable(true);
840         return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
841     }
842     curFocusNode->SetParentFocusable(true);
843     return nullptr;
844 }
845 
NextFocus(const RefPtr<FocusHub> & curFocusNode)846 WeakPtr<FocusHub> SwiperPattern::NextFocus(const RefPtr<FocusHub>& curFocusNode)
847 {
848     CHECK_NULL_RETURN(curFocusNode, nullptr);
849     RefPtr<FocusHub> indicatorNode;
850     RefPtr<FocusHub> rightArrowNode;
851     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
852     CHECK_NULL_RETURN(props, nullptr);
853     if (HasIndicatorNode()) {
854         indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
855         CHECK_NULL_RETURN(indicatorNode, nullptr);
856     }
857     if (HasRightButtonNode()) {
858         rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
859         CHECK_NULL_RETURN(rightArrowNode, nullptr);
860     }
861     if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
862         if (HasIndicatorNode()) {
863             isLastIndicatorFocused_ = true;
864             indicatorNode->SetParentFocusable(true);
865             return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
866         }
867         if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
868             curFocusNode->SetParentFocusable(true);
869             return nullptr;
870         }
871         isLastIndicatorFocused_ = true;
872         rightArrowNode->SetParentFocusable(true);
873         return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
874     }
875     if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
876         if (!HasRightButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ||
877             props->GetHoverShowValue(false)) {
878             isLastIndicatorFocused_ = true;
879             curFocusNode->SetParentFocusable(true);
880             return nullptr;
881         }
882         isLastIndicatorFocused_ = false;
883         rightArrowNode->SetParentFocusable(true);
884         return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
885     }
886     if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
887         isLastIndicatorFocused_ = false;
888         (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ? curFocusNode->SetParentFocusable(false)
889                                                                        : curFocusNode->SetParentFocusable(true);
890         return nullptr;
891     }
892     curFocusNode->SetParentFocusable(true);
893     return nullptr;
894 }
895 
GetLoopIndex(int32_t originalIndex) const896 int32_t SwiperPattern::GetLoopIndex(int32_t originalIndex) const
897 {
898     if (TotalCount() <= 0) {
899         return originalIndex;
900     }
901     auto loopIndex = originalIndex;
902     while (loopIndex < 0) {
903         loopIndex = loopIndex + TotalCount();
904     }
905     loopIndex %= TotalCount();
906     return loopIndex;
907 }
908 
AdjustCurrentFocusIndex()909 void SwiperPattern::AdjustCurrentFocusIndex()
910 {
911     if (GetDisplayCount() <= 1) {
912         currentFocusIndex_ = currentIndex_;
913         return;
914     }
915 
916     if (currentFocusIndex_ >= currentIndex_ && currentFocusIndex_ < currentIndex_ + GetDisplayCount()) {
917         return;
918     }
919 
920     currentFocusIndex_ = currentIndex_;
921 }
922 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)923 bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
924 {
925     if (!isDragging_ || isInit_) {
926         SetLazyLoadFeature(true);
927     }
928     if (!isInit_) {
929         OnIndexChange();
930         oldIndex_ = currentIndex_;
931     }
932 
933     auto isInit = isInit_;
934     isInit_ = false;
935 
936     if (!IsAutoPlay() && config.skipMeasure && config.skipLayout) {
937         return false;
938     }
939 
940     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
941     CHECK_NULL_RETURN(props, false);
942     auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm();
943     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
944     auto algo = DynamicCast<SwiperLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
945     CHECK_NULL_RETURN(algo, false);
946 
947     // set tabs invisible item freeze state.
948     if (hasTabsAncestor_) {
949         auto realTotalCount = RealTotalCount();
950         for (int32_t index = 0; index < realTotalCount; index++) {
951             auto childFrameNode = GetCurrentFrameNode(index);
952             if (childFrameNode) {
953                 auto isActive = childFrameNode->IsActive();
954                 childFrameNode->SetFreeze(!isActive);
955             }
956         }
957     }
958 
959     if (props->GetIsCustomAnimation().value_or(false)) {
960         needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
961         return false;
962     }
963     if (SupportSwiperCustomAnimation()) {
964         needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
965         itemPositionInAnimation_ = algo->GetItemsPositionInAnimation();
966         FireContentDidScrollEvent();
967     }
968 
969     autoLinearReachBoundary = false;
970     bool isJump = false;
971     startMainPos_ = algo->GetStartPosition();
972     endMainPos_ = algo->GetEndPosition();
973     startIndex_ = algo->GetStartIndex();
974     endIndex_ = algo->GetEndIndex();
975     cachedItems_ = algo->GetCachedItems();
976     layoutConstraint_ = algo->GetLayoutConstraint();
977     itemPosition_ = std::move(algo->GetItemPosition());
978     PostIdleTask(GetHost());
979     currentOffset_ -= algo->GetCurrentOffset();
980     if (!itemPosition_.empty()) {
981         const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
982         auto firstItem = GetFirstItemInfoInVisibleArea();
983         auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
984         if (turnPageRateCallback && isDragging_ && !NearZero(translateLength)) {
985             turnPageRateCallback(firstItem.first, -firstItem.second.startPos / translateLength);
986         }
987 
988         placeItemWidth_ = translateLength;
989     }
990     if (hasCachedCapture_) {
991         isCaptureReverse_ = algo->GetIsCaptureReverse();
992         UpdateTargetCapture(algo->GetIsNeedUpdateCapture());
993     }
994 
995     if (!targetIndex_) {
996         if (isUserFinish_) {
997             SetIndicatorJumpIndex(jumpIndex_);
998         }
999 
1000         CheckMarkDirtyNodeForRenderIndicator();
1001     }
1002 
1003     if (jumpIndex_) {
1004         auto pipeline = GetContext();
1005         if (pipeline) {
1006             pipeline->AddAfterRenderTask([weak = WeakClaim(this)]() {
1007                 auto swiper = weak.Upgrade();
1008                 CHECK_NULL_VOID(swiper);
1009                 AceAsyncTraceEndCommercial(
1010                     0, swiper->hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1011             });
1012         }
1013         isJump = true;
1014         UpdateCurrentIndex(algo->GetCurrentIndex());
1015         AdjustCurrentFocusIndex();
1016         auto curChild = dirty->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_));
1017         if (curChild && IsContentFocused()) {
1018             auto curChildFrame = curChild->GetHostNode();
1019             CHECK_NULL_RETURN(curChildFrame, false);
1020             FlushFocus(curChildFrame);
1021         }
1022         currentIndexOffset_ = 0.0f;
1023         if (!isInit) {
1024             OnIndexChange();
1025         }
1026         jumpIndex_.reset();
1027         pauseTargetIndex_.reset();
1028         auto delayTime = GetInterval() - GetDuration();
1029         delayTime = std::clamp(delayTime, 0, delayTime);
1030         if (NeedAutoPlay() && isUserFinish_) {
1031             PostTranslateTask(delayTime);
1032         }
1033 
1034         if (SupportSwiperCustomAnimation() && needFireCustomAnimationEvent_) {
1035             itemPositionInAnimation_ = itemPosition_;
1036             FireSwiperCustomAnimationEvent();
1037             itemPositionInAnimation_.clear();
1038         }
1039     } else if (RunningTranslateAnimation() && !NearEqual(oldContentMainSize_, algo->GetContentMainSize())) {
1040         auto pipeline = GetContext();
1041         RefPtr<TaskExecutor> taskExecutor = pipeline ? pipeline->GetTaskExecutor() : nullptr;
1042         if (taskExecutor) {
1043             resetLayoutTask_.Cancel();
1044             resetLayoutTask_.Reset([weak = AceType::WeakClaim(this)] {
1045                 auto swiper = weak.Upgrade();
1046                 CHECK_NULL_VOID(swiper);
1047                 if (swiper->RunningTranslateAnimation()) {
1048                     swiper->isUserFinish_ = false;
1049                     swiper->FinishAnimation();
1050                     swiper->currentDelta_ = 0.0f;
1051                     swiper->itemPosition_.clear();
1052                     swiper->isVoluntarilyClear_ = true;
1053                     swiper->jumpIndex_ = swiper->currentIndex_;
1054                     swiper->MarkDirtyNodeSelf();
1055                 }
1056             });
1057             taskExecutor->PostTask(resetLayoutTask_, TaskExecutor::TaskType::UI, "ArkUISwiperResetLayout");
1058         }
1059     } else if (targetIndex_) {
1060         auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
1061         auto iter = itemPosition_.find(targetIndexValue);
1062         if (iter != itemPosition_.end()) {
1063             float targetPos = iter->second.startPos;
1064             auto context = GetContext();
1065             auto props = GetLayoutProperty<SwiperLayoutProperty>();
1066             bool isNeedForwardTranslate = false;
1067             if (IsLoop()) {
1068                 auto lastItemIndex = Positive(props->GetCalculatedNextMargin())
1069                                          ? targetIndexValue + GetDisplayCount()
1070                                          : targetIndexValue + GetDisplayCount() - 1;
1071                 isNeedForwardTranslate = itemPosition_.find(lastItemIndex) == itemPosition_.end();
1072             }
1073             bool isNeedBackwardTranslate = false;
1074             if (IsLoop() && targetIndexValue < currentIndex_) {
1075                 auto firstItemIndex = Positive(props->GetCalculatedPrevMargin()) ? targetIndexValue + TotalCount() - 1
1076                                                                                  : targetIndexValue + TotalCount();
1077                 isNeedBackwardTranslate = itemPosition_.find(firstItemIndex) != itemPosition_.end();
1078             }
1079             bool isNeedPlayTranslateAnimation = translateAnimationIsRunning_ || isNeedForwardTranslate ||
1080                                                 isNeedBackwardTranslate || AutoLinearAnimationNeedReset(targetPos);
1081             if (context && !isNeedPlayTranslateAnimation && !SupportSwiperCustomAnimation()) {
1082                 // displayCount is auto, loop is false, if the content width less than windows size
1083                 // need offset to keep right aligned
1084                 bool isNeedOffset = (GetLoopIndex(iter->first) == TotalCount() - 1) &&
1085                                     !props->GetDisplayCount().has_value() && !IsLoop() &&
1086                                     LessNotEqual(iter->second.endPos - iter->second.startPos, CalculateVisibleSize());
1087                 float offset =
1088                     isNeedOffset ? CalculateVisibleSize() - iter->second.endPos + iter->second.startPos : 0.0;
1089                 targetPos -= offset;
1090 
1091                 context->AddAfterLayoutTask([weak = WeakClaim(this), targetPos, velocity = velocity_.value_or(0.0f),
1092                                                 nextIndex = iter->first]() {
1093                     auto swiper = weak.Upgrade();
1094                     CHECK_NULL_VOID(swiper);
1095                     swiper->PlayPropertyTranslateAnimation(-targetPos, nextIndex, velocity, false);
1096                     swiper->PlayIndicatorTranslateAnimation(-targetPos, nextIndex);
1097                 });
1098             } else {
1099                 PlayTranslateAnimation(
1100                     currentOffset_, currentOffset_ - targetPos, iter->first, false, velocity_.value_or(0.0f));
1101             }
1102         } else if (!itemPosition_.empty() && SwiperUtils::IsStretch(props)) {
1103             auto firstItem = GetFirstItemInfoInVisibleArea();
1104             auto targetPos = firstItem.second.startPos +
1105                              (targetIndexValue - firstItem.first) * (placeItemWidth_.value() + GetItemSpace());
1106             PlayTranslateAnimation(
1107                 currentOffset_, currentOffset_ - targetPos, targetIndexValue, false, velocity_.value_or(0.0f));
1108         } else {
1109             // AutoLinear Mode
1110             PlayTranslateAnimation(currentOffset_, currentOffset_ - algo->GetTargetStartPos(), targetIndexValue, false,
1111                 velocity_.value_or(0.0f));
1112         }
1113         velocity_.reset();
1114         pauseTargetIndex_ = targetIndex_;
1115     }
1116     mainSizeIsMeasured_ = algo->GetMainSizeIsMeasured();
1117     contentCrossSize_ = algo->GetContentCrossSize();
1118     currentDelta_ = 0.0f;
1119     contentMainSize_ = algo->GetContentMainSize();
1120     oldContentMainSize_ = contentMainSize_;
1121     crossMatchChild_ = algo->IsCrossMatchChild();
1122     oldIndex_ = currentIndex_;
1123     oldChildrenSize_ = TotalCount();
1124     needFireCustomAnimationEvent_ = true;
1125 
1126     if (windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION) {
1127         StartAutoPlay();
1128         windowSizeChangeReason_ = WindowSizeChangeReason::UNDEFINED;
1129     }
1130 
1131     const auto& paddingProperty = props->GetPaddingProperty();
1132     return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
1133 }
1134 
AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const1135 float SwiperPattern::AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const
1136 {
1137     if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
1138         return 0.0f;
1139     }
1140     if (isStartOverScroll && NonNegative(ignoreBlankOffset_)) {
1141         return prevMarginIgnoreBlank_ ? GetPrevMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1142     }
1143     if (!isStartOverScroll && NonPositive(ignoreBlankOffset_)) {
1144         return nextMarginIgnoreBlank_ ? -GetNextMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1145     }
1146     return 0.0f;
1147 }
1148 
UpdateIgnoreBlankOffsetWithIndex()1149 void SwiperPattern::UpdateIgnoreBlankOffsetWithIndex()
1150 {
1151     if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
1152         auto lastIgnoreBlankOffset = ignoreBlankOffset_;
1153         ignoreBlankOffset_ = 0.0f;
1154         UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1155         return;
1156     }
1157     if (jumpIndex_.has_value()) {
1158         if (prevMarginIgnoreBlank_ && jumpIndex_.value() == 0) {
1159             ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1160         } else if (nextMarginIgnoreBlank_ && jumpIndex_.value() >= (TotalCount() - GetDisplayCount())) {
1161             ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1162         } else {
1163             ignoreBlankOffset_ = 0.0f;
1164         }
1165         return;
1166     }
1167     if (targetIndex_.has_value()) {
1168         float lastIgnoreBlankOffset = ignoreBlankOffset_;
1169         if (prevMarginIgnoreBlank_ && targetIndex_.value() == 0) {
1170             ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1171         } else if (nextMarginIgnoreBlank_ && targetIndex_.value() >= (TotalCount() - GetDisplayCount())) {
1172             ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1173         } else {
1174             ignoreBlankOffset_ = 0.0f;
1175         }
1176         UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1177     }
1178 }
1179 
UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)1180 void SwiperPattern::UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)
1181 {
1182     if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
1183         return;
1184     }
1185     float lastIgnoreBlankOffset = ignoreBlankOffset_;
1186     if (prevMarginIgnoreBlank_ && overScrollDirection) {
1187         ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1188     } else if (nextMarginIgnoreBlank_ && !overScrollDirection) {
1189         ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1190     }
1191 
1192     UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1193 }
1194 
UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)1195 void SwiperPattern::UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)
1196 {
1197     if (NearEqual(ignoreBlankOffset_, lastIgnoreBlankOffset)) {
1198         return;
1199     }
1200 
1201     float adjustOffset = ignoreBlankOffset_ - lastIgnoreBlankOffset;
1202     for (auto& item : itemPosition_) {
1203         item.second.startPos -= adjustOffset;
1204         item.second.endPos -= adjustOffset;
1205     }
1206 }
1207 
IsAutoLinear() const1208 bool SwiperPattern::IsAutoLinear() const
1209 {
1210     auto props = GetLayoutProperty<SwiperLayoutProperty>();
1211     CHECK_NULL_RETURN(props, false);
1212     return !SwiperUtils::IsStretch(props);
1213 }
1214 
AutoLinearAnimationNeedReset(float translate) const1215 bool SwiperPattern::AutoLinearAnimationNeedReset(float translate) const
1216 {
1217     if (!IsAutoLinear()) {
1218         return false;
1219     }
1220 
1221     if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
1222         return false;
1223     }
1224 
1225     if (NonPositive(translate)) {
1226         return false;
1227     }
1228 
1229     auto iter = itemPosition_.rbegin();
1230     auto endPos = iter->second.endPos;
1231     if (endPos - CalculateVisibleSize() < translate) {
1232         return true;
1233     }
1234 
1235     return false;
1236 }
1237 
OnAnimationTranslateZero(int32_t nextIndex,bool stopAutoPlay)1238 void SwiperPattern::OnAnimationTranslateZero(int32_t nextIndex, bool stopAutoPlay)
1239 {
1240     ResetAndUpdateIndexOnAnimationEnd(nextIndex);
1241 
1242     if (!NeedAutoPlay() || !isUserFinish_) {
1243         return;
1244     }
1245 
1246     if (stopAutoPlay) {
1247         MarkDirtyNodeSelf();
1248     } else {
1249         auto delayTime = GetInterval() - GetDuration();
1250         delayTime = std::clamp(delayTime, 0, delayTime);
1251         PostTranslateTask(delayTime);
1252     }
1253 }
1254 
FireChangeEvent(int32_t preIndex,int32_t currentIndex) const1255 void SwiperPattern::FireChangeEvent(int32_t preIndex, int32_t currentIndex) const
1256 {
1257     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1258     CHECK_NULL_VOID(swiperEventHub);
1259     swiperEventHub->FireChangeEvent(preIndex, currentIndex);
1260     swiperEventHub->FireIndicatorChangeEvent(currentIndex);
1261     swiperEventHub->FireChangeDoneEvent(moveDirection_);
1262 
1263     if (jumpIndex_) {
1264         auto host = GetHost();
1265         CHECK_NULL_VOID(host);
1266         host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1267     }
1268 }
1269 
FireAnimationStartEvent(int32_t currentIndex,int32_t nextIndex,const AnimationCallbackInfo & info) const1270 void SwiperPattern::FireAnimationStartEvent(
1271     int32_t currentIndex, int32_t nextIndex, const AnimationCallbackInfo& info) const
1272 {
1273     TAG_LOGI(AceLogTag::ACE_SWIPER, "FireAnimationStartEvent, currentIndex: %{public}d, nextIndex: %{public}d",
1274         currentIndex, nextIndex);
1275     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1276     CHECK_NULL_VOID(swiperEventHub);
1277     swiperEventHub->FireAnimationStartEvent(currentIndex, nextIndex, info);
1278     auto host = GetHost();
1279     CHECK_NULL_VOID(host);
1280     host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
1281 }
1282 
FireAnimationEndEvent(int32_t currentIndex,const AnimationCallbackInfo & info,bool isInterrupt) const1283 void SwiperPattern::FireAnimationEndEvent(
1284     int32_t currentIndex, const AnimationCallbackInfo& info, bool isInterrupt) const
1285 {
1286     TAG_LOGI(AceLogTag::ACE_SWIPER,
1287         "FireAnimationEndEvent currentIndex: %{public}d, currentOffset: has_value %{public}d, value %{public}fvp, "
1288         "isForce: %{public}d",
1289         currentIndex, info.currentOffset.has_value(), info.currentOffset.value_or(0.0), info.isForceStop);
1290     if (currentIndex == -1) {
1291         return;
1292     }
1293     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1294     CHECK_NULL_VOID(swiperEventHub);
1295     isInterrupt ? swiperEventHub->FireAnimationEndOnForceEvent(currentIndex, info)
1296                 : swiperEventHub->FireAnimationEndEvent(currentIndex, info);
1297     auto host = GetHost();
1298     CHECK_NULL_VOID(host);
1299     host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1300 }
1301 
FireGestureSwipeEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const1302 void SwiperPattern::FireGestureSwipeEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
1303 {
1304     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1305     CHECK_NULL_VOID(swiperEventHub);
1306     swiperEventHub->FireGestureSwipeEvent(currentIndex, info);
1307 }
1308 
HandleSwiperCustomAnimation(float offset)1309 void SwiperPattern::HandleSwiperCustomAnimation(float offset)
1310 {
1311     if (!SupportSwiperCustomAnimation()) {
1312         return;
1313     }
1314     if (itemPosition_.empty()) {
1315         needUnmountIndexs_.clear();
1316         itemPositionInAnimation_.clear();
1317         return;
1318     }
1319     if (NearZero(offset)) {
1320         return;
1321     }
1322 
1323     if (itemPositionInAnimation_.empty()) {
1324         for (auto& item : itemPosition_) {
1325             UpdateItemInfoInCustomAnimation(item.first, item.second.startPos, item.second.endPos);
1326         }
1327     }
1328     indexsInAnimation_.clear();
1329     CalculateAndUpdateItemInfo(offset);
1330 
1331     auto visibleIndex = CalcVisibleIndex();
1332     auto visibleIndexWithOffset = CalcVisibleIndex(offset);
1333     std::set<int32_t> unmountIndexs;
1334     for (auto& item : itemPositionInAnimation_) {
1335         if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end() &&
1336             needUnmountIndexs_.find(item.first) == needUnmountIndexs_.end() &&
1337             visibleIndex.find(item.first) != visibleIndex.end() &&
1338             visibleIndexWithOffset.find(item.first) == visibleIndexWithOffset.end()) {
1339             indexsInAnimation_.insert(item.first);
1340             needUnmountIndexs_.insert(item.first);
1341             item.second.startPos += offset;
1342             item.second.endPos += offset;
1343             unmountIndexs.insert(item.first);
1344         }
1345     }
1346     for (const auto& index : unmountIndexs) {
1347         auto iter = itemPositionInAnimation_.find(index);
1348         if (iter == itemPositionInAnimation_.end()) {
1349             continue;
1350         }
1351 
1352         OnSwiperCustomAnimationFinish(iter->second.task, index, iter->second.isFinishAnimation);
1353     }
1354 
1355     FireSwiperCustomAnimationEvent();
1356 }
1357 
CalcVisibleIndex(float offset) const1358 std::set<int32_t> SwiperPattern::CalcVisibleIndex(float offset) const
1359 {
1360     auto visibleSize = CalculateVisibleSize();
1361     auto itemSpace = GetItemSpace();
1362     auto isLoop = IsLoop();
1363     auto displayCount = GetDisplayCount();
1364     auto swipeByGroup = IsSwipeByGroup();
1365     std::set<int32_t> visibleIndex;
1366 
1367     for (auto& item : itemPosition_) {
1368         auto index = item.first;
1369         auto startPos = item.second.startPos + offset;
1370         auto endPos = item.second.endPos + offset;
1371         auto itemPosDiff = endPos - startPos + itemSpace;
1372         auto pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index, displayCount) : index;
1373         auto pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index, displayCount) : index;
1374         auto pageStartPos = swipeByGroup ? startPos - itemPosDiff * (index - pageStartIndex) : startPos;
1375         auto pageEndPos = swipeByGroup ? endPos + itemPosDiff * (pageEndIndex - index) : endPos;
1376 
1377         if (LessOrEqual(pageEndPos, -GetPrevMarginWithItemSpace())) {
1378             continue;
1379         }
1380         if (GreatOrEqual(pageStartPos, visibleSize + GetNextMarginWithItemSpace())) {
1381             continue;
1382         }
1383 
1384         if (GreatNotEqual(startPos - itemSpace, -GetPrevMarginWithItemSpace()) &&
1385             itemPosition_.find(index - 1) == itemPosition_.end() && (isLoop || index > 0)) {
1386             pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index - 1, displayCount) : index - 1;
1387         }
1388         if (LessNotEqual(endPos + itemSpace, visibleSize + GetNextMarginWithItemSpace()) &&
1389             itemPosition_.find(index + 1) == itemPosition_.end() && (isLoop || index < RealTotalCount() - 1)) {
1390             pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index + 1, displayCount) : index + 1;
1391         }
1392         auto currentIndex = index - 1;
1393         while (currentIndex >= pageStartIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1394             visibleIndex.insert(GetLoopIndex(currentIndex));
1395             currentIndex--;
1396         }
1397         currentIndex = index + 1;
1398         while (currentIndex <= pageEndIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1399             visibleIndex.insert(GetLoopIndex(currentIndex));
1400             currentIndex++;
1401         }
1402         visibleIndex.insert(GetLoopIndex(index));
1403     }
1404 
1405     return visibleIndex;
1406 }
1407 
CalculateAndUpdateItemInfo(float offset)1408 void SwiperPattern::CalculateAndUpdateItemInfo(float offset)
1409 {
1410     auto prevMargin = GetPrevMargin();
1411     auto nextMargin = GetNextMargin();
1412     auto visibleSize = CalculateVisibleSize();
1413     auto itemSpace = GetItemSpace();
1414     auto isLoop = IsLoop();
1415     auto displayCount = GetDisplayCount();
1416     auto swipeByGroup = IsSwipeByGroup();
1417 
1418     for (auto& item : itemPosition_) {
1419         auto index = item.first;
1420         auto startPos = item.second.startPos + offset;
1421         auto endPos = item.second.endPos + offset;
1422         auto itemPosDiff = endPos - startPos + itemSpace;
1423         auto pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index, displayCount) : index;
1424         auto pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index, displayCount) : index;
1425         auto pageStartPos = swipeByGroup ? startPos - itemPosDiff * (index - pageStartIndex) : startPos;
1426         auto pageEndPos = swipeByGroup ? endPos + itemPosDiff * (pageEndIndex - index) : endPos;
1427 
1428         if (LessOrEqual(pageEndPos, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace)) {
1429             continue;
1430         }
1431         if (GreatOrEqual(pageStartPos, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace)) {
1432             continue;
1433         }
1434 
1435         if (GreatNotEqual(startPos - itemSpace, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace) &&
1436             itemPosition_.find(index - 1) == itemPosition_.end() && (isLoop || index > 0)) {
1437             pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index - 1, displayCount) : index - 1;
1438         }
1439         if (LessNotEqual(
1440                 endPos + itemSpace, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace) &&
1441             itemPosition_.find(index + 1) == itemPosition_.end() && (isLoop || index < RealTotalCount() - 1)) {
1442             pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index + 1, displayCount) : index + 1;
1443         }
1444         auto currentIndex = index - 1;
1445         while (currentIndex >= pageStartIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1446             UpdateItemInfoInCustomAnimation(currentIndex, startPos - itemPosDiff * (index - currentIndex),
1447                 endPos - itemPosDiff * (index - currentIndex));
1448             currentIndex--;
1449         }
1450         currentIndex = index + 1;
1451         while (currentIndex <= pageEndIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1452             UpdateItemInfoInCustomAnimation(currentIndex, startPos + itemPosDiff * (currentIndex - index),
1453                 endPos + itemPosDiff * (currentIndex - index));
1454             currentIndex++;
1455         }
1456         UpdateItemInfoInCustomAnimation(index, startPos, endPos);
1457     }
1458 }
1459 
UpdateItemInfoInCustomAnimation(int32_t index,float startPos,float endPos)1460 void SwiperPattern::UpdateItemInfoInCustomAnimation(int32_t index, float startPos, float endPos)
1461 {
1462     index = GetLoopIndex(index);
1463     if (IsSwipeByGroup() && index >= RealTotalCount()) {
1464         return;
1465     }
1466     indexsInAnimation_.insert(index);
1467     needUnmountIndexs_.erase(index);
1468     auto itemInAnimation = itemPositionInAnimation_.find(index);
1469     if (itemInAnimation == itemPositionInAnimation_.end()) {
1470         itemPositionInAnimation_[index] = { startPos, endPos, nullptr };
1471     } else {
1472         itemInAnimation->second.startPos = startPos;
1473         itemInAnimation->second.endPos = endPos;
1474         if (itemInAnimation->second.task) {
1475             itemInAnimation->second.task.Cancel();
1476         }
1477     }
1478 }
1479 
FireSwiperCustomAnimationEvent()1480 void SwiperPattern::FireSwiperCustomAnimationEvent()
1481 {
1482     CHECK_NULL_VOID(onSwiperCustomContentTransition_);
1483     auto transition = onSwiperCustomContentTransition_->transition;
1484     CHECK_NULL_VOID(transition);
1485 
1486     auto selectedIndex = GetCurrentIndex();
1487     for (auto& item : itemPositionInAnimation_) {
1488         if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1489             continue;
1490         }
1491         auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1492         if (IsHorizontalAndRightToLeft()) {
1493             offset = Dimension(-item.second.startPos, DimensionUnit::PX).ConvertToVp();
1494         }
1495         auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1496         if (NonPositive(mainAxisLength)) {
1497             continue;
1498         }
1499         auto position = offset / mainAxisLength;
1500         auto proxy = AceType::MakeRefPtr<SwiperContentTransitionProxy>();
1501         proxy->SetSelectedIndex(selectedIndex);
1502         proxy->SetIndex(item.first);
1503         proxy->SetPosition(position);
1504         proxy->SetMainAxisLength(mainAxisLength);
1505         proxy->SetFinishTransitionEvent([weak = WeakClaim(this), index = item.first]() {
1506             auto swiper = weak.Upgrade();
1507             CHECK_NULL_VOID(swiper);
1508             auto item = swiper->itemPositionInAnimation_.find(index);
1509             if (item == swiper->itemPositionInAnimation_.end()) {
1510                 return;
1511             }
1512             item->second.isFinishAnimation = true;
1513             swiper->OnSwiperCustomAnimationFinish(item->second.task, index, true);
1514         });
1515         transition(proxy);
1516     }
1517 }
1518 
FireContentDidScrollEvent()1519 void SwiperPattern::FireContentDidScrollEvent()
1520 {
1521     if (indexsInAnimation_.empty()) {
1522         return;
1523     }
1524 
1525     CHECK_NULL_VOID(onContentDidScroll_);
1526     auto event = *onContentDidScroll_;
1527     auto selectedIndex = GetCurrentIndex();
1528     for (auto& item : itemPositionInAnimation_) {
1529         if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1530             continue;
1531         }
1532         auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1533         auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1534         if (NonPositive(mainAxisLength)) {
1535             continue;
1536         }
1537         auto position = offset / mainAxisLength;
1538         event(selectedIndex, item.first, position, mainAxisLength);
1539     }
1540     indexsInAnimation_.clear();
1541 }
1542 
OnSwiperCustomAnimationFinish(CancelableCallback<void ()> & task,int32_t index,bool isFinishAnimation)1543 void SwiperPattern::OnSwiperCustomAnimationFinish(
1544     CancelableCallback<void()>& task, int32_t index, bool isFinishAnimation)
1545 {
1546     if (needUnmountIndexs_.find(index) == needUnmountIndexs_.end()) {
1547         return;
1548     }
1549     auto pipeline = PipelineContext::GetCurrentContext();
1550     CHECK_NULL_VOID(pipeline);
1551     auto taskExecutor = pipeline->GetTaskExecutor();
1552     CHECK_NULL_VOID(taskExecutor);
1553     if (task) {
1554         task.Cancel();
1555     }
1556 
1557     int32_t timeout = 0;
1558     if (onSwiperCustomContentTransition_ && !isFinishAnimation) {
1559         timeout = onSwiperCustomContentTransition_->timeout;
1560     }
1561 
1562     if (timeout == 0) {
1563         needUnmountIndexs_.erase(index);
1564         itemPositionInAnimation_.erase(index);
1565         MarkDirtyNodeSelf();
1566         return;
1567     }
1568 
1569     task.Reset([weak = AceType::WeakClaim(this), index] {
1570         auto swiper = weak.Upgrade();
1571         CHECK_NULL_VOID(swiper);
1572         swiper->needUnmountIndexs_.erase(index);
1573         swiper->itemPositionInAnimation_.erase(index);
1574         swiper->MarkDirtyNodeSelf();
1575     });
1576     taskExecutor->PostDelayedTask(task, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperDelayedCustomAnimation");
1577 }
1578 
SwipeToWithoutAnimation(int32_t index)1579 void SwiperPattern::SwipeToWithoutAnimation(int32_t index)
1580 {
1581     if (currentIndex_ != index) {
1582         FireWillShowEvent(index);
1583         FireWillHideEvent(currentIndex_);
1584     }
1585     if (IsVisibleChildrenSizeLessThanSwiper()) {
1586         return;
1587     }
1588 
1589     if (usePropertyAnimation_) {
1590         StopPropertyTranslateAnimation(isFinishAnimation_);
1591     }
1592 
1593     StopTranslateAnimation();
1594     StopFadeAnimation();
1595     StopSpringAnimationImmediately();
1596     StopIndicatorAnimation(true);
1597     jumpIndex_ = index;
1598     AceAsyncTraceBeginCommercial(0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1599     uiCastJumpIndex_ = index;
1600     MarkDirtyNodeSelf();
1601     FireAndCleanScrollingListener();
1602 }
1603 
StopSpringAnimationAndFlushImmediately()1604 void SwiperPattern::StopSpringAnimationAndFlushImmediately()
1605 {
1606     if (springAnimationIsRunning_) {
1607         StopSpringAnimationImmediately();
1608         currentDelta_ = 0.0f;
1609         itemPosition_.clear();
1610         isVoluntarilyClear_ = true;
1611         jumpIndex_ = currentIndex_;
1612         MarkDirtyNodeSelf();
1613         auto pipeline = PipelineContext::GetCurrentContext();
1614         if (pipeline) {
1615             pipeline->FlushUITasks();
1616         }
1617     }
1618 }
1619 
IsUseCustomAnimation() const1620 bool SwiperPattern::IsUseCustomAnimation() const
1621 {
1622     auto props = GetLayoutProperty<SwiperLayoutProperty>();
1623     CHECK_NULL_RETURN(props, false);
1624     return props->GetIsCustomAnimation().value_or(false);
1625 }
1626 
SwipeTo(int32_t index)1627 void SwiperPattern::SwipeTo(int32_t index)
1628 {
1629     auto targetIndex = IsLoop() ? index : (index < 0 || index > (TotalCount() - 1)) ? 0 : index;
1630     targetIndex = IsLoop() ? targetIndex : std::clamp(targetIndex, 0, TotalCount() - GetDisplayCount());
1631     if (!ContentWillChange(targetIndex)) {
1632         return;
1633     }
1634 
1635     if (IsUseCustomAnimation()) {
1636         OnCustomContentTransition(targetIndex);
1637         MarkDirtyNodeSelf();
1638         return;
1639     }
1640 
1641     if (IsVisibleChildrenSizeLessThanSwiper()) {
1642         return;
1643     }
1644 
1645     // If targetIndex_ has a value, means animation is still running, stop it before play new animation.
1646     if (currentIndex_ == targetIndex && !targetIndex_.has_value()) {
1647         return;
1648     }
1649     StopFadeAnimation();
1650     if (springAnimationIsRunning_) {
1651         StopSpringAnimationImmediately();
1652         jumpIndex_ = currentIndex_;
1653         MarkDirtyNodeSelf();
1654         auto pipeline = PipelineContext::GetCurrentContext();
1655         if (pipeline) {
1656             pipeline->FlushUITasks();
1657         }
1658     }
1659     StopAutoPlay();
1660     StopTranslateAnimation();
1661 
1662     StopIndicatorAnimation();
1663     if (usePropertyAnimation_) {
1664         StopPropertyTranslateAnimation(isFinishAnimation_);
1665     }
1666 
1667     targetIndex_ = targetIndex;
1668 
1669     UpdateTabBarAnimationDuration(index);
1670     if (GetDuration() == 0 || !isVisible_) {
1671         SwipeToWithoutAnimation(index);
1672         return;
1673     }
1674 
1675     if (currentIndex_ != targetIndex_.value_or(0)) {
1676         FireWillShowEvent(targetIndex_.value_or(0));
1677         FireWillHideEvent(currentIndex_);
1678     }
1679     MarkDirtyNodeSelf();
1680 }
1681 
UpdateTabBarAnimationDuration(int32_t index)1682 void SwiperPattern::UpdateTabBarAnimationDuration(int32_t index)
1683 {
1684     auto host = GetHost();
1685     CHECK_NULL_VOID(host);
1686     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1687     CHECK_NULL_VOID(tabsNode);
1688     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
1689     CHECK_NULL_VOID(tabBarNode);
1690     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
1691     CHECK_NULL_VOID(tabBarPattern);
1692     tabBarPattern->UpdateAnimationDuration();
1693 }
1694 
CheckTargetIndex(int32_t targetIndex,bool isForceBackward)1695 int32_t SwiperPattern::CheckTargetIndex(int32_t targetIndex, bool isForceBackward)
1696 {
1697     if (!IsAutoLinear()) {
1698         return targetIndex;
1699     }
1700     while (GetLoopIndex(targetIndex) != GetLoopIndex(currentIndex_)) {
1701         auto currentFrameNode = GetCurrentFrameNode(GetLoopIndex(targetIndex));
1702         CHECK_NULL_RETURN(currentFrameNode, targetIndex);
1703         auto props = currentFrameNode->GetLayoutProperty<LayoutProperty>();
1704         CHECK_NULL_RETURN(props, targetIndex);
1705         if (props->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
1706             return targetIndex;
1707         }
1708         if (isForceBackward || currentIndex_ < targetIndex) {
1709             if (IsHorizontalAndRightToLeft()) {
1710                 --targetIndex;
1711             } else {
1712                 ++targetIndex;
1713             }
1714         } else {
1715             if (IsHorizontalAndRightToLeft()) {
1716                 ++targetIndex;
1717             } else {
1718                 --targetIndex;
1719             }
1720         }
1721         if (!IsLoop() && (targetIndex < 0 || targetIndex >= TotalCount())) {
1722             return currentIndex_;
1723         }
1724     }
1725     return targetIndex;
1726 }
1727 
ShowNext()1728 void SwiperPattern::ShowNext()
1729 {
1730     if (IsVisibleChildrenSizeLessThanSwiper()) {
1731         return;
1732     }
1733     indicatorDoingAnimation_ = false;
1734     auto childrenSize = TotalCount();
1735     std::optional<int32_t> preIndex;
1736     auto loopIndex = usePropertyAnimation_ ? GetLoopIndex(propertyAnimationIndex_) : GetLoopIndex(currentIndex_);
1737     if (preTargetIndex_.has_value()) {
1738         loopIndex = GetLoopIndex(preTargetIndex_.value());
1739         preIndex = preTargetIndex_.value();
1740     }
1741     if (loopIndex >= childrenSize - GetDisplayCount() && !IsLoop()) {
1742         return;
1743     }
1744     if (childrenSize <= 0 || GetDisplayCount() == 0) {
1745         return;
1746     }
1747     StopAutoPlay();
1748 
1749     StopSpringAnimationAndFlushImmediately();
1750     StopFadeAnimation();
1751     StopIndicatorAnimation();
1752     if (preIndex || usePropertyAnimation_) {
1753         isUserFinish_ = false;
1754         FinishAnimation();
1755         if (!ContentWillChange(currentIndex_ + 1)) {
1756             return;
1757         }
1758     }
1759     moveDirection_ = true;
1760 
1761     auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1762     if (isVisibleArea_) {
1763         targetIndex_ = CheckTargetIndex(currentIndex_ + stepItems);
1764         preTargetIndex_ = targetIndex_;
1765         MarkDirtyNodeSelf();
1766         auto pipeline = PipelineContext::GetCurrentContext();
1767         if (pipeline) {
1768             pipeline->FlushUITasks();
1769         }
1770     } else {
1771         SwipeToWithoutAnimation(currentIndex_ + stepItems);
1772     }
1773     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1774     CHECK_NULL_VOID(swiperEventHub);
1775     swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1776 }
1777 
ShowPrevious()1778 void SwiperPattern::ShowPrevious()
1779 {
1780     if (IsVisibleChildrenSizeLessThanSwiper()) {
1781         return;
1782     }
1783 
1784     if (IsAutoLinear() && static_cast<int32_t>(itemPosition_.size()) == TotalCount() && !autoLinearReachBoundary) {
1785         return;
1786     }
1787 
1788     indicatorDoingAnimation_ = false;
1789     auto childrenSize = TotalCount();
1790     std::optional<int32_t> preIndex;
1791     auto loopIndex = usePropertyAnimation_ ? GetLoopIndex(propertyAnimationIndex_) : GetLoopIndex(currentIndex_);
1792     if (preTargetIndex_.has_value()) {
1793         loopIndex = GetLoopIndex(preTargetIndex_.value());
1794         preIndex = preTargetIndex_.value();
1795     }
1796     if (loopIndex <= 0 && !IsLoop()) {
1797         return;
1798     }
1799     if (childrenSize <= 0 || GetDisplayCount() == 0) {
1800         return;
1801     }
1802     StopAutoPlay();
1803     StopSpringAnimationAndFlushImmediately();
1804     StopFadeAnimation();
1805     StopIndicatorAnimation();
1806 
1807     if (preIndex || usePropertyAnimation_) {
1808         isUserFinish_ = false;
1809         FinishAnimation();
1810         if (!ContentWillChange(currentIndex_ - 1)) {
1811             return;
1812         }
1813     }
1814     moveDirection_ = false;
1815 
1816     auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1817     if (isVisibleArea_) {
1818         targetIndex_ = CheckTargetIndex(currentIndex_ - stepItems);
1819         preTargetIndex_ = targetIndex_;
1820         MarkDirtyNodeSelf();
1821         auto pipeline = PipelineContext::GetCurrentContext();
1822         if (pipeline) {
1823             pipeline->FlushUITasks();
1824         }
1825     } else {
1826         SwipeToWithoutAnimation(currentIndex_ - stepItems);
1827     }
1828     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1829     CHECK_NULL_VOID(swiperEventHub);
1830     swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1831 }
1832 
ChangeIndex(int32_t index,bool useAnimation)1833 void SwiperPattern::ChangeIndex(int32_t index, bool useAnimation)
1834 {
1835     auto displayCount = GetDisplayCount();
1836     if (RealTotalCount() <= 0 || displayCount == 0 || index < 0 || index >= RealTotalCount()) {
1837         return;
1838     }
1839     auto itemCount = TotalCount();
1840     auto loopCount = std::abs(currentIndex_ / itemCount);
1841     auto targetIndex = currentIndex_ >= 0 ? loopCount * itemCount + index : -(loopCount + 1) * itemCount + index;
1842     targetIndex = IsSwipeByGroup() ? SwiperUtils::ComputePageIndex(targetIndex, displayCount) : targetIndex;
1843     if (targetIndex_.has_value() && targetIndex_.value() == targetIndex) {
1844         return;
1845     }
1846 
1847     targetIndex = CheckTargetIndex(targetIndex);
1848     if (useAnimation) {
1849         if (GetMaxDisplayCount() > 0) {
1850             SetIndicatorChangeIndexStatus(true);
1851         }
1852 
1853         SwipeTo(targetIndex);
1854     } else {
1855         needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
1856 
1857         if (GetMaxDisplayCount() > 0) {
1858             SetIndicatorChangeIndexStatus(false);
1859         }
1860 
1861         SwipeToWithoutAnimation(GetLoopIndex(targetIndex));
1862     }
1863 }
1864 
FinishAnimation()1865 void SwiperPattern::FinishAnimation()
1866 {
1867     if (translateAnimationIsRunning_) {
1868         isFinishAnimation_ = true;
1869         StopTranslateAnimation();
1870     }
1871     StopSpringAnimation();
1872     StopFadeAnimation();
1873     StopIndicatorAnimation(true);
1874     if (usePropertyAnimation_) {
1875         isFinishAnimation_ = true;
1876         StopPropertyTranslateAnimation(isFinishAnimation_);
1877     }
1878     if (isUserFinish_) {
1879         if (swiperController_ && swiperController_->GetFinishCallback()) {
1880             auto finishCallback = swiperController_->GetFinishCallback();
1881             finishCallback();
1882             swiperController_->SetFinishCallback(nullptr);
1883         }
1884     } else {
1885         isUserFinish_ = true;
1886     }
1887 }
1888 
PreloadItems(const std::set<int32_t> & indexSet)1889 void SwiperPattern::PreloadItems(const std::set<int32_t>& indexSet)
1890 {
1891     std::set<int32_t> validIndexSet;
1892     auto childrenSize = RealTotalCount();
1893     for (const auto& index : indexSet) {
1894         if (index < 0 || index >= childrenSize) {
1895             FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
1896                 "BusinessError 401: Parameter error. Each value in indices must be valid index value of tab content.");
1897             return;
1898         }
1899         validIndexSet.emplace(index);
1900     }
1901 
1902     if (validIndexSet.empty()) {
1903         FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
1904             "BusinessError 401: Parameter error. The parameter indices must be a non-empty array.");
1905         return;
1906     }
1907 
1908     auto preloadTask = [weak = WeakClaim(this), indexSet]() {
1909         auto swiperPattern = weak.Upgrade();
1910         CHECK_NULL_VOID(swiperPattern);
1911         auto host = swiperPattern->GetHost();
1912         CHECK_NULL_VOID(host);
1913         auto parent = host->GetParent();
1914         if (AceType::InstanceOf<TabsNode>(parent)) {
1915             swiperPattern->DoTabsPreloadItems(indexSet);
1916         } else {
1917             swiperPattern->DoSwiperPreloadItems(indexSet);
1918         }
1919 
1920         swiperPattern->FirePreloadFinishEvent(ERROR_CODE_NO_ERROR);
1921     };
1922     auto host = GetHost();
1923     CHECK_NULL_VOID(host);
1924     auto pipeline = host->GetContext();
1925     CHECK_NULL_VOID(pipeline);
1926     auto taskExecutor = pipeline->GetTaskExecutor();
1927     CHECK_NULL_VOID(taskExecutor);
1928     taskExecutor->PostTask(preloadTask, TaskExecutor::TaskType::UI, "ArkUIFirePreloadFinish");
1929 }
1930 
FirePreloadFinishEvent(int32_t errorCode,std::string message)1931 void SwiperPattern::FirePreloadFinishEvent(int32_t errorCode, std::string message)
1932 {
1933     if (swiperController_ && swiperController_->GetPreloadFinishCallback()) {
1934         auto preloadFinishCallback = swiperController_->GetPreloadFinishCallback();
1935         swiperController_->SetPreloadFinishCallback(nullptr);
1936         preloadFinishCallback(errorCode, message);
1937     }
1938 }
1939 
DoTabsPreloadItems(const std::set<int32_t> & indexSet)1940 void SwiperPattern::DoTabsPreloadItems(const std::set<int32_t>& indexSet)
1941 {
1942     auto host = GetHost();
1943     CHECK_NULL_VOID(host);
1944     auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
1945     CHECK_NULL_VOID(props);
1946     auto geometryNode = host->GetGeometryNode();
1947     CHECK_NULL_VOID(geometryNode);
1948     auto contentConstraint = props->GetContentLayoutConstraint();
1949     auto frameSize = OptionalSizeF(geometryNode->GetPaddingSize());
1950     auto childConstraint = SwiperUtils::CreateChildConstraint(props, frameSize, false);
1951     for (auto index : indexSet) {
1952         auto tabContent = GetCurrentFrameNode(index);
1953         if (!tabContent) {
1954             continue;
1955         }
1956         if (!tabContent->GetChildren().empty()) {
1957             continue;
1958         }
1959         auto tabContentPattern = tabContent->GetPattern<TabContentPattern>();
1960         if (!tabContentPattern) {
1961             continue;
1962         }
1963         tabContentPattern->BeforeCreateLayoutWrapper();
1964 
1965         for (const auto& child : tabContent->GetChildren()) {
1966             child->Build(nullptr);
1967         }
1968         if (contentConstraint.has_value() && tabContent->GetGeometryNode()) {
1969             tabContent->GetGeometryNode()->SetParentLayoutConstraint(childConstraint);
1970             FrameNode::ProcessOffscreenNode(tabContent);
1971         }
1972     }
1973 }
1974 
DoSwiperPreloadItems(const std::set<int32_t> & indexSet)1975 void SwiperPattern::DoSwiperPreloadItems(const std::set<int32_t>& indexSet)
1976 {
1977     auto host = GetHost();
1978     CHECK_NULL_VOID(host);
1979     auto targetNode = FindLazyForEachNode(host);
1980     if (targetNode.has_value()) {
1981         auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
1982         CHECK_NULL_VOID(lazyForEachNode);
1983         for (auto index : indexSet) {
1984             if (lazyForEachNode) {
1985                 lazyForEachNode->GetFrameChildByIndex(index, true);
1986             }
1987         }
1988     }
1989     const auto& children = host->GetChildren();
1990     for (const auto& child : children) {
1991         if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
1992             continue;
1993         }
1994 
1995         auto forEachNode = AceType::DynamicCast<ForEachNode>(child);
1996         for (auto index : indexSet) {
1997             if (forEachNode && forEachNode->GetChildAtIndex(index)) {
1998                 forEachNode->GetChildAtIndex(index)->Build(nullptr);
1999                 continue;
2000             }
2001         }
2002     }
2003 }
2004 
OnTranslateAnimationFinish()2005 void SwiperPattern::OnTranslateAnimationFinish()
2006 {
2007     if (!translateAnimationIsRunning_) {
2008         return;
2009     }
2010     translateAnimationIsRunning_ = false;
2011     OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
2012 }
2013 
StopTranslateAnimation()2014 void SwiperPattern::StopTranslateAnimation()
2015 {
2016     if (translateAnimationIsRunning_) {
2017         auto host = GetHost();
2018         CHECK_NULL_VOID(host);
2019         translateAnimationIsRunning_ = false;
2020 
2021         if (NearZero(translateAnimationEndPos_ - currentOffset_)) {
2022             AnimationUtils::StopAnimation(translateAnimation_);
2023             targetIndex_.reset();
2024         } else {
2025             AnimationOption option;
2026             option.SetCurve(Curves::LINEAR);
2027             option.SetDuration(0);
2028             translateAnimation_ = AnimationUtils::StartAnimation(option, [host, weak = WeakClaim(this)]() {
2029                 auto swiper = weak.Upgrade();
2030                 CHECK_NULL_VOID(swiper);
2031                 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, swiper->currentOffset_);
2032             });
2033         }
2034 
2035         OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_, true);
2036     }
2037 }
2038 
StopSpringAnimationImmediately()2039 void SwiperPattern::StopSpringAnimationImmediately()
2040 {
2041     if (!springAnimationIsRunning_) {
2042         return;
2043     }
2044     AnimationOption option;
2045     option.SetCurve(Curves::LINEAR);
2046     option.SetDuration(0);
2047     springAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
2048         auto swiper = weak.Upgrade();
2049         CHECK_NULL_VOID(swiper);
2050         auto host = swiper->GetHost();
2051         CHECK_NULL_VOID(host);
2052         host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, swiper->currentIndexOffset_);
2053     });
2054     OnSpringAnimationFinish();
2055 }
2056 
StopSpringAnimation()2057 void SwiperPattern::StopSpringAnimation()
2058 {
2059     if (springAnimationIsRunning_) {
2060         AnimationUtils::StopAnimation(springAnimation_);
2061     }
2062 }
2063 
StopFadeAnimation()2064 void SwiperPattern::StopFadeAnimation()
2065 {
2066     AnimationUtils::StopAnimation(fadeAnimation_);
2067     if (fadeAnimationIsRunning_) {
2068         fadeAnimationIsRunning_ = false;
2069     }
2070 }
2071 
InitIndicator()2072 void SwiperPattern::InitIndicator()
2073 {
2074     auto swiperNode = GetHost();
2075     CHECK_NULL_VOID(swiperNode);
2076     RefPtr<FrameNode> indicatorNode;
2077     if (!HasIndicatorNode()) {
2078         if (!IsShowIndicator()) {
2079             return;
2080         }
2081         indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
2082             []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
2083         swiperNode->AddChild(indicatorNode);
2084     } else {
2085         indicatorNode =
2086             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetIndicatorId())));
2087         CHECK_NULL_VOID(indicatorNode);
2088         if (!IsShowIndicator()) {
2089             RemoveIndicatorNode();
2090             return;
2091         }
2092         if (GetIndicatorType() == SwiperIndicatorType::DIGIT && lastSwiperIndicatorType_ == SwiperIndicatorType::DOT) {
2093             RemoveIndicatorNode();
2094             indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
2095                 []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
2096             swiperNode->AddChild(indicatorNode);
2097         }
2098     }
2099     lastSwiperIndicatorType_ = GetIndicatorType();
2100     CHECK_NULL_VOID(indicatorNode);
2101     auto props = GetLayoutProperty<SwiperLayoutProperty>();
2102     CHECK_NULL_VOID(props);
2103     if (props->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DOT) {
2104         SwiperHelper::SaveDotIndicatorProperty(indicatorNode, *this);
2105     } else {
2106         SwiperHelper::SaveDigitIndicatorProperty(indicatorNode, *this);
2107     }
2108 
2109     auto renderContext = indicatorNode->GetRenderContext();
2110     CHECK_NULL_VOID(renderContext);
2111     BorderRadiusProperty radius;
2112     radius.SetRadius(INDICATOR_BORDER_RADIUS);
2113     renderContext->UpdateBorderRadius(radius);
2114 
2115     auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
2116     indicatorPattern->SetIndicatorInteractive(isIndicatorInteractive_);
2117 
2118     indicatorNode->MarkModifyDone();
2119     indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2120 }
2121 
InitArrow()2122 void SwiperPattern::InitArrow()
2123 {
2124     auto swiperNode = GetHost();
2125     CHECK_NULL_VOID(swiperNode);
2126     RefPtr<FrameNode> leftArrow;
2127     RefPtr<FrameNode> rightArrow;
2128     if (!HasLeftButtonNode() && !HasRightButtonNode()) {
2129         if (!IsShowArrow()) {
2130             return;
2131         }
2132         leftArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_LEFT_ARROW_ETS_TAG, GetLeftButtonId(),
2133             []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2134         swiperNode->AddChild(leftArrow);
2135         rightArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_ARROW_ETS_TAG, GetRightButtonId(),
2136             []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2137         swiperNode->AddChild(rightArrow);
2138     } else {
2139         leftArrow =
2140             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
2141         CHECK_NULL_VOID(leftArrow);
2142         rightArrow =
2143             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
2144         CHECK_NULL_VOID(rightArrow);
2145         if (!IsShowArrow()) {
2146             RemoveLeftButtonNode();
2147             RemoveRightButtonNode();
2148             return;
2149         }
2150     }
2151 
2152     SaveArrowProperty(leftArrow);
2153     SaveArrowProperty(rightArrow);
2154 
2155     leftArrow->MarkModifyDone();
2156     rightArrow->MarkModifyDone();
2157 }
2158 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)2159 void SwiperPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
2160 {
2161     if (direction_ == GetDirection() && panEvent_) {
2162         return;
2163     }
2164     // fade offset need to be reset when is still dragging
2165     if (direction_ != GetDirection()) {
2166         fadeOffset_ = 0.f;
2167     }
2168     direction_ = GetDirection();
2169 
2170     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2171         auto pattern = weak.Upgrade();
2172         pattern->InitIndexCanChangeMap();
2173         if (pattern) {
2174             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag start. SourceTool: %{public}d", info.GetSourceTool());
2175             if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2176                 return;
2177             }
2178             pattern->FireAndCleanScrollingListener();
2179             pattern->HandleDragStart(info);
2180             // notify scrollStart upwards
2181             pattern->NotifyParentScrollStart(weak, pattern->direction_ == Axis::HORIZONTAL ?
2182                 info.GetGlobalLocation().GetX() : info.GetGlobalLocation().GetY());
2183         }
2184     };
2185 
2186     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2187         auto pattern = weak.Upgrade();
2188         if (pattern) {
2189             if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2190                 if (!pattern->CheckSwiperPanEvent(info.GetMainDelta())) {
2191                     return;
2192                 }
2193                 if (GreatNotEqual(info.GetMainDelta(), 0.0)) {
2194                     pattern->ShowPrevious();
2195                 } else if (LessNotEqual(info.GetMainDelta(), 0.0)) {
2196                     pattern->ShowNext();
2197                 }
2198             } else {
2199                 pattern->HandleDragUpdate(info);
2200             }
2201         }
2202     };
2203 
2204     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2205         auto pattern = weak.Upgrade();
2206         if (pattern) {
2207             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag end. Velocity: %{public}f px/s, SourceTool: %{public}d",
2208                 info.GetMainVelocity(), info.GetSourceTool());
2209             if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2210                 return;
2211             }
2212             pattern->HandleDragEnd(info.GetMainVelocity());
2213         }
2214     };
2215 
2216     auto actionCancelTask = [weak = WeakClaim(this)]() {
2217         auto pattern = weak.Upgrade();
2218         if (pattern) {
2219             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag cancel");
2220             pattern->HandleDragEnd(0.0);
2221         }
2222     };
2223 
2224     AddPanEvent(gestureHub, std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask),
2225         std::move(actionCancelTask));
2226 }
2227 
AddPanEvent(const RefPtr<GestureEventHub> & gestureHub,GestureEventFunc && actionStart,GestureEventFunc && actionUpdate,GestureEventFunc && actionEnd,GestureEventNoParameter && actionCancel)2228 void SwiperPattern::AddPanEvent(const RefPtr<GestureEventHub>& gestureHub, GestureEventFunc&& actionStart,
2229     GestureEventFunc&& actionUpdate, GestureEventFunc&& actionEnd, GestureEventNoParameter&& actionCancel)
2230 {
2231     if (GetDirection() == Axis::VERTICAL) {
2232         panDirection_.type = PanDirection::VERTICAL;
2233     } else {
2234         panDirection_.type = PanDirection::HORIZONTAL;
2235     }
2236     if (panEvent_) {
2237         gestureHub->RemovePanEvent(panEvent_);
2238     }
2239 
2240     panEvent_ = MakeRefPtr<PanEvent>(
2241         std::move(actionStart), std::move(actionUpdate), std::move(actionEnd), std::move(actionCancel));
2242     gestureHub->AddPanEvent(panEvent_, panDirection_, 1, DEFAULT_PAN_DISTANCE);
2243 }
2244 
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)2245 void SwiperPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
2246 {
2247     if (touchEvent_) {
2248         return;
2249     }
2250 
2251     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2252         auto pattern = weak.Upgrade();
2253         if (pattern) {
2254             pattern->HandleTouchEvent(info);
2255         }
2256     };
2257 
2258     if (touchEvent_) {
2259         gestureHub->RemoveTouchEvent(touchEvent_);
2260     }
2261     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2262     gestureHub->AddTouchEvent(touchEvent_);
2263 }
2264 
InitOnFocusInternal(const RefPtr<FocusHub> & focusHub)2265 void SwiperPattern::InitOnFocusInternal(const RefPtr<FocusHub>& focusHub)
2266 {
2267     auto focusTask = [weak = WeakClaim(this)]() {
2268         auto pattern = weak.Upgrade();
2269         if (pattern) {
2270             pattern->HandleFocusInternal();
2271         }
2272     };
2273     focusHub->SetOnFocusInternal(std::move(focusTask));
2274 }
2275 
HandleFocusInternal()2276 void SwiperPattern::HandleFocusInternal()
2277 {
2278     currentFocusIndex_ = currentIndex_;
2279 }
2280 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)2281 void SwiperPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
2282 {
2283     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
2284         auto pattern = wp.Upgrade();
2285         if (pattern) {
2286             return pattern->OnKeyEvent(event);
2287         }
2288         return false;
2289     };
2290     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
2291 }
2292 
IsContentFocused()2293 bool SwiperPattern::IsContentFocused()
2294 {
2295     auto swiperHost = GetHost();
2296     CHECK_NULL_RETURN(swiperHost, true);
2297     auto swiperFocusHub = swiperHost->GetFocusHub();
2298     CHECK_NULL_RETURN(swiperFocusHub, true);
2299     auto focusChildren = swiperFocusHub->GetChildren();
2300     CHECK_NULL_RETURN(!focusChildren.empty(), true);
2301     for (const auto& child : focusChildren) {
2302         if (!child || !child->IsCurrentFocus()) {
2303             continue;
2304         }
2305         auto frameName = child->GetFrameName();
2306         if (frameName == V2::SWIPER_INDICATOR_ETS_TAG || frameName == V2::SWIPER_RIGHT_ARROW_ETS_TAG ||
2307             frameName == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
2308             return false;
2309         }
2310         break;
2311     }
2312     return true;
2313 }
2314 
OnKeyEvent(const KeyEvent & event)2315 bool SwiperPattern::OnKeyEvent(const KeyEvent& event)
2316 {
2317     if (event.action != KeyAction::DOWN) {
2318         return false;
2319     }
2320     if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
2321         (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
2322         auto onlyFlushFocus = IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ > currentIndex_;
2323         if (onlyFlushFocus) {
2324             currentFocusIndex_ =
2325                 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2326             FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2327         } else {
2328             ShowPrevious();
2329             currentFocusIndex_ =
2330                 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2331         }
2332 
2333         return true;
2334     }
2335     if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
2336         (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
2337         auto onlyFlushFocus =
2338             IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ < currentIndex_ + GetDisplayCount() - 1;
2339         if (onlyFlushFocus) {
2340             currentFocusIndex_ =
2341                 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2342             FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2343         } else {
2344             ShowNext();
2345             currentFocusIndex_ =
2346                 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2347         }
2348 
2349         return true;
2350     }
2351     return false;
2352 }
2353 
StopAutoPlay()2354 void SwiperPattern::StopAutoPlay()
2355 {
2356     if (IsAutoPlay()) {
2357         isInAutoPlay_ = false;
2358         translateTask_.Cancel();
2359     }
2360 }
2361 
StartAutoPlay()2362 void SwiperPattern::StartAutoPlay()
2363 {
2364     if (NeedAutoPlay() && !translateAnimationIsRunning_ && !usePropertyAnimation_) {
2365         PostTranslateTask(GetInterval());
2366     }
2367 }
2368 
OnVisibleChange(bool isVisible)2369 void SwiperPattern::OnVisibleChange(bool isVisible)
2370 {
2371     isVisible_ = isVisible;
2372     if (isInit_) {
2373         return;
2374     }
2375 
2376     if (!isVisible_) {
2377         StopAutoPlay();
2378         return;
2379     }
2380 
2381     if (NeedStartAutoPlay()) {
2382         StartAutoPlay();
2383     }
2384 }
2385 
UpdateCurrentOffset(float offset)2386 void SwiperPattern::UpdateCurrentOffset(float offset)
2387 {
2388     if (itemPosition_.empty()) {
2389         MarkDirtyNodeSelf();
2390         return;
2391     }
2392     if (!IsLoop() && (isDragging_ || childScrolling_)) {
2393         // handle edge effects
2394         if (CheckOverScroll(offset)) {
2395             return;
2396         }
2397     }
2398     if (!IsLoop() && GetEdgeEffect() != EdgeEffect::SPRING && IsOutOfBoundary(offset)) {
2399         offset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2400                                       : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2401     } else {
2402         offset = IsHorizontalAndRightToLeft() ? -offset : offset;
2403     }
2404     currentDelta_ -= offset;
2405     currentIndexOffset_ += offset;
2406     if (isDragging_ || childScrolling_) {
2407         AnimationCallbackInfo callbackInfo;
2408         callbackInfo.currentOffset =
2409             GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2410         if (IsHorizontalAndRightToLeft()) {
2411             callbackInfo.currentOffset =
2412                 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2413         }
2414         bool skipGestureSwipe = TotalCount() == 1 && GetEdgeEffect() == EdgeEffect::NONE;
2415         if (!skipGestureSwipe) {
2416             FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
2417         }
2418     }
2419     HandleSwiperCustomAnimation(offset);
2420     MarkDirtyNodeSelf();
2421 }
2422 
CheckOverScroll(float offset)2423 bool SwiperPattern::CheckOverScroll(float offset)
2424 {
2425     switch (GetEdgeEffect()) {
2426         case EdgeEffect::SPRING:
2427             if (SpringOverScroll(offset)) {
2428                 return true;
2429             }
2430             break;
2431         case EdgeEffect::FADE:
2432             if (FadeOverScroll(offset)) {
2433                 return true;
2434             }
2435             break;
2436         case EdgeEffect::NONE:
2437             if (IsOutOfBoundary(offset)) {
2438                 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2439                                                        : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2440                 currentDelta_ += IsHorizontalAndRightToLeft() ? realOffset : -realOffset;
2441                 HandleSwiperCustomAnimation(realOffset);
2442                 MarkDirtyNodeSelf();
2443                 return true;
2444             }
2445             break;
2446     }
2447     return false;
2448 }
2449 
SpringOverScroll(float offset)2450 bool SwiperPattern::SpringOverScroll(float offset)
2451 {
2452     bool outOfBounds = isTouchPad_ ? IsOutOfBoundary(offset) : IsOutOfBoundary();
2453     if (!outOfBounds) {
2454         return false;
2455     }
2456     offset = IsHorizontalAndRightToLeft() ? -offset : offset;
2457     targetIndex_.reset();
2458 
2459     auto visibleSize = CalculateVisibleSize();
2460     if (LessOrEqual(visibleSize, 0.0)) {
2461         return true;
2462     }
2463     auto friction = currentIndexOffset_ > 0
2464                         ? CalculateFriction(itemPosition_.begin()->second.startPos / visibleSize)
2465                         : CalculateFriction((visibleSize - itemPosition_.rbegin()->second.endPos) / visibleSize);
2466 
2467     currentDelta_ = currentDelta_ - friction * offset;
2468     currentIndexOffset_ += friction * offset;
2469     AnimationCallbackInfo callbackInfo;
2470     callbackInfo.currentOffset =
2471         GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2472     if (IsHorizontalAndRightToLeft()) {
2473         callbackInfo.currentOffset =
2474             GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2475     }
2476 
2477     FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
2478     HandleSwiperCustomAnimation(friction * offset);
2479     MarkDirtyNodeSelf();
2480     return true;
2481 }
2482 
FadeOverScroll(float offset)2483 bool SwiperPattern::FadeOverScroll(float offset)
2484 {
2485     if (IsOutOfBoundary(fadeOffset_ + offset)) {
2486         if (!IsVisibleChildrenSizeLessThanSwiper() && NearZero(fadeOffset_)) {
2487             UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart(offset));
2488             auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2489                                                    : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2490             currentDelta_ -= realOffset;
2491             offset -= realOffset;
2492             HandleSwiperCustomAnimation(realOffset);
2493         }
2494         fadeOffset_ += offset;
2495         auto host = GetHost();
2496         CHECK_NULL_RETURN(host, false);
2497         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2498         MarkDirtyNodeSelf();
2499         return true;
2500     }
2501     fadeOffset_ = 0.0f;
2502     return false;
2503 }
2504 
IsHorizontalAndRightToLeft() const2505 bool SwiperPattern::IsHorizontalAndRightToLeft() const
2506 {
2507     auto host = GetHost();
2508     CHECK_NULL_RETURN(host, false);
2509     CHECK_NULL_RETURN(host->GetLayoutProperty(), false);
2510     return GetDirection() == Axis::HORIZONTAL &&
2511            host->GetLayoutProperty()->GetNonAutoLayoutDirection() == TextDirection::RTL;
2512 }
2513 
GetNonAutoLayoutDirection() const2514 TextDirection SwiperPattern::GetNonAutoLayoutDirection() const
2515 {
2516     auto host = GetHost();
2517     CHECK_NULL_RETURN(host, TextDirection::LTR);
2518     CHECK_NULL_RETURN(host->GetLayoutProperty(), TextDirection::LTR);
2519     return host->GetLayoutProperty()->GetNonAutoLayoutDirection();
2520 }
2521 
UpdateNextValidIndex()2522 void SwiperPattern::UpdateNextValidIndex()
2523 {
2524     // item may be invalid in auto linear scene, mark next valid item
2525     if (IsAutoLinear()) {
2526         currentFirstIndex_ = CheckTargetIndex(currentFirstIndex_, true);
2527         nextValidIndex_ = GetLoopIndex(CheckTargetIndex(currentFirstIndex_ + 1, true));
2528     } else {
2529         nextValidIndex_ = -1;
2530     }
2531 }
2532 
CheckMarkDirtyNodeForRenderIndicator(float additionalOffset,std::optional<int32_t> nextIndex)2533 void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset, std::optional<int32_t> nextIndex)
2534 {
2535     additionalOffset = IsHorizontalAndRightToLeft() ? -additionalOffset : additionalOffset;
2536     if (!indicatorId_.has_value()) {
2537         return;
2538     }
2539     auto host = GetHost();
2540     CHECK_NULL_VOID(host);
2541     auto child = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
2542     CHECK_NULL_VOID(child);
2543 
2544     if (child->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
2545         return;
2546     }
2547 
2548     int32_t preFirstIndex = currentFirstIndex_;
2549     auto currentPageStatus = (IsHorizontalAndRightToLeft() && GetMaxDisplayCount() > 0)
2550                                  ? CalcCurrentPageStatusOnRTL(additionalOffset)
2551                                  : CalcCurrentPageStatus(additionalOffset);
2552     float currentTurnPageRate = currentPageStatus.first;
2553     currentFirstIndex_ = currentPageStatus.second;
2554 
2555     currentFirstIndex_ = nextIndex.value_or(currentFirstIndex_);
2556     UpdateNextValidIndex();
2557     currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
2558     auto isRtl = IsHorizontalAndRightToLeft() && GetMaxDisplayCount() <= 0;
2559     isRtl ? CalculateGestureStateOnRTL(additionalOffset, currentTurnPageRate, preFirstIndex)
2560           : CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
2561     turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
2562     turnPageRate_ = isRtl ? std::abs(turnPageRate_) - 1.0f : turnPageRate_;
2563     touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
2564     CheckMarkForIndicatorBoundary();
2565     isRtl ? HandleTouchBottomLoopOnRTL() : HandleTouchBottomLoop();
2566 
2567     if (IsVisibleChildrenSizeLessThanSwiper()) {
2568         turnPageRate_ = 0.0f;
2569         gestureState_ = GestureState::GESTURE_STATE_NONE;
2570         touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
2571     }
2572 
2573     if (!indicatorDoingAnimation_) {
2574         child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2575     }
2576     if (GetLoopIndex(currentIndex_) != currentFirstIndex_) {
2577         auto swiperEventHub = GetEventHub<SwiperEventHub>();
2578         CHECK_NULL_VOID(swiperEventHub);
2579         swiperEventHub->FireIndicatorChangeEvent(currentFirstIndex_);
2580     }
2581 }
2582 
CheckMarkForIndicatorBoundary()2583 void SwiperPattern::CheckMarkForIndicatorBoundary()
2584 {
2585     bool isRtl = IsHorizontalAndRightToLeft();
2586 
2587     auto startIndex = isRtl ? TotalCount() - 1 : 0;
2588     auto endIndex = isRtl ? 0 : TotalCount() - 1;
2589     if (!IsLoop() && ((currentFirstIndex_ == startIndex && GreatNotEqualCustomPrecision(turnPageRate_, 0.0f)) ||
2590                          (currentFirstIndex_ == endIndex && LessNotEqualCustomPrecision(turnPageRate_, 0.0f)))) {
2591         return;
2592     }
2593 }
2594 
UpdateAnimationProperty(float velocity)2595 void SwiperPattern::UpdateAnimationProperty(float velocity)
2596 {
2597     if (isDragging_ || childScrolling_) {
2598         targetIndex_ = CheckTargetIndex(ComputeNextIndexByVelocity(velocity));
2599         velocity_ = velocity;
2600     } else {
2601         targetIndex_ = pauseTargetIndex_;
2602         velocity_ = velocity;
2603     }
2604 
2605     MarkDirtyNodeSelf();
2606     moveDirection_ = velocity <= 0;
2607 }
2608 
HandleTouchEvent(const TouchEventInfo & info)2609 void SwiperPattern::HandleTouchEvent(const TouchEventInfo& info)
2610 {
2611     if (info.GetTouches().empty()) {
2612         return;
2613     }
2614     auto locationInfo = info.GetTouches().front();
2615     auto touchType = locationInfo.GetTouchType();
2616     if (touchType == TouchType::DOWN) {
2617         HandleTouchDown(locationInfo);
2618     } else if (touchType == TouchType::UP) {
2619         HandleTouchUp();
2620     } else if (touchType == TouchType::CANCEL) {
2621         HandleTouchUp();
2622     }
2623 }
2624 
InsideIndicatorRegion(const TouchLocationInfo & locationInfo)2625 bool SwiperPattern::InsideIndicatorRegion(const TouchLocationInfo& locationInfo)
2626 {
2627     if (!HasIndicatorNode()) {
2628         return false;
2629     }
2630 
2631     auto host = GetHost();
2632     CHECK_NULL_RETURN(host, false);
2633     auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
2634     CHECK_NULL_RETURN(indicatorNode, false);
2635     if (indicatorNode->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
2636         return false;
2637     }
2638 
2639     auto geometryNode = indicatorNode->GetGeometryNode();
2640     CHECK_NULL_RETURN(geometryNode, false);
2641     auto hotRegion = geometryNode->GetFrameRect();
2642     auto touchPoint = PointF(static_cast<float>(locationInfo.GetLocalLocation().GetX()),
2643         static_cast<float>(locationInfo.GetLocalLocation().GetY()));
2644 
2645     return hotRegion.IsInRegion(touchPoint);
2646 }
2647 
HandleTouchDown(const TouchLocationInfo & locationInfo)2648 void SwiperPattern::HandleTouchDown(const TouchLocationInfo& locationInfo)
2649 {
2650     ACE_SCOPED_TRACE("Swiper HandleTouchDown");
2651     TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchDown");
2652     isTouchDown_ = true;
2653     isTouchDownOnOverlong_ = true;
2654     if (InsideIndicatorRegion(locationInfo)) {
2655         return;
2656     }
2657 
2658     if (childScrolling_) {
2659         // Even if the child fails to notify scrollEnd, we reset childScrolling_ flag on TouchDown to ensure its
2660         // value is correct.
2661         childScrolling_ = false;
2662     }
2663 
2664     StopIndicatorAnimation(true);
2665     if (usePropertyAnimation_) {
2666         StopPropertyTranslateAnimation(isFinishAnimation_);
2667     }
2668 
2669     indicatorDoingAnimation_ = false;
2670     // Stop translate animation when touch down.
2671     if (translateAnimationIsRunning_) {
2672         StopTranslateAnimation();
2673     }
2674 
2675     if (springAnimationIsRunning_) {
2676         AnimationUtils::PauseAnimation(springAnimation_);
2677         isTouchDownSpringAnimation_ = true;
2678     }
2679 
2680     AnimationUtils::PauseAnimation(fadeAnimation_);
2681     if (fadeAnimationIsRunning_) {
2682         isTouchDownFadeAnimation_ = true;
2683     }
2684 
2685     // Stop auto play when touch down.
2686     StopAutoPlay();
2687 }
2688 
HandleTouchUp()2689 void SwiperPattern::HandleTouchUp()
2690 {
2691     ACE_SCOPED_TRACE("Swiper HandleTouchUp");
2692     TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchUp");
2693     isTouchDown_ = false;
2694     isTouchDownOnOverlong_ = false;
2695     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
2696     if (!isDragging_ && !childScrolling_ && !NearZero(firstItemInfoInVisibleArea.second.startPos) &&
2697         !isTouchDownSpringAnimation_) {
2698         UpdateAnimationProperty(0.0);
2699     }
2700 
2701     if (springAnimationIsRunning_ && isTouchDownSpringAnimation_) {
2702         isTouchDownSpringAnimation_ = false;
2703         AnimationUtils::ResumeAnimation(springAnimation_);
2704     }
2705 
2706     if (fadeAnimationIsRunning_ && isTouchDownFadeAnimation_) {
2707         isTouchDownFadeAnimation_ = false;
2708         AnimationUtils::ResumeAnimation(fadeAnimation_);
2709     }
2710 
2711     if (!isDragging_) {
2712         StartAutoPlay();
2713     }
2714 }
2715 
HandleDragStart(const GestureEvent & info)2716 void SwiperPattern::HandleDragStart(const GestureEvent& info)
2717 {
2718     if (!hasTabsAncestor_) {
2719         PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_SCROLL, PerfActionType::FIRST_MOVE, "");
2720     } else {
2721         AceAsyncTraceBeginCommercial(0, APP_TABS_SCROLL);
2722     }
2723     UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::START);
2724     StopAnimationOnScrollStart(
2725         info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD);
2726     StopAutoPlay();
2727 
2728     const auto& tabBarFinishCallback = swiperController_->GetTabBarFinishCallback();
2729     if (tabBarFinishCallback) {
2730         tabBarFinishCallback();
2731     }
2732 
2733     const auto& removeEventCallback = swiperController_->GetRemoveTabBarEventCallback();
2734     if (removeEventCallback) {
2735         removeEventCallback();
2736     }
2737 
2738     gestureSwipeIndex_ = currentIndex_;
2739     isDragging_ = true;
2740     isTouchDown_ = true;
2741     isTouchDownOnOverlong_ = true;
2742     mainDeltaSum_ = 0.0f;
2743     // in drag process, close lazy feature.
2744     SetLazyLoadFeature(false);
2745 }
2746 
StopAnimationOnScrollStart(bool flushImmediately)2747 void SwiperPattern::StopAnimationOnScrollStart(bool flushImmediately)
2748 {
2749     if (usePropertyAnimation_) {
2750         StopPropertyTranslateAnimation(isFinishAnimation_);
2751     }
2752     StopIndicatorAnimation();
2753     StopTranslateAnimation();
2754     StopFadeAnimation();
2755     if (flushImmediately) {
2756         StopSpringAnimationAndFlushImmediately();
2757     } else {
2758         StopSpringAnimationImmediately();
2759     }
2760 }
2761 
HandleDragUpdate(const GestureEvent & info)2762 void SwiperPattern::HandleDragUpdate(const GestureEvent& info)
2763 {
2764     auto velocity = info.GetMainVelocity();
2765     UpdateDragFRCSceneInfo(velocity, SceneStatus::RUNNING);
2766     UpdateNodeRate();
2767     if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD) {
2768         isTouchPad_ = true;
2769     }
2770 
2771     PointF dragPoint(
2772         static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
2773     NGGestureRecognizer::Transform(dragPoint, GetHost(), true, info.GetIsPostEventResult(), info.GetPostEventNodeId());
2774     if (IsOutOfHotRegion(dragPoint)) {
2775         isTouchPad_ = false;
2776         return;
2777     }
2778 
2779     auto mainDelta = static_cast<float>(info.GetMainDelta());
2780     ProcessDelta(mainDelta, contentMainSize_, mainDeltaSum_);
2781     mainDeltaSum_ += mainDelta;
2782 
2783     if (IsAutoLinear() && AutoLinearIsOutOfBoundary(static_cast<float>(mainDelta))) {
2784         return;
2785     }
2786 
2787     HandleScroll(static_cast<float>(mainDelta), SCROLL_FROM_UPDATE, NestedState::GESTURE, velocity);
2788     UpdateItemRenderGroup(true);
2789     isTouchPad_ = false;
2790 }
2791 
HandleDragEnd(double dragVelocity)2792 void SwiperPattern::HandleDragEnd(double dragVelocity)
2793 {
2794     if (!hasTabsAncestor_) {
2795         PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_SCROLL, false);
2796     } else {
2797         AceAsyncTraceEndCommercial(0, APP_TABS_SCROLL);
2798     }
2799     isTouchDown_ = false;
2800     isTouchDownOnOverlong_ = false;
2801     if (!CheckSwiperPanEvent(dragVelocity)) {
2802         dragVelocity = 0.0;
2803     }
2804     if (!childScrolling_) {
2805         UpdateDragFRCSceneInfo(dragVelocity, SceneStatus::END);
2806     }
2807     const auto& addEventCallback = swiperController_->GetAddTabBarEventCallback();
2808     if (addEventCallback) {
2809         addEventCallback();
2810     }
2811 
2812     auto pipeline = PipelineContext::GetCurrentContext();
2813     if (pipeline) {
2814         pipeline->FlushUITasks();
2815     }
2816     if (itemPosition_.empty()) {
2817         return;
2818     }
2819 
2820     if (IsAutoLinear() && AutoLinearIsOutOfBoundary(0.0f)) {
2821         return;
2822     }
2823 
2824     if (CheckDragOutOfBoundary(dragVelocity)) {
2825         return;
2826     }
2827 
2828     UpdateAnimationProperty(static_cast<float>(dragVelocity));
2829     // nested and reached end (but not out of bounds), need to pass velocity to parent scrollable
2830     auto parent = GetNestedScrollParent();
2831     if (!IsLoop() && parent && NearZero(GetDistanceToEdge())) {
2832         parent->HandleScrollVelocity(dragVelocity);
2833         StartAutoPlay();
2834     } else {
2835         NotifyParentScrollEnd();
2836     }
2837     if (pipeline) {
2838         pipeline->FlushUITasks();
2839         pipeline->FlushMessages();
2840     }
2841 
2842     isDragging_ = false;
2843 
2844     if (currentIndex_ != pauseTargetIndex_.value_or(0)) {
2845         FireWillShowEvent(pauseTargetIndex_.value_or(0));
2846         FireWillHideEvent(currentIndex_);
2847     }
2848 }
2849 
UpdateCurrentIndex(int32_t index)2850 void SwiperPattern::UpdateCurrentIndex(int32_t index)
2851 {
2852     currentIndex_ = index;
2853     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
2854     CHECK_NULL_VOID(props);
2855     props->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
2856 }
2857 
ComputeSwipePageNextIndex(float velocity,bool onlyDistance) const2858 int32_t SwiperPattern::ComputeSwipePageNextIndex(float velocity, bool onlyDistance) const
2859 {
2860     auto swiperWidth = CalculateVisibleSize();
2861     if (LessOrEqual(swiperWidth, 0)) {
2862         return currentIndex_;
2863     }
2864 
2865     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
2866     auto firstIndex = firstItemInfoInVisibleArea.first;
2867     auto displayCount = GetDisplayCount();
2868     auto endIndex = SwiperUtils::ComputePageEndIndex(firstIndex, displayCount);
2869     auto iter = itemPosition_.find(endIndex);
2870     if (iter == itemPosition_.end()) {
2871         return currentIndex_;
2872     }
2873 
2874     auto dragDistance = iter->second.endPos;
2875     auto dragForward = currentIndex_ > firstIndex;
2876     auto dragThresholdFlag = dragForward ? dragDistance > swiperWidth / 2 : dragDistance < swiperWidth / 2;
2877     auto nextIndex = currentIndex_;
2878     if (dragThresholdFlag) {
2879         nextIndex = dragForward ? currentIndex_ - displayCount : currentIndex_ + displayCount;
2880     }
2881 
2882     if (!onlyDistance && std::abs(velocity) > NEW_MIN_TURN_PAGE_VELOCITY && velocity != 0.0f) {
2883         auto direction = GreatNotEqual(velocity, 0.0f);
2884         if (dragForward != direction || !dragThresholdFlag) {
2885             nextIndex = velocity > 0.0f ? nextIndex - displayCount : nextIndex + displayCount;
2886         }
2887     }
2888 
2889     if (!IsAutoLinear() && nextIndex > currentIndex_ + displayCount) {
2890         nextIndex = currentIndex_ + displayCount;
2891     }
2892 
2893     if (!IsLoop()) {
2894         nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - displayCount));
2895     }
2896 
2897     return nextIndex;
2898 }
2899 
ComputeNextIndexInSinglePage(float velocity,bool onlyDistance) const2900 int32_t SwiperPattern::ComputeNextIndexInSinglePage(float velocity, bool onlyDistance) const
2901 {
2902     auto firstItemInfo = GetFirstItemInfoInVisibleArea();
2903     auto swiperWidthHalf = (firstItemInfo.second.endPos - firstItemInfo.second.startPos) / SWIPER_HALF;
2904     if (LessOrEqual(swiperWidthHalf, 0)) {
2905         return currentIndex_;
2906     }
2907     // if direction is true, expected index to decrease by 1
2908     bool direction = Positive(velocity);
2909     bool overTurnPageVelocity =
2910         !onlyDistance && (std::abs(velocity) > (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
2911                                                        ? NEW_MIN_TURN_PAGE_VELOCITY
2912                                                        : MIN_TURN_PAGE_VELOCITY));
2913 
2914     auto firstIndex = firstItemInfo.first;
2915     auto baseIndex = -firstItemInfo.second.startPos < swiperWidthHalf ? firstIndex : firstIndex + 1;
2916     if (overTurnPageVelocity) {
2917         return direction ? baseIndex - 1 : baseIndex + 1;
2918     }
2919     return baseIndex;
2920 }
2921 
ComputeNextIndexByVelocity(float velocity,bool onlyDistance) const2922 int32_t SwiperPattern::ComputeNextIndexByVelocity(float velocity, bool onlyDistance) const
2923 {
2924     velocity = IsHorizontalAndRightToLeft() ? -velocity : velocity;
2925     if (IsSwipeByGroup()) {
2926         return ComputeSwipePageNextIndex(velocity, onlyDistance);
2927     }
2928 
2929     auto nextIndex = currentIndex_;
2930     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
2931     auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
2932     if (LessOrEqual(firstItemLength, 0)) {
2933         return nextIndex;
2934     }
2935 
2936     auto firstIndex = firstItemInfoInVisibleArea.first;
2937     auto dragDistance = firstItemInfoInVisibleArea.second.endPos;
2938     if (firstIndex == currentIndex_ && firstItemInfoInVisibleArea.second.startPos > 0) {
2939         firstIndex--;
2940         dragDistance = firstItemInfoInVisibleArea.second.startPos;
2941     }
2942     auto direction = GreatNotEqual(velocity, 0.0);
2943     auto dragThresholdFlag =
2944         direction ? dragDistance > firstItemLength / 2 : firstItemInfoInVisibleArea.second.endPos < firstItemLength / 2;
2945     auto turnVelocity = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_MIN_TURN_PAGE_VELOCITY
2946                                                                                            : MIN_TURN_PAGE_VELOCITY;
2947     if ((!onlyDistance && std::abs(velocity) > turnVelocity) || dragThresholdFlag) {
2948         nextIndex = direction ? firstIndex : firstItemInfoInVisibleArea.first + 1;
2949     } else {
2950         nextIndex = direction ? firstIndex + 1 : firstItemInfoInVisibleArea.first;
2951     }
2952 
2953     auto props = GetLayoutProperty<SwiperLayoutProperty>();
2954     // don't run this in nested scroll. Parallel nested scroll can deviate > 1 page from currentIndex_
2955     if (!childScrolling_ && SwiperUtils::IsStretch(props) && GetDisplayCount() == 1) {
2956         nextIndex =
2957             std::clamp(ComputeNextIndexInSinglePage(velocity, onlyDistance), currentIndex_ - 1, currentIndex_ + 1);
2958     }
2959 
2960     if (!IsAutoLinear() && nextIndex > currentIndex_ + GetDisplayCount()) {
2961         nextIndex = currentIndex_ + GetDisplayCount();
2962     }
2963 
2964     if (!IsLoop()) {
2965         nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - GetDisplayCount()));
2966     }
2967     return nextIndex;
2968 }
2969 
NeedStartNewAnimation(const OffsetF & offset) const2970 bool SwiperPattern::NeedStartNewAnimation(const OffsetF& offset) const
2971 {
2972     if (itemPositionInAnimation_.empty()) {
2973         return true;
2974     }
2975 
2976     for (const auto& animationItem : itemPositionInAnimation_) {
2977         auto iter = itemPosition_.find(animationItem.first);
2978         if (iter == itemPosition_.end()) {
2979             return true;
2980         }
2981         if ((animationItem.second.node && animationItem.second.finalOffset != offset) ||
2982             !NearEqual(animationItem.second.startPos, iter->second.startPos) ||
2983             !NearEqual(animationItem.second.endPos, iter->second.endPos)) {
2984             return true;
2985         }
2986     }
2987 
2988     return false;
2989 }
2990 
UpdateCurrentFocus()2991 void SwiperPattern::UpdateCurrentFocus()
2992 {
2993     do {
2994         auto curChildFrame = GetCurrentFrameNode(currentIndex_);
2995         if (!curChildFrame) {
2996             break;
2997         }
2998         FlushFocus(curChildFrame);
2999         currentFocusIndex_ = currentIndex_;
3000     } while (0);
3001 }
3002 
CheckDragOutOfBoundary(double dragVelocity)3003 bool SwiperPattern::CheckDragOutOfBoundary(double dragVelocity)
3004 {
3005     if (IsLoop()) {
3006         return false;
3007     }
3008 
3009     auto edgeEffect = GetEdgeEffect();
3010     // edge effect is NONE and reached boundary
3011     const bool noneOutOfBoundary =
3012         (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) &&
3013         NearZero(GetDistanceToEdge()) && edgeEffect == EdgeEffect::NONE;
3014     if (IsOutOfBoundary() || !NearZero(fadeOffset_) || noneOutOfBoundary) {
3015         isDragging_ = false;
3016 
3017         if (edgeEffect == EdgeEffect::SPRING) {
3018             PlaySpringAnimation(dragVelocity);
3019             return true;
3020         }
3021 
3022         if (edgeEffect == EdgeEffect::FADE) {
3023             PlayFadeAnimation();
3024             return true;
3025         }
3026 
3027         auto nextIndex = ComputeNextIndexByVelocity(static_cast<float>(dragVelocity), true);
3028         if (currentIndex_ != nextIndex) {
3029             FireWillShowEvent(nextIndex_);
3030             FireWillHideEvent(currentIndex_);
3031 
3032             UpdateCurrentIndex(nextIndex);
3033             UpdateCurrentFocus();
3034             OnIndexChange();
3035             oldIndex_ = currentIndex_;
3036         }
3037 
3038         if (edgeEffect == EdgeEffect::NONE) {
3039             auto parent = GetNestedScrollParent();
3040             const bool isForward = NonPositive(dragVelocity);
3041             if (parent && GetNestedScroll().NeedParent(isForward)) {
3042                 parent->HandleScrollVelocity(dragVelocity);
3043             }
3044             StartAutoPlay();
3045             UpdateItemRenderGroup(false);
3046             return true;
3047         }
3048     }
3049 
3050     return false;
3051 }
3052 
PlayPropertyTranslateAnimation(float translate,int32_t nextIndex,float velocity,bool stopAutoPlay)3053 void SwiperPattern::PlayPropertyTranslateAnimation(
3054     float translate, int32_t nextIndex, float velocity, bool stopAutoPlay)
3055 {
3056     if (IsHorizontalAndRightToLeft()) {
3057         translate = -translate;
3058     }
3059     if (NearZero(translate)) {
3060         SetIndicatorChangeIndexStatus(false, GetLoopIndex(currentIndex_));
3061         OnAnimationTranslateZero(nextIndex, stopAutoPlay);
3062         return;
3063     }
3064 
3065     AnimationOption option;
3066     option.SetDuration(GetDuration());
3067     auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
3068     if (iter != frameRateRange_.end()) {
3069         TAG_LOGI(AceLogTag::ACE_SWIPER,
3070             "Property translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}",
3071             iter->second->min_, iter->second->max_, iter->second->preferred_);
3072         iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
3073         option.SetFrameRateRange(iter->second);
3074     } else {
3075         option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
3076     }
3077     motionVelocity_ = velocity / translate;
3078     auto curve = GetCurveIncludeMotion();
3079     auto minimumAmplitudeRatio = DEFAULT_MINIMUM_AMPLITUDE_PX / translate;
3080     if (InstanceOf<InterpolatingSpring>(curve) &&
3081         LessNotEqualCustomPrecision(
3082             minimumAmplitudeRatio, InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO)) {
3083         auto interpolatingSpring = AceType::DynamicCast<InterpolatingSpring>(curve);
3084         interpolatingSpring->UpdateMinimumAmplitudeRatio(minimumAmplitudeRatio);
3085     }
3086     option.SetCurve(curve);
3087     option.SetFinishCallbackType(GetFinishCallbackType());
3088     OffsetF offset;
3089     if (GetDirection() == Axis::HORIZONTAL) {
3090         offset.AddX(translate);
3091     } else {
3092         offset.AddY(translate);
3093     }
3094     if (usePropertyAnimation_) {
3095         if (!NeedStartNewAnimation(offset)) {
3096             stopIndicatorAnimation_ = false;
3097             return;
3098         }
3099         std::optional<int32_t> targetIndex;
3100         if (targetIndex_) {
3101             targetIndex = targetIndex_;
3102         }
3103         StopPropertyTranslateAnimation(isFinishAnimation_);
3104         StopIndicatorAnimation();
3105 
3106         if (targetIndex) {
3107             targetIndex_ = targetIndex;
3108             MarkDirtyNodeSelf();
3109             return;
3110         }
3111     }
3112     auto finishCallback = [weak = WeakClaim(this), offset]() {
3113         auto swiper = weak.Upgrade();
3114         CHECK_NULL_VOID(swiper);
3115 #ifdef OHOS_PLATFORM
3116         if (swiper->isInAutoPlay_) {
3117             ResSchedReport::GetInstance().ResSchedDataReport("auto_play_off");
3118         }
3119 #endif
3120         if (!swiper->hasTabsAncestor_) {
3121             PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_FLING, true);
3122         } else {
3123             AceAsyncTraceEndCommercial(0, APP_TABS_FLING);
3124         }
3125         OffsetF finalOffset =
3126             swiper->itemPosition_.empty() ? OffsetF()
3127             : swiper->itemPosition_.begin()->second.node
3128                 ? swiper->itemPosition_.begin()->second.node->GetRenderContext()->GetTranslateXYProperty()
3129                 : OffsetF();
3130         TAG_LOGI(AceLogTag::ACE_SWIPER,
3131             "Swiper finish property animation with offsetX: %{public}f, offsetY: %{public}f isVerifiedSuc %{public}d",
3132             finalOffset.GetX(), finalOffset.GetY(), !swiper->IsItemOverlay());
3133         ACE_SCOPED_TRACE_COMMERCIAL("%s finish property animation, X: %f, Y: %f isVerifiedSuc %d",
3134             swiper->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, finalOffset.GetX(), finalOffset.GetY(),
3135             !swiper->IsItemOverlay());
3136         swiper->OnPropertyTranslateAnimationFinish(offset);
3137     };
3138     // initial translate info.
3139     for (auto& item : itemPosition_) {
3140         auto frameNode = item.second.node;
3141         if (frameNode) {
3142             frameNode->GetRenderContext()->UpdateTranslateInXY(item.second.finalOffset);
3143         }
3144     }
3145     if (IsCaptureNodeValid()) {
3146         GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(captureFinalOffset_);
3147         GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(captureFinalOffset_);
3148     }
3149     // property callback will call immediately.
3150     auto propertyUpdateCallback = [swiper = WeakClaim(this), offset]() {
3151         auto swiperPattern = swiper.Upgrade();
3152         CHECK_NULL_VOID(swiperPattern);
3153 #ifdef OHOS_PLATFORM
3154         if (swiperPattern->isInAutoPlay_) {
3155             ResSchedReport::GetInstance().ResSchedDataReport("auto_play_on");
3156         }
3157 #endif
3158         if (!swiperPattern->hasTabsAncestor_) {
3159             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_FLING, PerfActionType::LAST_UP, "");
3160         } else {
3161             AceAsyncTraceBeginCommercial(0, APP_TABS_FLING);
3162         }
3163         TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper start property animation with offsetX: %{public}f, offsetY: %{public}f",
3164             offset.GetX(), offset.GetY());
3165         ACE_SCOPED_TRACE_COMMERCIAL("%s start property animation, X: %f, Y: %f",
3166             swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, offset.GetX(), offset.GetY());
3167         for (auto& item : swiperPattern->itemPosition_) {
3168             auto frameNode = item.second.node;
3169             if (frameNode) {
3170                 frameNode->GetRenderContext()->UpdateTranslateInXY(offset);
3171                 item.second.finalOffset = offset;
3172             }
3173         }
3174         swiperPattern->itemPositionInAnimation_ = swiperPattern->itemPosition_;
3175         if (swiperPattern->IsCaptureNodeValid()) {
3176             swiperPattern->GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(offset);
3177             swiperPattern->GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(offset);
3178             swiperPattern->captureFinalOffset_ = offset;
3179         }
3180     };
3181     usePropertyAnimation_ = true;
3182     propertyAnimationIndex_ = nextIndex;
3183     ElementRegister::GetInstance()->ReSyncGeometryTransition(GetHost(), option);
3184     AnimationUtils::Animate(option, propertyUpdateCallback, finishCallback);
3185     AnimationCallbackInfo info;
3186     info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3187     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3188     info.targetOffset = GetCustomPropertyTargetOffset() - Dimension(translate, DimensionUnit::PX).ConvertToVp();
3189     if (IsHorizontalAndRightToLeft()) {
3190         info.currentOffset =
3191             GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3192     }
3193 
3194     auto pipeline = PipelineContext::GetCurrentContext();
3195     CHECK_NULL_VOID(pipeline);
3196     if (GetDuration() == 0) {
3197         // if the duration is 0, the animation will be end immediately, so the start event should be triggered
3198         // after Layout Task to ensure the timing of events.
3199         pipeline->AddAfterLayoutTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3200             auto swiper = weak.Upgrade();
3201             CHECK_NULL_VOID(swiper);
3202             swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
3203             swiper->FireAndCleanScrollingListener();
3204         });
3205     } else {
3206         pipeline->AddAfterRenderTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3207             auto swiper = weak.Upgrade();
3208             CHECK_NULL_VOID(swiper);
3209             swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
3210             swiper->FireAndCleanScrollingListener();
3211         });
3212     }
3213 
3214     // enable lazy load feature.
3215     SetLazyLoadFeature(true);
3216     UpdateItemRenderGroup(true);
3217 }
3218 
UpdateOffsetAfterPropertyAnimation(float offset)3219 void SwiperPattern::UpdateOffsetAfterPropertyAnimation(float offset)
3220 {
3221     UpdateCurrentOffset(offset);
3222     auto host = GetHost();
3223     CHECK_NULL_VOID(host);
3224     host->SetLayoutDirtyMarked(true);
3225     auto context = host->GetContext();
3226     if (context) {
3227         context->FlushUITaskWithSingleDirtyNode(host);
3228     }
3229 }
3230 
OnPropertyTranslateAnimationFinish(const OffsetF & offset)3231 void SwiperPattern::OnPropertyTranslateAnimationFinish(const OffsetF& offset)
3232 {
3233     if (!usePropertyAnimation_) {
3234         // force stop.
3235         return;
3236     }
3237 
3238     usePropertyAnimation_ = false;
3239     targetIndex_.reset();
3240     // reset translate.
3241     for (auto& item : itemPositionInAnimation_) {
3242         auto frameNode = item.second.node;
3243         if (frameNode) {
3244             frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3245         }
3246         item.second.finalOffset = OffsetF();
3247     }
3248     itemPositionInAnimation_.clear();
3249     if (IsCaptureNodeValid()) {
3250         GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3251         GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3252         captureFinalOffset_ = OffsetF();
3253     }
3254     // update postion info.
3255     UpdateOffsetAfterPropertyAnimation(offset.GetMainOffset(GetDirection()));
3256     OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
3257 }
3258 
StopPropertyTranslateAnimation(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper,bool isInterrupt)3259 void SwiperPattern::StopPropertyTranslateAnimation(
3260     bool isFinishAnimation, bool isBeforeCreateLayoutWrapper, bool isInterrupt)
3261 {
3262     if (!usePropertyAnimation_) {
3263         return;
3264     }
3265     usePropertyAnimation_ = false;
3266     ACE_SCOPED_TRACE("Swiper stop property animation");
3267     // Stop CurrentAnimationProperty.
3268     AnimationOption option;
3269     option.SetDuration(0);
3270     option.SetCurve(Curves::LINEAR);
3271     auto propertyUpdateCallback = [weak = WeakClaim(this)]() {
3272         auto swiper = weak.Upgrade();
3273         CHECK_NULL_VOID(swiper);
3274         for (auto& item : swiper->itemPositionInAnimation_) {
3275             auto frameNode = item.second.node;
3276             if (!frameNode) {
3277                 continue;
3278             }
3279             frameNode->GetRenderContext()->CancelTranslateXYAnimation();
3280         }
3281         if (swiper->IsCaptureNodeValid()) {
3282             swiper->GetLeftCaptureNode()->GetRenderContext()->CancelTranslateXYAnimation();
3283             swiper->GetRightCaptureNode()->GetRenderContext()->CancelTranslateXYAnimation();
3284         }
3285     };
3286     AnimationUtils::Animate(option, propertyUpdateCallback);
3287     targetIndex_.reset();
3288     OffsetF currentOffset;
3289     for (auto& item : itemPositionInAnimation_) {
3290         auto frameNode = item.second.node;
3291         if (!frameNode) {
3292             continue;
3293         }
3294         currentOffset = frameNode->GetRenderContext()->GetTranslateXYProperty();
3295         frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3296         item.second.finalOffset = OffsetF();
3297     }
3298     itemPositionInAnimation_.clear();
3299     if (IsCaptureNodeValid()) {
3300         GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3301         GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3302         captureFinalOffset_ = OffsetF();
3303     }
3304     if (!isBeforeCreateLayoutWrapper) {
3305         UpdateOffsetAfterPropertyAnimation(currentOffset.GetMainOffset(GetDirection()));
3306     }
3307     OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation, true, isInterrupt);
3308 }
3309 
GetCurveIncludeMotion()3310 RefPtr<Curve> SwiperPattern::GetCurveIncludeMotion()
3311 {
3312     auto curve = GetCurve();
3313     auto container = Container::Current();
3314     bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
3315     if (isLauncherFeature) {
3316         finishCallbackType_ = FinishCallbackType::LOGICALLY;
3317     }
3318 
3319     if (curve) {
3320         if (InstanceOf<SpringCurve>(curve)) {
3321             auto springCurve = DynamicCast<SpringCurve>(curve);
3322             // check velocity to judge if this current velocity.
3323             if (springCurve->GetCurrentVelocity() < 0) {
3324                 return AceType::MakeRefPtr<SpringCurve>(
3325                     motionVelocity_, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
3326             }
3327         }
3328         if (InstanceOf<InterpolatingSpring>(curve)) {
3329             auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
3330             // check velocity to judge if this current velocity.
3331             if (interpolatingSpring->GetVelocity() < 0) {
3332                 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, interpolatingSpring->GetMass(),
3333                     interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
3334             }
3335         }
3336         return curve;
3337     }
3338     // use spring motion feature.
3339     // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
3340     return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, 1, 328, 34);
3341 }
3342 
PlayIndicatorTranslateAnimation(float translate,std::optional<int32_t> nextIndex)3343 void SwiperPattern::PlayIndicatorTranslateAnimation(float translate, std::optional<int32_t> nextIndex)
3344 {
3345     if (!stopIndicatorAnimation_) {
3346         stopIndicatorAnimation_ = true;
3347         return;
3348     }
3349     const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
3350     if (!indicatorId_.has_value() && !turnPageRateCallback) {
3351         return;
3352     }
3353     CheckMarkDirtyNodeForRenderIndicator(translate, nextIndex);
3354     AnimationUtils::StopAnimation(indicatorAnimation_);
3355     indicatorAnimationIsRunning_ = false;
3356     if (itemPosition_.empty()) {
3357         return;
3358     }
3359 
3360     auto host = GetHost();
3361     CHECK_NULL_VOID(host);
3362     auto weak = AceType::WeakClaim(this);
3363     host->CreateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0, [weak](float value) {
3364         auto swiper = weak.Upgrade();
3365         CHECK_NULL_VOID(swiper);
3366         const auto& turnPageRateCallback = swiper->swiperController_->GetTurnPageRateCallback();
3367         auto firstItem = swiper->GetFirstItemInfoInVisibleArea();
3368         auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
3369         if (turnPageRateCallback && !NearZero(translateLength)) {
3370             turnPageRateCallback(firstItem.first, (-firstItem.second.startPos - value) / translateLength);
3371         }
3372     });
3373 
3374     AnimationOption option;
3375     option.SetDuration(GetDuration());
3376     option.SetCurve(Curves::LINEAR);
3377 
3378     host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0);
3379     indicatorAnimationIsRunning_ = true;
3380     indicatorAnimation_ = AnimationUtils::StartAnimation(
3381         option, [host, translate]() { host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, translate); },
3382         [weak]() {
3383             auto swiperPattern = weak.Upgrade();
3384             CHECK_NULL_VOID(swiperPattern);
3385             swiperPattern->indicatorAnimationIsRunning_ = false;
3386         });
3387 }
3388 
PlayTranslateAnimation(float startPos,float endPos,int32_t nextIndex,bool restartAutoPlay,float velocity)3389 void SwiperPattern::PlayTranslateAnimation(
3390     float startPos, float endPos, int32_t nextIndex, bool restartAutoPlay, float velocity)
3391 {
3392     if (translateAnimationIsRunning_) {
3393         return;
3394     }
3395     if (NearZero(endPos - startPos)) {
3396         OnAnimationTranslateZero(nextIndex, restartAutoPlay);
3397         return;
3398     }
3399 
3400     if (indicatorId_.has_value()) {
3401         CheckMarkDirtyNodeForRenderIndicator(endPos - startPos, nextIndex);
3402     }
3403 
3404     auto host = GetHost();
3405     CHECK_NULL_VOID(host);
3406     auto weak = AceType::WeakClaim(this);
3407     host->CreateAnimatablePropertyFloat(
3408         TRANSLATE_PROPERTY_NAME, 0,
3409         [weak](float value) {
3410             auto swiper = weak.Upgrade();
3411             CHECK_NULL_VOID(swiper);
3412             if (swiper->IsHorizontalAndRightToLeft()) {
3413                 swiper->UpdateCurrentOffset(-static_cast<float>(value - swiper->currentOffset_));
3414             } else {
3415                 swiper->UpdateCurrentOffset(static_cast<float>(value - swiper->currentOffset_));
3416             }
3417         },
3418         PropertyUnit::PIXEL_POSITION);
3419 
3420     AnimationOption option;
3421     auto duration = GetDuration();
3422     bool finishAnimation = (duration == 0);
3423     motionVelocity_ = velocity / (endPos - startPos);
3424     option.SetCurve(GetCurveIncludeMotion());
3425     option.SetDuration(duration);
3426     auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
3427     if (iter != frameRateRange_.end()) {
3428         TAG_LOGI(AceLogTag::ACE_SWIPER,
3429             "Translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}",
3430             iter->second->min_, iter->second->max_, iter->second->preferred_);
3431         iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
3432         option.SetFrameRateRange(iter->second);
3433     } else {
3434         option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
3435     }
3436     host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, startPos);
3437     translateAnimationIsRunning_ = true;
3438     propertyAnimationIndex_ = nextIndex;
3439     translateAnimationEndPos_ = endPos;
3440     translateAnimation_ = AnimationUtils::StartAnimation(
3441         option,
3442         [host, weak, startPos, endPos, nextIndex, velocity]() {
3443             host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, endPos);
3444             auto swiper = weak.Upgrade();
3445             CHECK_NULL_VOID(swiper);
3446             AceAsyncTraceBeginCommercial(
3447                 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
3448             AnimationCallbackInfo info;
3449             info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3450             info.currentOffset = swiper->GetCustomPropertyOffset() +
3451                                  Dimension(swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3452             info.targetOffset =
3453                 swiper->GetCustomPropertyTargetOffset() + Dimension(startPos - endPos, DimensionUnit::PX).ConvertToVp();
3454             if (swiper->IsHorizontalAndRightToLeft()) {
3455                 info.currentOffset = swiper->GetCustomPropertyOffset() +
3456                                      Dimension(-swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3457             }
3458             swiper->FireAnimationStartEvent(
3459                 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex), info);
3460             swiper->FireAndCleanScrollingListener();
3461         },
3462         [weak, nextIndex, restartAutoPlay, finishAnimation]() {
3463             auto swiper = weak.Upgrade();
3464             CHECK_NULL_VOID(swiper);
3465             AceAsyncTraceEndCommercial(
3466                 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
3467             if (finishAnimation && swiper->translateAnimationIsRunning_) {
3468                 swiper->isFinishAnimation_ = true;
3469             }
3470             swiper->targetIndex_.reset();
3471             swiper->OnTranslateAnimationFinish();
3472         });
3473 
3474     SetLazyLoadFeature(true);
3475     UpdateItemRenderGroup(true);
3476 }
3477 
OnSpringAnimationStart(float velocity)3478 void SwiperPattern::OnSpringAnimationStart(float velocity)
3479 {
3480     AnimationCallbackInfo info;
3481     info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3482     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3483     if (IsHorizontalAndRightToLeft()) {
3484         info.currentOffset =
3485             GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3486     }
3487 
3488     nextIndex_ = ComputeNextIndexByVelocity(velocity, true);
3489     if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
3490         info.targetOffset = info.currentOffset;
3491     } else {
3492         FireWillShowEvent(nextIndex_);
3493         FireWillHideEvent(currentIndex_);
3494         auto iter = itemPosition_.find(nextIndex_);
3495         auto nextOffset = iter != itemPosition_.end() ? iter->second.startPos : 0.0f;
3496         info.targetOffset = GetCustomPropertyTargetOffset() + Dimension(nextOffset, DimensionUnit::PX).ConvertToVp();
3497     }
3498 
3499     FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
3500 }
3501 
OnSpringAnimationFinish()3502 void SwiperPattern::OnSpringAnimationFinish()
3503 {
3504     if (!springAnimationIsRunning_) {
3505         return;
3506     }
3507     PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_LIST_FLING, false);
3508     AceAsyncTraceEndCommercial(0, TRAILING_ANIMATION);
3509     TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper finish spring animation offset %{public}f",
3510         currentIndexOffset_);
3511     ACE_SCOPED_TRACE_COMMERCIAL("%s finish spring animation, offset: %f",
3512         hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, currentIndexOffset_);
3513     springAnimationIsRunning_ = false;
3514     isTouchDownSpringAnimation_ = false;
3515     OnSpringAndFadeAnimationFinish();
3516 }
3517 
OnSpringAndFadeAnimationFinish()3518 void SwiperPattern::OnSpringAndFadeAnimationFinish()
3519 {
3520     auto itemInfoInVisibleArea = std::make_pair(0, SwiperItemInfo {});
3521     if (!itemPosition_.empty()) {
3522         auto item = itemPosition_.find(nextIndex_);
3523         itemInfoInVisibleArea =
3524             std::make_pair(item->first, SwiperItemInfo { item->second.startPos, item->second.endPos });
3525     }
3526     if (GetLoopIndex(currentIndex_) != GetLoopIndex(nextIndex_)) {
3527         UpdateCurrentIndex(nextIndex_);
3528         UpdateCurrentFocus();
3529         OnIndexChange();
3530         oldIndex_ = currentIndex_;
3531     }
3532     AnimationCallbackInfo info;
3533     auto indexStartPos = itemInfoInVisibleArea.second.startPos;
3534     info.currentOffset = GetCustomPropertyOffset() + Dimension(indexStartPos, DimensionUnit::PX).ConvertToVp();
3535     if (IsHorizontalAndRightToLeft()) {
3536         info.currentOffset = GetCustomPropertyOffset() + Dimension(-indexStartPos, DimensionUnit::PX).ConvertToVp();
3537     }
3538     FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
3539     currentIndexOffset_ = indexStartPos;
3540     UpdateItemRenderGroup(false);
3541     NotifyParentScrollEnd();
3542 
3543     if (!isTouchDown_) {
3544         StartAutoPlay();
3545     }
3546 
3547     fadeAnimationIsRunning_ = false;
3548     isTouchDownFadeAnimation_ = false;
3549 }
3550 
OnFadeAnimationStart()3551 void SwiperPattern::OnFadeAnimationStart()
3552 {
3553     AnimationCallbackInfo info;
3554     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3555     if (IsHorizontalAndRightToLeft()) {
3556         info.currentOffset =
3557             GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3558     }
3559     nextIndex_ = ComputeNextIndexByVelocity(0.0);
3560     if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
3561         info.targetOffset = info.currentOffset;
3562     } else {
3563         FireWillShowEvent(nextIndex_);
3564         FireWillHideEvent(currentIndex_);
3565         info.targetOffset = GetCustomPropertyTargetOffset();
3566     }
3567 
3568     FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
3569     fadeAnimationIsRunning_ = true;
3570 }
3571 
PlayFadeAnimation()3572 void SwiperPattern::PlayFadeAnimation()
3573 {
3574     if (NearZero(fadeOffset_)) {
3575         fadeAnimationIsRunning_ = false;
3576         return;
3577     }
3578 
3579     auto host = GetHost();
3580     CHECK_NULL_VOID(host);
3581     auto weak = AceType::WeakClaim(this);
3582     host->CreateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0, Animation<double>::ValueCallback([weak](float value) {
3583         auto swiper = weak.Upgrade();
3584         if (swiper && swiper->GetHost() && !swiper->isTouchDown_) {
3585             swiper->fadeOffset_ = value;
3586             swiper->GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3587         }
3588     }));
3589 
3590     AnimationOption option;
3591     option.SetDuration(FADE_DURATION);
3592     option.SetCurve(Curves::LINEAR);
3593 
3594     host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, fadeOffset_);
3595     constexpr float end = 0.0f;
3596     nextIndex_ = currentIndex_;
3597     fadeAnimation_ = AnimationUtils::StartAnimation(
3598         option,
3599         [weak, host, end]() {
3600             auto swiperPattern = weak.Upgrade();
3601             CHECK_NULL_VOID(swiperPattern);
3602             swiperPattern->OnFadeAnimationStart();
3603             host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, end);
3604         },
3605         [weak]() {
3606             auto swiperPattern = weak.Upgrade();
3607             CHECK_NULL_VOID(swiperPattern);
3608             swiperPattern->OnSpringAndFadeAnimationFinish();
3609         });
3610 }
3611 
CreateSpringProperty()3612 void SwiperPattern::CreateSpringProperty()
3613 {
3614     auto host = GetHost();
3615     CHECK_NULL_VOID(host);
3616     host->CreateAnimatablePropertyFloat(
3617         SPRING_PROPERTY_NAME, 0,
3618         [weak = AceType::WeakClaim(this)](float position) {
3619             auto swiper = weak.Upgrade();
3620             CHECK_NULL_VOID(swiper);
3621             auto positionDelta = static_cast<float>(position) - swiper->currentIndexOffset_;
3622             if (swiper->IsHorizontalAndRightToLeft()) {
3623                 positionDelta = -positionDelta;
3624             }
3625             swiper->UpdateCurrentOffset(positionDelta);
3626             if (LessNotEqual(std::abs(positionDelta), 1) && !NearZero(positionDelta)) {
3627                 AceAsyncTraceBeginCommercial(0, TRAILING_ANIMATION);
3628             }
3629         },
3630         PropertyUnit::PIXEL_POSITION);
3631 }
3632 
PlaySpringAnimation(double dragVelocity)3633 void SwiperPattern::PlaySpringAnimation(double dragVelocity)
3634 {
3635     UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart());
3636     if (springAnimationIsRunning_) {
3637         return;
3638     }
3639     auto host = GetHost();
3640     CHECK_NULL_VOID(host);
3641     auto mainSize = CalculateVisibleSize();
3642     if (LessOrEqual(mainSize, 0) || itemPosition_.empty()) {
3643         return;
3644     }
3645     childScrolling_ = false;
3646     auto leading = currentIndexOffset_ + mainSize - itemPosition_.rbegin()->second.endPos;
3647     auto trailing = currentIndexOffset_ - itemPosition_.begin()->second.startPos;
3648     ExtentPair extentPair = ExtentPair(leading, trailing);
3649     CreateSpringProperty();
3650     host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, currentIndexOffset_);
3651     auto delta = currentIndexOffset_ < 0.0f ? extentPair.Leading() : extentPair.Trailing();
3652     if (IsVisibleChildrenSizeLessThanSwiper()) {
3653         delta = extentPair.Trailing();
3654     }
3655     // spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
3656     auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
3657     AnimationOption option;
3658     option.SetCurve(springCurve);
3659     option.SetDuration(SPRING_DURATION);
3660     nextIndex_ = currentIndex_;
3661     springAnimation_ = AnimationUtils::StartAnimation(
3662         option,
3663         [weak = AceType::WeakClaim(this), dragVelocity, host, delta]() {
3664             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_LIST_FLING, PerfActionType::FIRST_MOVE, "");
3665             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper start spring animation with offset:%{public}f", delta);
3666             auto swiperPattern = weak.Upgrade();
3667             CHECK_NULL_VOID(swiperPattern);
3668             ACE_SCOPED_TRACE_COMMERCIAL(
3669                 "%s start spring animation", swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG);
3670             host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, delta);
3671         },
3672         [weak = AceType::WeakClaim(this)]() {
3673             auto swiperPattern = weak.Upgrade();
3674             CHECK_NULL_VOID(swiperPattern);
3675             swiperPattern->OnSpringAnimationFinish();
3676         });
3677     OnSpringAnimationStart(static_cast<float>(dragVelocity));
3678     springAnimationIsRunning_ = true;
3679 }
3680 
IsOutOfBoundary(float mainOffset) const3681 bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
3682 {
3683     if (IsLoop() || itemPosition_.empty()) {
3684         return false;
3685     }
3686     if (IsHorizontalAndRightToLeft()) {
3687         mainOffset = -mainOffset;
3688     }
3689 
3690     auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
3691     startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
3692     auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
3693     auto visibleWindowSize = CalculateVisibleSize();
3694     auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
3695     endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
3696     auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
3697     return isOutOfStart || isOutOfEnd;
3698 }
3699 
IsOutOfStart(float mainOffset) const3700 bool SwiperPattern::IsOutOfStart(float mainOffset) const
3701 {
3702     if (IsLoop() || itemPosition_.empty()) {
3703         return false;
3704     }
3705     if (IsHorizontalAndRightToLeft()) {
3706         mainOffset = -mainOffset;
3707     }
3708 
3709     auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
3710     startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
3711     return itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.f);
3712 }
3713 
IsOutOfEnd(float mainOffset) const3714 bool SwiperPattern::IsOutOfEnd(float mainOffset) const
3715 {
3716     if (IsLoop() || itemPosition_.empty()) {
3717         return false;
3718     }
3719     if (IsHorizontalAndRightToLeft()) {
3720         mainOffset = -mainOffset;
3721     }
3722 
3723     auto visibleWindowSize = CalculateVisibleSize();
3724     auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
3725     endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
3726     return itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
3727 }
3728 
IsAtStart() const3729 bool SwiperPattern::IsAtStart() const
3730 {
3731     if (IsLoop() || itemPosition_.empty()) {
3732         return false;
3733     }
3734 
3735     auto startPos = itemPosition_.begin()->second.startPos;
3736     startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
3737     return itemPosition_.begin()->first == 0 && GreatOrEqual(startPos, 0.f);
3738 }
3739 
IsAtEnd() const3740 bool SwiperPattern::IsAtEnd() const
3741 {
3742     if (IsLoop() || itemPosition_.empty()) {
3743         return false;
3744     }
3745 
3746     auto visibleWindowSize = CalculateVisibleSize();
3747     auto endPos = itemPosition_.rbegin()->second.endPos;
3748     endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
3749     return itemPosition_.rbegin()->first == TotalCount() - 1 && LessOrEqual(endPos, visibleWindowSize);
3750 }
3751 
AutoLinearIsOutOfBoundary(float mainOffset) const3752 bool SwiperPattern::AutoLinearIsOutOfBoundary(float mainOffset) const
3753 {
3754     if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
3755         return false;
3756     }
3757 
3758     auto startPos = itemPosition_.begin()->second.startPos;
3759     auto isOutOfStart = GreatNotEqual(startPos + mainOffset, 0.0);
3760 
3761     auto visibleWindowSize = CalculateVisibleSize();
3762     auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
3763     auto isOutOfEnd = LessNotEqual(endPos, visibleWindowSize);
3764 
3765     return isOutOfStart || isOutOfEnd;
3766 }
3767 
GetDistanceToEdge() const3768 float SwiperPattern::GetDistanceToEdge() const
3769 {
3770     if (IsLoop() || itemPosition_.empty()) {
3771         return 0.0f;
3772     }
3773     if (itemPosition_.begin()->first == 0) {
3774         return -itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
3775     }
3776     auto visibleWindowSize = CalculateVisibleSize();
3777     return itemPosition_.rbegin()->second.endPos - visibleWindowSize + AdjustIgnoreBlankOverScrollOffSet(false);
3778 }
3779 
MainSize() const3780 float SwiperPattern::MainSize() const
3781 {
3782     auto host = GetHost();
3783     CHECK_NULL_RETURN(host, 0.0);
3784     auto geometryNode = host->GetGeometryNode();
3785     CHECK_NULL_RETURN(geometryNode, 0.0);
3786     return geometryNode->GetFrameSize().MainSize(GetDirection());
3787 }
3788 
GetMainContentSize() const3789 float SwiperPattern::GetMainContentSize() const
3790 {
3791     auto host = GetHost();
3792     CHECK_NULL_RETURN(host, 0.0);
3793     auto geometryNode = host->GetGeometryNode();
3794     CHECK_NULL_RETURN(geometryNode, 0.0);
3795     return geometryNode->GetPaddingSize().Width();
3796 }
3797 
GetItemSpace() const3798 float SwiperPattern::GetItemSpace() const
3799 {
3800     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3801     CHECK_NULL_RETURN(props, 0.0f);
3802     if (props->IgnoreItemSpace()) {
3803         return 0.0f;
3804     }
3805     auto itemSpace =
3806         ConvertToPx(props->GetItemSpace().value_or(0.0_vp), props->GetLayoutConstraint()->scaleProperty, 0.0f)
3807             .value_or(0.0f);
3808     auto host = GetHost();
3809     CHECK_NULL_RETURN(host, 0.0f);
3810     auto geometryNode = host->GetGeometryNode();
3811     CHECK_NULL_RETURN(geometryNode, 0.0f);
3812     auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
3813     if (itemSpace > mainSize) {
3814         itemSpace = 0.0f;
3815     }
3816     return itemSpace;
3817 }
3818 
GetPrevMargin() const3819 float SwiperPattern::GetPrevMargin() const
3820 {
3821     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3822     CHECK_NULL_RETURN(props, 0.0f);
3823     return props->GetCalculatedPrevMargin();
3824 }
3825 
GetNextMargin() const3826 float SwiperPattern::GetNextMargin() const
3827 {
3828     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3829     CHECK_NULL_RETURN(props, 0.0f);
3830     return props->GetCalculatedNextMargin();
3831 }
3832 
GetDirection() const3833 Axis SwiperPattern::GetDirection() const
3834 {
3835     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3836     CHECK_NULL_RETURN(props, Axis::HORIZONTAL);
3837     return props->GetDirection().value_or(Axis::HORIZONTAL);
3838 }
3839 
CurrentIndex() const3840 int32_t SwiperPattern::CurrentIndex() const
3841 {
3842     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3843     CHECK_NULL_RETURN(props, 0);
3844     return props->GetIndex().value_or(0);
3845 }
3846 
GetDisplayCount() const3847 int32_t SwiperPattern::GetDisplayCount() const
3848 {
3849     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3850     CHECK_NULL_RETURN(props, 1);
3851     auto displayCount = CalculateDisplayCount();
3852     return displayCount;
3853 }
3854 
CalculateDisplayCount() const3855 int32_t SwiperPattern::CalculateDisplayCount() const
3856 {
3857     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3858     CHECK_NULL_RETURN(props, 1);
3859     bool isAutoFill = IsAutoFill();
3860     if (isAutoFill) {
3861         auto minSize = props->GetMinSize()->ConvertToPx();
3862         float contentWidth = GetMainContentSize();
3863         auto displayCount =
3864             CalculateCount(contentWidth, minSize, SWIPER_MARGIN.ConvertToPx(), SWIPER_GUTTER.ConvertToPx());
3865         if (LessOrEqual(minSize, 0)) {
3866             displayCount = 1;
3867         }
3868 
3869         displayCount = displayCount > 0 ? displayCount : 1;
3870         auto totalCount = TotalCount();
3871         displayCount = displayCount > totalCount ? totalCount : displayCount;
3872         auto displayCountProperty = props->GetDisplayCount().value_or(1);
3873         if (displayCountProperty != displayCount) {
3874             props->UpdateDisplayCount(displayCount);
3875             auto host = GetHost();
3876             CHECK_NULL_RETURN(host, 1);
3877             host->MarkDirtyNode(
3878                 (crossMatchChild_ ? PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD : PROPERTY_UPDATE_MEASURE_SELF) |
3879                 PROPERTY_UPDATE_RENDER);
3880         }
3881         return displayCount;
3882     } else {
3883         return props->GetDisplayCount().value_or(1);
3884     }
3885 }
3886 
CalculateCount(float contentWidth,float minSize,float margin,float gutter,float swiperPadding) const3887 int32_t SwiperPattern::CalculateCount(
3888     float contentWidth, float minSize, float margin, float gutter, float swiperPadding) const
3889 {
3890     return static_cast<int32_t>(floor((contentWidth - 2 * margin + gutter - 2 * swiperPadding) / (minSize + gutter)));
3891 }
3892 
IsAutoFill() const3893 bool SwiperPattern::IsAutoFill() const
3894 {
3895     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3896     CHECK_NULL_RETURN(props, false);
3897     return props->GetMinSize().has_value();
3898 }
3899 
IsAutoPlay() const3900 bool SwiperPattern::IsAutoPlay() const
3901 {
3902     auto props = GetPaintProperty<SwiperPaintProperty>();
3903     CHECK_NULL_RETURN(props, false);
3904     return props->GetAutoPlay().value_or(false);
3905 }
3906 
GetDuration() const3907 int32_t SwiperPattern::GetDuration() const
3908 {
3909     const int32_t DEFAULT_DURATION = 400;
3910     auto props = GetPaintProperty<SwiperPaintProperty>();
3911     CHECK_NULL_RETURN(props, DEFAULT_DURATION);
3912     return props->GetDuration().value_or(DEFAULT_DURATION);
3913 }
3914 
GetInterval() const3915 int32_t SwiperPattern::GetInterval() const
3916 {
3917     const int32_t DEFAULT_INTERVAL = 3000;
3918     auto props = GetPaintProperty<SwiperPaintProperty>();
3919     CHECK_NULL_RETURN(props, DEFAULT_INTERVAL);
3920     return props->GetAutoPlayInterval().value_or(DEFAULT_INTERVAL);
3921 }
3922 
GetCurve() const3923 RefPtr<Curve> SwiperPattern::GetCurve() const
3924 {
3925     auto props = GetPaintProperty<SwiperPaintProperty>();
3926     CHECK_NULL_RETURN(props, nullptr);
3927     return props->GetCurve().value_or(nullptr);
3928 }
3929 
IsLoop() const3930 bool SwiperPattern::IsLoop() const
3931 {
3932     if (hasCachedCapture_) {
3933         return true;
3934     }
3935     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
3936     CHECK_NULL_RETURN(props, true);
3937     if (TotalDisPlayCount() > TotalCount() ||
3938         (TotalDisPlayCount() == TotalCount() && SwiperUtils::IsStretch(props) &&
3939             (NonPositive(props->GetCalculatedPrevMargin()) || NonPositive(props->GetCalculatedNextMargin())))) {
3940         return false;
3941     }
3942     return props->GetLoop().value_or(true);
3943 }
3944 
IsEnabled() const3945 bool SwiperPattern::IsEnabled() const
3946 {
3947     auto props = GetPaintProperty<SwiperPaintProperty>();
3948     CHECK_NULL_RETURN(props, true);
3949     return props->GetEnabled().value_or(true);
3950 }
3951 
GetEdgeEffect() const3952 EdgeEffect SwiperPattern::GetEdgeEffect() const
3953 {
3954     auto props = GetPaintProperty<SwiperPaintProperty>();
3955     CHECK_NULL_RETURN(props, EdgeEffect::SPRING);
3956     return props->GetEdgeEffect().value_or(EdgeEffect::SPRING);
3957 }
3958 
IsDisableSwipe() const3959 bool SwiperPattern::IsDisableSwipe() const
3960 {
3961     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3962     CHECK_NULL_RETURN(props, false);
3963     return props->GetDisableSwipe().value_or(false);
3964 }
3965 
IsShowIndicator() const3966 bool SwiperPattern::IsShowIndicator() const
3967 {
3968     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3969     CHECK_NULL_RETURN(props, true);
3970     return props->GetShowIndicatorValue(true);
3971 }
3972 
IsShowArrow() const3973 bool SwiperPattern::IsShowArrow() const
3974 {
3975     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3976     CHECK_NULL_RETURN(props, true);
3977     return props->GetDisplayArrowValue(false);
3978 }
3979 
GetIndicatorType() const3980 SwiperIndicatorType SwiperPattern::GetIndicatorType() const
3981 {
3982     auto props = GetLayoutProperty<SwiperLayoutProperty>();
3983     CHECK_NULL_RETURN(props, SwiperIndicatorType::DOT);
3984     return props->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
3985 }
3986 
GetSwiperParameters() const3987 std::shared_ptr<SwiperParameters> SwiperPattern::GetSwiperParameters() const
3988 {
3989     if (swiperParameters_ == nullptr) {
3990         swiperParameters_ = std::make_shared<SwiperParameters>();
3991         auto pipelineContext = PipelineBase::GetCurrentContext();
3992         CHECK_NULL_RETURN(pipelineContext, swiperParameters_);
3993         auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
3994         CHECK_NULL_RETURN(swiperIndicatorTheme, swiperParameters_);
3995         swiperParameters_->itemWidth = swiperIndicatorTheme->GetSize();
3996         swiperParameters_->itemHeight = swiperIndicatorTheme->GetSize();
3997         swiperParameters_->selectedItemWidth = swiperIndicatorTheme->GetSize();
3998         swiperParameters_->selectedItemHeight = swiperIndicatorTheme->GetSize();
3999         swiperParameters_->maskValue = false;
4000         swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
4001         swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
4002         swiperParameters_->maxDisplayCountVal = 0;
4003     }
4004     return swiperParameters_;
4005 }
4006 
GetSwiperDigitalParameters() const4007 std::shared_ptr<SwiperDigitalParameters> SwiperPattern::GetSwiperDigitalParameters() const
4008 {
4009     if (swiperDigitalParameters_ == nullptr) {
4010         swiperDigitalParameters_ = std::make_shared<SwiperDigitalParameters>();
4011         auto pipelineContext = PipelineBase::GetCurrentContext();
4012         CHECK_NULL_RETURN(pipelineContext, swiperDigitalParameters_);
4013         auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4014         swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
4015         swiperDigitalParameters_->selectedFontColor =
4016             swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
4017         swiperDigitalParameters_->fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
4018         swiperDigitalParameters_->selectedFontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
4019         swiperDigitalParameters_->fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
4020         swiperDigitalParameters_->selectedFontWeight =
4021             swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
4022     }
4023     return swiperDigitalParameters_;
4024 }
4025 
TotalCount() const4026 int32_t SwiperPattern::TotalCount() const
4027 {
4028     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4029     CHECK_NULL_RETURN(props, 1);
4030     auto displayCount = props->GetDisplayCount().value_or(1);
4031     auto totalCount = RealTotalCount();
4032     if (IsSwipeByGroup() && displayCount != 0) {
4033         totalCount =
4034             static_cast<int32_t>(std::ceil(static_cast<float>(totalCount) / static_cast<float>(displayCount))) *
4035             displayCount;
4036     }
4037 
4038     return totalCount;
4039 }
4040 
RealTotalCount() const4041 int32_t SwiperPattern::RealTotalCount() const
4042 {
4043     auto host = GetHost();
4044     CHECK_NULL_RETURN(host, 0);
4045     // last child is swiper indicator
4046     int num = 0;
4047     if (IsShowIndicator() && HasIndicatorNode()) {
4048         num += 1;
4049     }
4050     if (HasLeftButtonNode()) {
4051         num += 1;
4052     }
4053     if (HasRightButtonNode()) {
4054         num += 1;
4055     }
4056     if (hasCachedCapture_ && leftCaptureId_.has_value() && rightCaptureId_.has_value()) {
4057         num += CAPTURE_COUNT;
4058     }
4059     return host->TotalChildCount() - num;
4060 }
4061 
GetFirstItemInfoInVisibleArea() const4062 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetFirstItemInfoInVisibleArea() const
4063 {
4064     if (itemPosition_.empty()) {
4065         return std::make_pair(0, SwiperItemInfo {});
4066     }
4067     for (const auto& item : itemPosition_) {
4068         if (item.second.startPos < 0 && item.second.endPos < 0) {
4069             continue;
4070         }
4071         if (item.second.startPos <= 0 && item.second.endPos > 0) {
4072             return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
4073         }
4074         if (item.second.startPos > 0 && item.second.endPos > 0) {
4075             return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
4076         }
4077     }
4078     return std::make_pair(itemPosition_.begin()->first,
4079         SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
4080 }
4081 
GetLastItemInfoInVisibleArea() const4082 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetLastItemInfoInVisibleArea() const
4083 {
4084     if (itemPosition_.empty()) {
4085         return std::make_pair(0, SwiperItemInfo {});
4086     }
4087     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4088     auto lastItemIndex = firstItemInfoInVisibleArea.first + GetDisplayCount() - 1;
4089     auto iter = itemPosition_.find(lastItemIndex);
4090     if (iter != itemPosition_.end()) {
4091         return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
4092     }
4093     return std::make_pair(itemPosition_.rbegin()->first,
4094         SwiperItemInfo { itemPosition_.rbegin()->second.startPos, itemPosition_.rbegin()->second.endPos });
4095 }
4096 
GetSecondItemInfoInVisibleArea() const4097 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetSecondItemInfoInVisibleArea() const
4098 {
4099     if (itemPosition_.empty()) {
4100         return std::make_pair(0, SwiperItemInfo {});
4101     }
4102     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4103     auto secondItemIndex = firstItemInfoInVisibleArea.first + 1;
4104     auto iter = itemPosition_.find(secondItemIndex);
4105     if (iter != itemPosition_.end()) {
4106         return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
4107     }
4108     return std::make_pair(itemPosition_.begin()->first,
4109         SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
4110 }
4111 
IsOutOfHotRegion(const PointF & dragPoint) const4112 bool SwiperPattern::IsOutOfHotRegion(const PointF& dragPoint) const
4113 {
4114     auto host = GetHost();
4115     CHECK_NULL_RETURN(host, true);
4116     auto context = host->GetRenderContext();
4117     CHECK_NULL_RETURN(context, true);
4118 
4119     auto hotRegion = context->GetPaintRectWithoutTransform();
4120     return !hotRegion.IsInRegion(dragPoint + OffsetF(hotRegion.GetX(), hotRegion.GetY()));
4121 }
4122 
UpdatePaintProperty(const RefPtr<FrameNode> & indicatorNode)4123 void SwiperPattern::UpdatePaintProperty(const RefPtr<FrameNode>& indicatorNode)
4124 {
4125     CHECK_NULL_VOID(indicatorNode);
4126     auto paintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
4127     CHECK_NULL_VOID(paintProperty);
4128     auto pipelineContext = PipelineBase::GetCurrentContext();
4129     CHECK_NULL_VOID(pipelineContext);
4130     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4131     CHECK_NULL_VOID(swiperIndicatorTheme);
4132     auto swiperParameters = GetSwiperParameters();
4133     CHECK_NULL_VOID(swiperParameters);
4134     paintProperty->UpdateItemWidth(swiperParameters->itemWidth.value_or(swiperIndicatorTheme->GetSize()));
4135     paintProperty->UpdateItemHeight(swiperParameters->itemHeight.value_or(swiperIndicatorTheme->GetSize()));
4136     paintProperty->UpdateSelectedItemWidth(
4137         swiperParameters->selectedItemWidth.value_or(swiperIndicatorTheme->GetSize()));
4138     paintProperty->UpdateSelectedItemHeight(
4139         swiperParameters->selectedItemHeight.value_or(swiperIndicatorTheme->GetSize()));
4140     paintProperty->UpdateIndicatorMask(swiperParameters->maskValue.value_or(false));
4141     paintProperty->UpdateColor(swiperParameters->colorVal.value_or(swiperIndicatorTheme->GetColor()));
4142     paintProperty->UpdateSelectedColor(
4143         swiperParameters->selectedColorVal.value_or(swiperIndicatorTheme->GetSelectedColor()));
4144     paintProperty->UpdateIsCustomSize(isCustomSize_);
4145 
4146     MarkDirtyNodeSelf();
4147     indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4148 }
4149 
SetDigitStartAndEndProperty(const RefPtr<FrameNode> & indicatorNode)4150 void SwiperPattern::SetDigitStartAndEndProperty(const RefPtr<FrameNode>& indicatorNode)
4151 {
4152     CHECK_NULL_VOID(indicatorNode);
4153     auto indicatorProps = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
4154     CHECK_NULL_VOID(indicatorProps);
4155     auto props = GetLayoutProperty<SwiperLayoutProperty>();
4156     CHECK_NULL_VOID(props);
4157     const auto digitalParams = GetSwiperDigitalParameters();
4158     CHECK_NULL_VOID(digitalParams);
4159     bool isRtl = GetNonAutoLayoutDirection() == TextDirection::RTL;
4160     if (digitalParams->dimStart.has_value()) {
4161         auto dimValue = digitalParams->dimStart.value().Value() >= 0.0 ? digitalParams->dimStart.value()
4162                                                                        : Dimension(0.0, DimensionUnit::VP);
4163         isRtl ? indicatorProps->UpdateRight(dimValue) : indicatorProps->UpdateLeft(dimValue);
4164         isRtl ? props->UpdateRight(dimValue) : props->UpdateLeft(digitalParams->dimLeft.value_or(0.0_vp));
4165         ;
4166     } else if (digitalParams->dimEnd.has_value()) {
4167         auto dimValue = digitalParams->dimEnd.value().Value() >= 0.0 ? digitalParams->dimEnd.value()
4168                                                                      : Dimension(0.0, DimensionUnit::VP);
4169         isRtl ? indicatorProps->UpdateLeft(dimValue) : indicatorProps->UpdateRight(dimValue);
4170         isRtl ? props->UpdateLeft(dimValue) : props->UpdateRight(digitalParams->dimRight.value_or(0.0_vp));
4171     }
4172 }
4173 
PostTranslateTask(uint32_t delayTime)4174 void SwiperPattern::PostTranslateTask(uint32_t delayTime)
4175 {
4176     auto pipeline = PipelineContext::GetCurrentContext();
4177     CHECK_NULL_VOID(pipeline);
4178     auto taskExecutor = pipeline->GetTaskExecutor();
4179     CHECK_NULL_VOID(taskExecutor);
4180 
4181     if (translateTask_) {
4182         translateTask_.Cancel();
4183     }
4184 
4185     auto weak = AceType::WeakClaim(this);
4186     translateTask_.Reset([weak, delayTime] {
4187         auto swiper = weak.Upgrade();
4188         if (swiper) {
4189             swiper->isInAutoPlay_ = true;
4190             auto childrenSize = swiper->TotalCount();
4191             auto displayCount = swiper->GetDisplayCount();
4192             if (childrenSize <= 0 || displayCount <= 0 || swiper->itemPosition_.empty()) {
4193                 return;
4194             }
4195             if (!swiper->IsLoop() && swiper->GetLoopIndex(swiper->currentIndex_) + 1 > (childrenSize - displayCount)) {
4196                 return;
4197             }
4198             auto stepItems = swiper->IsSwipeByGroup() ? displayCount : 1;
4199             swiper->targetIndex_ = swiper->CheckTargetIndex(swiper->currentIndex_ + stepItems);
4200             ACE_SCOPED_TRACE("Swiper autoPlay delayTime %d targetIndex %d isVisibleArea_ %d isWindowShow_ %d",
4201                 delayTime, swiper->targetIndex_.value(), swiper->isVisibleArea_, swiper->isWindowShow_);
4202             swiper->MarkDirtyNodeSelf();
4203             auto pipeline = PipelineContext::GetCurrentContext();
4204             if (pipeline) {
4205                 pipeline->FlushUITasks();
4206             }
4207         }
4208     });
4209 
4210     taskExecutor->PostDelayedTask(translateTask_, TaskExecutor::TaskType::UI, delayTime, "ArkUISwiperTranslate");
4211 }
4212 
HandleVisibleChange(bool visible)4213 void SwiperPattern::HandleVisibleChange(bool visible)
4214 {
4215     isVisibleArea_ = visible;
4216     if (!visible) {
4217         translateTask_.Cancel();
4218         isInAutoPlay_ = false;
4219         return;
4220     }
4221 
4222     if (NeedStartAutoPlay()) {
4223         StartAutoPlay();
4224     }
4225 }
4226 
RegisterVisibleAreaChange()4227 void SwiperPattern::RegisterVisibleAreaChange()
4228 {
4229     auto pipeline = PipelineContext::GetCurrentContext();
4230     CHECK_NULL_VOID(pipeline);
4231     auto host = GetHost();
4232     CHECK_NULL_VOID(host);
4233     pipeline->AddWindowStateChangedCallback(host->GetId());
4234 
4235     if (hasVisibleChangeRegistered_) {
4236         return;
4237     }
4238 
4239     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
4240         auto swiperPattern = weak.Upgrade();
4241         CHECK_NULL_VOID(swiperPattern);
4242         swiperPattern->HandleVisibleChange(visible);
4243     };
4244     pipeline->RemoveVisibleAreaChangeNode(host->GetId());
4245     std::vector<double> ratioList = { 0.0 };
4246     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false);
4247     hasVisibleChangeRegistered_ = true;
4248 
4249     auto isFormRender = pipeline->IsFormRender();
4250     auto formMgr = pipeline->GetFormVisibleManager();
4251     if (!isFormRender || !formMgr) {
4252         return;
4253     }
4254     formMgr->RemoveFormVisibleChangeNode(host->GetId());
4255     auto formCallback = [weak = WeakClaim(this)](bool visible) {
4256         auto swiperPattern = weak.Upgrade();
4257         CHECK_NULL_VOID(swiperPattern);
4258         swiperPattern->HandleVisibleChange(visible);
4259     };
4260     formMgr->AddFormVisibleChangeNode(host, formCallback);
4261 }
4262 
NeedAutoPlay() const4263 bool SwiperPattern::NeedAutoPlay() const
4264 {
4265     bool reachEnd = GetLoopIndex(CurrentIndex()) >= TotalCount() - 1 && !IsLoop();
4266     return IsAutoPlay() && !reachEnd && NeedStartAutoPlay() && !isIndicatorLongPress_;
4267 }
4268 
TriggerAnimationEndOnSwipeToLeft()4269 void SwiperPattern::TriggerAnimationEndOnSwipeToLeft()
4270 {
4271     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4272     auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
4273     auto firstIndexStartPos = firstItemInfoInVisibleArea.second.startPos;
4274     if (std::abs(firstIndexStartPos) < (firstItemLength / 2)) {
4275         currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
4276         UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
4277     } else {
4278         auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
4279         currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
4280         UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
4281     }
4282 }
4283 
TriggerAnimationEndOnSwipeToRight()4284 void SwiperPattern::TriggerAnimationEndOnSwipeToRight()
4285 {
4286     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4287     auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
4288     auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
4289     auto secondIndexStartPos = secondItemInfoInVisibleArea.second.startPos;
4290     if (std::abs(secondIndexStartPos) < (firstItemLength / 2)) {
4291         currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
4292         UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
4293     } else {
4294         currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
4295         UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
4296     }
4297 }
4298 
UpdateIndexOnAnimationStop()4299 void SwiperPattern::UpdateIndexOnAnimationStop()
4300 {
4301     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4302     if (currentIndex_ == firstItemInfoInVisibleArea.first) {
4303         // swipe to left
4304         TriggerAnimationEndOnSwipeToLeft();
4305     } else {
4306         // swipe to right
4307         TriggerAnimationEndOnSwipeToRight();
4308     }
4309 }
4310 
UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)4311 void SwiperPattern::UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)
4312 {
4313     auto iter = itemPosition_.find(currentIndex_);
4314     if (iter == itemPosition_.end()) {
4315         UpdateCurrentIndex(pauseTargetIndex);
4316         if (itemPosition_.find(pauseTargetIndex) != itemPosition_.end()) {
4317             currentIndexOffset_ = itemPosition_.find(pauseTargetIndex)->second.startPos;
4318         }
4319         return;
4320     }
4321 
4322     auto swiperWidth = MainSize();
4323     auto currentOffset = iter->second.startPos;
4324     if (std::abs(currentOffset) < (swiperWidth / SWIPER_HALF)) {
4325         return;
4326     }
4327 
4328     if (currentOffset < 0.0f) {
4329         auto nextPageIndex = currentIndex_ + GetDisplayCount();
4330         auto nextIter = itemPosition_.find(nextPageIndex);
4331         if (nextIter == itemPosition_.end()) {
4332             return;
4333         }
4334 
4335         auto nextPageOffset = nextIter->second.startPos;
4336         currentIndexOffset_ = nextPageOffset;
4337         UpdateCurrentIndex(nextPageIndex);
4338     } else {
4339         auto prevPageIndex = currentIndex_ - GetDisplayCount();
4340         auto prevIter = itemPosition_.find(prevPageIndex);
4341         if (prevIter == itemPosition_.end()) {
4342             return;
4343         }
4344 
4345         auto prevPageOffset = prevIter->second.startPos;
4346         currentIndexOffset_ = prevPageOffset;
4347         UpdateCurrentIndex(prevPageIndex);
4348     }
4349 }
4350 
TriggerAnimationEndOnForceStop(bool isInterrupt)4351 void SwiperPattern::TriggerAnimationEndOnForceStop(bool isInterrupt)
4352 {
4353     auto pauseTargetIndex = pauseTargetIndex_.has_value() ? pauseTargetIndex_.value() : currentIndex_;
4354     if (currentIndex_ != pauseTargetIndex) {
4355         if (IsSwipeByGroup()) {
4356             UpdateIndexOnSwipePageStop(pauseTargetIndex);
4357         } else {
4358             UpdateIndexOnAnimationStop();
4359         }
4360 
4361         UpdateCurrentFocus();
4362         OnIndexChange();
4363         oldIndex_ = currentIndex_;
4364     }
4365     AnimationCallbackInfo info;
4366     info.isForceStop = true;
4367     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4368     if (IsHorizontalAndRightToLeft()) {
4369         info.currentOffset =
4370             GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4371     }
4372     FireAnimationEndEvent(GetLoopIndex(currentIndex_), info, isInterrupt);
4373     UpdateItemRenderGroup(false);
4374 }
4375 
TriggerEventOnFinish(int32_t nextIndex)4376 void SwiperPattern::TriggerEventOnFinish(int32_t nextIndex)
4377 {
4378     ResetAndUpdateIndexOnAnimationEnd(nextIndex);
4379 
4380     AnimationCallbackInfo info;
4381     info.isForceStop = false;
4382     info.currentOffset = GetCustomPropertyOffset();
4383     FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
4384 }
4385 
GetCachedCount() const4386 int32_t SwiperPattern::GetCachedCount() const
4387 {
4388     auto host = GetHost();
4389     CHECK_NULL_RETURN(host, 1);
4390     auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
4391     CHECK_NULL_RETURN(props, 1);
4392     auto cachedCount = props->GetCachedCount().value_or(1);
4393 
4394     if (IsSwipeByGroup()) {
4395         cachedCount *= GetDisplayCount();
4396     }
4397 
4398     return cachedCount;
4399 }
4400 
SetLazyLoadFeature(bool useLazyLoad)4401 void SwiperPattern::SetLazyLoadFeature(bool useLazyLoad)
4402 {
4403     requestLongPredict_ = useLazyLoad;
4404     SetLazyForEachLongPredict(useLazyLoad);
4405 
4406     if (!useLazyLoad) {
4407         return;
4408     }
4409     auto cacheCount = std::min(GetCachedCount(), RealTotalCount());
4410     std::set<int32_t> forEachIndexSet;
4411     for (auto count = 1; count <= cacheCount; count++) {
4412         forEachIndexSet.emplace(GetLoopIndex(currentIndex_ + count));
4413         forEachIndexSet.emplace(GetLoopIndex(currentIndex_ - count));
4414     }
4415     if (forEachIndexSet.empty()) {
4416         return;
4417     }
4418 
4419     auto host = GetHost();
4420     CHECK_NULL_VOID(host);
4421     const auto& children = host->GetChildren();
4422     for (const auto& child : children) {
4423         if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
4424             continue;
4425         }
4426         auto pipeline = GetContext();
4427         CHECK_NULL_VOID(pipeline);
4428         auto taskExecutor = pipeline->GetTaskExecutor();
4429         CHECK_NULL_VOID(taskExecutor);
4430         taskExecutor->PostTask(
4431             [weak = WeakClaim(RawPtr(child)), forEachIndexSet]() {
4432                 auto node = weak.Upgrade();
4433                 CHECK_NULL_VOID(node);
4434                 auto forEachNode = AceType::DynamicCast<ForEachNode>(node);
4435                 CHECK_NULL_VOID(forEachNode);
4436                 for (auto index : forEachIndexSet) {
4437                     auto childNode = forEachNode->GetChildAtIndex(index);
4438                     CHECK_NULL_VOID(childNode);
4439                     childNode->Build(nullptr);
4440                 }
4441             },
4442             TaskExecutor::TaskType::UI, "ArkUISwiperSetLazyLoadFeature");
4443     }
4444 }
4445 
SetLazyForEachLongPredict(bool useLazyLoad) const4446 void SwiperPattern::SetLazyForEachLongPredict(bool useLazyLoad) const
4447 {
4448     // lazyBuild feature.
4449     auto host = GetHost();
4450     CHECK_NULL_VOID(host);
4451     auto targetNode = FindLazyForEachNode(host);
4452     if (targetNode.has_value()) {
4453         auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
4454         CHECK_NULL_VOID(lazyForEachNode);
4455         lazyForEachNode->SetRequestLongPredict(useLazyLoad);
4456     }
4457 }
4458 
SetLazyLoadIsLoop() const4459 void SwiperPattern::SetLazyLoadIsLoop() const
4460 {
4461     auto host = GetHost();
4462     CHECK_NULL_VOID(host);
4463     auto targetNode = FindLazyForEachNode(host);
4464     if (targetNode.has_value()) {
4465         auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
4466         if (lazyForEachNode) {
4467             lazyForEachNode->SetIsLoop(IsLoop());
4468         }
4469         auto repeatVirtualNode = AceType::DynamicCast<RepeatVirtualScrollNode>(targetNode.value());
4470         if (repeatVirtualNode) {
4471             repeatVirtualNode->SetIsLoop(IsLoop());
4472         }
4473     }
4474 }
4475 
PostIdleTask(const RefPtr<FrameNode> & frameNode)4476 void SwiperPattern::PostIdleTask(const RefPtr<FrameNode>& frameNode)
4477 {
4478     if (cachedItems_.empty()) {
4479         return;
4480     }
4481     auto pipelineContext = GetContext();
4482     CHECK_NULL_VOID(pipelineContext);
4483     pipelineContext->AddPredictTask(
4484         [weak = WeakClaim(RawPtr(frameNode))](int64_t deadline, bool canUseLongPredictTask) {
4485             auto frameNode = weak.Upgrade();
4486             CHECK_NULL_VOID(frameNode);
4487             auto pattern = frameNode->GetPattern<SwiperPattern>();
4488             CHECK_NULL_VOID(pattern);
4489             if (!canUseLongPredictTask || !pattern->GetRequestLongPredict()) {
4490                 pattern->PostIdleTask(frameNode);
4491                 return;
4492             }
4493             auto cachedItems = pattern->GetCachedItems();
4494             for (auto it = cachedItems.begin(); it != cachedItems.end();) {
4495                 if (GetSysTimestamp() > deadline) {
4496                     break;
4497                 }
4498                 ACE_SCOPED_TRACE("Swiper cached self index: %d", *it);
4499                 auto wrapper = frameNode->GetOrCreateChildByIndex(*it, false, true);
4500                 if (!wrapper) {
4501                     it = cachedItems.erase(it);
4502                     continue;
4503                 }
4504                 auto childNode = wrapper->GetHostNode();
4505                 if (childNode) {
4506                     childNode->GetGeometryNode()->SetParentLayoutConstraint(pattern->GetLayoutConstraint());
4507                     FrameNode::ProcessOffscreenNode(childNode);
4508                 }
4509                 it = cachedItems.erase(it);
4510             }
4511             pattern->SetCachedItems(cachedItems);
4512             if (!cachedItems.empty()) {
4513                 pattern->PostIdleTask(frameNode);
4514             }
4515         });
4516 }
4517 
IsVisibleChildrenSizeLessThanSwiper() const4518 bool SwiperPattern::IsVisibleChildrenSizeLessThanSwiper() const
4519 {
4520     if (itemPosition_.empty() || GetDisplayCount() > TotalCount()) {
4521         return true;
4522     }
4523     const auto firstItem = GetFirstItemInfoInVisibleArea();
4524     const auto lastItem = GetLastItemInfoInVisibleArea();
4525     const int32_t visibleItemCnt = lastItem.first - firstItem.first + 1;
4526     if (TotalCount() != visibleItemCnt) {
4527         return false;
4528     }
4529     const float childrenLength = lastItem.second.endPos - firstItem.second.startPos;
4530     if (NonPositive(childrenLength)) {
4531         return true;
4532     }
4533     return LessOrEqual(childrenLength, CalculateVisibleSize());
4534 }
4535 
UpdateItemRenderGroup(bool itemRenderGroup)4536 void SwiperPattern::UpdateItemRenderGroup(bool itemRenderGroup)
4537 {
4538     for (auto& item : itemPosition_) {
4539         if (auto frameNode = item.second.node) {
4540             groupedItems_.insert(frameNode);
4541         }
4542     }
4543     auto host = GetHost();
4544     CHECK_NULL_VOID(host);
4545     for (auto child : host->GetChildren()) {
4546         auto frameNode = DynamicCast<FrameNode>(child);
4547         if (!frameNode || child->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
4548             continue;
4549         }
4550         groupedItems_.insert(frameNode);
4551     }
4552     for (auto iter = groupedItems_.begin(); iter != groupedItems_.end();) {
4553         if (auto node = iter->Upgrade()) {
4554             auto context = node->GetRenderContext();
4555             CHECK_NULL_VOID(context);
4556             context->UpdateSuggestedRenderGroup(itemRenderGroup);
4557             ++iter;
4558         } else {
4559             iter = groupedItems_.erase(iter);
4560         }
4561     }
4562 }
4563 
OnTranslateFinish(int32_t nextIndex,bool restartAutoPlay,bool isFinishAnimation,bool forceStop,bool isInterrupt)4564 void SwiperPattern::OnTranslateFinish(
4565     int32_t nextIndex, bool restartAutoPlay, bool isFinishAnimation, bool forceStop, bool isInterrupt)
4566 {
4567     if (forceStop && !isFinishAnimation) {
4568         TriggerAnimationEndOnForceStop(isInterrupt);
4569     } else {
4570         TriggerEventOnFinish(nextIndex);
4571     }
4572 
4573     auto host = GetHost();
4574     CHECK_NULL_VOID(host);
4575     if (HasIndicatorNode()) {
4576         auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
4577         CHECK_NULL_VOID(indicatorNode);
4578         if (indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
4579             indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4580             MarkDirtyNodeSelf();
4581         }
4582     }
4583 
4584     auto delayTime = GetInterval() - GetDuration();
4585     delayTime = std::clamp(delayTime, 0, delayTime);
4586     if (NeedAutoPlay() && isUserFinish_ && !forceStop) {
4587         PostTranslateTask(delayTime);
4588     }
4589     UpdateItemRenderGroup(false);
4590 }
4591 
OnWindowShow()4592 void SwiperPattern::OnWindowShow()
4593 {
4594     if (!isParentHiddenChange_) {
4595         FireWillShowEvent(currentIndex_);
4596     }
4597     isWindowShow_ = true;
4598     if (NeedStartAutoPlay()) {
4599         StartAutoPlay();
4600     }
4601 }
4602 
OnWindowHide()4603 void SwiperPattern::OnWindowHide()
4604 {
4605     if (!isParentHiddenChange_) {
4606         FireWillHideEvent(currentIndex_);
4607     }
4608     isWindowShow_ = false;
4609     StopAutoPlay();
4610 
4611     if (isDragging_) {
4612         HandleDragEnd(0.0);
4613     }
4614 
4615     StopSpringAnimationAndFlushImmediately();
4616 }
4617 
ArrowHover(bool hoverFlag)4618 void SwiperPattern::ArrowHover(bool hoverFlag)
4619 {
4620     if (HasLeftButtonNode() && HasRightButtonNode()) {
4621         auto swiperNode = GetHost();
4622         CHECK_NULL_VOID(swiperNode);
4623         auto leftArrowNode =
4624             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
4625         CHECK_NULL_VOID(leftArrowNode);
4626         auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
4627         CHECK_NULL_VOID(leftArrowPattern);
4628         leftArrowPattern->SetButtonVisible(hoverFlag);
4629         auto rightArrowNode =
4630             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
4631         CHECK_NULL_VOID(rightArrowNode);
4632         auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
4633         CHECK_NULL_VOID(rightArrowPattern);
4634         rightArrowPattern->SetButtonVisible(hoverFlag);
4635     }
4636 }
4637 
SaveArrowProperty(const RefPtr<FrameNode> & arrowNode)4638 void SwiperPattern::SaveArrowProperty(const RefPtr<FrameNode>& arrowNode)
4639 {
4640     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4641     CHECK_NULL_VOID(props);
4642     const auto paintProps = GetPaintProperty<SwiperPaintProperty>();
4643     CHECK_NULL_VOID(props);
4644     const auto arrowProps = arrowNode->GetLayoutProperty<SwiperArrowLayoutProperty>();
4645     CHECK_NULL_VOID(arrowProps);
4646     arrowProps->UpdateDirection(props->GetDirection().value_or(Axis::HORIZONTAL));
4647     arrowProps->UpdateIndex(props->GetIndex().value_or(0));
4648     arrowProps->UpdateLoop(props->GetLoop().value_or(true));
4649     arrowProps->UpdateEnabled(paintProps->GetEnabled().value_or(true));
4650     arrowProps->UpdateDisplayArrow(props->GetDisplayArrowValue());
4651     arrowProps->UpdateHoverShow(props->GetHoverShowValue());
4652     arrowProps->UpdateIsShowBackground(props->GetIsShowBackgroundValue());
4653     arrowProps->UpdateBackgroundSize(props->GetBackgroundSizeValue());
4654     arrowProps->UpdateBackgroundColor(props->GetBackgroundColorValue());
4655     arrowProps->UpdateArrowSize(props->GetArrowSizeValue());
4656     arrowProps->UpdateArrowColor(props->GetArrowColorValue());
4657     arrowProps->UpdateIsSidebarMiddle(props->GetIsSidebarMiddleValue());
4658 }
4659 
SetAccessibilityAction()4660 void SwiperPattern::SetAccessibilityAction()
4661 {
4662     auto host = GetHost();
4663     CHECK_NULL_VOID(host);
4664     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
4665     CHECK_NULL_VOID(accessibilityProperty);
4666     accessibilityProperty->SetActionScrollForward(
4667         [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
4668             const auto& pattern = weakPtr.Upgrade();
4669             CHECK_NULL_VOID(pattern);
4670             const auto& accessibilityProperty = accessibility.Upgrade();
4671             CHECK_NULL_VOID(accessibilityProperty);
4672             if (!accessibilityProperty->IsScrollable()) {
4673                 return;
4674             }
4675             pattern->ShowNext();
4676         });
4677 
4678     accessibilityProperty->SetActionScrollBackward(
4679         [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
4680             const auto& pattern = weakPtr.Upgrade();
4681             CHECK_NULL_VOID(pattern);
4682             const auto& accessibilityProperty = accessibility.Upgrade();
4683             CHECK_NULL_VOID(accessibilityProperty);
4684             if (!accessibilityProperty->IsScrollable()) {
4685                 return;
4686             }
4687             pattern->ShowPrevious();
4688         });
4689 }
4690 
NeedStartAutoPlay() const4691 bool SwiperPattern::NeedStartAutoPlay() const
4692 {
4693     return isWindowShow_ && isVisibleArea_;
4694 }
4695 
ProvideRestoreInfo()4696 std::string SwiperPattern::ProvideRestoreInfo()
4697 {
4698     auto jsonObj = JsonUtil::Create(true);
4699     auto props = GetLayoutProperty<SwiperLayoutProperty>();
4700     CHECK_NULL_RETURN(props, "");
4701     jsonObj->Put("Index", props->GetIndex().value_or(0));
4702     return jsonObj->ToString();
4703 }
4704 
OnRestoreInfo(const std::string & restoreInfo)4705 void SwiperPattern::OnRestoreInfo(const std::string& restoreInfo)
4706 {
4707     auto props = GetLayoutProperty<SwiperLayoutProperty>();
4708     CHECK_NULL_VOID(props);
4709     auto info = JsonUtil::ParseJsonString(restoreInfo);
4710     if (!info->IsValid() || !info->IsObject()) {
4711         return;
4712     }
4713     auto jsonIsOn = info->GetValue("Index");
4714     props->UpdateIndex(jsonIsOn->GetInt());
4715     OnModifyDone();
4716 }
4717 
InitHoverMouseEvent()4718 void SwiperPattern::InitHoverMouseEvent()
4719 {
4720     auto host = GetHost();
4721     CHECK_NULL_VOID(host);
4722     auto eventHub = host->GetEventHub<EventHub>();
4723     CHECK_NULL_VOID(eventHub);
4724     auto inputHub = eventHub->GetOrCreateInputEventHub();
4725     CHECK_NULL_VOID(inputHub);
4726 
4727     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
4728         auto pattern = weak.Upgrade();
4729         CHECK_NULL_VOID(pattern);
4730         if (!pattern->IsShowIndicator()) {
4731             pattern->ArrowHover(isHover);
4732         }
4733     };
4734 
4735     if (!hoverEvent_) {
4736         hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
4737         inputHub->AddOnHoverEvent(hoverEvent_);
4738     }
4739 
4740     auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
4741         auto pattern = weak.Upgrade();
4742         if (pattern) {
4743             pattern->HandleMouseEvent(info);
4744         }
4745     };
4746     if (mouseEvent_) {
4747         inputHub->RemoveOnMouseEvent(mouseEvent_);
4748     }
4749     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
4750     inputHub->AddOnMouseEvent(mouseEvent_);
4751 }
4752 
HandleMouseEvent(const MouseInfo & info)4753 void SwiperPattern::HandleMouseEvent(const MouseInfo& info)
4754 {
4755     auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
4756     auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
4757     auto mousePoint = PointF(mouseOffsetX, mouseOffsetY);
4758     if (IsShowIndicator()) {
4759         CheckAndSetArrowHoverState(mousePoint);
4760     }
4761 }
4762 
CheckAndSetArrowHoverState(const PointF & mousePoint)4763 void SwiperPattern::CheckAndSetArrowHoverState(const PointF& mousePoint)
4764 {
4765     if (!HasLeftButtonNode() || !HasRightButtonNode() || !HasIndicatorNode()) {
4766         return;
4767     }
4768 
4769     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4770     CHECK_NULL_VOID(props);
4771     if (props->GetIsSidebarMiddleValue(false)) {
4772         return;
4773     }
4774 
4775     RectF leftNodeRect;
4776     RectF rightNodeRect;
4777 
4778     leftNodeRect = GetArrowFrameRect(GetLeftButtonId());
4779     rightNodeRect = GetArrowFrameRect(GetRightButtonId());
4780 
4781     if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
4782         leftNodeRect = GetArrowFrameRect(GetIndicatorId());
4783     }
4784 
4785     if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
4786         rightNodeRect = GetArrowFrameRect(GetIndicatorId());
4787     }
4788     RectF newNodeRect;
4789     if (GetDirection() == Axis::HORIZONTAL) {
4790         newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(), rightNodeRect.Right() - leftNodeRect.Left(),
4791             std::min(rightNodeRect.Height(), leftNodeRect.Height()));
4792     } else {
4793         newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(),
4794             std::min(rightNodeRect.Width(), leftNodeRect.Width()), rightNodeRect.Bottom() - leftNodeRect.Top());
4795     }
4796 
4797     isAtHotRegion_ = newNodeRect.IsInRegion(mousePoint);
4798     ArrowHover(isAtHotRegion_);
4799 }
4800 
GetArrowFrameRect(const int32_t index) const4801 RectF SwiperPattern::GetArrowFrameRect(const int32_t index) const
4802 {
4803     auto swiperNode = GetHost();
4804     CHECK_NULL_RETURN(swiperNode, RectF(0, 0, 0, 0));
4805     auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(index)));
4806     CHECK_NULL_RETURN(arrowNode, RectF(0, 0, 0, 0));
4807     auto arrowGeometryNode = arrowNode->GetGeometryNode();
4808     CHECK_NULL_RETURN(arrowGeometryNode, RectF(0, 0, 0, 0));
4809     return arrowGeometryNode->GetFrameRect();
4810 }
4811 
GetCustomPropertyOffset() const4812 float SwiperPattern::GetCustomPropertyOffset() const
4813 {
4814     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4815     CHECK_NULL_RETURN(props, 0.0);
4816     auto paddingAndBorder = props->CreatePaddingAndBorder();
4817     auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
4818                                      ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
4819                                      : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
4820     return Dimension(paddingAndBorderValue + GetPrevMarginWithItemSpace(), DimensionUnit::PX).ConvertToVp();
4821 }
4822 
GetCustomPropertyTargetOffset() const4823 float SwiperPattern::GetCustomPropertyTargetOffset() const
4824 {
4825     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4826     CHECK_NULL_RETURN(props, 0.0);
4827     auto paddingAndBorder = props->CreatePaddingAndBorder();
4828     auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
4829                                      ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
4830                                      : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
4831 
4832     auto preMarginPX = GetPrevMarginWithItemSpace();
4833     if (IsHorizontalAndRightToLeft()) {
4834         return Dimension(paddingAndBorderValue - preMarginPX, DimensionUnit::PX).ConvertToVp();
4835     }
4836     return Dimension(paddingAndBorderValue + preMarginPX, DimensionUnit::PX).ConvertToVp();
4837 }
4838 
TotalDisPlayCount() const4839 int32_t SwiperPattern::TotalDisPlayCount() const
4840 {
4841     auto props = GetLayoutProperty<SwiperLayoutProperty>();
4842     CHECK_NULL_RETURN(props, 1);
4843     auto displayCount = GetDisplayCount();
4844     if (SwiperUtils::IsStretch(props)) {
4845         if (Positive(props->GetCalculatedPrevMargin())) {
4846             displayCount++;
4847         }
4848         if (Positive(props->GetCalculatedNextMargin())) {
4849             displayCount++;
4850         }
4851     }
4852     return displayCount;
4853 }
4854 
MarkDirtyNodeSelf()4855 void SwiperPattern::MarkDirtyNodeSelf()
4856 {
4857     auto host = GetHost();
4858     CHECK_NULL_VOID(host);
4859     if (!crossMatchChild_) {
4860         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4861     } else {
4862         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
4863     }
4864 }
4865 
ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)4866 void SwiperPattern::ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)
4867 {
4868     auto host = GetHost();
4869     CHECK_NULL_VOID(host);
4870     targetIndex_.reset();
4871     if (preTargetIndex_.has_value()) {
4872         preTargetIndex_.reset();
4873     }
4874 
4875     if (isFinishAnimation_) {
4876         currentDelta_ = 0.0f;
4877         itemPosition_.clear();
4878         isVoluntarilyClear_ = true;
4879         jumpIndex_ = nextIndex;
4880         MarkDirtyNodeSelf();
4881         auto pipeline = PipelineContext::GetCurrentContext();
4882         if (pipeline) {
4883             pipeline->FlushUITasks();
4884         }
4885         isFinishAnimation_ = false;
4886     } else if (currentIndex_ != nextIndex) {
4887         UpdateCurrentIndex(nextIndex);
4888         if (currentFocusIndex_ < currentIndex_ || currentFocusIndex_ >= currentIndex_ + GetDisplayCount()) {
4889             currentFocusIndex_ = currentIndex_;
4890         }
4891         do {
4892             auto curChildFrame =
4893                 DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_)));
4894             if (!curChildFrame || !IsContentFocused()) {
4895                 break;
4896             }
4897             FlushFocus(curChildFrame);
4898         } while (0);
4899         auto tempOldIndex = oldIndex_;
4900         oldIndex_ = nextIndex;
4901         currentFirstIndex_ = GetLoopIndex(nextIndex);
4902         turnPageRate_ = 0.0f;
4903         currentIndexOffset_ = 0.0f;
4904         auto pipeline = PipelineContext::GetCurrentContext();
4905         if (pipeline) {
4906             if (pipeline->IsLayouting()) {
4907                 pipeline->FlushUITaskWithSingleDirtyNode(host);
4908             } else {
4909                 pipeline->FlushUITasks();
4910                 pipeline->FlushMessages();
4911             }
4912         }
4913         FireChangeEvent(tempOldIndex, GetLoopIndex(currentIndex_));
4914         // lazyBuild feature.
4915         SetLazyLoadFeature(true);
4916     }
4917 }
4918 
OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child,float position,float)4919 void SwiperPattern::OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child, float position, float /* velocity */)
4920 {
4921     SetIsNestedInterrupt(false);
4922     if (IsDisableSwipe()) {
4923         return;
4924     }
4925     childScrolling_ = true;
4926     gestureSwipeIndex_ = currentIndex_;
4927     StopAnimationOnScrollStart(false);
4928     NotifyParentScrollStart(child, position);
4929 }
4930 
NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child,float position)4931 void SwiperPattern::NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child, float position)
4932 {
4933     if (!GetIsFixedNestedScrollMode()) {
4934         SetParentScrollable();
4935     }
4936     auto parent = GetNestedScrollParent();
4937     CHECK_NULL_VOID(parent);
4938     const auto& nestedScroll = GetNestedScroll();
4939     if (parent && nestedScroll.NeedParent()) {
4940         parent->OnScrollStartRecursive(child, position);
4941     }
4942 }
4943 
OnScrollEndRecursive(const std::optional<float> & velocity)4944 void SwiperPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
4945 {
4946     if (IsDisableSwipe()) {
4947         return;
4948     }
4949     // in case child didn't call swiper's HandleScrollVelocity
4950     if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
4951         HandleDragEnd(velocity.value_or(0.0f));
4952     }
4953     SetIsNestedInterrupt(false);
4954     childScrolling_ = false;
4955     InitIndexCanChangeMap();
4956 }
4957 
OnScrollDragEndRecursive()4958 void SwiperPattern::OnScrollDragEndRecursive()
4959 {
4960     NestableScrollContainer::OnScrollDragEndRecursive();
4961     if (IsDisableSwipe()) {
4962         return;
4963     }
4964     // Swiper and child handle drag end event together.
4965     if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
4966         HandleDragEnd(0.0f);
4967     }
4968 }
4969 
NotifyParentScrollEnd()4970 void SwiperPattern::NotifyParentScrollEnd()
4971 {
4972     auto parent = GetNestedScrollParent();
4973     const auto& nestedScroll = GetNestedScroll();
4974     if (parent && (nestedScroll.NeedParent() || GetIsNestedInterrupt())) {
4975         parent->OnScrollEndRecursive(std::nullopt);
4976     }
4977 }
4978 
DuringTranslateAnimation() const4979 inline bool SwiperPattern::DuringTranslateAnimation() const
4980 {
4981     return (springAnimation_ && springAnimationIsRunning_ && !isTouchDownSpringAnimation_) || targetIndex_ ||
4982            usePropertyAnimation_ || translateAnimationIsRunning_;
4983 }
4984 
RunningTranslateAnimation() const4985 inline bool SwiperPattern::RunningTranslateAnimation() const
4986 {
4987     return springAnimationIsRunning_ || usePropertyAnimation_ || translateAnimationIsRunning_;
4988 }
4989 
DuringFadeAnimation() const4990 inline bool SwiperPattern::DuringFadeAnimation() const
4991 {
4992     return fadeAnimation_ && fadeAnimationIsRunning_ && !isTouchDownFadeAnimation_;
4993 }
4994 
HandleScrollVelocity(float velocity,const RefPtr<NestableScrollContainer> & child)4995 bool SwiperPattern::HandleScrollVelocity(float velocity, const RefPtr<NestableScrollContainer>& child)
4996 {
4997     if (IsDisableSwipe()) {
4998         return false;
4999     }
5000     if (IsHorizontalAndRightToLeft()) {
5001         velocity = -velocity;
5002     }
5003     DestructSetter<bool> scope(childScrolling_, false);
5004     // haven't reached edge
5005     if (GetDistanceToEdge() > 0.0f || IsLoop()) {
5006         HandleDragEnd(velocity);
5007         return true;
5008     }
5009 
5010     auto parent = GetNestedScrollParent();
5011     const auto nestedScroll = GetNestedScroll();
5012     if (parent && nestedScroll.NeedParent(NonPositive(velocity))) {
5013         // after reach end, parent handle velocity first
5014         if (parent->HandleScrollVelocity(velocity)) {
5015             return true;
5016         }
5017     }
5018     HandleDragEnd(velocity);
5019     // after reached end, NONE doesn't consume velocity, other edge effects do
5020     return GetEdgeEffect() != EdgeEffect::NONE;
5021 }
5022 
HandleScroll(float offset,int32_t source,NestedState state,float velocity)5023 ScrollResult SwiperPattern::HandleScroll(float offset, int32_t source, NestedState state, float velocity)
5024 {
5025     if (IsHorizontalAndRightToLeft() && state != NestedState::GESTURE) {
5026         offset = -offset;
5027     }
5028     if (IsDisableSwipe()) {
5029         return { offset, true };
5030     }
5031     if (source == SCROLL_FROM_ANIMATION && DuringTranslateAnimation()) {
5032         // deny conflicting animation from child
5033         return { offset, true };
5034     }
5035     if (!CheckSwiperPanEvent(offset)) {
5036         return { offset, true };
5037     }
5038     if (state != NestedState::GESTURE) {
5039         // handle situations when multiple children are notifying scrollStart / scrollEnd
5040         // reset flag and animations to correct states when scroll happens
5041         childScrolling_ = true;
5042         if (DuringTranslateAnimation()) {
5043             StopAnimationOnScrollStart(false);
5044         }
5045     }
5046     // mouse scroll triggers showNext / showPrev instead of updating offset
5047     if (source == SCROLL_FROM_AXIS) {
5048         auto targetBfr = targetIndex_;
5049         (offset > 0) ? ShowPrevious() : ShowNext();
5050         if (targetBfr == targetIndex_) {
5051             // unchanged targetIndex_ implies Swiper has reached the edge and the mouse scroll isn't consumed.
5052             return { offset, true };
5053         }
5054         return { 0.0f, false };
5055     }
5056     auto parent = GetNestedScrollParent();
5057     auto nestedScroll = GetNestedScroll();
5058     if (!parent || !nestedScroll.NeedParent()) {
5059         if (IsOutOfBoundary(offset) && ChildFirst(state)) {
5060             CloseTheGap(offset);
5061             return { offset, true };
5062         }
5063         UpdateCurrentOffset(offset);
5064         return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5065     }
5066     ScrollResult result = { 0.f, !IsLoop() && GetDistanceToEdge() <= 0.f };
5067     if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::PARENT_FIRST) ||
5068                       (Positive(offset) && nestedScroll.backward == NestedScrollMode::PARENT_FIRST))) {
5069         result = HandleScrollParentFirst(offset, source, state, velocity);
5070     } else if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::SELF_FIRST) ||
5071                              (Positive(offset) && nestedScroll.backward == NestedScrollMode::SELF_FIRST))) {
5072         result = HandleScrollSelfFirst(offset, source, state, velocity);
5073     }
5074     return result;
5075 }
5076 
HandleScrollParentFirst(float offset,int32_t source,NestedState state,float velocity)5077 ScrollResult SwiperPattern::HandleScrollParentFirst(float offset, int32_t source, NestedState state, float velocity)
5078 {
5079     // priority: parent scroll > self scroll > self overScroll > parent overScroll
5080     auto parent = GetNestedScrollParent();
5081     // skip CHECK_NULL, already checked in HandleScroll
5082     auto result = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
5083     offset = result.remain;
5084     if (IsOutOfBoundary(offset)) {
5085         if (NearZero(offset)) {
5086             return { 0.f, true };
5087         }
5088         CloseTheGap(offset);
5089         if (ChildFirst(state)) {
5090             if (result.reachEdge) {
5091                 result = parent->HandleScroll(offset, source, NestedState::CHILD_OVER_SCROLL, velocity);
5092             }
5093             return { result.remain, true };
5094         }
5095     }
5096     // self Scroll && self overScroll
5097     UpdateCurrentOffset(offset);
5098     return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5099 }
5100 
HandleScrollSelfFirst(float offset,int32_t source,NestedState state,float velocity)5101 ScrollResult SwiperPattern::HandleScrollSelfFirst(float offset, int32_t source, NestedState state, float velocity)
5102 {
5103     // priority: self scroll > parent scroll > parent overScroll > self overScroll
5104     if ((IsOutOfStart(offset) && Positive(offset)) || (IsOutOfEnd(offset) && Negative(offset))) {
5105         CloseTheGap(offset);
5106         // skip CHECK_NULL, already checked in HandleScroll
5107         auto parent = GetNestedScrollParent();
5108 
5109         // reached edge, pass offset to parent
5110         auto res = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
5111         if (res.remain == 0.0f) {
5112             return { 0.0f, true };
5113         }
5114         // parent handle overScroll first
5115         if (res.reachEdge) {
5116             res = parent->HandleScroll(res.remain, source, NestedState::CHILD_OVER_SCROLL, velocity);
5117         }
5118         if (ChildFirst(state)) {
5119             return { res.remain, true };
5120         }
5121         if (res.remain != 0.0f) {
5122             // self overScroll
5123             UpdateCurrentOffset(res.remain);
5124         }
5125     } else {
5126         // regular scroll
5127         UpdateCurrentOffset(offset);
5128     }
5129     return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5130 }
5131 
CloseTheGap(float & offset)5132 void SwiperPattern::CloseTheGap(float& offset)
5133 {
5134     float distanceToEdge = GetDistanceToEdge();
5135     if (Positive(distanceToEdge)) {
5136         if (GreatOrEqual(std::abs(offset), distanceToEdge)) {
5137             UpdateCurrentOffset(Positive(offset) ? distanceToEdge : -distanceToEdge);
5138             offset = Positive(offset) ? offset - distanceToEdge : offset + distanceToEdge;
5139         }
5140     }
5141 }
5142 
ChildFirst(NestedState state)5143 inline bool SwiperPattern::ChildFirst(NestedState state)
5144 {
5145     // SELF/CHILD priority: self scroll > child scroll > self overScroll > child overScroll
5146     return state == NestedState::CHILD_SCROLL // child hasn't reach edge
5147            || GetEdgeEffect() == EdgeEffect::NONE;
5148 }
5149 
UpdateDragFRCSceneInfo(float speed,SceneStatus sceneStatus)5150 void SwiperPattern::UpdateDragFRCSceneInfo(float speed, SceneStatus sceneStatus)
5151 {
5152     auto host = GetHost();
5153     CHECK_NULL_VOID(host);
5154     host->AddFRCSceneInfo(SWIPER_DRAG_SCENE, speed, sceneStatus);
5155 }
5156 
GetLoopIndex(int32_t index,int32_t childrenSize) const5157 int32_t SwiperPattern::GetLoopIndex(int32_t index, int32_t childrenSize) const
5158 {
5159     if (childrenSize <= 0) {
5160         return index;
5161     }
5162     auto loopIndex = index;
5163     while (loopIndex < 0) {
5164         loopIndex = loopIndex + childrenSize;
5165     }
5166     loopIndex %= childrenSize;
5167     return loopIndex;
5168 }
5169 
DumpAdvanceInfo()5170 void SwiperPattern::DumpAdvanceInfo()
5171 {
5172     SwiperHelper::DumpAdvanceInfo(*this);
5173 }
5174 
RegisterScrollingListener(const RefPtr<ScrollingListener> listener)5175 void SwiperPattern::RegisterScrollingListener(const RefPtr<ScrollingListener> listener)
5176 {
5177     CHECK_NULL_VOID(listener);
5178     scrollingListener_.emplace_back(listener);
5179 }
5180 
FireAndCleanScrollingListener()5181 void SwiperPattern::FireAndCleanScrollingListener()
5182 {
5183     for (auto listener : scrollingListener_) {
5184         CHECK_NULL_VOID(listener);
5185         listener->NotifyScrollingEvent();
5186     }
5187     scrollingListener_.clear();
5188 }
5189 
CleanScrollingListener()5190 void SwiperPattern::CleanScrollingListener()
5191 {
5192     scrollingListener_.clear();
5193 }
5194 
IsSwipeByGroup() const5195 bool SwiperPattern::IsSwipeByGroup() const
5196 {
5197     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
5198     CHECK_NULL_RETURN(layoutProperty, false);
5199     return layoutProperty->GetSwipeByGroup().value_or(false);
5200 }
5201 
GetCurrentFrameNode(int32_t currentIndex) const5202 RefPtr<FrameNode> SwiperPattern::GetCurrentFrameNode(int32_t currentIndex) const
5203 {
5204     auto host = GetHost();
5205     CHECK_NULL_RETURN(host, nullptr);
5206     auto currentLayoutWrapper = host->GetChildByIndex(GetLoopIndex(currentIndex), true);
5207     CHECK_NULL_RETURN(currentLayoutWrapper, nullptr);
5208     return currentLayoutWrapper->GetHostNode();
5209 }
5210 
OnCustomContentTransition(int32_t toIndex)5211 void SwiperPattern::OnCustomContentTransition(int32_t toIndex)
5212 {
5213     if (!currentProxyInAnimation_ && toIndex == CurrentIndex()) {
5214         return;
5215     }
5216 
5217     customAnimationToIndex_ = toIndex;
5218     indexsInAnimation_.insert(toIndex);
5219     auto fromIndex = CurrentIndex();
5220     if (currentProxyInAnimation_) {
5221         fromIndex = currentProxyInAnimation_->GetToIndex();
5222 
5223         FireChangeEvent(CurrentIndex(), fromIndex);
5224 
5225         UpdateCurrentIndex(fromIndex);
5226         oldIndex_ = fromIndex;
5227 
5228         AnimationCallbackInfo info;
5229         info.currentOffset = GetCustomPropertyOffset();
5230         FireAnimationEndEvent(fromIndex, info);
5231 
5232         currentProxyInAnimation_->SetHasOnChanged(true);
5233     }
5234     if (fromIndex != toIndex) {
5235         FireWillShowEvent(toIndex);
5236         FireWillHideEvent(fromIndex);
5237     }
5238     auto pipelineContext = PipelineContext::GetCurrentContext();
5239     CHECK_NULL_VOID(pipelineContext);
5240 
5241     pipelineContext->AddAfterLayoutTask([weak = WeakClaim(this), fromIndex, toIndex]() {
5242         auto swiperPattern = weak.Upgrade();
5243         CHECK_NULL_VOID(swiperPattern);
5244         swiperPattern->TriggerCustomContentTransitionEvent(fromIndex, toIndex);
5245     });
5246 
5247     MarkDirtyNodeSelf();
5248 }
5249 
TriggerCustomContentTransitionEvent(int32_t fromIndex,int32_t toIndex)5250 void SwiperPattern::TriggerCustomContentTransitionEvent(int32_t fromIndex, int32_t toIndex)
5251 {
5252     CHECK_NULL_VOID(onTabsCustomContentTransition_);
5253 
5254     auto tabContentAnimatedTransition = (*onTabsCustomContentTransition_)(fromIndex, toIndex);
5255     auto transition = tabContentAnimatedTransition.transition;
5256 
5257     if (!transition) {
5258         OnCustomAnimationFinish(fromIndex, toIndex, false);
5259         return;
5260     }
5261 
5262     auto proxy = AceType::MakeRefPtr<TabContentTransitionProxy>();
5263     proxy->SetFromIndex(fromIndex);
5264     proxy->SetToIndex(toIndex);
5265     proxy->SetFinishTransitionEvent([weak = WeakClaim(this), fromIndex, toIndex](bool hasOnChanged) {
5266         auto swiperPattern = weak.Upgrade();
5267         CHECK_NULL_VOID(swiperPattern);
5268         swiperPattern->OnCustomAnimationFinish(fromIndex, toIndex, hasOnChanged);
5269     });
5270 
5271     transition(proxy);
5272     currentProxyInAnimation_ = proxy;
5273 
5274     AnimationCallbackInfo info;
5275     info.currentOffset = GetCustomPropertyOffset();
5276     info.targetOffset = GetCustomPropertyTargetOffset();
5277     FireAnimationStartEvent(fromIndex, toIndex, info);
5278 
5279     auto pipeline = PipelineContext::GetCurrentContext();
5280     CHECK_NULL_VOID(pipeline);
5281     auto taskExecutor = pipeline->GetTaskExecutor();
5282     CHECK_NULL_VOID(taskExecutor);
5283 
5284     auto timeout = tabContentAnimatedTransition.timeout;
5285     auto timeoutTask = [weak = AceType::WeakClaim(AceType::RawPtr(proxy)), fromIndex, toIndex] {
5286         auto transitionProxy = weak.Upgrade();
5287         CHECK_NULL_VOID(transitionProxy);
5288         transitionProxy->FinishTransition();
5289     };
5290 
5291     taskExecutor->PostDelayedTask(timeoutTask, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperFinishTransition");
5292 }
5293 
OnCustomAnimationFinish(int32_t fromIndex,int32_t toIndex,bool hasOnChanged)5294 void SwiperPattern::OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged)
5295 {
5296     customAnimationToIndex_.reset();
5297     needUnmountIndexs_.insert(fromIndex);
5298     indexsInAnimation_.erase(toIndex);
5299 
5300     if (!hasOnChanged) {
5301         const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5302         CHECK_NULL_VOID(props);
5303         props->UpdateIndexWithoutMeasure(GetLoopIndex(toIndex));
5304         oldIndex_ = fromIndex;
5305 
5306         AnimationCallbackInfo info;
5307         info.currentOffset = GetCustomPropertyOffset();
5308         FireAnimationEndEvent(toIndex, info);
5309     }
5310 
5311     if (indexsInAnimation_.empty()) {
5312         currentProxyInAnimation_ = nullptr;
5313     }
5314     auto curChildFrame = GetCurrentFrameNode(toIndex);
5315     if (curChildFrame) {
5316         FlushFocus(curChildFrame);
5317     }
5318     auto host = GetHost();
5319     CHECK_NULL_VOID(host);
5320     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5321     auto pipeline = PipelineContext::GetCurrentContext();
5322     if (pipeline) {
5323         pipeline->FlushUITasks();
5324         pipeline->FlushMessages();
5325     }
5326 }
5327 
SetSwiperEventCallback(bool disableSwipe)5328 void SwiperPattern::SetSwiperEventCallback(bool disableSwipe)
5329 {
5330     CHECK_NULL_VOID(swiperController_);
5331     auto removeSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
5332         auto swiperPattern = weak.Upgrade();
5333         CHECK_NULL_VOID(swiperPattern);
5334         auto host = swiperPattern->GetHost();
5335         CHECK_NULL_VOID(host);
5336         auto hub = host->GetEventHub<EventHub>();
5337         CHECK_NULL_VOID(hub);
5338         auto gestureHub = hub->GetOrCreateGestureEventHub();
5339         CHECK_NULL_VOID(gestureHub);
5340         gestureHub->RemoveTouchEvent(swiperPattern->touchEvent_);
5341         if (!disableSwipe) {
5342             gestureHub->RemovePanEvent(swiperPattern->panEvent_);
5343         }
5344     };
5345     swiperController_->SetRemoveSwiperEventCallback(std::move(removeSwiperEventCallback));
5346 
5347     auto addSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
5348         auto swiperPattern = weak.Upgrade();
5349         CHECK_NULL_VOID(swiperPattern);
5350         auto host = swiperPattern->GetHost();
5351         CHECK_NULL_VOID(host);
5352         auto hub = host->GetEventHub<EventHub>();
5353         CHECK_NULL_VOID(hub);
5354         auto gestureHub = hub->GetOrCreateGestureEventHub();
5355         CHECK_NULL_VOID(gestureHub);
5356         gestureHub->AddTouchEvent(swiperPattern->touchEvent_);
5357         if (!disableSwipe) {
5358             gestureHub->AddPanEvent(swiperPattern->panEvent_, swiperPattern->panDirection_, 1, DEFAULT_PAN_DISTANCE);
5359         }
5360     };
5361     swiperController_->SetAddSwiperEventCallback(std::move(addSwiperEventCallback));
5362 }
5363 
UpdateSwiperPanEvent(bool disableSwipe)5364 void SwiperPattern::UpdateSwiperPanEvent(bool disableSwipe)
5365 {
5366     auto host = GetHost();
5367     CHECK_NULL_VOID(host);
5368     auto hub = host->GetEventHub<EventHub>();
5369     CHECK_NULL_VOID(hub);
5370     auto gestureHub = hub->GetOrCreateGestureEventHub();
5371     CHECK_NULL_VOID(gestureHub);
5372 
5373     if (!disableSwipe) {
5374         InitPanEvent(gestureHub);
5375     } else if (panEvent_) {
5376         gestureHub->RemovePanEvent(panEvent_);
5377         panEvent_.Reset();
5378         if (isDragging_) {
5379             HandleDragEnd(0.0);
5380         }
5381     }
5382 }
5383 
ProcessDelta(float & delta,float mainSize,float deltaSum)5384 void SwiperPattern::ProcessDelta(float& delta, float mainSize, float deltaSum)
5385 {
5386     if (std::abs(delta) > mainSize) {
5387         delta = delta > 0 ? mainSize : -mainSize;
5388     }
5389 
5390     if ((std::abs(deltaSum + delta)) > mainSize) {
5391         delta = GreatNotEqual((deltaSum + delta), 0) ? (mainSize - deltaSum) : (-deltaSum - mainSize);
5392     }
5393 }
5394 
ContentWillChange(int32_t comingIndex)5395 bool SwiperPattern::ContentWillChange(int32_t comingIndex)
5396 {
5397     return ContentWillChange(GetCurrentIndex(), comingIndex);
5398 }
5399 
ContentWillChange(int32_t currentIndex,int32_t comingIndex)5400 bool SwiperPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
5401 {
5402     auto host = GetHost();
5403     CHECK_NULL_RETURN(host, true);
5404     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
5405     CHECK_NULL_RETURN(tabsNode, true);
5406     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
5407     CHECK_NULL_RETURN(tabsPattern, true);
5408     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
5409     CHECK_NULL_RETURN(tabBarNode, true);
5410     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
5411     CHECK_NULL_RETURN(tabBarPattern, true);
5412     if (!tabBarPattern->GetTabContentWillChangeFlag() && tabsPattern->GetInterceptStatus() &&
5413         currentIndex != comingIndex) {
5414         tabBarPattern->ResetTabContentWillChangeFlag();
5415         auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
5416         return ret.has_value() ? ret.value() : true;
5417     }
5418     tabBarPattern->ResetTabContentWillChangeFlag();
5419     return true;
5420 }
5421 
ParseTabsIsRtl()5422 bool SwiperPattern::ParseTabsIsRtl()
5423 {
5424     auto host = GetHost();
5425     CHECK_NULL_RETURN(host, false);
5426     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
5427     CHECK_NULL_RETURN(tabsNode, false);
5428     auto tabLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
5429     CHECK_NULL_RETURN(tabLayoutProperty, false);
5430     bool isRTL = tabLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
5431     return isRTL;
5432 }
5433 
CheckSwiperPanEvent(float mainDeltaOrVelocity)5434 bool SwiperPattern::CheckSwiperPanEvent(float mainDeltaOrVelocity)
5435 {
5436     int32_t currentIndex = GetCurrentIndex();
5437     int32_t comingIndex = currentIndex;
5438     auto isRtl = ParseTabsIsRtl();
5439     if (isRtl) {
5440         mainDeltaOrVelocity = -mainDeltaOrVelocity;
5441     }
5442     if (GreatNotEqual(mainDeltaOrVelocity, 0.0)) {
5443         comingIndex = comingIndex < 1 ? 0 : comingIndex - 1;
5444     } else if (LessNotEqual(mainDeltaOrVelocity, 0.0)) {
5445         comingIndex = comingIndex > TotalCount() - INDEX_DIFF_TWO ? TotalCount() - 1 : comingIndex + 1;
5446     }
5447 
5448     auto iter = indexCanChangeMap_.find(comingIndex);
5449     if (iter != indexCanChangeMap_.end()) {
5450         return iter->second;
5451     }
5452     bool ret = ContentWillChange(currentIndex, comingIndex);
5453     indexCanChangeMap_.emplace(comingIndex, ret);
5454     return ret;
5455 }
5456 
HandleTouchBottomLoopOnRTL()5457 void SwiperPattern::HandleTouchBottomLoopOnRTL()
5458 {
5459     auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5460     auto currentIndex = GetLoopIndex(currentIndex_);
5461     bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
5462     bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
5463                                                      gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
5464     if (followTouchBottom) {
5465         if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
5466             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5467         } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
5468             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5469         }
5470         return;
5471     }
5472 
5473     if (currentFirstIndex == 0 && currentIndex == TotalCount() - 1 &&
5474         gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT) {
5475         touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5476         return;
5477     }
5478 
5479     if (currentFirstIndex == TotalCount() - 1 && currentIndex == 0 &&
5480         gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
5481         touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5482         return;
5483     }
5484 }
5485 
HandleTouchBottomLoop()5486 void SwiperPattern::HandleTouchBottomLoop()
5487 {
5488     auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5489     auto currentIndex = GetLoopIndex(currentIndex_);
5490     if (IsHorizontalAndRightToLeft()) {
5491         currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
5492         currentIndex = TotalCount() - 1 - currentIndex;
5493     }
5494 
5495     bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
5496     bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
5497                                                      gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
5498     if (followTouchBottom) {
5499         if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
5500             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5501         } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
5502             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5503         }
5504         return;
5505     }
5506 
5507     bool leftReleaseTouchBottom = (commTouchBottom && (currentIndex == 0 && gestureState_ ==
5508         GestureState::GESTURE_STATE_RELEASE_LEFT));
5509     bool rightReleaseTouchBottom = ((currentFirstIndex == 0) && (currentIndex == TotalCount() - 1) &&
5510                                     gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT);
5511     if (leftReleaseTouchBottom || rightReleaseTouchBottom) {
5512         if (currentIndex == 0) {
5513             // left bottom
5514             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5515         } else if (currentIndex == TotalCount() - 1) {
5516             // right bottom
5517             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5518         }
5519     }
5520     return;
5521 }
5522 
CalculateGestureStateOnRTL(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)5523 void SwiperPattern::CalculateGestureStateOnRTL(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
5524 {
5525     if (GreatNotEqual(additionalOffset, 0.0f)) {
5526         gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
5527         needTurn_ = false;
5528         return;
5529     }
5530 
5531     if (LessNotEqual(additionalOffset, 0.0f)) {
5532         gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
5533         needTurn_ = false;
5534         return;
5535     }
5536 
5537     auto currentIndex = GetLoopIndex(currentIndex_);
5538     auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5539     if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
5540         needTurn_ = true;
5541         if (isTouchDown_ && GreatOrEqual(mainDeltaSum_, 0.0f)) {
5542             needTurn_ = false;
5543         }
5544     } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
5545         needTurn_ = true;
5546         if (isTouchDown_ && (LessOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
5547             needTurn_ = false;
5548         }
5549     }
5550 
5551     if (!IsLoop()) {
5552         needTurn_ = false;
5553     }
5554 
5555     if (currentFirstIndex >= currentIndex) {
5556         gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
5557         return;
5558     }
5559 
5560     gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
5561 }
5562 
CalculateGestureState(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)5563 void SwiperPattern::CalculateGestureState(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
5564 {
5565     auto currentIndex = GetLoopIndex(currentIndex_);
5566     auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5567     if (IsHorizontalAndRightToLeft()) {
5568         preFirstIndex = TotalCount() - 1 - preFirstIndex;
5569         currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
5570         currentIndex = TotalCount() - 1 - currentIndex;
5571     }
5572 
5573     // Keep follow hand
5574     if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
5575         needTurn_ = true;
5576         if (isTouchDown_ && LessOrEqual(mainDeltaSum_, 0.0f)) {
5577             needTurn_ = false;
5578         }
5579     } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
5580         needTurn_ = true;
5581         if (isTouchDown_ && (GreatOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
5582             needTurn_ = false;
5583         }
5584     }
5585 
5586     if (GreatNotEqual(additionalOffset, 0.0f)) {
5587         gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
5588         needTurn_ = false;
5589     } else if (LessNotEqual(additionalOffset, 0.0f)) {
5590         gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
5591         needTurn_ = false;
5592     } else if (currentFirstIndex >= currentIndex) {
5593         gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
5594 
5595         if (!IsLoop() && currentFirstIndex == 0 && GreatOrEqual(mainDeltaSum_, 0.0f)) {
5596             gestureState_ = GestureState::GESTURE_STATE_FOLLOW_LEFT;
5597             needTurn_ = false;
5598         }
5599 
5600         if (!IsLoop() && currentFirstIndex == TotalCount() - 1 && LessOrEqual(mainDeltaSum_, 0.0f)) {
5601             gestureState_ = GestureState::GESTURE_STATE_FOLLOW_RIGHT;
5602             needTurn_ = false;
5603         }
5604     } else if (currentFirstIndex < currentIndex) {
5605         gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
5606     }
5607     return;
5608 }
5609 
CalcCurrentPageStatusOnRTL(float additionalOffset) const5610 std::pair<float, float> SwiperPattern::CalcCurrentPageStatusOnRTL(float additionalOffset) const
5611 {
5612     float currentTurnPageRate = FLT_MAX;
5613     auto firstIndex = currentFirstIndex_;
5614     auto itemMainSize = CalculateVisibleSize();
5615     for (auto iter = itemPosition_.rbegin(); iter != itemPosition_.rend(); iter++) {
5616         auto startPos = itemMainSize - iter->second.endPos;
5617         auto endPos = itemMainSize - iter->second.startPos;
5618         if (LessNotEqual((startPos + additionalOffset), 0) && LessNotEqual((endPos + additionalOffset), 0)) {
5619             continue;
5620         }
5621         if (GreatOrEqual((startPos + additionalOffset), 0) && GreatNotEqual((endPos + additionalOffset), 0)) {
5622             firstIndex = iter->first;
5623             currentTurnPageRate = 0.0f;
5624             break;
5625         }
5626         if (GreatNotEqual((endPos + additionalOffset), 0)) {
5627             firstIndex = iter->first;
5628             currentTurnPageRate =
5629                 (NearEqual(endPos, startPos) ? 0 : ((startPos + additionalOffset) / (endPos - startPos)));
5630             break;
5631         }
5632     }
5633 
5634     return std::make_pair(currentTurnPageRate, firstIndex);
5635 }
5636 
CalcCurrentPageStatus(float additionalOffset) const5637 std::pair<float, float> SwiperPattern::CalcCurrentPageStatus(float additionalOffset) const
5638 {
5639     float currentTurnPageRate = FLT_MAX;
5640     auto firstIndex = currentFirstIndex_;
5641     for (const auto& iter : itemPosition_) {
5642         if (LessNotEqual((iter.second.startPos + additionalOffset), 0) &&
5643             LessNotEqual((iter.second.endPos + additionalOffset), 0)) {
5644             continue;
5645         }
5646         if (GreatOrEqual((iter.second.startPos + additionalOffset), 0) &&
5647             GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
5648             firstIndex = iter.first;
5649             currentTurnPageRate = 0.0f;
5650             break;
5651         }
5652         if (GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
5653             firstIndex = iter.first;
5654             currentTurnPageRate =
5655                 (NearEqual(iter.second.endPos, iter.second.startPos)
5656                         ? 0
5657                         : ((iter.second.startPos + additionalOffset) / (iter.second.endPos - iter.second.startPos)));
5658             break;
5659         }
5660     }
5661 
5662     return std::make_pair(currentTurnPageRate, firstIndex);
5663 }
5664 
StopIndicatorAnimation(bool ifImmediately)5665 void SwiperPattern::StopIndicatorAnimation(bool ifImmediately)
5666 {
5667     AnimationUtils::StopAnimation(indicatorAnimation_);
5668 
5669     if (stopIndicatorAnimationFunc_) {
5670         stopIndicatorAnimationFunc_(ifImmediately);
5671     }
5672 }
5673 
FireWillHideEvent(int32_t willHideIndex) const5674 void SwiperPattern::FireWillHideEvent(int32_t willHideIndex) const
5675 {
5676     if (!hasTabsAncestor_) {
5677         return;
5678     }
5679     auto host = GetHost();
5680     CHECK_NULL_VOID(host);
5681     auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willHideIndex));
5682     CHECK_NULL_VOID(tabContentNode);
5683     auto tabContentEventHub = tabContentNode->GetEventHub<TabContentEventHub>();
5684     CHECK_NULL_VOID(tabContentEventHub);
5685     tabContentEventHub->FireWillHideEvent();
5686 }
5687 
FireWillShowEvent(int32_t willShowIndex) const5688 void SwiperPattern::FireWillShowEvent(int32_t willShowIndex) const
5689 {
5690     if (!hasTabsAncestor_) {
5691         return;
5692     }
5693     auto host = GetHost();
5694     CHECK_NULL_VOID(host);
5695     auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willShowIndex));
5696     CHECK_NULL_VOID(tabContentNode);
5697     auto tabContentEventHub = tabContentNode->GetEventHub<TabContentEventHub>();
5698     CHECK_NULL_VOID(tabContentEventHub);
5699     tabContentEventHub->FireWillShowEvent();
5700 }
5701 
SetOnHiddenChangeForParent()5702 void SwiperPattern::SetOnHiddenChangeForParent()
5703 {
5704     auto host = GetHost();
5705     CHECK_NULL_VOID(host);
5706     auto parent = host->GetAncestorNodeOfFrame();
5707     CHECK_NULL_VOID(parent);
5708     while (parent) {
5709         if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
5710             break;
5711         }
5712         parent = parent->GetAncestorNodeOfFrame();
5713     }
5714     auto onHiddenChange = [weak = WeakClaim(this)](bool isShow) {
5715         auto swiperPattern = weak.Upgrade();
5716         CHECK_NULL_VOID(swiperPattern);
5717         auto index = swiperPattern->GetCurrentIndex();
5718 
5719         if (isShow) {
5720             swiperPattern->FireWillShowEvent(index);
5721         } else {
5722             swiperPattern->FireWillHideEvent(index);
5723         }
5724         swiperPattern->isParentHiddenChange_ = true;
5725     };
5726     CHECK_NULL_VOID(parent);
5727     if (parent->GetTag() == V2::PAGE_ETS_TAG) {
5728         auto pagePattern = parent->GetPattern<PagePattern>();
5729         CHECK_NULL_VOID(pagePattern);
5730         pagePattern->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
5731     }
5732 
5733     if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
5734         auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
5735         CHECK_NULL_VOID(navDestinationePattern);
5736         auto navDestinationEventHub = navDestinationePattern->GetEventHub<NavDestinationEventHub>();
5737         CHECK_NULL_VOID(navDestinationEventHub);
5738         navDestinationEventHub->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
5739     }
5740 }
5741 
RemoveOnHiddenChange()5742 void SwiperPattern::RemoveOnHiddenChange()
5743 {
5744     auto host = GetHost();
5745     CHECK_NULL_VOID(host);
5746     auto parent = host->GetAncestorNodeOfFrame();
5747     CHECK_NULL_VOID(parent);
5748     while (parent) {
5749         if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
5750             break;
5751         }
5752         parent = parent->GetAncestorNodeOfFrame();
5753     }
5754     CHECK_NULL_VOID(parent);
5755     if (parent->GetTag() == V2::PAGE_ETS_TAG) {
5756         auto pagePattern = parent->GetPattern<PagePattern>();
5757         CHECK_NULL_VOID(pagePattern);
5758         pagePattern->RemoveOnHiddenChange(host->GetId());
5759     }
5760     if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
5761         auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
5762         CHECK_NULL_VOID(navDestinationePattern);
5763         auto navDestinationEventHub = navDestinationePattern->GetEventHub<NavDestinationEventHub>();
5764         CHECK_NULL_VOID(navDestinationEventHub);
5765         navDestinationEventHub->RemoveOnHiddenChange(host->GetId());
5766     }
5767 }
5768 
FindLazyForEachNode(RefPtr<UINode> baseNode,bool isSelfNode) const5769 std::optional<RefPtr<UINode>> SwiperPattern::FindLazyForEachNode(RefPtr<UINode> baseNode, bool isSelfNode) const
5770 {
5771     if (AceType::DynamicCast<LazyForEachNode>(baseNode)) {
5772         return baseNode;
5773     }
5774     if (AceType::DynamicCast<RepeatVirtualScrollNode>(baseNode)) {
5775         return baseNode;
5776     }
5777     if (!isSelfNode && AceType::DynamicCast<FrameNode>(baseNode)) {
5778         return std::nullopt;
5779     }
5780     for (const auto& child : baseNode->GetChildren()) {
5781         auto targetNode = FindLazyForEachNode(child, false);
5782         if (targetNode.has_value()) {
5783             return targetNode;
5784         }
5785     }
5786     return std::nullopt;
5787 }
5788 
CreateNodePaintMethod()5789 RefPtr<NodePaintMethod> SwiperPattern::CreateNodePaintMethod()
5790 {
5791     const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5792     CHECK_NULL_RETURN(props, nullptr);
5793     const auto& paddingProperty = props->GetPaddingProperty();
5794     bool needClipPadding = paddingProperty != nullptr;
5795     bool needPaintFade = !IsLoop() && GetEdgeEffect() == EdgeEffect::FADE && !NearZero(fadeOffset_);
5796     auto paintMethod = MakeRefPtr<SwiperPaintMethod>(GetDirection(), fadeOffset_);
5797     paintMethod->SetNeedPaintFade(needPaintFade);
5798     paintMethod->SetNeedClipPadding(needClipPadding);
5799     return paintMethod;
5800 }
5801 
UpdateNodeRate()5802 void SwiperPattern::UpdateNodeRate()
5803 {
5804     auto host = GetHost();
5805     CHECK_NULL_VOID(host);
5806     auto pipelineContext = host->GetContext();
5807     CHECK_NULL_VOID(pipelineContext);
5808     auto frameRateManager = pipelineContext->GetFrameRateManager();
5809     CHECK_NULL_VOID(frameRateManager);
5810     auto nodeId = host->GetId();
5811     auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::GESTURE);
5812     if (iter != frameRateRange_.end() && iter->second->IsValid()) {
5813         auto expectedRate = iter->second->preferred_;
5814         TAG_LOGI(AceLogTag::ACE_SWIPER, "Expected gesture frame rate is: %{public}d", expectedRate);
5815         frameRateManager->UpdateNodeRate(nodeId, expectedRate);
5816     }
5817 }
5818 
GetMaxDisplayCount() const5819 int32_t SwiperPattern::GetMaxDisplayCount() const
5820 {
5821     if (!swiperParameters_ || !swiperParameters_->maxDisplayCountVal.has_value()) {
5822         return 0;
5823     }
5824 
5825     auto maxDisplayCount = swiperParameters_->maxDisplayCountVal.value();
5826     if (maxDisplayCount < MAX_DISPLAY_COUNT_MIN || maxDisplayCount > MAX_DISPLAY_COUNT_MAX) {
5827         return 0;
5828     }
5829 
5830     auto childrenSize = RealTotalCount();
5831     if (childrenSize <= maxDisplayCount) {
5832         return 0;
5833     }
5834 
5835     return maxDisplayCount;
5836 }
5837 
SetIndicatorChangeIndexStatus(bool withAnimation,std::optional<int32_t> startIndex)5838 void SwiperPattern::SetIndicatorChangeIndexStatus(bool withAnimation, std::optional<int32_t> startIndex)
5839 {
5840     auto host = GetHost();
5841     CHECK_NULL_VOID(host);
5842 
5843     auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
5844     if (!indicatorNode || indicatorNode->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
5845         return;
5846     }
5847 
5848     auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
5849     CHECK_NULL_VOID(indicatorPattern);
5850 
5851     indicatorPattern->SetChangeIndexWithAnimation(withAnimation);
5852     indicatorPattern->SetStartIndex(startIndex);
5853 }
5854 
SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)5855 void SwiperPattern::SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)
5856 {
5857     if (GetMaxDisplayCount() <= 0) {
5858         return;
5859     }
5860 
5861     auto host = GetHost();
5862     CHECK_NULL_VOID(host);
5863 
5864     auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
5865     if (!indicatorNode || indicatorNode->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
5866         return;
5867     }
5868 
5869     auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
5870     CHECK_NULL_VOID(indicatorPattern);
5871 
5872     indicatorPattern->SetJumpIndex(jumpIndex);
5873 }
5874 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const5875 void SwiperPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
5876 {
5877     Pattern::ToJsonValue(json, filter);
5878     /* no fixed attr below, just return */
5879     if (filter.IsFastFilter()) {
5880         return;
5881     }
5882 
5883     auto nestedScroll = GetNestedScroll().forward;
5884     json->PutExtAttr("nestedScroll",
5885         nestedScroll == NestedScrollMode::SELF_ONLY ? "SwiperNestedScrollMode.SELF_ONLY"
5886                                                     : "SwiperNestedScrollMode.SELF_FIRST",
5887         filter);
5888     json->PutExtAttr("currentIndex", currentIndex_, filter);
5889     json->PutExtAttr("currentOffset", currentOffset_, filter);
5890     json->PutExtAttr("uiCastJumpIndex", uiCastJumpIndex_.value_or(-1), filter);
5891 
5892     if (indicatorIsBoolean_) {
5893         return;
5894     }
5895 
5896     auto indicatorType = GetIndicatorType();
5897     if (indicatorType == SwiperIndicatorType::DOT) {
5898         json->PutExtAttr("indicator", SwiperHelper::GetDotIndicatorStyle(GetSwiperParameters()).c_str(), filter);
5899     } else {
5900         json->PutExtAttr(
5901             "indicator", SwiperHelper::GetDigitIndicatorStyle(GetSwiperDigitalParameters()).c_str(), filter);
5902     }
5903 }
5904 
FromJson(const std::unique_ptr<JsonValue> & json)5905 void SwiperPattern::FromJson(const std::unique_ptr<JsonValue>& json)
5906 {
5907     currentIndex_ = json->GetInt("currentIndex");
5908     auto currentOffset = json->GetDouble("currentOffset");
5909     auto jumpIndex = json->GetInt("uiCastJumpIndex");
5910     if (currentOffset != currentOffset_) {
5911         auto delta = currentOffset - currentOffset_;
5912         UpdateCurrentOffset(delta);
5913     } else if (jumpIndex >= 0) {
5914         jumpIndex_ = jumpIndex;
5915         MarkDirtyNodeSelf();
5916     }
5917     Pattern::FromJson(json);
5918 }
5919 
GetGestureState()5920 GestureState SwiperPattern::GetGestureState()
5921 {
5922     auto gestureState = gestureState_;
5923     if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
5924         gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
5925         gestureState_ = GestureState::GESTURE_STATE_NONE;
5926     }
5927 
5928     return gestureState;
5929 }
5930 
SetSwiperController(const RefPtr<SwiperController> & controller)5931 void SwiperPattern::SetSwiperController(const RefPtr<SwiperController>& controller)
5932 {
5933     swiperController_ = controller;
5934     SwiperHelper::InitSwiperController(controller, WeakClaim(this));
5935 }
5936 
IsItemOverlay() const5937 bool SwiperPattern::IsItemOverlay() const
5938 {
5939     if (itemPosition_.empty()) {
5940         return false;
5941     }
5942     float lastItemEndPos = 0.0f;
5943     for (auto& item : itemPosition_) {
5944         auto frameNode = item.second.node;
5945         if (!frameNode) {
5946             continue;
5947         }
5948         auto renderContext = frameNode->GetRenderContext();
5949         if (!renderContext) {
5950             continue;
5951         }
5952         RectF rect = renderContext->GetPaintRectWithoutTransform();
5953         if (item.first == itemPosition_.begin()->first) {
5954             lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
5955             continue;
5956         }
5957         float currentItemStartPos = direction_ == Axis::HORIZONTAL ? rect.Left() : rect.Top();
5958         if (GreatNotEqual(lastItemEndPos, currentItemStartPos)) {
5959             return true;
5960         }
5961         lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
5962     }
5963     return false;
5964 }
5965 
CheckSpecialItemCount() const5966 void SwiperPattern::CheckSpecialItemCount() const
5967 {
5968     auto swiperNode = AceType::DynamicCast<SwiperNode>(GetHost());
5969     CHECK_NULL_VOID(swiperNode);
5970     swiperNode->SetSpecialItemCount(indicatorId_.has_value() + leftButtonId_.has_value() + rightButtonId_.has_value() +
5971                                     leftCaptureId_.has_value() + rightCaptureId_.has_value());
5972 }
5973 } // namespace OHOS::Ace::NG
5974