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