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