• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <cstdint>
21 #include <optional>
22 
23 #include "base/error/error_code.h"
24 #include "base/geometry/axis.h"
25 #include "base/geometry/dimension.h"
26 #include "base/geometry/ng/offset_t.h"
27 #include "base/log/dump_log.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/scrollable/scrollable_properties.h"
39 #include "core/components_ng/pattern/swiper/swiper_layout_algorithm.h"
40 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
41 #include "core/components_ng/pattern/swiper/swiper_model.h"
42 #include "core/components_ng/pattern/swiper/swiper_paint_property.h"
43 #include "core/components_ng/pattern/swiper/swiper_utils.h"
44 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_arrow_pattern.h"
45 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_pattern.h"
46 #include "core/components_ng/pattern/tabs/tabs_node.h"
47 #include "core/components_ng/pattern/tabs/tabs_pattern.h"
48 #include "core/components_ng/property/measure_utils.h"
49 #include "core/components_ng/property/property.h"
50 #include "core/components_ng/syntax/for_each_node.h"
51 #include "core/components_ng/syntax/lazy_for_each_node.h"
52 #include "core/components_v2/inspector/inspector_constants.h"
53 #include "core/event/ace_events.h"
54 #include "core/event/touch_event.h"
55 #include "core/pipeline_ng/pipeline_context.h"
56 
57 namespace OHOS::Ace::NG {
58 namespace {
59 
60 // TODO use theme.
61 constexpr int32_t MIN_TURN_PAGE_VELOCITY = 1200;
62 constexpr int32_t NEW_MIN_TURN_PAGE_VELOCITY = 780;
63 constexpr Dimension INDICATOR_BORDER_RADIUS = 16.0_vp;
64 
65 constexpr Dimension SWIPER_MARGIN = 16.0_vp;
66 constexpr Dimension SWIPER_GUTTER = 16.0_vp;
67 constexpr float PX_EPSILON = 0.01f;
68 constexpr float FADE_DURATION = 500.0f;
69 constexpr float SPRING_DURATION = 600.0f;
70 constexpr int32_t INDEX_DIFF_TWO = 2;
71 const std::string SWIPER_DRAG_SCENE = "swiper_drag_scene";
72 const std::string FADE_PROPERTY_NAME = "fade";
73 const std::string SPRING_PROPERTY_NAME = "spring";
74 const std::string INDICATOR_PROPERTY_NAME = "indicator";
75 // TODO define as common method
CalculateFriction(float gamma)76 float CalculateFriction(float gamma)
77 {
78     constexpr float SCROLL_RATIO = 0.72f;
79     if (GreatOrEqual(gamma, 1.0)) {
80         gamma = 1.0;
81     }
82     return SCROLL_RATIO * static_cast<float>(std::pow(1.0 - gamma, SQUARE));
83 }
84 
85 } // namespace
86 
SwiperPattern()87 SwiperPattern::SwiperPattern()
88 {
89     swiperController_ = MakeRefPtr<SwiperController>();
90     InitSwiperController();
91 }
92 
OnAttachToFrameNode()93 void SwiperPattern::OnAttachToFrameNode()
94 {
95     auto host = GetHost();
96     CHECK_NULL_VOID(host);
97     host->GetRenderContext()->SetClipToFrame(true);
98     host->GetRenderContext()->SetClipToBounds(true);
99     host->GetRenderContext()->UpdateClipEdge(true);
100     InitSurfaceChangedCallback();
101 }
102 
OnDetachFromFrameNode(FrameNode * node)103 void SwiperPattern::OnDetachFromFrameNode(FrameNode* node)
104 {
105     auto pipeline = PipelineContext::GetCurrentContext();
106     CHECK_NULL_VOID(pipeline);
107     if (HasSurfaceChangedCallback()) {
108         pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
109     }
110     pipeline->RemoveWindowStateChangedCallback(node->GetId());
111 }
112 
CreateLayoutAlgorithm()113 RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
114 {
115     auto host = GetHost();
116     CHECK_NULL_RETURN(host, nullptr);
117     auto swiperLayoutProperty = host->GetLayoutProperty<SwiperLayoutProperty>();
118     CHECK_NULL_RETURN(swiperLayoutProperty, nullptr);
119 
120     auto swiperLayoutAlgorithm = MakeRefPtr<SwiperLayoutAlgorithm>();
121     if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
122         swiperLayoutAlgorithm->SetUseCustomAnimation(true);
123         swiperLayoutAlgorithm->SetCustomAnimationToIndex(customAnimationToIndex_);
124         swiperLayoutAlgorithm->SetIndexsInAnimation(indexsInAnimation_);
125         swiperLayoutAlgorithm->SetNeedUnmountIndexs(needUnmountIndexs_);
126         return swiperLayoutAlgorithm;
127     }
128 
129     if (jumpIndex_) {
130         swiperLayoutAlgorithm->SetJumpIndex(jumpIndex_.value());
131     } else if (targetIndex_) {
132         swiperLayoutAlgorithm->SetTargetIndex(targetIndex_.value());
133     }
134     swiperLayoutAlgorithm->SetContentCrossSize(contentCrossSize_);
135     swiperLayoutAlgorithm->SetMainSizeIsMeasured(mainSizeIsMeasured_);
136     swiperLayoutAlgorithm->SetContentMainSize(contentMainSize_);
137     swiperLayoutAlgorithm->SetCurrentDelta(currentDelta_);
138     swiperLayoutAlgorithm->SetItemsPosition(itemPosition_);
139     swiperLayoutAlgorithm->SetIsNeedResetPrevMarginAndNextMargin();
140     if (IsOutOfBoundary() && !IsLoop()) {
141         swiperLayoutAlgorithm->SetOverScrollFeature();
142     }
143     swiperLayoutAlgorithm->SetTotalItemCount(TotalCount());
144     swiperLayoutAlgorithm->SetIsLoop(IsLoop());
145     swiperLayoutAlgorithm->SetSwipeByGroup(IsSwipeByGroup());
146     swiperLayoutAlgorithm->SetRealTotalCount(RealTotalCount());
147     swiperLayoutAlgorithm->SetPlaceItemWidth(placeItemWidth_);
148 
149     auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
150     CHECK_NULL_RETURN(host, nullptr);
151     auto effect = swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
152     bool canOverScroll = effect == EdgeEffect::SPRING;
153     swiperLayoutAlgorithm->SetCanOverScroll(canOverScroll);
154     return swiperLayoutAlgorithm;
155 }
156 
OnIndexChange()157 void SwiperPattern::OnIndexChange()
158 {
159     auto totalCount = TotalCount();
160     if (NonPositive(totalCount)) {
161         return;
162     }
163 
164     auto oldIndex = GetLoopIndex(oldIndex_);
165     if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != totalCount) {
166         oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
167         oldChildrenSize_ = totalCount;
168     }
169 
170     auto targetIndex = GetLoopIndex(CurrentIndex());
171     if (oldIndex != targetIndex) {
172         auto swiperEventHub = GetEventHub<SwiperEventHub>();
173         CHECK_NULL_VOID(swiperEventHub);
174         swiperEventHub->FireChangeEvent(targetIndex);
175         swiperEventHub->FireIndicatorChangeEvent(targetIndex);
176         swiperEventHub->FireChangeDoneEvent(moveDirection_);
177         // lazyBuild feature.
178         SetLazyLoadFeature(true);
179     }
180 }
181 
StopAndResetSpringAnimation()182 void SwiperPattern::StopAndResetSpringAnimation()
183 {
184     if (springAnimationIsRunning_) {
185         AnimationUtils::StopAnimation(springAnimation_);
186         currentDelta_ = 0.0f;
187         itemPosition_.clear();
188         isVoluntarilyClear_ = true;
189         jumpIndex_ = currentIndex_;
190         springAnimationIsRunning_ = false;
191     }
192 }
193 
OnLoopChange()194 void SwiperPattern::OnLoopChange()
195 {
196     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
197     CHECK_NULL_VOID(layoutProperty);
198 
199     if (!preLoop_.has_value()) {
200         preLoop_ = layoutProperty->GetLoop().value_or(true);
201         return;
202     }
203 
204     if (preLoop_.value() != layoutProperty->GetLoop().value_or(true) &&
205         (layoutProperty->GetPrevMargin().has_value() || layoutProperty->GetNextMargin().has_value())) {
206         jumpIndex_ = GetLoopIndex(currentIndex_);
207         preLoop_ = layoutProperty->GetLoop().value_or(true);
208     }
209 }
210 
AdjustCurrentIndexOnSwipePage(int32_t index)211 void SwiperPattern::AdjustCurrentIndexOnSwipePage(int32_t index)
212 {
213     auto adjustIndex = SwiperUtils::ComputePageIndex(index, GetDisplayCount());
214     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
215     CHECK_NULL_VOID(layoutProperty);
216     layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(adjustIndex));
217     currentIndex_ = GetLoopIndex(adjustIndex);
218 }
219 
OnModifyDone()220 void SwiperPattern::OnModifyDone()
221 {
222     currentOffset_ = 0.0f;
223     Pattern::OnModifyDone();
224     auto host = GetHost();
225     CHECK_NULL_VOID(host);
226     auto hub = host->GetEventHub<EventHub>();
227     CHECK_NULL_VOID(hub);
228     auto gestureHub = hub->GetOrCreateGestureEventHub();
229     CHECK_NULL_VOID(gestureHub);
230     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
231     CHECK_NULL_VOID(layoutProperty);
232 
233     InitIndicator();
234     InitArrow();
235     SetLazyLoadIsLoop();
236     RegisterVisibleAreaChange();
237     InitTouchEvent(gestureHub);
238     InitHoverMouseEvent();
239     StopAndResetSpringAnimation();
240     OnLoopChange();
241     if ((layoutProperty->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) {
242         StopPropertyTranslateAnimation(isFinishAnimation_);
243         StopTranslateAnimation();
244         StopSpringAnimation();
245         StopFadeAnimation();
246         StopIndicatorAnimation();
247         currentOffset_ = 0.0f;
248         mainSizeIsMeasured_ = false;
249         itemPosition_.clear();
250         isVoluntarilyClear_ = true;
251         jumpIndex_ = currentIndex_;
252         for (const auto& child : host->GetChildren()) {
253             if (child->GetTag() == V2::JS_LAZY_FOR_EACH_ETS_TAG) {
254                 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(child);
255                 CHECK_NULL_VOID(lazyForEachNode);
256                 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
257             }
258         }
259     }
260     bool disableSwipe = IsDisableSwipe();
261     UpdateSwiperPanEvent(disableSwipe);
262 
263     auto focusHub = host->GetFocusHub();
264     if (focusHub) {
265         InitOnKeyEvent(focusHub);
266         InitOnFocusInternal(focusHub);
267     }
268 
269     SetSwiperEventCallback(disableSwipe);
270 
271     auto updateCubicCurveCallback = [weak = WeakClaim(this)]() {
272         auto swiperPattern = weak.Upgrade();
273         CHECK_NULL_VOID(swiperPattern);
274         auto host = swiperPattern->GetHost();
275         CHECK_NULL_VOID(host);
276         auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
277         CHECK_NULL_VOID(swiperPaintProperty);
278         auto curve = MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
279         swiperPaintProperty->UpdateCurve(curve);
280     };
281     swiperController_->SetUpdateCubicCurveCallback(std::move(updateCubicCurveCallback));
282 
283     if (IsAutoPlay()) {
284         StartAutoPlay();
285     } else {
286         translateTask_.Cancel();
287     }
288 
289     SetAccessibilityAction();
290     placeItemWidth_.reset();
291 
292     if (IsSwipeByGroup()) {
293         needAdjustIndex_ = true;
294     }
295 }
296 
OnAfterModifyDone()297 void SwiperPattern::OnAfterModifyDone()
298 {
299     auto host = GetHost();
300     CHECK_NULL_VOID(host);
301     auto inspectorId = host->GetInspectorId().value_or("");
302     if (!inspectorId.empty()) {
303         Recorder::NodeDataCache::Get().PutInt(inspectorId, CurrentIndex());
304     }
305 }
306 
BeforeCreateLayoutWrapper()307 void SwiperPattern::BeforeCreateLayoutWrapper()
308 {
309     auto host = GetHost();
310     CHECK_NULL_VOID(host);
311     if (host->GetChildrenUpdated() != -1 && NeedAutoPlay() && !translateTask_) {
312         StartAutoPlay();
313         host->ChildrenUpdatedFrom(-1);
314     }
315 
316     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
317     CHECK_NULL_VOID(layoutProperty);
318     oldIndex_ = currentIndex_;
319     auto userSetCurrentIndex = CurrentIndex();
320     auto oldIndex = GetLoopIndex(oldIndex_);
321     if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != TotalCount()) {
322         oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
323         if (HasIndicatorNode()) {
324             StopIndicatorAnimation();
325             auto host = GetHost();
326             CHECK_NULL_VOID(host);
327             auto indicatorNode = DynamicCast<FrameNode>(
328                 host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
329             if (indicatorNode && indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
330                 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
331             }
332         }
333     }
334     if (userSetCurrentIndex < 0 || userSetCurrentIndex >= TotalCount()) {
335         currentIndex_ = 0;
336         layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
337     } else {
338         if (oldIndex != userSetCurrentIndex) {
339             currentIndex_ = userSetCurrentIndex;
340             propertyAnimationIndex_ = GetLoopIndex(propertyAnimationIndex_);
341         }
342     }
343 
344     if (IsSwipeByGroup() && needAdjustIndex_) {
345         AdjustCurrentIndexOnSwipePage(CurrentIndex());
346         needAdjustIndex_ = false;
347     }
348 
349     if (oldIndex_ != currentIndex_ || (itemPosition_.empty() && !isVoluntarilyClear_)) {
350         jumpIndex_ = GetLoopIndex(currentIndex_);
351         currentFirstIndex_ = jumpIndex_.value_or(0);
352         turnPageRate_ = 0.0f;
353     }
354     isVoluntarilyClear_ = false;
355     if (jumpIndex_) {
356         if ((jumpIndex_.value() < 0 || jumpIndex_.value() >= TotalCount()) && !IsLoop()) {
357             jumpIndex_ = 0;
358         }
359         targetIndex_.reset();
360         if (usePropertyAnimation_) {
361             StopPropertyTranslateAnimation(false, true);
362             currentDelta_ = 0.0f;
363             StopIndicatorAnimation();
364         }
365     }
366     if (mainSizeIsMeasured_ && isNeedResetPrevMarginAndNextMargin_) {
367         layoutProperty->UpdatePrevMarginWithoutMeasure(0.0_px);
368         layoutProperty->UpdateNextMarginWithoutMeasure(0.0_px);
369     }
370 }
371 
InitSurfaceChangedCallback()372 void SwiperPattern::InitSurfaceChangedCallback()
373 {
374     auto host = GetHost();
375     CHECK_NULL_VOID(host);
376     auto pipeline = host->GetContext();
377     CHECK_NULL_VOID(pipeline);
378     if (!HasSurfaceChangedCallback()) {
379         auto callbackId = pipeline->RegisterSurfaceChangedCallback(
380             [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
381                 WindowSizeChangeReason type) {
382                 if (type == WindowSizeChangeReason::UNDEFINED) {
383                     return;
384                 }
385                 auto swiper = weak.Upgrade();
386                 if (!swiper) {
387                     return;
388                 }
389 
390                 if (type == WindowSizeChangeReason::ROTATION) {
391                     swiper->windowSizeChangeReason_ = type;
392                     swiper->StopAutoPlay();
393                 }
394 
395                 swiper->StopPropertyTranslateAnimation(swiper->isFinishAnimation_);
396                 swiper->StopTranslateAnimation();
397                 swiper->StopSpringAnimation();
398                 swiper->StopFadeAnimation();
399                 swiper->StopIndicatorAnimation();
400 
401                 const auto& surfaceChangeCallback = swiper->swiperController_->GetSurfaceChangeCallback();
402                 if (surfaceChangeCallback) {
403                     surfaceChangeCallback();
404                 }
405                 swiper->currentOffset_ = 0.0f;
406                 swiper->itemPosition_.clear();
407                 swiper->isVoluntarilyClear_ = true;
408                 swiper->jumpIndex_ = swiper->currentIndex_;
409                 swiper->MarkDirtyNodeSelf();
410                 auto swiperNode = swiper->GetHost();
411                 CHECK_NULL_VOID(swiperNode);
412                 for (const auto& child : swiperNode->GetChildren()) {
413                     if (child->GetTag() == V2::JS_LAZY_FOR_EACH_ETS_TAG) {
414                         auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(child);
415                         CHECK_NULL_VOID(lazyForEachNode);
416                         lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
417                     }
418                 }
419             });
420         UpdateSurfaceChangedCallbackId(callbackId);
421     }
422 }
423 
FlushFocus(const RefPtr<FrameNode> & curShowFrame)424 void SwiperPattern::FlushFocus(const RefPtr<FrameNode>& curShowFrame)
425 {
426     CHECK_NULL_VOID(curShowFrame);
427     auto swiperHost = GetHost();
428     CHECK_NULL_VOID(swiperHost);
429     auto swiperFocusHub = swiperHost->GetFocusHub();
430     CHECK_NULL_VOID(swiperFocusHub);
431     auto showChildFocusHub = curShowFrame->GetFirstFocusHubChild();
432     CHECK_NULL_VOID(showChildFocusHub);
433     auto focusChildren = swiperFocusHub->GetChildren();
434     CHECK_NULL_VOID(!focusChildren.empty());
435     auto iter = focusChildren.rbegin();
436     if (IsShowIndicator()) {
437         ++iter;
438     }
439     if (HasLeftButtonNode()) {
440         ++iter;
441     }
442     if (HasRightButtonNode()) {
443         ++iter;
444     }
445     while (iter != focusChildren.rend()) {
446         auto child = *iter;
447         if (!child) {
448             ++iter;
449             continue;
450         }
451         if (child != showChildFocusHub) {
452             child->SetParentFocusable(false);
453         } else {
454             child->SetParentFocusable(true);
455         }
456         ++iter;
457     }
458 
459     RefPtr<FocusHub> needFocusNode = showChildFocusHub;
460     if (IsShowIndicator() && isLastIndicatorFocused_) {
461         needFocusNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
462     }
463     CHECK_NULL_VOID(needFocusNode);
464     lastWeakShowNode_ = AceType::WeakClaim(AceType::RawPtr(curShowFrame));
465     if (swiperFocusHub->IsCurrentFocus()) {
466         needFocusNode->RequestFocusImmediately();
467     } else {
468         swiperFocusHub->SetLastWeakFocusNode(AceType::WeakClaim(AceType::RawPtr(needFocusNode)));
469     }
470 }
GetFocusHubChild(std::string childFrameName)471 RefPtr<FocusHub> SwiperPattern::GetFocusHubChild(std::string childFrameName)
472 {
473     auto swiperHost = GetHost();
474     CHECK_NULL_RETURN(swiperHost, nullptr);
475     auto swiperFocusHub = swiperHost->GetFocusHub();
476     CHECK_NULL_RETURN(swiperFocusHub, nullptr);
477     auto focusChildren = swiperFocusHub->GetChildren();
478     CHECK_NULL_RETURN(!focusChildren.empty(), nullptr);
479     for (const auto& child : focusChildren) {
480         CHECK_NULL_RETURN(child, nullptr);
481         if (child->GetFrameName() == childFrameName) {
482             return child;
483         }
484     }
485     return nullptr;
486 }
487 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)488 WeakPtr<FocusHub> SwiperPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
489 {
490     auto curFocusNode = currentFocusNode.Upgrade();
491     CHECK_NULL_RETURN(curFocusNode, nullptr);
492     if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::UP) ||
493         (GetDirection() == Axis::HORIZONTAL && step == FocusStep::SHIFT_TAB) ||
494         (GetDirection() == Axis::VERTICAL && step == FocusStep::LEFT)) {
495         return PreviousFocus(curFocusNode);
496     }
497     if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
498         (GetDirection() == Axis::HORIZONTAL && step == FocusStep::TAB) ||
499         (GetDirection() == Axis::VERTICAL && step == FocusStep::RIGHT)) {
500         return NextFocus(curFocusNode);
501     }
502     return nullptr;
503 }
504 
PreviousFocus(const RefPtr<FocusHub> & curFocusNode)505 WeakPtr<FocusHub> SwiperPattern::PreviousFocus(const RefPtr<FocusHub>& curFocusNode)
506 {
507     CHECK_NULL_RETURN(curFocusNode, nullptr);
508     RefPtr<FocusHub> indicatorNode;
509     RefPtr<FocusHub> leftArrowNode;
510     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
511     CHECK_NULL_RETURN(layoutProperty, nullptr);
512     if (HasLeftButtonNode()) {
513         leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
514         CHECK_NULL_RETURN(leftArrowNode, nullptr);
515     }
516     if (HasIndicatorNode()) {
517         indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
518         CHECK_NULL_RETURN(indicatorNode, nullptr);
519     }
520     if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
521         isLastIndicatorFocused_ = false;
522         (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ? curFocusNode->SetParentFocusable(false)
523                                                         : curFocusNode->SetParentFocusable(true);
524         return nullptr;
525     }
526     if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
527         if (!HasLeftButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ||
528             layoutProperty->GetHoverShowValue(false)) {
529             isLastIndicatorFocused_ = true;
530             curFocusNode->SetParentFocusable(true);
531             return nullptr;
532         }
533         isLastIndicatorFocused_ = false;
534         leftArrowNode->SetParentFocusable(true);
535         return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
536     }
537     if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
538         if (HasIndicatorNode()) {
539             isLastIndicatorFocused_ = true;
540             indicatorNode->SetParentFocusable(true);
541             return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
542         }
543         if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
544             curFocusNode->SetParentFocusable(true);
545             return nullptr;
546         }
547         isLastIndicatorFocused_ = true;
548         leftArrowNode->SetParentFocusable(true);
549         return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
550     }
551     curFocusNode->SetParentFocusable(true);
552     return nullptr;
553 }
554 
NextFocus(const RefPtr<FocusHub> & curFocusNode)555 WeakPtr<FocusHub> SwiperPattern::NextFocus(const RefPtr<FocusHub>& curFocusNode)
556 {
557     CHECK_NULL_RETURN(curFocusNode, nullptr);
558     RefPtr<FocusHub> indicatorNode;
559     RefPtr<FocusHub> rightArrowNode;
560     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
561     CHECK_NULL_RETURN(layoutProperty, nullptr);
562     if (HasIndicatorNode()) {
563         indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
564         CHECK_NULL_RETURN(indicatorNode, nullptr);
565     }
566     if (HasRightButtonNode()) {
567         rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
568         CHECK_NULL_RETURN(rightArrowNode, nullptr);
569     }
570     if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
571         if (HasIndicatorNode()) {
572             isLastIndicatorFocused_ = true;
573             indicatorNode->SetParentFocusable(true);
574             return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
575         }
576         if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
577             curFocusNode->SetParentFocusable(true);
578             return nullptr;
579         }
580         isLastIndicatorFocused_ = true;
581         rightArrowNode->SetParentFocusable(true);
582         return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
583     }
584     if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
585         if (!HasRightButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ||
586             layoutProperty->GetHoverShowValue(false)) {
587             isLastIndicatorFocused_ = true;
588             curFocusNode->SetParentFocusable(true);
589             return nullptr;
590         }
591         isLastIndicatorFocused_ = false;
592         rightArrowNode->SetParentFocusable(true);
593         return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
594     }
595     if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
596         isLastIndicatorFocused_ = false;
597         (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ? curFocusNode->SetParentFocusable(false)
598                                                                        : curFocusNode->SetParentFocusable(true);
599         return nullptr;
600     }
601     curFocusNode->SetParentFocusable(true);
602     return nullptr;
603 }
604 
GetLoopIndex(int32_t originalIndex) const605 int32_t SwiperPattern::GetLoopIndex(int32_t originalIndex) const
606 {
607     if (TotalCount() <= 0) {
608         return originalIndex;
609     }
610     auto loopIndex = originalIndex;
611     while (loopIndex < 0) {
612         loopIndex = loopIndex + TotalCount();
613     }
614     loopIndex %= TotalCount();
615     return loopIndex;
616 }
617 
AdjustCurrentFocusIndex()618 void SwiperPattern::AdjustCurrentFocusIndex()
619 {
620     if (GetDisplayCount() <= 1) {
621         currentFocusIndex_ = currentIndex_;
622         return;
623     }
624 
625     if (currentFocusIndex_ >= currentIndex_ && currentFocusIndex_ < currentIndex_ + GetDisplayCount()) {
626         return;
627     }
628 
629     currentFocusIndex_ = currentIndex_;
630 }
631 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)632 bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
633 {
634     if (!isDragging_) {
635         SetLazyLoadFeature(true);
636     }
637 
638     auto isNotInit = true;
639     if (isInit_) {
640         isNotInit = false;
641         isInit_ = false;
642         // first load Swiper to preload page.
643         SetLazyLoadFeature(true);
644     } else {
645         OnIndexChange();
646         oldIndex_ = currentIndex_;
647     }
648 
649     if (!IsAutoPlay() && config.skipMeasure && config.skipLayout) {
650         return false;
651     }
652 
653     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
654     CHECK_NULL_RETURN(layoutProperty, false);
655     auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm();
656     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
657     auto swiperLayoutAlgorithm = DynamicCast<SwiperLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
658     CHECK_NULL_RETURN(swiperLayoutAlgorithm, false);
659 
660     if (layoutProperty->GetIsCustomAnimation().value_or(false)) {
661         needUnmountIndexs_ = swiperLayoutAlgorithm->GetNeedUnmountIndexs();
662         return false;
663     }
664 
665     autoLinearReachBoundary = false;
666     bool isJump = false;
667     itemPosition_ = std::move(swiperLayoutAlgorithm->GetItemPosition());
668     currentOffset_ -= swiperLayoutAlgorithm->GetCurrentOffset();
669     if (!itemPosition_.empty()) {
670         const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
671         if (turnPageRateCallback && isDragging_ && !NearZero(GetTranslateLength())) {
672             turnPageRateCallback(
673                 itemPosition_.begin()->first, -itemPosition_.begin()->second.startPos / GetTranslateLength());
674         }
675 
676         placeItemWidth_ = itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
677     }
678     auto host = GetHost();
679     CHECK_NULL_RETURN(host, false);
680     if (!targetIndex_) {
681         CheckMarkDirtyNodeForRenderIndicator();
682     }
683 
684     if (jumpIndex_) {
685         isJump = true;
686         UpdateCurrentIndex(swiperLayoutAlgorithm->GetCurrentIndex());
687         AdjustCurrentFocusIndex();
688         auto curChild = dirty->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_));
689         if (curChild) {
690             auto curChildFrame = curChild->GetHostNode();
691             CHECK_NULL_RETURN(curChildFrame, false);
692             FlushFocus(curChildFrame);
693         }
694         currentIndexOffset_ = 0.0f;
695         if (isNotInit) {
696             OnIndexChange();
697         }
698         jumpIndex_.reset();
699         auto delayTime = GetInterval() - GetDuration();
700         delayTime = std::clamp(delayTime, 0, delayTime);
701         if (NeedAutoPlay() && isUserFinish_) {
702             PostTranslateTask(delayTime);
703         }
704     } else if (targetIndex_) {
705         auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
706         auto iter = itemPosition_.find(targetIndexValue);
707         if (iter != itemPosition_.end()) {
708             float targetPos = 0.0f;
709             targetPos = iter->second.startPos;
710             auto context = PipelineContext::GetCurrentContext();
711             if (context) {
712                 // displayCount is auto, loop is false, if the content width less than windows size
713                 // need offset to keep right aligned
714                 bool isNeedOffset = (GetLoopIndex(iter->first) == TotalCount() - 1)
715                     && !layoutProperty->GetDisplayCount().has_value() && !IsLoop()
716                     && LessNotEqual(iter->second.endPos - iter->second.startPos, CalculateVisibleSize());
717                 float offset = isNeedOffset
718                     ? CalculateVisibleSize() - iter->second.endPos + iter->second.startPos : 0.0;
719                 targetPos -= offset;
720 
721                 auto nextIndex = iter->first;
722                 auto stopAutoPlay = false;
723                 if (AutoLinearAnimationNeedReset(targetPos)) {
724                     auto firstItem = GetFirstItemInfoInVisibleArea();
725                     nextIndex = firstItem.first;
726                     targetPos = firstItem.second.startPos;
727                     stopAutoPlay = true;
728                     autoLinearReachBoundary = true;
729                 }
730 
731                 context->AddAfterLayoutTask([weak = WeakClaim(this), targetPos, velocity = velocity_.value_or(0.0f),
732                                                 nextIndex, stopAutoPlay]() {
733                     auto swiper = weak.Upgrade();
734                     CHECK_NULL_VOID(swiper);
735                     swiper->PlayPropertyTranslateAnimation(-targetPos, nextIndex, velocity, stopAutoPlay);
736                     swiper->PlayIndicatorTranslateAnimation(-targetPos);
737                 });
738             } else {
739                 PlayTranslateAnimation(
740                     currentOffset_, currentOffset_ - targetPos, iter->first, false, velocity_.value_or(0.0f));
741             }
742             velocity_.reset();
743         }
744         pauseTargetIndex_ = targetIndex_;
745     }
746     mainSizeIsMeasured_ = swiperLayoutAlgorithm->GetMainSizeIsMeasured();
747     isNeedResetPrevMarginAndNextMargin_ = swiperLayoutAlgorithm->GetIsNeedResetPrevMarginAndNextMargin();
748     contentCrossSize_ = swiperLayoutAlgorithm->GetContentCrossSize();
749     currentDelta_ = 0.0f;
750     contentMainSize_ = swiperLayoutAlgorithm->GetContentMainSize();
751     startMainPos_ = swiperLayoutAlgorithm->GetStartPosition();
752     endMainPos_ = swiperLayoutAlgorithm->GetEndPosition();
753     startIndex_ = swiperLayoutAlgorithm->GetStartIndex();
754     endIndex_ = swiperLayoutAlgorithm->GetEndIndex();
755     crossMatchChild_ = swiperLayoutAlgorithm->IsCrossMatchChild();
756     oldIndex_ = currentIndex_;
757     oldChildrenSize_ = TotalCount();
758 
759     if (windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION) {
760         StartAutoPlay();
761         windowSizeChangeReason_ = WindowSizeChangeReason::UNDEFINED;
762     }
763 
764     const auto& paddingProperty = layoutProperty->GetPaddingProperty();
765     return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
766 }
767 
IsAutoLinear() const768 bool SwiperPattern::IsAutoLinear() const
769 {
770     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
771     CHECK_NULL_RETURN(swiperLayoutProperty, false);
772     return !SwiperUtils::IsStretch(swiperLayoutProperty);
773 }
774 
AutoLinearAnimationNeedReset(float translate) const775 bool SwiperPattern::AutoLinearAnimationNeedReset(float translate) const
776 {
777     if (!IsAutoLinear()) {
778         return false;
779     }
780 
781     if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
782         return false;
783     }
784 
785     if (NonPositive(translate)) {
786         return false;
787     }
788 
789     auto iter = itemPosition_.rbegin();
790     auto endPos = iter->second.endPos;
791     if (endPos - CalculateVisibleSize() < translate) {
792         return true;
793     }
794 
795     return false;
796 }
797 
OnAnimationTranslateZero(int32_t nextIndex,bool stopAutoPlay)798 void SwiperPattern::OnAnimationTranslateZero(int32_t nextIndex, bool stopAutoPlay)
799 {
800     ResetAndUpdateIndexOnAnimationEnd(nextIndex);
801 
802     if (!NeedAutoPlay() || !isUserFinish_) {
803         return;
804     }
805 
806     if (stopAutoPlay) {
807         MarkDirtyNodeSelf();
808     } else {
809         auto delayTime = GetInterval() - GetDuration();
810         delayTime = std::clamp(delayTime, 0, delayTime);
811         PostTranslateTask(delayTime);
812     }
813 }
814 
FireChangeEvent() const815 void SwiperPattern::FireChangeEvent() const
816 {
817     auto swiperEventHub = GetEventHub<SwiperEventHub>();
818     CHECK_NULL_VOID(swiperEventHub);
819     swiperEventHub->FireChangeEvent(GetLoopIndex(currentIndex_));
820     swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
821     swiperEventHub->FireChangeDoneEvent(moveDirection_);
822 }
823 
FireAnimationStartEvent(int32_t currentIndex,int32_t nextIndex,const AnimationCallbackInfo & info) const824 void SwiperPattern::FireAnimationStartEvent(
825     int32_t currentIndex, int32_t nextIndex, const AnimationCallbackInfo& info) const
826 {
827     auto swiperEventHub = GetEventHub<SwiperEventHub>();
828     CHECK_NULL_VOID(swiperEventHub);
829     swiperEventHub->FireAnimationStartEvent(currentIndex, nextIndex, info);
830     auto host = GetHost();
831     CHECK_NULL_VOID(host);
832     host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
833 }
834 
FireAnimationEndEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const835 void SwiperPattern::FireAnimationEndEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
836 {
837     PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_FLING, false);
838     if (currentIndex == -1) {
839         return;
840     }
841     auto swiperEventHub = GetEventHub<SwiperEventHub>();
842     CHECK_NULL_VOID(swiperEventHub);
843     swiperEventHub->FireAnimationEndEvent(currentIndex, info);
844 }
845 
FireGestureSwipeEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const846 void SwiperPattern::FireGestureSwipeEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
847 {
848     auto swiperEventHub = GetEventHub<SwiperEventHub>();
849     CHECK_NULL_VOID(swiperEventHub);
850     swiperEventHub->FireGestureSwipeEvent(currentIndex, info);
851 }
852 
SwipeToWithoutAnimation(int32_t index)853 void SwiperPattern::SwipeToWithoutAnimation(int32_t index)
854 {
855     if (IsVisibleChildrenSizeLessThanSwiper()) {
856         return;
857     }
858 
859     if (usePropertyAnimation_) {
860         StopPropertyTranslateAnimation(isFinishAnimation_);
861     }
862 
863     StopFadeAnimation();
864     StopSpringAnimation();
865     jumpIndex_ = index;
866     uiCastJumpIndex_ = index;
867     MarkDirtyNodeSelf();
868     FireAndCleanScrollingListener();
869 }
870 
StopSpringAnimationAndFlushImmediately()871 void SwiperPattern::StopSpringAnimationAndFlushImmediately()
872 {
873     if (springAnimationIsRunning_) {
874         AnimationUtils::StopAnimation(springAnimation_);
875         currentDelta_ = 0.0f;
876         itemPosition_.clear();
877         isVoluntarilyClear_ = true;
878         jumpIndex_ = currentIndex_;
879         springAnimationIsRunning_ = false;
880         MarkDirtyNodeSelf();
881         auto pipeline = PipelineContext::GetCurrentContext();
882         if (pipeline) {
883             pipeline->FlushUITasks();
884         }
885     }
886 }
887 
IsUseCustomAnimation() const888 bool SwiperPattern::IsUseCustomAnimation() const
889 {
890     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
891     CHECK_NULL_RETURN(swiperLayoutProperty, false);
892     return swiperLayoutProperty->GetIsCustomAnimation().value_or(false);
893 }
894 
SwipeTo(int32_t index)895 void SwiperPattern::SwipeTo(int32_t index)
896 {
897     auto targetIndex = IsLoop() ? index : (index < 0 || index > (TotalCount() - 1)) ? 0 : index;
898     targetIndex = IsLoop() ? targetIndex : std::clamp(targetIndex, 0, TotalCount() - GetDisplayCount());
899     if (!ContentWillChange(targetIndex)) {
900         return;
901     }
902 
903     if (IsUseCustomAnimation()) {
904         OnCustomContentTransition(targetIndex);
905         MarkDirtyNodeSelf();
906         return;
907     }
908 
909     if (IsVisibleChildrenSizeLessThanSwiper()) {
910         return;
911     }
912 
913     // If targetIndex_ has a value, means animation is still running, stop it before play new animation.
914     if (currentIndex_ == targetIndex && !targetIndex_.has_value()) {
915         return;
916     }
917     StopFadeAnimation();
918     if (springAnimationIsRunning_) {
919         AnimationUtils::StopAnimation(springAnimation_);
920         jumpIndex_ = currentIndex_;
921         springAnimationIsRunning_ = false;
922         MarkDirtyNodeSelf();
923         auto pipeline = PipelineContext::GetCurrentContext();
924         if (pipeline) {
925             pipeline->FlushUITasks();
926         }
927     }
928     StopAutoPlay();
929     StopTranslateAnimation();
930     StopIndicatorAnimation();
931     if (usePropertyAnimation_) {
932         StopPropertyTranslateAnimation(isFinishAnimation_);
933     }
934 
935     targetIndex_ = targetIndex;
936 
937     if (GetDuration() == 0 || !isVisible_) {
938         SwipeToWithoutAnimation(index);
939         return;
940     }
941 
942     MarkDirtyNodeSelf();
943 }
944 
CheckTargetIndex(int32_t targetIndex,bool isForceBackward)945 int32_t SwiperPattern::CheckTargetIndex(int32_t targetIndex, bool isForceBackward)
946 {
947     if (!IsAutoLinear()) {
948         return targetIndex;
949     }
950     while (GetLoopIndex(targetIndex) != GetLoopIndex(currentIndex_)) {
951         auto currentFrameNode = GetCurrentFrameNode(GetLoopIndex(targetIndex));
952         CHECK_NULL_RETURN(currentFrameNode, targetIndex);
953         auto swiperLayoutProperty = currentFrameNode->GetLayoutProperty<LayoutProperty>();
954         CHECK_NULL_RETURN(swiperLayoutProperty, targetIndex);
955         if (swiperLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
956             return targetIndex;
957         }
958         if (isForceBackward || currentIndex_ < targetIndex) {
959             ++targetIndex;
960         } else {
961             --targetIndex;
962         }
963         if (!IsLoop() && (targetIndex < 0 || targetIndex >= TotalCount())) {
964             return currentIndex_;
965         }
966     }
967     return targetIndex;
968 }
969 
ShowNext()970 void SwiperPattern::ShowNext()
971 {
972     if (IsVisibleChildrenSizeLessThanSwiper()) {
973         return;
974     }
975     indicatorDoingAnimation_ = false;
976     auto childrenSize = TotalCount();
977     std::optional<int32_t> preIndex;
978     if (preTargetIndex_.has_value()) {
979         if (GetLoopIndex(preTargetIndex_.value()) >= childrenSize - GetDisplayCount() && !IsLoop()) {
980             return;
981         }
982         preIndex = preTargetIndex_.value();
983     } else if (GetLoopIndex(currentIndex_) >= childrenSize - GetDisplayCount() && !IsLoop()) {
984         return;
985     }
986     if (childrenSize <= 0 || GetDisplayCount() == 0) {
987         return;
988     }
989     StopAutoPlay();
990     StopTranslateAnimation();
991 
992     StopSpringAnimationAndFlushImmediately();
993     StopFadeAnimation();
994     StopIndicatorAnimation();
995     if (preIndex) {
996         isUserFinish_ = false;
997         FinishAnimation();
998         if (!ContentWillChange(currentIndex_ + 1)) {
999             return;
1000         }
1001     }
1002     moveDirection_ = true;
1003 
1004     auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1005     if (isVisible_) {
1006         targetIndex_ = CheckTargetIndex(currentIndex_ + stepItems);
1007         preTargetIndex_ = targetIndex_;
1008         MarkDirtyNodeSelf();
1009         auto pipeline = PipelineContext::GetCurrentContext();
1010         if (pipeline) {
1011             pipeline->FlushUITasks();
1012         }
1013     } else {
1014         SwipeToWithoutAnimation(currentIndex_ + stepItems);
1015     }
1016     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1017     CHECK_NULL_VOID(swiperEventHub);
1018     swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1019 }
1020 
ShowPrevious()1021 void SwiperPattern::ShowPrevious()
1022 {
1023     if (IsVisibleChildrenSizeLessThanSwiper()) {
1024         return;
1025     }
1026 
1027     if (IsAutoLinear() && static_cast<int32_t>(itemPosition_.size()) == TotalCount() && !autoLinearReachBoundary) {
1028         return;
1029     }
1030 
1031     indicatorDoingAnimation_ = false;
1032     auto childrenSize = TotalCount();
1033     std::optional<int32_t> preIndex;
1034     if (preTargetIndex_.has_value()) {
1035         if (GetLoopIndex(preTargetIndex_.value()) <= 0 && !IsLoop()) {
1036             return;
1037         }
1038         preIndex = preTargetIndex_.value();
1039     } else if (GetLoopIndex(currentIndex_) <= 0 && !IsLoop()) {
1040         return;
1041     }
1042     if (childrenSize <= 0 || GetDisplayCount() == 0) {
1043         return;
1044     }
1045     StopAutoPlay();
1046     StopTranslateAnimation();
1047     StopSpringAnimationAndFlushImmediately();
1048     StopFadeAnimation();
1049     StopIndicatorAnimation();
1050 
1051     if (preIndex) {
1052         isUserFinish_ = false;
1053         FinishAnimation();
1054         if (!ContentWillChange(currentIndex_ - 1)) {
1055             return;
1056         }
1057     }
1058     moveDirection_ = false;
1059 
1060     auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1061     if (isVisible_) {
1062         targetIndex_ = CheckTargetIndex(currentIndex_ - stepItems);
1063         preTargetIndex_ = targetIndex_;
1064         MarkDirtyNodeSelf();
1065         auto pipeline = PipelineContext::GetCurrentContext();
1066         if (pipeline) {
1067             pipeline->FlushUITasks();
1068         }
1069     } else {
1070         SwipeToWithoutAnimation(currentIndex_ - stepItems);
1071     }
1072     auto swiperEventHub = GetEventHub<SwiperEventHub>();
1073     CHECK_NULL_VOID(swiperEventHub);
1074     swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1075 }
1076 
FinishAnimation()1077 void SwiperPattern::FinishAnimation()
1078 {
1079     StopTranslateAnimation();
1080     StopSpringAnimation();
1081     StopFadeAnimation();
1082     StopIndicatorAnimation();
1083 
1084     if (usePropertyAnimation_) {
1085         isFinishAnimation_ = true;
1086         StopPropertyTranslateAnimation(isFinishAnimation_);
1087     }
1088     if (isUserFinish_) {
1089         if (swiperController_ && swiperController_->GetFinishCallback()) {
1090             auto finishCallback = swiperController_->GetFinishCallback();
1091             finishCallback();
1092             swiperController_->SetFinishCallback(nullptr);
1093         }
1094     } else {
1095         isUserFinish_ = true;
1096     }
1097 }
1098 
PreloadItems(const std::set<int32_t> & indexSet)1099 void SwiperPattern::PreloadItems(const std::set<int32_t>& indexSet)
1100 {
1101     std::set<int32_t> validIndexSet;
1102     auto childrenSize = RealTotalCount();
1103     auto errorCode = ERROR_CODE_NO_ERROR;
1104     for (const auto& index : indexSet) {
1105         if (index < 0 || index >= childrenSize) {
1106             errorCode = ERROR_CODE_PARAM_INVALID;
1107             break;
1108         }
1109 
1110         validIndexSet.emplace(index);
1111     }
1112 
1113     if (errorCode != ERROR_CODE_PARAM_INVALID) {
1114         DoPreloadItems(validIndexSet, errorCode);
1115         return;
1116     }
1117 
1118     FirePreloadFinishEvent(errorCode);
1119 }
1120 
FirePreloadFinishEvent(int32_t errorCode)1121 void SwiperPattern::FirePreloadFinishEvent(int32_t errorCode)
1122 {
1123     if (swiperController_ && swiperController_->GetPreloadFinishCallback()) {
1124         auto preloadFinishCallback = swiperController_->GetPreloadFinishCallback();
1125         swiperController_->SetPreloadFinishCallback(nullptr);
1126         preloadFinishCallback(errorCode);
1127     }
1128 }
1129 
DoPreloadItems(const std::set<int32_t> & indexSet,int32_t errorCode)1130 void SwiperPattern::DoPreloadItems(const std::set<int32_t>& indexSet, int32_t errorCode)
1131 {
1132     if (indexSet.empty()) {
1133         FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID);
1134         return;
1135     }
1136 
1137     auto preloadTask = [weak = WeakClaim(this), indexSet, errorCode]() {
1138         auto swiperPattern = weak.Upgrade();
1139         CHECK_NULL_VOID(swiperPattern);
1140         auto host = swiperPattern->GetHost();
1141         CHECK_NULL_VOID(host);
1142         const auto& children = host->GetChildren();
1143         for (const auto& child : children) {
1144             if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG && child->GetTag() != V2::JS_LAZY_FOR_EACH_ETS_TAG) {
1145                 continue;
1146             }
1147 
1148             auto forEachNode = AceType::DynamicCast<ForEachNode>(child);
1149             auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(child);
1150             for (auto index : indexSet) {
1151                 if (forEachNode && forEachNode->GetChildAtIndex(index)) {
1152                     forEachNode->GetChildAtIndex(index)->Build(nullptr);
1153                     continue;
1154                 }
1155 
1156                 if (lazyForEachNode) {
1157                     lazyForEachNode->GetFrameChildByIndex(index, true);
1158                 }
1159             }
1160         }
1161 
1162         swiperPattern->FirePreloadFinishEvent(errorCode);
1163     };
1164     auto pipeline = PipelineContext::GetCurrentContext();
1165     CHECK_NULL_VOID(pipeline);
1166     auto taskExecutor = pipeline->GetTaskExecutor();
1167     CHECK_NULL_VOID(taskExecutor);
1168     taskExecutor->PostTask(preloadTask, TaskExecutor::TaskType::UI);
1169 }
1170 
StopTranslateAnimation()1171 void SwiperPattern::StopTranslateAnimation()
1172 {
1173     if (controller_ && !controller_->IsStopped()) {
1174         isFinishAnimation_ = true;
1175         controller_->Stop();
1176     }
1177 }
1178 
StopSpringAnimation()1179 void SwiperPattern::StopSpringAnimation()
1180 {
1181     AnimationUtils::StopAnimation(springAnimation_);
1182     if (springAnimationIsRunning_) {
1183         springAnimationIsRunning_ = false;
1184     }
1185 }
1186 
StopFadeAnimation()1187 void SwiperPattern::StopFadeAnimation()
1188 {
1189     AnimationUtils::StopAnimation(fadeAnimation_);
1190     if (fadeAnimationIsRunning_) {
1191         fadeAnimationIsRunning_ = false;
1192     }
1193 }
1194 
InitSwiperController()1195 void SwiperPattern::InitSwiperController()
1196 {
1197     swiperController_->SetSwipeToImpl([weak = WeakClaim(this)](int32_t index, bool reverse) {
1198         auto swiper = weak.Upgrade();
1199         if (swiper) {
1200             swiper->SwipeTo(index);
1201         }
1202     });
1203 
1204     swiperController_->SetSwipeToWithoutAnimationImpl([weak = WeakClaim(this)](int32_t index) {
1205         auto swiper = weak.Upgrade();
1206         if (swiper) {
1207             swiper->SwipeToWithoutAnimation(index);
1208         }
1209     });
1210 
1211     swiperController_->SetShowNextImpl([weak = WeakClaim(this)]() {
1212         auto swiper = weak.Upgrade();
1213         if (swiper) {
1214             auto swiperNode = swiper->GetHost();
1215             CHECK_NULL_VOID(swiperNode);
1216             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper ShowNext, id:%{public}d", swiperNode->GetId());
1217             swiper->ShowNext();
1218         }
1219     });
1220 
1221     swiperController_->SetShowPrevImpl([weak = WeakClaim(this)]() {
1222         auto swiper = weak.Upgrade();
1223         if (swiper) {
1224             auto swiperNode = swiper->GetHost();
1225             CHECK_NULL_VOID(swiperNode);
1226             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper SetShowPrevImpl, id:%{public}d", swiperNode->GetId());
1227             swiper->ShowPrevious();
1228         }
1229     });
1230 
1231     swiperController_->SetFinishImpl([weak = WeakClaim(this)]() {
1232         auto swiper = weak.Upgrade();
1233         if (swiper) {
1234             swiper->FinishAnimation();
1235         }
1236     });
1237 
1238     swiperController_->SetPreloadItemsImpl([weak = WeakClaim(this)](const std::set<int32_t>& indexSet) {
1239         auto swiper = weak.Upgrade();
1240         if (swiper) {
1241             swiper->PreloadItems(indexSet);
1242         }
1243     });
1244 }
1245 
InitIndicator()1246 void SwiperPattern::InitIndicator()
1247 {
1248     auto swiperNode = GetHost();
1249     CHECK_NULL_VOID(swiperNode);
1250     RefPtr<FrameNode> indicatorNode;
1251     if (!HasIndicatorNode()) {
1252         if (!IsShowIndicator()) {
1253             return;
1254         }
1255         indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
1256             []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
1257         swiperNode->AddChild(indicatorNode);
1258     } else {
1259         indicatorNode =
1260             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetIndicatorId())));
1261         CHECK_NULL_VOID(indicatorNode);
1262         if (!IsShowIndicator()) {
1263             RemoveIndicatorNode();
1264             return;
1265         }
1266         if (GetIndicatorType() == SwiperIndicatorType::DIGIT && lastSwiperIndicatorType_ == SwiperIndicatorType::DOT) {
1267             RemoveIndicatorNode();
1268             indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
1269                 []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
1270             swiperNode->AddChild(indicatorNode);
1271         }
1272     }
1273     lastSwiperIndicatorType_ = GetIndicatorType();
1274     CHECK_NULL_VOID(indicatorNode);
1275     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
1276     CHECK_NULL_VOID(layoutProperty);
1277     if (layoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DOT) {
1278         SaveDotIndicatorProperty(indicatorNode);
1279     } else {
1280         SaveDigitIndicatorProperty(indicatorNode);
1281     }
1282 
1283     auto renderContext = indicatorNode->GetRenderContext();
1284     CHECK_NULL_VOID(renderContext);
1285     BorderRadiusProperty radius;
1286     radius.SetRadius(INDICATOR_BORDER_RADIUS);
1287     renderContext->UpdateBorderRadius(radius);
1288 
1289     indicatorNode->MarkModifyDone();
1290     indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1291 }
1292 
InitArrow()1293 void SwiperPattern::InitArrow()
1294 {
1295     auto swiperNode = GetHost();
1296     CHECK_NULL_VOID(swiperNode);
1297     RefPtr<FrameNode> leftArrow;
1298     RefPtr<FrameNode> rightArrow;
1299     if (!HasLeftButtonNode() && !HasRightButtonNode()) {
1300         if (!IsShowArrow()) {
1301             return;
1302         }
1303         leftArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_LEFT_ARROW_ETS_TAG, GetLeftButtonId(),
1304             []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
1305         swiperNode->AddChild(leftArrow);
1306         rightArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_ARROW_ETS_TAG, GetRightButtonId(),
1307             []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
1308         swiperNode->AddChild(rightArrow);
1309     } else {
1310         leftArrow =
1311             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
1312         CHECK_NULL_VOID(leftArrow);
1313         rightArrow =
1314             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
1315         CHECK_NULL_VOID(rightArrow);
1316         if (!IsShowArrow()) {
1317             RemoveLeftButtonNode();
1318             RemoveRightButtonNode();
1319             return;
1320         }
1321     }
1322 
1323     SaveArrowProperty(leftArrow);
1324     SaveArrowProperty(rightArrow);
1325 
1326     leftArrow->MarkModifyDone();
1327     rightArrow->MarkModifyDone();
1328 }
1329 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)1330 void SwiperPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1331 {
1332     if (direction_ == GetDirection() && panEvent_) {
1333         return;
1334     }
1335     direction_ = GetDirection();
1336 
1337     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1338         auto pattern = weak.Upgrade();
1339         pattern->InitIndexCanChangeMap();
1340         if (pattern) {
1341             if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1342                 return;
1343             }
1344             pattern->FireAndCleanScrollingListener();
1345             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag start");
1346             pattern->HandleDragStart(info);
1347             // notify scrollStart upwards
1348             pattern->NotifyParentScrollStart(pattern->direction_ == Axis::HORIZONTAL ? info.GetGlobalLocation().GetX()
1349                                                                                      : info.GetGlobalLocation().GetY());
1350         }
1351     };
1352 
1353     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1354         auto pattern = weak.Upgrade();
1355         if (!pattern->CheckSwiperPanEvent(info)) {
1356             return;
1357         }
1358         if (pattern) {
1359             if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1360                 if (GreatNotEqual(info.GetMainDelta(), 0.0)) {
1361                     pattern->ShowPrevious();
1362                 } else if (LessNotEqual(info.GetMainDelta(), 0.0)) {
1363                     pattern->ShowNext();
1364                 }
1365             } else {
1366                 pattern->HandleDragUpdate(info);
1367             }
1368         }
1369     };
1370 
1371     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1372         auto pattern = weak.Upgrade();
1373         if (!pattern->CheckSwiperPanEvent(info)) {
1374             pattern->HandleDragEnd(0.0);
1375             return;
1376         }
1377         if (pattern) {
1378             if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1379                 return;
1380             }
1381             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag end. Velocity: %{public}f px/s", info.GetMainVelocity());
1382             pattern->HandleDragEnd(info.GetMainVelocity());
1383         }
1384     };
1385 
1386     auto actionCancelTask = [weak = WeakClaim(this)]() {
1387         auto pattern = weak.Upgrade();
1388         if (pattern) {
1389             TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag cancel");
1390             pattern->HandleDragEnd(0.0);
1391         }
1392     };
1393 
1394     AddPanEvent(gestureHub, std::move(actionStartTask), std::move(actionUpdateTask),
1395         std::move(actionEndTask), std::move(actionCancelTask));
1396 }
1397 
AddPanEvent(const RefPtr<GestureEventHub> & gestureHub,GestureEventFunc && actionStart,GestureEventFunc && actionUpdate,GestureEventFunc && actionEnd,GestureEventNoParameter && actionCancel)1398 void SwiperPattern::AddPanEvent(const RefPtr<GestureEventHub>& gestureHub, GestureEventFunc&& actionStart,
1399     GestureEventFunc&& actionUpdate, GestureEventFunc&& actionEnd, GestureEventNoParameter&& actionCancel)
1400 {
1401     if (GetDirection() == Axis::VERTICAL) {
1402         panDirection_.type = PanDirection::VERTICAL;
1403     } else {
1404         panDirection_.type = PanDirection::HORIZONTAL;
1405     }
1406     if (panEvent_) {
1407         gestureHub->RemovePanEvent(panEvent_);
1408     }
1409 
1410     panEvent_ = MakeRefPtr<PanEvent>(
1411         std::move(actionStart), std::move(actionUpdate), std::move(actionEnd), std::move(actionCancel));
1412     gestureHub->AddPanEvent(panEvent_, panDirection_, 1, DEFAULT_PAN_DISTANCE);
1413 }
1414 
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)1415 void SwiperPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
1416 {
1417     if (touchEvent_) {
1418         return;
1419     }
1420 
1421     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
1422         auto pattern = weak.Upgrade();
1423         if (pattern) {
1424             pattern->HandleTouchEvent(info);
1425         }
1426     };
1427 
1428     if (touchEvent_) {
1429         gestureHub->RemoveTouchEvent(touchEvent_);
1430     }
1431     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
1432     gestureHub->AddTouchEvent(touchEvent_);
1433 }
1434 
InitOnFocusInternal(const RefPtr<FocusHub> & focusHub)1435 void SwiperPattern::InitOnFocusInternal(const RefPtr<FocusHub>& focusHub)
1436 {
1437     auto focusTask = [weak = WeakClaim(this)]() {
1438         auto pattern = weak.Upgrade();
1439         if (pattern) {
1440             pattern->HandleFocusInternal();
1441         }
1442     };
1443     focusHub->SetOnFocusInternal(std::move(focusTask));
1444 }
1445 
HandleFocusInternal()1446 void SwiperPattern::HandleFocusInternal()
1447 {
1448     currentFocusIndex_ = currentIndex_;
1449 }
1450 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1451 void SwiperPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1452 {
1453     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1454         auto pattern = wp.Upgrade();
1455         if (pattern) {
1456             return pattern->OnKeyEvent(event);
1457         }
1458         return false;
1459     };
1460     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1461 }
1462 
IsContentFocused()1463 bool SwiperPattern::IsContentFocused()
1464 {
1465     RefPtr<FocusHub> indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
1466     RefPtr<FocusHub> rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
1467     RefPtr<FocusHub> leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
1468 
1469     return !((indicatorNode && indicatorNode->IsCurrentFocus()) ||
1470              (rightArrowNode && rightArrowNode->IsCurrentFocus()) ||
1471              (leftArrowNode && leftArrowNode->IsCurrentFocus()));
1472 }
1473 
OnKeyEvent(const KeyEvent & event)1474 bool SwiperPattern::OnKeyEvent(const KeyEvent& event)
1475 {
1476     if (event.action != KeyAction::DOWN) {
1477         return false;
1478     }
1479     if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
1480         (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
1481         auto onlyFlushFocus = IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ > currentIndex_;
1482         if (onlyFlushFocus) {
1483             currentFocusIndex_ = IsLoop() ? currentFocusIndex_ - 1 :
1484                                             std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
1485             FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
1486         } else {
1487             ShowPrevious();
1488             currentFocusIndex_ = IsLoop() ? currentFocusIndex_ - 1 :
1489                                             std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
1490         }
1491 
1492         return true;
1493     }
1494     if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
1495         (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
1496         auto onlyFlushFocus =
1497             IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ < currentIndex_ + GetDisplayCount() - 1;
1498         if (onlyFlushFocus) {
1499             currentFocusIndex_ = IsLoop() ? currentFocusIndex_ + 1 :
1500                                             std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
1501             FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
1502         } else {
1503             ShowNext();
1504             currentFocusIndex_ = IsLoop() ? currentFocusIndex_ + 1 :
1505                                             std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
1506         }
1507 
1508         return true;
1509     }
1510     return false;
1511 }
1512 
StopAutoPlay()1513 void SwiperPattern::StopAutoPlay()
1514 {
1515     if (IsAutoPlay()) {
1516         translateTask_.Cancel();
1517     }
1518 }
1519 
StartAutoPlay()1520 void SwiperPattern::StartAutoPlay()
1521 {
1522     if (NeedAutoPlay()) {
1523         PostTranslateTask(GetInterval());
1524     }
1525 }
1526 
OnVisibleChange(bool isVisible)1527 void SwiperPattern::OnVisibleChange(bool isVisible)
1528 {
1529     isVisible_ = isVisible;
1530     if (isInit_) {
1531         return;
1532     }
1533 
1534     if (!isVisible_) {
1535         StopAutoPlay();
1536         return;
1537     }
1538 
1539     if (NeedStartAutoPlay()) {
1540         StartAutoPlay();
1541     }
1542 }
1543 
UpdateCurrentOffset(float offset)1544 void SwiperPattern::UpdateCurrentOffset(float offset)
1545 {
1546     if (itemPosition_.empty()) {
1547         MarkDirtyNodeSelf();
1548         return;
1549     }
1550     if (!IsLoop() && (isDragging_ || childScrolling_)) {
1551         // handle edge effects
1552         if (CheckOverScroll(offset)) {
1553             return;
1554         }
1555     }
1556     currentDelta_ = currentDelta_ - offset;
1557     currentIndexOffset_ += offset;
1558     if (isDragging_) {
1559         AnimationCallbackInfo callbackInfo;
1560         callbackInfo.currentOffset =
1561             GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
1562         FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
1563     }
1564     MarkDirtyNodeSelf();
1565 }
1566 
CheckOverScroll(float offset)1567 bool SwiperPattern::CheckOverScroll(float offset)
1568 {
1569     switch (GetEdgeEffect()) {
1570         case EdgeEffect::SPRING:
1571             if (SpringOverScroll(offset)) {
1572                 return true;
1573             }
1574             break;
1575         case EdgeEffect::FADE:
1576             if (FadeOverScroll(offset)) {
1577                 return true;
1578             }
1579             break;
1580         case EdgeEffect::NONE:
1581             if (IsOutOfBoundary(offset)) {
1582                 currentDelta_ = currentDelta_ - offset;
1583                 MarkDirtyNodeSelf();
1584                 return true;
1585             }
1586             break;
1587     }
1588     return false;
1589 }
1590 
SpringOverScroll(float offset)1591 bool SwiperPattern::SpringOverScroll(float offset)
1592 {
1593     bool outOfBounds = isTouchPad_ ? IsOutOfBoundary(offset) : IsOutOfBoundary();
1594     if (!outOfBounds) {
1595         return false;
1596     }
1597     targetIndex_.reset();
1598 
1599     auto visibleSize = CalculateVisibleSize();
1600     if (LessOrEqual(visibleSize, 0.0)) {
1601         return true;
1602     }
1603     auto friction = currentIndexOffset_ > 0
1604                         ? CalculateFriction(itemPosition_.begin()->second.startPos / visibleSize)
1605                         : CalculateFriction((visibleSize - itemPosition_.rbegin()->second.endPos) / visibleSize);
1606 
1607     currentDelta_ = currentDelta_ - friction * offset;
1608     currentIndexOffset_ += friction * offset;
1609     AnimationCallbackInfo callbackInfo;
1610     callbackInfo.currentOffset =
1611         GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
1612     FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
1613     MarkDirtyNodeSelf();
1614     return true;
1615 }
1616 
FadeOverScroll(float offset)1617 bool SwiperPattern::FadeOverScroll(float offset)
1618 {
1619     if (IsOutOfBoundary(fadeOffset_ + offset)) {
1620         auto onlyUpdateFadeOffset = (itemPosition_.begin()->first == 0 && offset < 0.0f) ||
1621                                (itemPosition_.rbegin()->first == TotalCount() - 1 && offset > 0.0f);
1622         if (!IsVisibleChildrenSizeLessThanSwiper() && !onlyUpdateFadeOffset) {
1623             currentDelta_ = currentDelta_ - offset;
1624         }
1625         auto host = GetHost();
1626         CHECK_NULL_RETURN(host, false);
1627         if (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) {
1628             auto remainOffset = GetDistanceToEdge();
1629             fadeOffset_ += (offset - remainOffset);
1630         }
1631         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1632         MarkDirtyNodeSelf();
1633         return true;
1634     }
1635 
1636     fadeOffset_ = 0.0f;
1637     return false;
1638 }
1639 
HandleTouchBottomLoop()1640 void SwiperPattern::HandleTouchBottomLoop()
1641 {
1642     auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
1643     auto currentIndex = GetLoopIndex(currentIndex_);
1644     bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
1645     bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
1646                                                      gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
1647     if (followTouchBottom) {
1648         if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
1649             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
1650         } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
1651             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
1652         }
1653         return;
1654     }
1655     bool leftReleaseTouchBottom = (commTouchBottom && (currentIndex == 0 && gestureState_ ==
1656         GestureState::GESTURE_STATE_RELEASE_LEFT));
1657     bool rightReleaseTouchBottom = ((currentFirstIndex == 0) && (currentIndex == TotalCount() - 1) &&
1658                                     gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT);
1659     if (leftReleaseTouchBottom || rightReleaseTouchBottom) {
1660         if (currentIndex == 0) {
1661             // left bottom
1662             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
1663         } else if (currentIndex == TotalCount() - 1) {
1664             // right bottom
1665             touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
1666         }
1667     }
1668     return;
1669 }
1670 
CalculateGestureState(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)1671 void SwiperPattern::CalculateGestureState(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
1672 {
1673     // Keep follow hand
1674     if ((preFirstIndex == 0 && currentFirstIndex_ == TotalCount() - 1) ||
1675         (preFirstIndex == TotalCount() - 1 && currentFirstIndex_ == 0)) {
1676         needTurn_ = true;
1677     }
1678 
1679     if (GreatNotEqual(additionalOffset, 0.0f)) {
1680         gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
1681         needTurn_ = false;
1682     } else if (LessNotEqual(additionalOffset, 0.0f)) {
1683         gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
1684         needTurn_ = false;
1685     } else if (GetLoopIndex(currentFirstIndex_) >= GetLoopIndex(currentIndex_)) {
1686         gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
1687     } else if (GetLoopIndex(currentFirstIndex_) < GetLoopIndex(currentIndex_)) {
1688         gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
1689     }
1690     return;
1691 }
1692 
UpdateNextValidIndex()1693 void SwiperPattern::UpdateNextValidIndex()
1694 {
1695     // item may be invalid in auto linear scene, mark next valid item
1696     if (IsAutoLinear()) {
1697         currentFirstIndex_ = CheckTargetIndex(currentFirstIndex_, true);
1698         nextValidIndex_ = GetLoopIndex(CheckTargetIndex(currentFirstIndex_ + 1, true));
1699     } else {
1700         nextValidIndex_ = -1;
1701     }
1702 }
1703 
CheckMarkDirtyNodeForRenderIndicator(float additionalOffset)1704 void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset)
1705 {
1706     if (!indicatorId_.has_value()) {
1707         return;
1708     }
1709     auto host = GetHost();
1710     CHECK_NULL_VOID(host);
1711     auto child = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
1712     if (!child || child->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
1713         return;
1714     }
1715 
1716     int32_t preFirstIndex = currentFirstIndex_;
1717     float currentTurnPageRate = FLT_MAX;
1718     for (const auto& iter : itemPosition_) {
1719         if (LessNotEqual((iter.second.startPos + additionalOffset), 0) &&
1720             LessNotEqual((iter.second.endPos + additionalOffset), 0)) {
1721             continue;
1722         }
1723         if (GreatOrEqual((iter.second.startPos + additionalOffset), 0) &&
1724             GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
1725             currentFirstIndex_ = iter.first;
1726             currentTurnPageRate = 0.0f;
1727             break;
1728         }
1729         if (GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
1730             currentFirstIndex_ = iter.first;
1731             currentTurnPageRate = (NearEqual(iter.second.endPos, iter.second.startPos) ? 0 :
1732                 ((iter.second.startPos + additionalOffset) / (iter.second.endPos - iter.second.startPos)));
1733             break;
1734         }
1735     }
1736 
1737     UpdateNextValidIndex();
1738     currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
1739     CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
1740     turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
1741 
1742     touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
1743     if (!IsLoop() && ((currentFirstIndex_ == 0 && GreatNotEqualCustomPrecision(turnPageRate_, 0.0f)) ||
1744         (currentFirstIndex_ == TotalCount() - 1 && LessNotEqualCustomPrecision(turnPageRate_, 0.0f)))) {
1745         return;
1746     }
1747     HandleTouchBottomLoop();
1748 
1749     if (!indicatorDoingAnimation_) {
1750         child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1751     }
1752     if (GetLoopIndex(currentIndex_) != currentFirstIndex_) {
1753         auto swiperEventHub = GetEventHub<SwiperEventHub>();
1754         CHECK_NULL_VOID(swiperEventHub);
1755         swiperEventHub->FireIndicatorChangeEvent(currentFirstIndex_);
1756     }
1757 }
1758 
UpdateAnimationProperty(float velocity)1759 void SwiperPattern::UpdateAnimationProperty(float velocity)
1760 {
1761     if (isDragging_ || childScrolling_) {
1762         targetIndex_ = CheckTargetIndex(ComputeNextIndexByVelocity(velocity));
1763         velocity_ = velocity;
1764     } else {
1765         targetIndex_ = pauseTargetIndex_;
1766         velocity_ = velocity;
1767     }
1768 
1769     MarkDirtyNodeSelf();
1770     moveDirection_ = velocity <= 0;
1771 }
1772 
OnTouchTestHit(SourceType hitTestType)1773 void SwiperPattern::OnTouchTestHit(SourceType hitTestType)
1774 {
1775     // in mouse hover test case.
1776     if (hitTestType == SourceType::MOUSE) {
1777         return;
1778     }
1779     if (!isTouchDown_) {
1780         isTouchDown_ = true;
1781     }
1782 }
1783 
HandleTouchEvent(const TouchEventInfo & info)1784 void SwiperPattern::HandleTouchEvent(const TouchEventInfo& info)
1785 {
1786     if (info.GetTouches().empty()) {
1787         return;
1788     }
1789     auto locationInfo = info.GetTouches().front();
1790     auto touchType = locationInfo.GetTouchType();
1791     if (touchType == TouchType::DOWN) {
1792         HandleTouchDown(locationInfo);
1793     } else if (touchType == TouchType::UP) {
1794         HandleTouchUp();
1795     } else if (touchType == TouchType::CANCEL) {
1796         HandleTouchUp();
1797     }
1798 }
1799 
HandleTouchDown(const TouchLocationInfo & locationInfo)1800 void SwiperPattern::HandleTouchDown(const TouchLocationInfo& locationInfo)
1801 {
1802     isTouchDown_ = true;
1803     if (HasIndicatorNode()) {
1804         auto host = GetHost();
1805         CHECK_NULL_VOID(host);
1806         auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
1807         CHECK_NULL_VOID(indicatorNode);
1808         if (indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
1809             auto geometryNode = indicatorNode->GetGeometryNode();
1810             CHECK_NULL_VOID(geometryNode);
1811             auto hotRegion = geometryNode->GetFrameRect();
1812             auto touchPoint = PointF(static_cast<float>(locationInfo.GetLocalLocation().GetX()),
1813                 static_cast<float>(locationInfo.GetLocalLocation().GetY()));
1814             if (hotRegion.IsInRegion(touchPoint)) {
1815                 return;
1816             }
1817         }
1818     }
1819 
1820     if (childScrolling_) {
1821         // Even if the child fails to notify scrollEnd, we reset childScrolling_ flag on TouchDown to ensure its
1822         // value is correct.
1823         childScrolling_ = false;
1824     }
1825 
1826     StopIndicatorAnimation();
1827     if (usePropertyAnimation_) {
1828         StopPropertyTranslateAnimation(isFinishAnimation_);
1829     }
1830 
1831     indicatorDoingAnimation_ = false;
1832     // Stop translate animation when touch down.
1833     if (controller_ && controller_->IsRunning()) {
1834         controller_->Stop();
1835     }
1836 
1837     AnimationUtils::PauseAnimation(springAnimation_);
1838     if (springAnimationIsRunning_) {
1839         isTouchDownSpringAnimation_ = true;
1840         springAnimationIsRunning_ = false;
1841     }
1842 
1843     AnimationUtils::PauseAnimation(fadeAnimation_);
1844     if (fadeAnimationIsRunning_) {
1845         fadeAnimationIsRunning_ = false;
1846     }
1847 
1848     // Stop auto play when touch down.
1849     StopAutoPlay();
1850 }
1851 
HandleTouchUp()1852 void SwiperPattern::HandleTouchUp()
1853 {
1854     isTouchDown_ = false;
1855     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
1856     if (!isDragging_ && !childScrolling_ && !NearZero(firstItemInfoInVisibleArea.second.startPos)) {
1857         UpdateAnimationProperty(0.0);
1858     }
1859 
1860     if (!springAnimationIsRunning_ && isTouchDownSpringAnimation_) {
1861         isTouchDownSpringAnimation_ = false;
1862         springAnimationIsRunning_ = true;
1863         AnimationUtils::ResumeAnimation(springAnimation_);
1864     }
1865 
1866     if (!fadeAnimationIsRunning_) {
1867         fadeAnimationIsRunning_ = true;
1868         AnimationUtils::ResumeAnimation(fadeAnimation_);
1869     }
1870 
1871     if (!isDragging_) {
1872         StartAutoPlay();
1873     }
1874 }
1875 
HandleDragStart(const GestureEvent & info)1876 void SwiperPattern::HandleDragStart(const GestureEvent& info)
1877 {
1878     PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_SCROLL, PerfActionType::FIRST_MOVE, "");
1879     UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::START);
1880 
1881     StopAnimationOnScrollStart(
1882         info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD);
1883     StopAutoPlay();
1884 
1885     const auto& tabBarFinishCallback = swiperController_->GetTabBarFinishCallback();
1886     if (tabBarFinishCallback) {
1887         tabBarFinishCallback();
1888     }
1889 
1890     const auto& removeEventCallback = swiperController_->GetRemoveTabBarEventCallback();
1891     if (removeEventCallback) {
1892         removeEventCallback();
1893     }
1894 #ifdef OHOS_PLATFORM
1895     // Increase the cpu frequency when sliding.
1896     ResSchedReport::GetInstance().ResSchedDataReport("slide_on");
1897 #endif
1898 
1899     gestureSwipeIndex_ = currentIndex_;
1900     isDragging_ = true;
1901     isTouchDown_ = true;
1902     mainDeltaSum_ = 0.0f;
1903     // in drag process, close lazy feature.
1904     SetLazyLoadFeature(false);
1905     StopFadeAnimation();
1906 }
1907 
StopAnimationOnScrollStart(bool flushImmediately)1908 void SwiperPattern::StopAnimationOnScrollStart(bool flushImmediately)
1909 {
1910     if (usePropertyAnimation_) {
1911         StopPropertyTranslateAnimation(isFinishAnimation_);
1912     }
1913 
1914     StopIndicatorAnimation();
1915     StopTranslateAnimation();
1916     if (flushImmediately) {
1917         StopSpringAnimationAndFlushImmediately();
1918     } else {
1919         StopSpringAnimation();
1920     }
1921 }
1922 
HandleDragUpdate(const GestureEvent & info)1923 void SwiperPattern::HandleDragUpdate(const GestureEvent& info)
1924 {
1925     UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::RUNNING);
1926     auto mainDelta = static_cast<float>(info.GetMainDelta());
1927     if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD) {
1928         isTouchPad_ = true;
1929     }
1930     auto mainSize = CalculateVisibleSize();
1931     ProcessDelta(mainDelta, mainSize, mainDeltaSum_);
1932     mainDeltaSum_ += mainDelta;
1933 
1934     PointF dragPoint(static_cast<float>(info.GetGlobalLocation().GetX()),
1935         static_cast<float>(info.GetGlobalLocation().GetY()));
1936     NGGestureRecognizer::Transform(dragPoint, GetHost(), true);
1937     if (IsOutOfHotRegion(dragPoint)) {
1938         isTouchPad_ = false;
1939         return;
1940     }
1941 
1942     if (IsAutoLinear() && AutoLinearIsOutOfBoundary(static_cast<float>(mainDelta))) {
1943         return;
1944     }
1945 
1946     HandleScroll(static_cast<float>(mainDelta), SCROLL_FROM_UPDATE, NestedState::GESTURE);
1947     UpdateItemRenderGroup(true);
1948     isTouchPad_ = false;
1949 }
1950 
HandleDragEnd(double dragVelocity)1951 void SwiperPattern::HandleDragEnd(double dragVelocity)
1952 {
1953     PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_SCROLL, false);
1954     PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_FLING, PerfActionType::FIRST_MOVE, "");
1955     isTouchDown_ = false;
1956     UpdateDragFRCSceneInfo(dragVelocity, SceneStatus::END);
1957     const auto& addEventCallback = swiperController_->GetAddTabBarEventCallback();
1958     if (addEventCallback) {
1959         addEventCallback();
1960     }
1961 
1962     auto pipeline = PipelineContext::GetCurrentContext();
1963     if (pipeline) {
1964         pipeline->FlushUITasks();
1965     }
1966     if (itemPosition_.empty()) {
1967         return;
1968     }
1969 
1970     if (IsAutoLinear() && AutoLinearIsOutOfBoundary(0.0f)) {
1971         return;
1972     }
1973 
1974     auto edgeEffect = GetEdgeEffect();
1975     // edge effect is NONE and reached boundary
1976     bool noneOutOfBoundary = (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) &&
1977                              NearZero(GetDistanceToEdge()) && edgeEffect == EdgeEffect::NONE;
1978     if (!IsLoop() && (IsOutOfBoundary() || !NearZero(fadeOffset_) || noneOutOfBoundary)) {
1979         isDragging_ = false;
1980 
1981         if (edgeEffect == EdgeEffect::SPRING) {
1982             PlaySpringAnimation(dragVelocity);
1983             return;
1984         }
1985 
1986         if (edgeEffect == EdgeEffect::FADE) {
1987             PlayFadeAnimation();
1988             return;
1989         }
1990 
1991         auto nextIndex = ComputeNextIndexByVelocity(static_cast<float>(dragVelocity), true);
1992         if (currentIndex_ != nextIndex) {
1993             UpdateCurrentIndex(nextIndex);
1994             do {
1995                 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
1996                 if (!curChildFrame) {
1997                     break;
1998                 }
1999                 FlushFocus(curChildFrame);
2000                 currentFocusIndex_ = currentIndex_;
2001             } while (0);
2002             OnIndexChange();
2003             oldIndex_ = currentIndex_;
2004         }
2005 
2006         if (edgeEffect == EdgeEffect::NONE) {
2007             auto parent = parent_.Upgrade();
2008             if (parent) {
2009                 parent->HandleScrollVelocity(dragVelocity);
2010             }
2011             StartAutoPlay();
2012             UpdateItemRenderGroup(false);
2013             return;
2014         }
2015     }
2016 
2017 #ifdef OHOS_PLATFORM
2018     ResSchedReport::GetInstance().ResSchedDataReport("slide_off");
2019 #endif
2020 
2021     // nested and reached end, need to pass velocity to parent scrollable
2022     auto parent = parent_.Upgrade();
2023     if (!IsLoop() && parent && NearZero(GetDistanceToEdge())) {
2024         parent->HandleScrollVelocity(dragVelocity);
2025         StartAutoPlay();
2026     } else {
2027         UpdateAnimationProperty(static_cast<float>(dragVelocity));
2028         NotifyParentScrollEnd();
2029     }
2030     if (pipeline) {
2031         pipeline->FlushUITasks();
2032     }
2033 
2034     isDragging_ = false;
2035 }
2036 
UpdateCurrentIndex(int32_t index)2037 void SwiperPattern::UpdateCurrentIndex(int32_t index)
2038 {
2039     currentIndex_ = index;
2040     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2041     CHECK_NULL_VOID(layoutProperty);
2042     layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
2043 }
2044 
ComputeSwipePageNextIndex(float velocity,bool onlyDistance) const2045 int32_t SwiperPattern::ComputeSwipePageNextIndex(float velocity, bool onlyDistance) const
2046 {
2047     auto swiperWidth = CalculateVisibleSize();
2048     if (LessOrEqual(swiperWidth, 0)) {
2049         return currentIndex_;
2050     }
2051 
2052     auto iter = itemPosition_.find(currentIndex_);
2053     if (iter == itemPosition_.end()) {
2054         return currentIndex_;
2055     }
2056 
2057     auto currentOffset = iter->second.startPos;
2058     auto direction = GreatNotEqual(velocity, 0.0);
2059     auto dragThresholdFlag = direction ? currentOffset > swiperWidth / 2 : -currentOffset > swiperWidth / 2;
2060     auto nextIndex = currentIndex_;
2061     auto displayCount = GetDisplayCount();
2062 
2063     if (!IsLoop()) {
2064         if (GetLoopIndex(currentIndex_) == 0 && direction) {
2065             return nextIndex;
2066         }
2067 
2068         auto currentPageIndex = SwiperUtils::ComputePageIndex(currentIndex_, displayCount);
2069         auto endPageIndex = SwiperUtils::ComputePageIndex(TotalCount() - 1, displayCount);
2070         if (!direction && currentPageIndex == endPageIndex) {
2071             return nextIndex;
2072         }
2073     }
2074 
2075     if ((!onlyDistance && std::abs(velocity) > NEW_MIN_TURN_PAGE_VELOCITY) || dragThresholdFlag) {
2076         nextIndex = direction ? currentIndex_ - displayCount : currentIndex_ + displayCount;
2077     }
2078 
2079     if (!IsAutoLinear() && nextIndex > currentIndex_ + displayCount) {
2080         nextIndex = currentIndex_ + displayCount;
2081     }
2082 
2083     return nextIndex;
2084 }
2085 
ComputeNextIndexByVelocity(float velocity,bool onlyDistance) const2086 int32_t SwiperPattern::ComputeNextIndexByVelocity(float velocity, bool onlyDistance) const
2087 {
2088     if (IsSwipeByGroup()) {
2089         return ComputeSwipePageNextIndex(velocity, onlyDistance);
2090     }
2091 
2092     auto nextIndex = currentIndex_;
2093     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
2094     auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
2095     if (LessOrEqual(firstItemLength, 0)) {
2096         return nextIndex;
2097     }
2098 
2099     auto firstIndex = firstItemInfoInVisibleArea.first;
2100     auto dragDistance = firstItemInfoInVisibleArea.second.endPos;
2101     if (firstIndex == currentIndex_ && firstItemInfoInVisibleArea.second.startPos > 0) {
2102         firstIndex--;
2103         dragDistance = firstItemInfoInVisibleArea.second.startPos;
2104     }
2105     auto direction = GreatNotEqual(velocity, 0.0);
2106     auto dragThresholdFlag =
2107         direction ? dragDistance > firstItemLength / 2 : firstItemInfoInVisibleArea.second.endPos < firstItemLength / 2;
2108     auto turnVelocity = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_MIN_TURN_PAGE_VELOCITY
2109                                                                                            : MIN_TURN_PAGE_VELOCITY;
2110     if ((!onlyDistance && std::abs(velocity) > turnVelocity) || dragThresholdFlag) {
2111         nextIndex = direction ? firstIndex : firstItemInfoInVisibleArea.first + 1;
2112     } else {
2113         nextIndex = direction ? firstIndex + 1 : firstItemInfoInVisibleArea.first;
2114     }
2115 
2116     if (!IsAutoLinear() && nextIndex > currentIndex_ + GetDisplayCount()) {
2117         nextIndex = currentIndex_ + GetDisplayCount();
2118     }
2119 
2120     if (!IsLoop()) {
2121         nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - GetDisplayCount()));
2122     }
2123     return nextIndex;
2124 }
2125 
PlayPropertyTranslateAnimation(float translate,int32_t nextIndex,float velocity,bool stopAutoPlay)2126 void SwiperPattern::PlayPropertyTranslateAnimation(
2127     float translate, int32_t nextIndex, float velocity, bool stopAutoPlay)
2128 {
2129     if (NearZero(translate)) {
2130         OnAnimationTranslateZero(nextIndex, stopAutoPlay);
2131         return;
2132     }
2133 
2134     AnimationOption option;
2135     option.SetDuration(GetDuration());
2136     motionVelocity_ = velocity / translate;
2137     option.SetCurve(GetCurveIncludeMotion());
2138     option.SetFinishCallbackType(GetFinishCallbackType());
2139     OffsetF offset;
2140     if (GetDirection() == Axis::HORIZONTAL) {
2141         offset.AddX(translate);
2142     } else {
2143         offset.AddY(translate);
2144     }
2145     if (usePropertyAnimation_) {
2146         auto startNewAnimationFlag = false;
2147         if (itemPositionInAnimation_.empty()) {
2148             startNewAnimationFlag = true;
2149         }
2150         if (!startNewAnimationFlag) {
2151             for (const auto& animationItem : itemPositionInAnimation_) {
2152                 auto iter = itemPosition_.find(animationItem.first);
2153                 if (iter == itemPosition_.end()) {
2154                     startNewAnimationFlag = true;
2155                     break;
2156                 }
2157                 if (animationItem.second.finialOffset != offset ||
2158                     !NearEqual(animationItem.second.startPos, iter->second.startPos) ||
2159                     !NearEqual(animationItem.second.endPos, iter->second.endPos)) {
2160                     startNewAnimationFlag = true;
2161                     break;
2162                 }
2163             }
2164         }
2165         if (!startNewAnimationFlag) {
2166             stopIndicatorAnimation_ = false;
2167             return;
2168         }
2169         std::optional<int32_t> targetIndex;
2170         if (targetIndex_) {
2171             targetIndex = targetIndex_;
2172         }
2173         StopPropertyTranslateAnimation(isFinishAnimation_);
2174         StopIndicatorAnimation();
2175 
2176         if (targetIndex) {
2177             targetIndex_ = targetIndex;
2178             MarkDirtyNodeSelf();
2179             return;
2180         }
2181     }
2182     auto finishCallback = [weak = WeakClaim(this), offset]() {
2183         auto swiper = weak.Upgrade();
2184         CHECK_NULL_VOID(swiper);
2185         swiper->targetIndex_.reset();
2186         swiper->OnPropertyTranslateAnimationFinish(offset);
2187     };
2188     // initial translate info.
2189     for (auto& item : itemPosition_) {
2190         auto frameNode = item.second.node;
2191         if (frameNode) {
2192             frameNode->GetRenderContext()->UpdateTranslateInXY(item.second.finialOffset);
2193         }
2194     }
2195     // property callback will call immediately.
2196     auto propertyUpdateCallback = [swiper = WeakClaim(this), offset]() {
2197         auto swiperPattern = swiper.Upgrade();
2198         if (!swiperPattern) {
2199             return;
2200         }
2201         for (auto& item : swiperPattern->itemPosition_) {
2202             auto frameNode = item.second.node;
2203             if (frameNode) {
2204                 frameNode->GetRenderContext()->UpdateTranslateInXY(offset);
2205                 item.second.finialOffset = offset;
2206             }
2207         }
2208         swiperPattern->itemPositionInAnimation_ = swiperPattern->itemPosition_;
2209     };
2210     usePropertyAnimation_ = true;
2211     propertyAnimationIndex_ = nextIndex;
2212     ElementRegister::GetInstance()->ReSyncGeometryTransition(GetHost(), option);
2213     AnimationUtils::Animate(option, propertyUpdateCallback, finishCallback);
2214     AnimationCallbackInfo info;
2215     info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
2216     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2217     info.targetOffset = GetCustomPropertyOffset() - Dimension(translate, DimensionUnit::PX).ConvertToVp();
2218 
2219     auto pipeline = PipelineContext::GetCurrentContext();
2220     if (pipeline) {
2221         pipeline->AddAfterRenderTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
2222             auto swiper = weak.Upgrade();
2223             CHECK_NULL_VOID(swiper);
2224             swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
2225             swiper->FireAndCleanScrollingListener();
2226         });
2227     }
2228 
2229     // enable lazy load feature.
2230     SetLazyLoadFeature(true);
2231     UpdateItemRenderGroup(true);
2232 }
2233 
UpdateOffsetAfterPropertyAnimation(float offset)2234 void SwiperPattern::UpdateOffsetAfterPropertyAnimation(float offset)
2235 {
2236     UpdateCurrentOffset(offset);
2237     auto pipeline = PipelineContext::GetCurrentContext();
2238     if (pipeline) {
2239         pipeline->FlushUITasks();
2240     }
2241 }
2242 
OnPropertyTranslateAnimationFinish(const OffsetF & offset)2243 void SwiperPattern::OnPropertyTranslateAnimationFinish(const OffsetF& offset)
2244 {
2245     if (!usePropertyAnimation_) {
2246         // force stop.
2247         return;
2248     }
2249 
2250     usePropertyAnimation_ = false;
2251     // reset translate.
2252     for (auto& item : itemPositionInAnimation_) {
2253         auto frameNode = item.second.node;
2254         if (frameNode) {
2255             frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
2256         }
2257         item.second.finialOffset = OffsetF();
2258     }
2259     itemPositionInAnimation_.clear();
2260     // update postion info.
2261     UpdateOffsetAfterPropertyAnimation(offset.GetMainOffset(GetDirection()));
2262     OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
2263 }
2264 
StopPropertyTranslateAnimation(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper)2265 void SwiperPattern::StopPropertyTranslateAnimation(bool isFinishAnimation, bool isBeforeCreateLayoutWrapper)
2266 {
2267     if (!usePropertyAnimation_) {
2268         return;
2269     }
2270     usePropertyAnimation_ = false;
2271 
2272     // Stop CurrentAnimationProperty.
2273     AnimationOption option;
2274     option.SetDuration(0);
2275     option.SetCurve(Curves::LINEAR);
2276     auto propertyUpdateCallback = [weak = WeakClaim(this)]() {
2277         auto swiper = weak.Upgrade();
2278         CHECK_NULL_VOID(swiper);
2279         for (auto& item : swiper->itemPositionInAnimation_) {
2280             auto frameNode = item.second.node;
2281             if (!frameNode) {
2282                 continue;
2283             }
2284             frameNode->GetRenderContext()->CancelTranslateXYAnimation();
2285         }
2286     };
2287     AnimationUtils::Animate(option, propertyUpdateCallback);
2288     OffsetF currentOffset;
2289     for (auto& item : itemPositionInAnimation_) {
2290         auto frameNode = item.second.node;
2291         if (!frameNode) {
2292             continue;
2293         }
2294         currentOffset = frameNode->GetRenderContext()->GetTranslateXYProperty();
2295         frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
2296         item.second.finialOffset = OffsetF();
2297     }
2298     itemPositionInAnimation_.clear();
2299     if (!isBeforeCreateLayoutWrapper) {
2300         UpdateOffsetAfterPropertyAnimation(currentOffset.GetMainOffset(GetDirection()));
2301     }
2302     OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation, true);
2303 }
2304 
GetCurveIncludeMotion()2305 RefPtr<Curve> SwiperPattern::GetCurveIncludeMotion()
2306 {
2307     auto curve = GetCurve();
2308     auto container = Container::Current();
2309     bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
2310     if (!curve && !isLauncherFeature) {
2311         curve = Curves::LINEAR;
2312     }
2313 
2314     if (isLauncherFeature) {
2315         finishCallbackType_ = FinishCallbackType::LOGICALLY;
2316     }
2317 
2318     if (curve) {
2319         if (InstanceOf<SpringCurve>(curve)) {
2320             auto springCurve = DynamicCast<SpringCurve>(curve);
2321             // check velocity to judge if this current velocity.
2322             if (springCurve->GetCurrentVelocity() < 0) {
2323                 return AceType::MakeRefPtr<SpringCurve>(
2324                     motionVelocity_, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
2325             }
2326         }
2327         if (InstanceOf<InterpolatingSpring>(curve)) {
2328             auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
2329             // check velocity to judge if this current velocity.
2330             if (interpolatingSpring->GetVelocity() < 0) {
2331                 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, interpolatingSpring->GetMass(),
2332                     interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
2333             }
2334         }
2335         return curve;
2336     }
2337     // use spring motion feature.
2338     // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
2339     return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, 1, 328, 34);
2340 }
2341 
PlayIndicatorTranslateAnimation(float translate)2342 void SwiperPattern::PlayIndicatorTranslateAnimation(float translate)
2343 {
2344     if (!stopIndicatorAnimation_) {
2345         stopIndicatorAnimation_ = true;
2346         return;
2347     }
2348     const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
2349     if (!indicatorId_.has_value() && !turnPageRateCallback) {
2350         return;
2351     }
2352     CheckMarkDirtyNodeForRenderIndicator(translate);
2353     AnimationUtils::StopAnimation(indicatorAnimation_);
2354     indicatorAnimationIsRunning_ = false;
2355     if (itemPosition_.empty()) {
2356         return;
2357     }
2358 
2359     auto host = GetHost();
2360     CHECK_NULL_VOID(host);
2361     auto weak = AceType::WeakClaim(this);
2362     host->CreateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0, [weak](float value) {
2363             auto swiper = weak.Upgrade();
2364             CHECK_NULL_VOID(swiper);
2365             auto currentContentOffset = -(swiper->itemPosition_.begin()->second.startPos);
2366             auto index = swiper->itemPosition_.begin()->first;
2367             const auto& turnPageRateCallback = swiper->swiperController_->GetTurnPageRateCallback();
2368             if (turnPageRateCallback && !NearZero(swiper->GetTranslateLength())) {
2369                 turnPageRateCallback(index, (currentContentOffset - value) / swiper->GetTranslateLength());
2370             }
2371         });
2372 
2373     AnimationOption option;
2374     option.SetDuration(GetDuration());
2375     option.SetCurve(Curves::LINEAR);
2376 
2377     host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0);
2378     indicatorAnimationIsRunning_ = true;
2379     indicatorAnimation_ = AnimationUtils::StartAnimation(
2380         option, [host, translate]() { host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, translate); },
2381         [weak]() {
2382             auto swiperPattern = weak.Upgrade();
2383             CHECK_NULL_VOID(swiperPattern);
2384             swiperPattern->indicatorAnimationIsRunning_ = false;
2385         });
2386 }
2387 
PlayTranslateAnimation(float startPos,float endPos,int32_t nextIndex,bool restartAutoPlay,float velocity)2388 void SwiperPattern::PlayTranslateAnimation(
2389     float startPos, float endPos, int32_t nextIndex, bool restartAutoPlay, float velocity)
2390 {
2391     auto host = GetHost();
2392     CHECK_NULL_VOID(host);
2393     auto curve = GetCurve();
2394 
2395     // If animation is still running, stop it before play new animation.
2396     StopSpringAnimation();
2397     StopFadeAnimation();
2398     StopTranslateAnimation();
2399     StopAutoPlay();
2400 
2401     SetLazyLoadFeature(false);
2402 
2403     if (!controller_) {
2404         controller_ = CREATE_ANIMATOR(host->GetContext());
2405     }
2406     controller_->ClearStartListeners();
2407     controller_->ClearStopListeners();
2408     controller_->ClearInterpolators();
2409 
2410     auto weak = WeakClaim(this);
2411     auto targetOffset = Dimension(startPos - endPos, DimensionUnit::PX).ConvertToVp();
2412     controller_->AddStartListener([weak, nextIndex, targetOffset, velocity]() {
2413         auto swiper = weak.Upgrade();
2414         CHECK_NULL_VOID(swiper);
2415         AnimationCallbackInfo info;
2416         info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
2417         info.currentOffset =
2418             swiper->GetCustomPropertyOffset() + Dimension(swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2419         info.targetOffset = swiper->GetCustomPropertyOffset() + targetOffset;
2420         swiper->FireAnimationStartEvent(
2421             swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex), info);
2422     });
2423 
2424     auto container = Container::Current();
2425     bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
2426     if (!curve && !isLauncherFeature) {
2427         curve = Curves::LINEAR;
2428     }
2429 
2430     if (curve) {
2431         auto currentIndexStartPos = currentIndexOffset_;
2432         auto translate = AceType::MakeRefPtr<CurveAnimation<double>>(startPos, endPos, curve);
2433         translate->AddListener(
2434             Animation<double>::ValueCallback([weak, startPos, endPos, currentIndexStartPos](double value) {
2435                 auto swiper = weak.Upgrade();
2436                 CHECK_NULL_VOID(swiper);
2437                 if (!NearEqual(value, startPos) && !NearEqual(value, endPos) && !NearEqual(startPos, endPos)) {
2438                     float moveRate =
2439                         Curves::EASE_OUT->MoveInternal(static_cast<float>((value - startPos) / (endPos - startPos)));
2440                     value = startPos + (endPos - startPos) * moveRate;
2441                     auto moveOffset = (endPos - startPos) * moveRate;
2442                     swiper->currentIndexOffset_ = currentIndexStartPos + moveOffset;
2443                 }
2444                 swiper->UpdateCurrentOffset(static_cast<float>(value - swiper->currentOffset_));
2445             }));
2446         controller_->AddStopListener([weak, nextIndex, restartAutoPlay]() {
2447             auto swiper = weak.Upgrade();
2448             CHECK_NULL_VOID(swiper);
2449             swiper->OnTranslateFinish(nextIndex, restartAutoPlay, swiper->isFinishAnimation_);
2450         });
2451         controller_->SetDuration(GetDuration());
2452         controller_->AddInterpolator(translate);
2453         controller_->Play();
2454         return;
2455     }
2456     // use spring motion feature.
2457     // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
2458     static const auto springProperty = AceType::MakeRefPtr<SpringProperty>(1, 328, 34);
2459     auto scrollMotion = AceType::MakeRefPtr<SpringMotion>(startPos, endPos, velocity, springProperty);
2460     scrollMotion->AddListener([weak](double value) {
2461         auto swiper = weak.Upgrade();
2462         if (swiper) {
2463             swiper->UpdateCurrentOffset(static_cast<float>(value) - swiper->currentOffset_);
2464         }
2465     });
2466     controller_->AddStopListener([weak, nextIndex, restartAutoPlay]() {
2467         auto swiper = weak.Upgrade();
2468         CHECK_NULL_VOID(swiper);
2469         swiper->OnTranslateFinish(nextIndex, restartAutoPlay, swiper->isFinishAnimation_);
2470     });
2471     controller_->PlayMotion(scrollMotion);
2472 }
2473 
OnSpringAnimationStart(float velocity)2474 void SwiperPattern::OnSpringAnimationStart(float velocity)
2475 {
2476     AnimationCallbackInfo info;
2477     info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
2478     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2479 
2480     nextIndex_ = ComputeNextIndexByVelocity(velocity);
2481     if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
2482         info.targetOffset = info.currentOffset;
2483     } else {
2484         auto iter = itemPosition_.find(nextIndex_);
2485         auto nextOffset = iter != itemPosition_.end() ? iter->second.startPos : 0.0f;
2486         info.targetOffset = GetCustomPropertyOffset() + Dimension(nextOffset, DimensionUnit::PX).ConvertToVp();
2487     }
2488 
2489     FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
2490 }
2491 
OnSpringAndFadeAnimationFinish()2492 void SwiperPattern::OnSpringAndFadeAnimationFinish()
2493 {
2494     auto itemInfoInVisibleArea = std::make_pair(0, SwiperItemInfo {});
2495     if (!itemPosition_.empty()) {
2496         auto item = itemPosition_.find(nextIndex_);
2497         itemInfoInVisibleArea = std::make_pair(item->first,
2498             SwiperItemInfo { item->second.startPos, item->second.endPos });
2499     }
2500     if (GetLoopIndex(currentIndex_) != GetLoopIndex(nextIndex_)) {
2501         UpdateCurrentIndex(nextIndex_);
2502         do {
2503             auto curChildFrame = GetCurrentFrameNode(currentIndex_);
2504             if (!curChildFrame) {
2505                 break;
2506             }
2507             FlushFocus(curChildFrame);
2508             currentFocusIndex_ = currentIndex_;
2509         } while (0);
2510         OnIndexChange();
2511         oldIndex_ = currentIndex_;
2512     }
2513     AnimationCallbackInfo info;
2514     auto indexStartPos = itemInfoInVisibleArea.second.startPos;
2515     info.currentOffset = GetCustomPropertyOffset() + Dimension(indexStartPos, DimensionUnit::PX).ConvertToVp();
2516     FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
2517     currentIndexOffset_ = indexStartPos;
2518     UpdateItemRenderGroup(false);
2519     NotifyParentScrollEnd();
2520     StartAutoPlay();
2521     fadeAnimationIsRunning_ = false;
2522 }
2523 
OnFadeAnimationStart()2524 void SwiperPattern::OnFadeAnimationStart()
2525 {
2526     AnimationCallbackInfo info;
2527     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2528     nextIndex_ = ComputeNextIndexByVelocity(0.0);
2529     if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
2530         info.targetOffset = info.currentOffset;
2531     } else {
2532         info.targetOffset = GetCustomPropertyOffset();
2533     }
2534 
2535     FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
2536     fadeAnimationIsRunning_ = true;
2537 }
2538 
PlayFadeAnimation()2539 void SwiperPattern::PlayFadeAnimation()
2540 {
2541     if (NearZero(fadeOffset_)) {
2542         fadeAnimationIsRunning_ = false;
2543         return;
2544     }
2545 
2546     auto host = GetHost();
2547     CHECK_NULL_VOID(host);
2548     auto weak = AceType::WeakClaim(this);
2549     host->CreateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0, Animation<double>::ValueCallback([weak](float value) {
2550         auto swiper = weak.Upgrade();
2551         if (swiper && swiper->GetHost() && !swiper->isTouchDown_) {
2552             swiper->fadeOffset_ = value;
2553             swiper->GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2554         }
2555     }));
2556 
2557     AnimationOption option;
2558     option.SetDuration(FADE_DURATION);
2559     option.SetCurve(Curves::LINEAR);
2560 
2561     host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, fadeOffset_);
2562     constexpr float end = 0.0f;
2563     nextIndex_ = currentIndex_;
2564     fadeAnimation_ = AnimationUtils::StartAnimation(option,
2565         [weak, host, end]() {
2566             auto swiperPattern = weak.Upgrade();
2567             CHECK_NULL_VOID(swiperPattern);
2568             swiperPattern->OnFadeAnimationStart();
2569             host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, end);
2570         },
2571         [weak]() {
2572             auto swiperPattern = weak.Upgrade();
2573             CHECK_NULL_VOID(swiperPattern);
2574             swiperPattern->OnSpringAndFadeAnimationFinish();
2575         });
2576 }
2577 
PlaySpringAnimation(double dragVelocity)2578 void SwiperPattern::PlaySpringAnimation(double dragVelocity)
2579 {
2580     auto host = GetHost();
2581     CHECK_NULL_VOID(host);
2582 
2583     auto mainSize = CalculateVisibleSize();
2584     if (LessOrEqual(mainSize, 0)) {
2585         return;
2586     }
2587     if (itemPosition_.empty()) {
2588         return;
2589     }
2590     childScrolling_ = false;
2591     auto leading = currentOffset_ + mainSize - itemPosition_.rbegin()->second.endPos;
2592     auto trailing = currentOffset_ - itemPosition_.begin()->second.startPos;
2593     ExtentPair extentPair = ExtentPair(leading, trailing);
2594 
2595     host->CreateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, 0, [weak = AceType::WeakClaim(this)](float position) {
2596         auto swiper = weak.Upgrade();
2597         CHECK_NULL_VOID(swiper);
2598         if (!swiper->isTouchDown_) {
2599             swiper->UpdateCurrentOffset(static_cast<float>(position) - swiper->currentOffset_);
2600         }
2601     }, PropertyUnit::PIXEL_POSITION);
2602 
2603     host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, currentOffset_);
2604     auto delta = currentOffset_ < 0.0f ? extentPair.Leading() : extentPair.Trailing();
2605 
2606     // spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
2607     auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
2608     AnimationOption option;
2609     option.SetCurve(springCurve);
2610     option.SetDuration(SPRING_DURATION);
2611 
2612     nextIndex_ = currentIndex_;
2613     springAnimation_ = AnimationUtils::StartAnimation(
2614         option,
2615         [weak = AceType::WeakClaim(this), dragVelocity, host, delta]() {
2616             auto swiperPattern = weak.Upgrade();
2617             CHECK_NULL_VOID(swiperPattern);
2618             swiperPattern->springAnimationIsRunning_ = true;
2619             swiperPattern->OnSpringAnimationStart(static_cast<float>(dragVelocity));
2620             host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, delta);
2621         },
2622         [weak = AceType::WeakClaim(this)]() {
2623             auto swiperPattern = weak.Upgrade();
2624             CHECK_NULL_VOID(swiperPattern);
2625             swiperPattern->springAnimationIsRunning_ = false;
2626             swiperPattern->isTouchDownSpringAnimation_ = false;
2627             swiperPattern->OnSpringAndFadeAnimationFinish();
2628         });
2629 }
2630 
IsOutOfBoundary(float mainOffset) const2631 bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
2632 {
2633     if (IsLoop() || itemPosition_.empty()) {
2634         return false;
2635     }
2636 
2637     auto startPos = itemPosition_.begin()->second.startPos;
2638     startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
2639     auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
2640 
2641     auto visibleWindowSize = CalculateVisibleSize();
2642     auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
2643     endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
2644     auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
2645 
2646     return isOutOfStart || isOutOfEnd;
2647 }
2648 
AutoLinearIsOutOfBoundary(float mainOffset) const2649 bool SwiperPattern::AutoLinearIsOutOfBoundary(float mainOffset) const
2650 {
2651     if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
2652         return false;
2653     }
2654 
2655     auto startPos = itemPosition_.begin()->second.startPos;
2656     auto isOutOfStart = GreatNotEqual(startPos + mainOffset, 0.0);
2657 
2658     auto visibleWindowSize = CalculateVisibleSize();
2659     auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
2660     auto isOutOfEnd = LessNotEqual(endPos, visibleWindowSize);
2661 
2662     return isOutOfStart || isOutOfEnd;
2663 }
2664 
GetDistanceToEdge() const2665 float SwiperPattern::GetDistanceToEdge() const
2666 {
2667     if (IsLoop() || itemPosition_.empty()) {
2668         return 0.0f;
2669     }
2670     if (itemPosition_.begin()->first == 0) {
2671         return -itemPosition_.begin()->second.startPos;
2672     }
2673     auto visibleWindowSize = CalculateVisibleSize();
2674     return itemPosition_.rbegin()->second.endPos - visibleWindowSize;
2675 }
2676 
MainSize() const2677 float SwiperPattern::MainSize() const
2678 {
2679     auto host = GetHost();
2680     CHECK_NULL_RETURN(host, 0.0);
2681     auto geometryNode = host->GetGeometryNode();
2682     CHECK_NULL_RETURN(geometryNode, 0.0);
2683     return geometryNode->GetFrameSize().MainSize(GetDirection());
2684 }
2685 
GetMainContentSize() const2686 float SwiperPattern::GetMainContentSize() const
2687 {
2688     auto host = GetHost();
2689     CHECK_NULL_RETURN(host, 0.0);
2690     auto geometryNode = host->GetGeometryNode();
2691     CHECK_NULL_RETURN(geometryNode, 0.0);
2692     return geometryNode->GetPaddingSize().Width();
2693 }
2694 
CalculateVisibleSize() const2695 float SwiperPattern::CalculateVisibleSize() const
2696 {
2697     auto prevMargin = GetPrevMargin();
2698     auto nextMargin = GetNextMargin();
2699     auto itemSpace = GetItemSpace();
2700     auto host = GetHost();
2701     CHECK_NULL_RETURN(host, 0.0f);
2702     auto geometryNode = host->GetGeometryNode();
2703     CHECK_NULL_RETURN(geometryNode, 0.0);
2704     auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
2705     if (itemSpace > mainSize) {
2706         itemSpace = 0.0f;
2707     }
2708     if (prevMargin != 0.0f) {
2709         if (nextMargin != 0.0f) {
2710             return contentMainSize_ - prevMargin - nextMargin - 2 * itemSpace;
2711         }
2712         return contentMainSize_ - prevMargin - itemSpace;
2713     }
2714 
2715     if (nextMargin != 0.0f) {
2716         return contentMainSize_ - nextMargin - itemSpace;
2717     }
2718     return contentMainSize_;
2719 }
2720 
GetItemSpace() const2721 float SwiperPattern::GetItemSpace() const
2722 {
2723     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2724     CHECK_NULL_RETURN(swiperLayoutProperty, 0.0f);
2725     if (swiperLayoutProperty->IgnoreItemSpace()) {
2726         return 0.0f;
2727     }
2728     return ConvertToPx(swiperLayoutProperty->GetItemSpace().value_or(0.0_vp),
2729         swiperLayoutProperty->GetLayoutConstraint()->scaleProperty, 0.0f)
2730         .value_or(0.0f);
2731 }
2732 
GetPrevMargin() const2733 float SwiperPattern::GetPrevMargin() const
2734 {
2735     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2736     CHECK_NULL_RETURN(swiperLayoutProperty, 0.0f);
2737     return SwiperUtils::IsStretch(swiperLayoutProperty) ?
2738         ConvertToPx(swiperLayoutProperty->GetPrevMargin().value_or(0.0_vp),
2739         swiperLayoutProperty->GetLayoutConstraint()->scaleProperty, 0).value_or(0) : 0.0f;
2740 }
2741 
GetNextMargin() const2742 float SwiperPattern::GetNextMargin() const
2743 {
2744     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2745     CHECK_NULL_RETURN(swiperLayoutProperty, 0.0f);
2746     return SwiperUtils::IsStretch(swiperLayoutProperty) ?
2747         ConvertToPx(swiperLayoutProperty->GetNextMargin().value_or(0.0_vp),
2748         swiperLayoutProperty->GetLayoutConstraint()->scaleProperty, 0).value_or(0) : 0.0f;
2749 }
2750 
GetDirection() const2751 Axis SwiperPattern::GetDirection() const
2752 {
2753     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2754     CHECK_NULL_RETURN(swiperLayoutProperty, Axis::HORIZONTAL);
2755     return swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
2756 }
2757 
CurrentIndex() const2758 int32_t SwiperPattern::CurrentIndex() const
2759 {
2760     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2761     CHECK_NULL_RETURN(swiperLayoutProperty, 0);
2762     return swiperLayoutProperty->GetIndex().value_or(0);
2763 }
2764 
GetDisplayCount() const2765 int32_t SwiperPattern::GetDisplayCount() const
2766 {
2767     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2768     CHECK_NULL_RETURN(swiperLayoutProperty, 1);
2769     auto displayCount = CalculateDisplayCount();
2770     return displayCount;
2771 }
2772 
CalculateDisplayCount() const2773 int32_t SwiperPattern::CalculateDisplayCount() const
2774 {
2775     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2776     CHECK_NULL_RETURN(swiperLayoutProperty, 1);
2777     bool isAutoFill = IsAutoFill();
2778     if (isAutoFill) {
2779         auto minSize = swiperLayoutProperty->GetMinSize()->ConvertToPx();
2780         float contentWidth = GetMainContentSize();
2781         auto displayCount =
2782             CalculateCount(contentWidth, minSize, SWIPER_MARGIN.ConvertToPx(), SWIPER_GUTTER.ConvertToPx());
2783         if (LessOrEqual(minSize, 0)) {
2784             displayCount = 1;
2785         }
2786         displayCount = displayCount > 0 ? displayCount : 1;
2787         auto totalCount = TotalCount();
2788         displayCount = displayCount > totalCount ? totalCount : displayCount;
2789         auto displayCountProperty = swiperLayoutProperty->GetDisplayCount().value_or(1);
2790 
2791         if (displayCountProperty != displayCount) {
2792             swiperLayoutProperty->UpdateDisplayCount(displayCount);
2793             auto host = GetHost();
2794             CHECK_NULL_RETURN(host, 1);
2795             host->MarkDirtyNode(
2796                 (crossMatchChild_ ? PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD : PROPERTY_UPDATE_MEASURE_SELF) |
2797                 PROPERTY_UPDATE_RENDER);
2798         }
2799         return displayCount;
2800     } else {
2801         return swiperLayoutProperty->GetDisplayCount().value_or(1);
2802     }
2803 }
2804 
CalculateCount(float contentWidth,float minSize,float margin,float gutter,float swiperPadding) const2805 int32_t SwiperPattern::CalculateCount(
2806     float contentWidth, float minSize, float margin, float gutter, float swiperPadding) const
2807 {
2808     return static_cast<int32_t>(floor((contentWidth - 2 * margin + gutter - 2 * swiperPadding) / (minSize + gutter)));
2809 }
2810 
IsAutoFill() const2811 bool SwiperPattern::IsAutoFill() const
2812 {
2813     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2814     CHECK_NULL_RETURN(swiperLayoutProperty, false);
2815     return swiperLayoutProperty->GetMinSize().has_value();
2816 }
2817 
IsAutoPlay() const2818 bool SwiperPattern::IsAutoPlay() const
2819 {
2820     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2821     CHECK_NULL_RETURN(swiperPaintProperty, false);
2822     return swiperPaintProperty->GetAutoPlay().value_or(false);
2823 }
2824 
GetDuration() const2825 int32_t SwiperPattern::GetDuration() const
2826 {
2827     const int32_t DEFAULT_DURATION = 400;
2828     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2829     CHECK_NULL_RETURN(swiperPaintProperty, DEFAULT_DURATION);
2830     return swiperPaintProperty->GetDuration().value_or(DEFAULT_DURATION);
2831 }
2832 
GetInterval() const2833 int32_t SwiperPattern::GetInterval() const
2834 {
2835     const int32_t DEFAULT_INTERVAL = 3000;
2836     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2837     CHECK_NULL_RETURN(swiperPaintProperty, DEFAULT_INTERVAL);
2838     return swiperPaintProperty->GetAutoPlayInterval().value_or(DEFAULT_INTERVAL);
2839 }
2840 
GetCurve() const2841 RefPtr<Curve> SwiperPattern::GetCurve() const
2842 {
2843     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2844     CHECK_NULL_RETURN(swiperPaintProperty, nullptr);
2845     return swiperPaintProperty->GetCurve().value_or(nullptr);
2846 }
2847 
IsLoop() const2848 bool SwiperPattern::IsLoop() const
2849 {
2850     if (TotalDisPlayCount() >= TotalCount()) {
2851         return false;
2852     }
2853     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2854     CHECK_NULL_RETURN(swiperLayoutProperty, true);
2855     return swiperLayoutProperty->GetLoop().value_or(true);
2856 }
2857 
IsEnabled() const2858 bool SwiperPattern::IsEnabled() const
2859 {
2860     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2861     CHECK_NULL_RETURN(swiperPaintProperty, true);
2862     return swiperPaintProperty->GetEnabled().value_or(true);
2863 }
2864 
GetEdgeEffect() const2865 EdgeEffect SwiperPattern::GetEdgeEffect() const
2866 {
2867     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2868     CHECK_NULL_RETURN(swiperPaintProperty, EdgeEffect::SPRING);
2869     return swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
2870 }
2871 
IsDisableSwipe() const2872 bool SwiperPattern::IsDisableSwipe() const
2873 {
2874     auto props = GetLayoutProperty<SwiperLayoutProperty>();
2875     CHECK_NULL_RETURN(props, false);
2876     return props->GetDisableSwipe().value_or(false);
2877 }
2878 
IsShowIndicator() const2879 bool SwiperPattern::IsShowIndicator() const
2880 {
2881     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2882     CHECK_NULL_RETURN(swiperLayoutProperty, true);
2883     return swiperLayoutProperty->GetShowIndicatorValue(true);
2884 }
2885 
IsShowArrow() const2886 bool SwiperPattern::IsShowArrow() const
2887 {
2888     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2889     CHECK_NULL_RETURN(swiperLayoutProperty, true);
2890     return swiperLayoutProperty->GetDisplayArrowValue(false);
2891 }
2892 
GetIndicatorType() const2893 SwiperIndicatorType SwiperPattern::GetIndicatorType() const
2894 {
2895     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2896     CHECK_NULL_RETURN(swiperLayoutProperty, SwiperIndicatorType::DOT);
2897     return swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
2898 }
2899 
GetSwiperParameters() const2900 std::shared_ptr<SwiperParameters> SwiperPattern::GetSwiperParameters() const
2901 {
2902     if (swiperParameters_ == nullptr) {
2903         swiperParameters_ = std::make_shared<SwiperParameters>();
2904         auto pipelineContext = PipelineBase::GetCurrentContext();
2905         CHECK_NULL_RETURN(pipelineContext, swiperParameters_);
2906         auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
2907         swiperParameters_->itemWidth = swiperIndicatorTheme->GetSize();
2908         swiperParameters_->itemHeight = swiperIndicatorTheme->GetSize();
2909         swiperParameters_->selectedItemWidth = swiperIndicatorTheme->GetSize();
2910         swiperParameters_->selectedItemHeight = swiperIndicatorTheme->GetSize();
2911         swiperParameters_->maskValue = false;
2912         swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
2913         swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
2914     }
2915     return swiperParameters_;
2916 }
2917 
GetSwiperDigitalParameters() const2918 std::shared_ptr<SwiperDigitalParameters> SwiperPattern::GetSwiperDigitalParameters() const
2919 {
2920     if (swiperDigitalParameters_ == nullptr) {
2921         swiperDigitalParameters_ = std::make_shared<SwiperDigitalParameters>();
2922         auto pipelineContext = PipelineBase::GetCurrentContext();
2923         CHECK_NULL_RETURN(pipelineContext, swiperDigitalParameters_);
2924         auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
2925         swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
2926         swiperDigitalParameters_->selectedFontColor =
2927             swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
2928         swiperDigitalParameters_->fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
2929         swiperDigitalParameters_->selectedFontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
2930         swiperDigitalParameters_->fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
2931         swiperDigitalParameters_->selectedFontWeight =
2932             swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
2933     }
2934     return swiperDigitalParameters_;
2935 }
2936 
TotalCount() const2937 int32_t SwiperPattern::TotalCount() const
2938 {
2939     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2940     CHECK_NULL_RETURN(layoutProperty, 1);
2941     auto displayCount = layoutProperty->GetDisplayCount().value_or(1);
2942     auto totalCount = RealTotalCount();
2943     if (IsSwipeByGroup() && displayCount != 0) {
2944         totalCount =
2945             static_cast<int32_t>(std::ceil(static_cast<float>(totalCount) / static_cast<float>(displayCount))) *
2946             displayCount;
2947     }
2948 
2949     return totalCount;
2950 }
2951 
RealTotalCount() const2952 int32_t SwiperPattern::RealTotalCount() const
2953 {
2954     auto host = GetHost();
2955     CHECK_NULL_RETURN(host, 0);
2956     // last child is swiper indicator
2957     int num = 0;
2958     if (IsShowIndicator()) {
2959         num += 1;
2960     }
2961     if (HasLeftButtonNode()) {
2962         num += 1;
2963     }
2964     if (HasRightButtonNode()) {
2965         num += 1;
2966     }
2967 
2968     return host->TotalChildCount() - num;
2969 }
2970 
GetTranslateLength() const2971 float SwiperPattern::GetTranslateLength() const
2972 {
2973     if (itemPosition_.empty()) {
2974         return 0.0f;
2975     }
2976     return itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
2977 }
2978 
GetFirstItemInfoInVisibleArea() const2979 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetFirstItemInfoInVisibleArea() const
2980 {
2981     if (itemPosition_.empty()) {
2982         return std::make_pair(0, SwiperItemInfo {});
2983     }
2984     auto targetIndex = 0;
2985     if (GetPrevMargin() != 0.0f) {
2986         for (const auto& item : itemPosition_) {
2987             if (item.second.startPos < 0 && item.second.endPos < 0) {
2988                 continue;
2989             }
2990             if (item.second.startPos <= 0 && item.second.endPos > 0) {
2991                 targetIndex = item.first;
2992                 return std::make_pair(targetIndex, SwiperItemInfo { item.second.startPos, item.second.endPos });
2993             }
2994             if (item.second.startPos > 0 && item.second.endPos > 0) {
2995                 targetIndex = item.first;
2996                 return std::make_pair(targetIndex, SwiperItemInfo { item.second.startPos, item.second.endPos });
2997             }
2998         }
2999     }
3000     return std::make_pair(itemPosition_.begin()->first,
3001         SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
3002 }
3003 
GetLastItemInfoInVisibleArea() const3004 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetLastItemInfoInVisibleArea() const
3005 {
3006     if (itemPosition_.empty()) {
3007         return std::make_pair(0, SwiperItemInfo {});
3008     }
3009     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3010     auto targetVisableIndex = firstItemInfoInVisibleArea.first;
3011     targetVisableIndex += GetDisplayCount() - 1;
3012     auto iter = itemPosition_.find(targetVisableIndex);
3013     if (iter != itemPosition_.end()) {
3014         return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
3015     }
3016     return std::make_pair(itemPosition_.rbegin()->first,
3017         SwiperItemInfo { itemPosition_.rbegin()->second.startPos, itemPosition_.rbegin()->second.endPos });
3018 }
3019 
GetSecondItemInfoInVisibleArea() const3020 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetSecondItemInfoInVisibleArea() const
3021 {
3022     if (itemPosition_.empty()) {
3023         return std::make_pair(0, SwiperItemInfo {});
3024     }
3025     auto targetIndex = itemPosition_.begin()->first;
3026     if (GetPrevMargin() != 0.0f) {
3027         for (const auto& item : itemPosition_) {
3028             if (item.second.startPos < 0 && item.second.endPos < 0) {
3029                 continue;
3030             }
3031             if (item.second.startPos <= 0 && item.second.endPos > 0) {
3032                 targetIndex = item.first;
3033                 break;
3034             }
3035             if (item.second.startPos > 0 && item.second.endPos > 0) {
3036                 targetIndex = item.first;
3037                 break;
3038             }
3039         }
3040     }
3041 
3042     targetIndex++;
3043     auto iter = itemPosition_.find(targetIndex);
3044     if (iter != itemPosition_.end()) {
3045         return std::make_pair(targetIndex, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
3046     }
3047     return std::make_pair(itemPosition_.begin()->first,
3048         SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
3049 }
3050 
IsOutOfHotRegion(const PointF & dragPoint) const3051 bool SwiperPattern::IsOutOfHotRegion(const PointF& dragPoint) const
3052 {
3053     auto host = GetHost();
3054     CHECK_NULL_RETURN(host, true);
3055     auto context = host->GetRenderContext();
3056     CHECK_NULL_RETURN(context, true);
3057 
3058     auto hotRegion = context->GetPaintRectWithoutTransform();
3059     return !hotRegion.IsInRegion(dragPoint + OffsetF(hotRegion.GetX(), hotRegion.GetY()));
3060 }
3061 
SaveDotIndicatorProperty(const RefPtr<FrameNode> & indicatorNode)3062 void SwiperPattern::SaveDotIndicatorProperty(const RefPtr<FrameNode>& indicatorNode)
3063 {
3064     CHECK_NULL_VOID(indicatorNode);
3065     auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
3066     CHECK_NULL_VOID(indicatorPattern);
3067     auto layoutProperty = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
3068     CHECK_NULL_VOID(layoutProperty);
3069     auto paintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
3070     CHECK_NULL_VOID(paintProperty);
3071     auto pipelineContext = PipelineBase::GetCurrentContext();
3072     CHECK_NULL_VOID(pipelineContext);
3073     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
3074     CHECK_NULL_VOID(swiperIndicatorTheme);
3075     auto swiperParameters = GetSwiperParameters();
3076     CHECK_NULL_VOID(swiperParameters);
3077     layoutProperty->ResetIndicatorLayoutStyle();
3078     if (swiperParameters->dimLeft.has_value()) {
3079         layoutProperty->UpdateLeft(swiperParameters->dimLeft.value());
3080     }
3081     if (swiperParameters->dimTop.has_value()) {
3082         layoutProperty->UpdateTop(swiperParameters->dimTop.value());
3083     }
3084     if (swiperParameters->dimRight.has_value()) {
3085         layoutProperty->UpdateRight(swiperParameters->dimRight.value());
3086     }
3087     if (swiperParameters->dimBottom.has_value()) {
3088         layoutProperty->UpdateBottom(swiperParameters->dimBottom.value());
3089     }
3090     paintProperty->UpdateItemWidth(swiperParameters->itemWidth.value_or(swiperIndicatorTheme->GetSize()));
3091     paintProperty->UpdateItemHeight(swiperParameters->itemHeight.value_or(swiperIndicatorTheme->GetSize()));
3092     paintProperty->UpdateSelectedItemWidth(
3093         swiperParameters->selectedItemWidth.value_or(swiperIndicatorTheme->GetSize()));
3094     paintProperty->UpdateSelectedItemHeight(
3095         swiperParameters->selectedItemHeight.value_or(swiperIndicatorTheme->GetSize()));
3096     paintProperty->UpdateIndicatorMask(swiperParameters->maskValue.value_or(false));
3097     paintProperty->UpdateColor(swiperParameters->colorVal.value_or(swiperIndicatorTheme->GetColor()));
3098     paintProperty->UpdateSelectedColor(
3099         swiperParameters->selectedColorVal.value_or(swiperIndicatorTheme->GetSelectedColor()));
3100     paintProperty->UpdateIsCustomSize(IsCustomSize_);
3101 
3102     MarkDirtyNodeSelf();
3103     indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3104 }
3105 
SaveDigitIndicatorProperty(const RefPtr<FrameNode> & indicatorNode)3106 void SwiperPattern::SaveDigitIndicatorProperty(const RefPtr<FrameNode>& indicatorNode)
3107 {
3108     CHECK_NULL_VOID(indicatorNode);
3109     auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
3110     CHECK_NULL_VOID(indicatorPattern);
3111     auto layoutProperty = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
3112     CHECK_NULL_VOID(layoutProperty);
3113     auto pipelineContext = PipelineBase::GetCurrentContext();
3114     CHECK_NULL_VOID(pipelineContext);
3115     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
3116     auto swiperDigitalParameters = GetSwiperDigitalParameters();
3117     CHECK_NULL_VOID(swiperDigitalParameters);
3118     layoutProperty->ResetIndicatorLayoutStyle();
3119     if (swiperDigitalParameters->dimLeft.has_value()) {
3120         layoutProperty->UpdateLeft(swiperDigitalParameters->dimLeft.value());
3121     }
3122     if (swiperDigitalParameters->dimTop.has_value()) {
3123         layoutProperty->UpdateTop(swiperDigitalParameters->dimTop.value());
3124     }
3125     if (swiperDigitalParameters->dimRight.has_value()) {
3126         layoutProperty->UpdateRight(swiperDigitalParameters->dimRight.value());
3127     }
3128     if (swiperDigitalParameters->dimBottom.has_value()) {
3129         layoutProperty->UpdateBottom(swiperDigitalParameters->dimBottom.value());
3130     }
3131     layoutProperty->UpdateFontColor(swiperDigitalParameters->fontColor.value_or(
3132         swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor()));
3133     layoutProperty->UpdateSelectedFontColor(swiperDigitalParameters->selectedFontColor.value_or(
3134         swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor()));
3135     layoutProperty->UpdateFontSize(
3136         swiperDigitalParameters->fontSize.value_or(swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize()));
3137     layoutProperty->UpdateSelectedFontSize(swiperDigitalParameters->selectedFontSize.value_or(
3138         swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize()));
3139     layoutProperty->UpdateFontWeight(swiperDigitalParameters->fontWeight.value_or(
3140         swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight()));
3141     layoutProperty->UpdateSelectedFontWeight(swiperDigitalParameters->selectedFontWeight.value_or(
3142         swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight()));
3143     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3144     CHECK_NULL_VOID(swiperLayoutProperty);
3145     swiperLayoutProperty->UpdateLeft(swiperDigitalParameters->dimLeft.value_or(0.0_vp));
3146     swiperLayoutProperty->UpdateTop(swiperDigitalParameters->dimTop.value_or(0.0_vp));
3147     swiperLayoutProperty->UpdateRight(swiperDigitalParameters->dimRight.value_or(0.0_vp));
3148     swiperLayoutProperty->UpdateBottom(swiperDigitalParameters->dimBottom.value_or(0.0_vp));
3149 }
3150 
PostTranslateTask(uint32_t delayTime)3151 void SwiperPattern::PostTranslateTask(uint32_t delayTime)
3152 {
3153     auto pipeline = PipelineContext::GetCurrentContext();
3154     CHECK_NULL_VOID(pipeline);
3155     auto taskExecutor = pipeline->GetTaskExecutor();
3156     CHECK_NULL_VOID(taskExecutor);
3157 
3158     if (translateTask_) {
3159         translateTask_.Cancel();
3160     }
3161 
3162     auto weak = AceType::WeakClaim(this);
3163     translateTask_.Reset([weak, delayTime] {
3164         auto swiper = weak.Upgrade();
3165         if (swiper) {
3166             auto childrenSize = swiper->TotalCount();
3167             auto displayCount = swiper->GetDisplayCount();
3168             if (childrenSize <= 0 || displayCount <= 0 || swiper->itemPosition_.empty()) {
3169                 return;
3170             }
3171             if (!swiper->IsLoop() && swiper->GetLoopIndex(swiper->currentIndex_) + 1 > (childrenSize - displayCount)) {
3172                 return;
3173             }
3174             auto stepItems = swiper->IsSwipeByGroup() ? displayCount : 1;
3175             swiper->targetIndex_ = swiper->CheckTargetIndex(swiper->currentIndex_ + stepItems);
3176             swiper->MarkDirtyNodeSelf();
3177             auto pipeline = PipelineContext::GetCurrentContext();
3178             if (pipeline) {
3179                 pipeline->FlushUITasks();
3180             }
3181         }
3182     });
3183 
3184     taskExecutor->PostDelayedTask(translateTask_, TaskExecutor::TaskType::UI, delayTime);
3185 }
3186 
RegisterVisibleAreaChange()3187 void SwiperPattern::RegisterVisibleAreaChange()
3188 {
3189     auto pipeline = PipelineContext::GetCurrentContext();
3190     CHECK_NULL_VOID(pipeline);
3191     auto host = GetHost();
3192     CHECK_NULL_VOID(host);
3193     pipeline->AddWindowStateChangedCallback(host->GetId());
3194 
3195     if (hasVisibleChangeRegistered_ || !IsAutoPlay()) {
3196         return;
3197     }
3198 
3199     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
3200         auto swiperPattern = weak.Upgrade();
3201         CHECK_NULL_VOID(swiperPattern);
3202         swiperPattern->isVisibleArea_ = visible;
3203         if (!visible) {
3204             swiperPattern->translateTask_.Cancel();
3205             return;
3206         }
3207 
3208         if (swiperPattern->NeedStartAutoPlay()) {
3209             swiperPattern->StartAutoPlay();
3210         }
3211     };
3212     pipeline->RemoveVisibleAreaChangeNode(host->GetId());
3213     pipeline->AddVisibleAreaChangeNode(host, 0.0f, callback, false);
3214     hasVisibleChangeRegistered_ = true;
3215 }
3216 
NeedAutoPlay() const3217 bool SwiperPattern::NeedAutoPlay() const
3218 {
3219     bool reachEnd = GetLoopIndex(CurrentIndex()) >= TotalCount() - 1 && !IsLoop();
3220     return IsAutoPlay() && !reachEnd && isVisible_ && !isIndicatorLongPress_;
3221 }
3222 
TriggerAnimationEndOnSwipeToLeft()3223 void SwiperPattern::TriggerAnimationEndOnSwipeToLeft()
3224 {
3225     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3226     auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3227     auto firstIndexStartPos = firstItemInfoInVisibleArea.second.startPos;
3228     if (std::abs(firstIndexStartPos) < (firstItemLength / 2)) {
3229         currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
3230         UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
3231     } else {
3232         auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
3233         currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
3234         UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
3235     }
3236 }
3237 
TriggerAnimationEndOnSwipeToRight()3238 void SwiperPattern::TriggerAnimationEndOnSwipeToRight()
3239 {
3240     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3241     auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3242     auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
3243     auto secondIndexStartPos = secondItemInfoInVisibleArea.second.startPos;
3244     if (std::abs(secondIndexStartPos) < (firstItemLength / 2)) {
3245         currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
3246         UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
3247     } else {
3248         currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
3249         UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
3250     }
3251 }
3252 
UpdateIndexOnAnimationStop()3253 void SwiperPattern::UpdateIndexOnAnimationStop()
3254 {
3255     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3256     if (currentIndex_ == firstItemInfoInVisibleArea.first) {
3257         // swipe to left
3258         TriggerAnimationEndOnSwipeToLeft();
3259     } else {
3260         // swipe to right
3261         TriggerAnimationEndOnSwipeToRight();
3262     }
3263 }
3264 
UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)3265 void SwiperPattern::UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)
3266 {
3267     auto iter = itemPosition_.find(currentIndex_);
3268     if (iter == itemPosition_.end()) {
3269         UpdateCurrentIndex(pauseTargetIndex);
3270         if (itemPosition_.find(pauseTargetIndex) != itemPosition_.end()) {
3271             currentIndexOffset_ = itemPosition_.find(pauseTargetIndex)->second.startPos;
3272         }
3273         return;
3274     }
3275 
3276     auto swiperWidth = MainSize();
3277     auto currentOffset = iter->second.startPos;
3278     if (std::abs(currentOffset) < (swiperWidth / 2)) {
3279         return;
3280     }
3281 
3282     if (currentOffset < 0.0f) {
3283         auto nextPageIndex = currentIndex_ + GetDisplayCount();
3284         auto nextIter = itemPosition_.find(nextPageIndex);
3285         if (nextIter == itemPosition_.end()) {
3286             return;
3287         }
3288 
3289         auto nextPageOffset = nextIter->second.startPos;
3290         currentIndexOffset_ = nextPageOffset;
3291         UpdateCurrentIndex(nextPageIndex);
3292     } else {
3293         auto prevPageIndex = currentIndex_ - GetDisplayCount();
3294         auto prevIter = itemPosition_.find(prevPageIndex);
3295         if (prevIter == itemPosition_.end()) {
3296             return;
3297         }
3298 
3299         auto prevPageOffset = prevIter->second.startPos;
3300         currentIndexOffset_ = prevPageOffset;
3301         UpdateCurrentIndex(prevPageIndex);
3302     }
3303 }
3304 
TriggerAnimationEndOnForceStop()3305 void SwiperPattern::TriggerAnimationEndOnForceStop()
3306 {
3307     auto pauseTargetIndex = pauseTargetIndex_.has_value() ? pauseTargetIndex_.value() : currentIndex_;
3308     if (currentIndex_ != pauseTargetIndex) {
3309         if (IsSwipeByGroup()) {
3310             UpdateIndexOnSwipePageStop(pauseTargetIndex);
3311         } else {
3312             UpdateIndexOnAnimationStop();
3313         }
3314         do {
3315             auto curChildFrame = GetCurrentFrameNode(currentIndex_);
3316             if (!curChildFrame) {
3317                 break;
3318             }
3319             FlushFocus(curChildFrame);
3320             currentFocusIndex_ = currentIndex_;
3321         } while (0);
3322 
3323         OnIndexChange();
3324         oldIndex_ = currentIndex_;
3325     }
3326     AnimationCallbackInfo info;
3327     info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3328     FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
3329     UpdateItemRenderGroup(false);
3330 }
3331 
TriggerEventOnFinish(int32_t nextIndex)3332 void SwiperPattern::TriggerEventOnFinish(int32_t nextIndex)
3333 {
3334     ResetAndUpdateIndexOnAnimationEnd(nextIndex);
3335 
3336     AnimationCallbackInfo info;
3337     info.currentOffset = GetCustomPropertyOffset();
3338     FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
3339 }
3340 
GetCachedCount() const3341 int32_t SwiperPattern::GetCachedCount() const
3342 {
3343     auto host = GetHost();
3344     CHECK_NULL_RETURN(host, 1);
3345     auto layoutProperty = host->GetLayoutProperty<SwiperLayoutProperty>();
3346     CHECK_NULL_RETURN(layoutProperty, 1);
3347     auto cachedCount = layoutProperty->GetCachedCount().value_or(1);
3348 
3349     if (IsSwipeByGroup()) {
3350         cachedCount *= GetDisplayCount();
3351     }
3352 
3353     return cachedCount;
3354 }
3355 
SetLazyLoadFeature(bool useLazyLoad) const3356 void SwiperPattern::SetLazyLoadFeature(bool useLazyLoad) const
3357 {
3358     SetLazyForEachLongPredict(useLazyLoad);
3359 
3360     if (useLazyLoad) {
3361         auto cacheCount = GetCachedCount();
3362         std::set<int32_t> forEachIndexSet;
3363         for (auto count = 1; count <= cacheCount; count++) {
3364             forEachIndexSet.emplace(GetLoopIndex(currentIndex_ + count));
3365             forEachIndexSet.emplace(GetLoopIndex(currentIndex_ - count));
3366         }
3367         if (forEachIndexSet.empty()) {
3368             return;
3369         }
3370 
3371         auto host = GetHost();
3372         CHECK_NULL_VOID(host);
3373         const auto& children = host->GetChildren();
3374         for (const auto& child : children) {
3375             if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
3376                 continue;
3377             }
3378             auto pipeline = PipelineContext::GetCurrentContext();
3379             CHECK_NULL_VOID(pipeline);
3380             auto taskExecutor = pipeline->GetTaskExecutor();
3381             CHECK_NULL_VOID(taskExecutor);
3382             taskExecutor->PostTask(
3383                 [weak = WeakClaim(RawPtr(child)), forEachIndexSet]() {
3384                     auto node = weak.Upgrade();
3385                     CHECK_NULL_VOID(node);
3386                     auto forEachNode = AceType::DynamicCast<ForEachNode>(node);
3387                     CHECK_NULL_VOID(forEachNode);
3388                     for (auto index : forEachIndexSet) {
3389                         auto childNode = forEachNode->GetChildAtIndex(index);
3390                         CHECK_NULL_VOID(childNode);
3391                         childNode->Build(nullptr);
3392                     }
3393                 },
3394                 TaskExecutor::TaskType::UI);
3395         }
3396     }
3397 }
3398 
SetLazyForEachLongPredict(bool useLazyLoad) const3399 void SwiperPattern::SetLazyForEachLongPredict(bool useLazyLoad) const
3400 {
3401     // lazyBuild feature.
3402     auto host = GetHost();
3403     CHECK_NULL_VOID(host);
3404     const auto& children = host->GetChildren();
3405     for (auto&& child : children) {
3406         auto lazyForEach = DynamicCast<LazyForEachNode>(child);
3407         if (lazyForEach) {
3408             lazyForEach->SetRequestLongPredict(useLazyLoad);
3409         }
3410     }
3411 }
3412 
SetLazyLoadIsLoop() const3413 void SwiperPattern::SetLazyLoadIsLoop() const
3414 {
3415     auto host = GetHost();
3416     CHECK_NULL_VOID(host);
3417     const auto& children = host->GetChildren();
3418     for (auto&& child : children) {
3419         auto lazyForEach = DynamicCast<LazyForEachNode>(child);
3420         if (lazyForEach) {
3421             lazyForEach->SetIsLoop(IsLoop());
3422         }
3423     }
3424 }
3425 
IsVisibleChildrenSizeLessThanSwiper()3426 bool SwiperPattern::IsVisibleChildrenSizeLessThanSwiper()
3427 {
3428     if (itemPosition_.empty()) {
3429         return true;
3430     }
3431     auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3432     auto lastItemInfoInVisibleArea = GetLastItemInfoInVisibleArea();
3433     auto calcDisPlayCount = lastItemInfoInVisibleArea.first - firstItemInfoInVisibleArea.first + 1;
3434     if (Positive(TotalCount() - calcDisPlayCount)) {
3435         return false;
3436     }
3437     if (static_cast<int32_t>(itemPosition_.size()) == TotalCount()) {
3438         auto totalChildrenSize = lastItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3439         if (NonPositive(totalChildrenSize)) {
3440             return true;
3441         }
3442         auto prevMargin = GetPrevMargin();
3443         auto nextMargin = GetNextMargin();
3444         auto itemSpace = GetItemSpace();
3445         auto host = GetHost();
3446         CHECK_NULL_RETURN(host, true);
3447         auto geometryNode = host->GetGeometryNode();
3448         CHECK_NULL_RETURN(geometryNode, true);
3449         auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
3450         if (itemSpace > mainSize) {
3451             itemSpace = 0.0f;
3452         }
3453         auto prevMarginMontage = Positive(prevMargin) ? prevMargin + itemSpace : 0.0f;
3454         auto nextMarginMontage = Positive(nextMargin) ? nextMargin + itemSpace : 0.0f;
3455 
3456         if (totalChildrenSize <= (contentMainSize_ - prevMarginMontage - nextMarginMontage)) {
3457             return true;
3458         }
3459     }
3460     return false;
3461 }
3462 
UpdateItemRenderGroup(bool itemRenderGroup)3463 void SwiperPattern::UpdateItemRenderGroup(bool itemRenderGroup)
3464 {
3465     for (auto& item : itemPosition_) {
3466         if (auto frameNode = item.second.node) {
3467             auto context = frameNode->GetRenderContext();
3468             CHECK_NULL_VOID(context);
3469             context->UpdateSuggestedRenderGroup(itemRenderGroup);
3470         }
3471     }
3472     auto host = GetHost();
3473     CHECK_NULL_VOID(host);
3474     for (auto child : host->GetChildren()) {
3475         auto frameNode = DynamicCast<FrameNode>(child);
3476         if (!frameNode || child->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
3477             continue;
3478         }
3479         auto context = frameNode->GetRenderContext();
3480         CHECK_NULL_VOID(context);
3481         context->UpdateSuggestedRenderGroup(itemRenderGroup);
3482     }
3483 }
3484 
OnTranslateFinish(int32_t nextIndex,bool restartAutoPlay,bool isFinishAnimation,bool forceStop)3485 void SwiperPattern::OnTranslateFinish(int32_t nextIndex, bool restartAutoPlay, bool isFinishAnimation, bool forceStop)
3486 {
3487     if (forceStop && !isFinishAnimation) {
3488         TriggerAnimationEndOnForceStop();
3489     } else {
3490         TriggerEventOnFinish(nextIndex);
3491     }
3492 
3493     auto host = GetHost();
3494     CHECK_NULL_VOID(host);
3495     if (HasIndicatorNode()) {
3496         auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
3497         CHECK_NULL_VOID(indicatorNode);
3498         if (indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
3499             indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3500             MarkDirtyNodeSelf();
3501         }
3502     }
3503 
3504     auto delayTime = GetInterval() - GetDuration();
3505     delayTime = std::clamp(delayTime, 0, delayTime);
3506     if (NeedAutoPlay() && isUserFinish_ && !forceStop) {
3507         PostTranslateTask(delayTime);
3508     }
3509     host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
3510     UpdateItemRenderGroup(false);
3511 }
3512 
OnWindowShow()3513 void SwiperPattern::OnWindowShow()
3514 {
3515     isWindowShow_ = true;
3516     if (NeedStartAutoPlay()) {
3517         StartAutoPlay();
3518     }
3519 }
3520 
OnWindowHide()3521 void SwiperPattern::OnWindowHide()
3522 {
3523     isWindowShow_ = false;
3524     StopAutoPlay();
3525 
3526     if (isDragging_) {
3527         HandleDragEnd(0.0);
3528     }
3529 
3530     StopSpringAnimationAndFlushImmediately();
3531 }
3532 
ArrowHover(bool hoverFlag)3533 void SwiperPattern::ArrowHover(bool hoverFlag)
3534 {
3535     if (HasLeftButtonNode() && HasRightButtonNode()) {
3536         auto swiperNode = GetHost();
3537         CHECK_NULL_VOID(swiperNode);
3538         auto leftArrowNode =
3539             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
3540         CHECK_NULL_VOID(leftArrowNode);
3541         auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
3542         CHECK_NULL_VOID(leftArrowPattern);
3543         leftArrowPattern->SetButtonVisible(hoverFlag);
3544         auto rightArrowNode =
3545             DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
3546         CHECK_NULL_VOID(rightArrowNode);
3547         auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
3548         CHECK_NULL_VOID(rightArrowPattern);
3549         rightArrowPattern->SetButtonVisible(hoverFlag);
3550     }
3551 }
3552 
SaveArrowProperty(const RefPtr<FrameNode> & arrowNode)3553 void SwiperPattern::SaveArrowProperty(const RefPtr<FrameNode>& arrowNode)
3554 {
3555     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3556     CHECK_NULL_VOID(layoutProperty);
3557     auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
3558     CHECK_NULL_VOID(swiperPaintProperty);
3559     auto arrowLayoutProperty = arrowNode->GetLayoutProperty<SwiperArrowLayoutProperty>();
3560     CHECK_NULL_VOID(arrowLayoutProperty);
3561     arrowLayoutProperty->UpdateDirection(layoutProperty->GetDirection().value_or(Axis::HORIZONTAL));
3562     arrowLayoutProperty->UpdateIndex(layoutProperty->GetIndex().value_or(0));
3563     arrowLayoutProperty->UpdateLoop(layoutProperty->GetLoop().value_or(true));
3564     arrowLayoutProperty->UpdateEnabled(swiperPaintProperty->GetEnabled().value_or(true));
3565     arrowLayoutProperty->UpdateDisplayArrow(layoutProperty->GetDisplayArrowValue());
3566     arrowLayoutProperty->UpdateHoverShow(layoutProperty->GetHoverShowValue());
3567     arrowLayoutProperty->UpdateIsShowBackground(layoutProperty->GetIsShowBackgroundValue());
3568     arrowLayoutProperty->UpdateBackgroundSize(layoutProperty->GetBackgroundSizeValue());
3569     arrowLayoutProperty->UpdateBackgroundColor(layoutProperty->GetBackgroundColorValue());
3570     arrowLayoutProperty->UpdateArrowSize(layoutProperty->GetArrowSizeValue());
3571     arrowLayoutProperty->UpdateArrowColor(layoutProperty->GetArrowColorValue());
3572     arrowLayoutProperty->UpdateIsSidebarMiddle(layoutProperty->GetIsSidebarMiddleValue());
3573 }
3574 
SetAccessibilityAction()3575 void SwiperPattern::SetAccessibilityAction()
3576 {
3577     auto host = GetHost();
3578     CHECK_NULL_VOID(host);
3579     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
3580     CHECK_NULL_VOID(accessibilityProperty);
3581     accessibilityProperty->SetActionScrollForward(
3582         [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
3583             const auto& pattern = weakPtr.Upgrade();
3584             CHECK_NULL_VOID(pattern);
3585             const auto& accessibilityProperty = accessibility.Upgrade();
3586             CHECK_NULL_VOID(accessibilityProperty);
3587             if (!accessibilityProperty->IsScrollable()) {
3588                 return;
3589             }
3590             pattern->ShowNext();
3591         });
3592 
3593     accessibilityProperty->SetActionScrollBackward(
3594         [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
3595             const auto& pattern = weakPtr.Upgrade();
3596             CHECK_NULL_VOID(pattern);
3597             const auto& accessibilityProperty = accessibility.Upgrade();
3598             CHECK_NULL_VOID(accessibilityProperty);
3599             if (!accessibilityProperty->IsScrollable()) {
3600                 return;
3601             }
3602             pattern->ShowPrevious();
3603         });
3604 }
3605 
NeedStartAutoPlay() const3606 bool SwiperPattern::NeedStartAutoPlay() const
3607 {
3608     return isWindowShow_ && isVisibleArea_ && isVisible_;
3609 }
3610 
ProvideRestoreInfo()3611 std::string SwiperPattern::ProvideRestoreInfo()
3612 {
3613     auto jsonObj = JsonUtil::Create(true);
3614     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3615     CHECK_NULL_RETURN(swiperLayoutProperty, "");
3616     jsonObj->Put("Index", swiperLayoutProperty->GetIndex().value_or(0));
3617     return jsonObj->ToString();
3618 }
3619 
OnRestoreInfo(const std::string & restoreInfo)3620 void SwiperPattern::OnRestoreInfo(const std::string& restoreInfo)
3621 {
3622     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3623     CHECK_NULL_VOID(swiperLayoutProperty);
3624     auto info = JsonUtil::ParseJsonString(restoreInfo);
3625     if (!info->IsValid() || !info->IsObject()) {
3626         return;
3627     }
3628     auto jsonIsOn = info->GetValue("Index");
3629     swiperLayoutProperty->UpdateIndex(jsonIsOn->GetInt());
3630     OnModifyDone();
3631 }
3632 
InitHoverMouseEvent()3633 void SwiperPattern::InitHoverMouseEvent()
3634 {
3635     auto host = GetHost();
3636     CHECK_NULL_VOID(host);
3637     auto eventHub = host->GetEventHub<EventHub>();
3638     CHECK_NULL_VOID(eventHub);
3639     auto inputHub = eventHub->GetOrCreateInputEventHub();
3640     CHECK_NULL_VOID(inputHub);
3641 
3642     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
3643         auto pattern = weak.Upgrade();
3644         CHECK_NULL_VOID(pattern);
3645         if (!pattern->IsShowIndicator()) {
3646             pattern->ArrowHover(isHover);
3647         }
3648     };
3649 
3650     if (!hoverEvent_) {
3651         hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
3652         inputHub->AddOnHoverEvent(hoverEvent_);
3653     }
3654 
3655     auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
3656         auto pattern = weak.Upgrade();
3657         if (pattern) {
3658             pattern->HandleMouseEvent(info);
3659         }
3660     };
3661     if (mouseEvent_) {
3662         inputHub->RemoveOnMouseEvent(mouseEvent_);
3663     }
3664     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
3665     inputHub->AddOnMouseEvent(mouseEvent_);
3666 }
3667 
HandleMouseEvent(const MouseInfo & info)3668 void SwiperPattern::HandleMouseEvent(const MouseInfo& info)
3669 {
3670     auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
3671     auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
3672     auto mousePoint = PointF(mouseOffsetX, mouseOffsetY);
3673     if (IsShowIndicator()) {
3674         CheckAndSetArrowHoverState(mousePoint);
3675     }
3676 }
3677 
CheckAndSetArrowHoverState(const PointF & mousePoint)3678 void SwiperPattern::CheckAndSetArrowHoverState(const PointF& mousePoint)
3679 {
3680     if (!HasLeftButtonNode() || !HasRightButtonNode() || !HasIndicatorNode()) {
3681         return;
3682     }
3683 
3684     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3685     CHECK_NULL_VOID(layoutProperty);
3686     if (layoutProperty->GetIsSidebarMiddleValue(false)) {
3687         return;
3688     }
3689 
3690     RectF leftNodeRect;
3691     RectF rightNodeRect;
3692 
3693     leftNodeRect = GetArrowFrameRect(GetLeftButtonId());
3694     rightNodeRect = GetArrowFrameRect(GetRightButtonId());
3695 
3696     if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
3697         leftNodeRect = GetArrowFrameRect(GetIndicatorId());
3698     }
3699 
3700     if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
3701         rightNodeRect = GetArrowFrameRect(GetIndicatorId());
3702     }
3703     RectF newNodeRect;
3704     if (GetDirection() == Axis::HORIZONTAL) {
3705         newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(), rightNodeRect.Right() - leftNodeRect.Left(),
3706             std::min(rightNodeRect.Height(), leftNodeRect.Height()));
3707     } else {
3708         newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(),
3709             std::min(rightNodeRect.Width(), leftNodeRect.Width()), rightNodeRect.Bottom() - leftNodeRect.Top());
3710     }
3711 
3712     isAtHotRegion_ = newNodeRect.IsInRegion(mousePoint);
3713     ArrowHover(isAtHotRegion_);
3714 }
3715 
GetArrowFrameRect(const int32_t index) const3716 RectF SwiperPattern::GetArrowFrameRect(const int32_t index) const
3717 {
3718     auto swiperNode = GetHost();
3719     CHECK_NULL_RETURN(swiperNode, RectF(0, 0, 0, 0));
3720     auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(index)));
3721     CHECK_NULL_RETURN(arrowNode, RectF(0, 0, 0, 0));
3722     auto arrowGeometryNode = arrowNode->GetGeometryNode();
3723     CHECK_NULL_RETURN(arrowGeometryNode, RectF(0, 0, 0, 0));
3724     return arrowGeometryNode->GetFrameRect();
3725 }
3726 
GetCustomPropertyOffset() const3727 float SwiperPattern::GetCustomPropertyOffset() const
3728 {
3729     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3730     CHECK_NULL_RETURN(layoutProperty, 0.0);
3731     auto paddingAndBorder = layoutProperty->CreatePaddingAndBorder();
3732     auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
3733                                      ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
3734                                      : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
3735 
3736     auto preMarginPX = GetPrevMargin();
3737     if (layoutProperty->GetPrevMargin().has_value() && preMarginPX > 0.0) {
3738         preMarginPX += GetItemSpace();
3739     }
3740 
3741     return Dimension(paddingAndBorderValue + preMarginPX, DimensionUnit::PX).ConvertToVp();
3742 }
3743 
GetCurrentFirstIndexStartPos() const3744 float SwiperPattern::GetCurrentFirstIndexStartPos() const
3745 {
3746     if (itemPosition_.empty()) {
3747         return 0.0;
3748     }
3749 
3750     return itemPosition_.begin()->second.startPos;
3751 }
3752 
TotalDisPlayCount() const3753 int32_t SwiperPattern::TotalDisPlayCount() const
3754 {
3755     auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3756     CHECK_NULL_RETURN(swiperLayoutProperty, 1);
3757     auto displayCount = GetDisplayCount();
3758     if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
3759         if (Positive(swiperLayoutProperty->GetPrevMarginValue(0.0_px).ConvertToPx())) {
3760             displayCount++;
3761         }
3762         if (Positive(swiperLayoutProperty->GetNextMarginValue(0.0_px).ConvertToPx())) {
3763             displayCount++;
3764         }
3765     }
3766     return displayCount;
3767 }
3768 
MarkDirtyNodeSelf()3769 void SwiperPattern::MarkDirtyNodeSelf()
3770 {
3771     auto host = GetHost();
3772     CHECK_NULL_VOID(host);
3773     if (!crossMatchChild_) {
3774         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3775     } else {
3776         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
3777     }
3778 }
3779 
ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)3780 void SwiperPattern::ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)
3781 {
3782     auto host = GetHost();
3783     CHECK_NULL_VOID(host);
3784     targetIndex_.reset();
3785     if (preTargetIndex_.has_value()) {
3786         preTargetIndex_.reset();
3787     }
3788 
3789     if (currentIndex_ == nextIndex) {
3790         return;
3791     }
3792 
3793     if (isFinishAnimation_) {
3794         currentDelta_ = 0.0f;
3795         itemPosition_.clear();
3796         isVoluntarilyClear_ = true;
3797         jumpIndex_ = nextIndex;
3798         MarkDirtyNodeSelf();
3799         auto pipeline = PipelineContext::GetCurrentContext();
3800         if (pipeline) {
3801             pipeline->FlushUITasks();
3802         }
3803         isFinishAnimation_ = false;
3804     } else {
3805         UpdateCurrentIndex(nextIndex);
3806         if (currentFocusIndex_ < currentIndex_ || currentFocusIndex_ >= currentIndex_ + GetDisplayCount()) {
3807             currentFocusIndex_ = currentIndex_;
3808         }
3809         do {
3810             auto curChildFrame = GetCurrentFrameNode(currentFocusIndex_);
3811             if (!curChildFrame) {
3812                 break;
3813             }
3814             FlushFocus(curChildFrame);
3815         } while (0);
3816         oldIndex_ = nextIndex;
3817         currentFirstIndex_ = GetLoopIndex(nextIndex);
3818         turnPageRate_ = 0.0f;
3819         currentIndexOffset_ = 0.0f;
3820         auto pipeline = PipelineContext::GetCurrentContext();
3821         if (pipeline) {
3822             pipeline->FlushUITasks();
3823             pipeline->FlushMessages();
3824         }
3825         FireChangeEvent();
3826         // lazyBuild feature.
3827         SetLazyLoadFeature(true);
3828     }
3829 }
3830 
UpdateDragFRCSceneInfo(float speed,SceneStatus sceneStatus)3831 void SwiperPattern::UpdateDragFRCSceneInfo(float speed, SceneStatus sceneStatus)
3832 {
3833     auto host = GetHost();
3834     CHECK_NULL_VOID(host);
3835     host->AddFRCSceneInfo(SWIPER_DRAG_SCENE, speed, sceneStatus);
3836 }
3837 
OnScrollStartRecursive(float position)3838 void SwiperPattern::OnScrollStartRecursive(float position)
3839 {
3840     if (IsDisableSwipe()) {
3841         return;
3842     }
3843     childScrolling_ = true;
3844     gestureSwipeIndex_ = currentIndex_;
3845     StopAnimationOnScrollStart(false);
3846     NotifyParentScrollStart(position);
3847 }
3848 
NotifyParentScrollStart(float position)3849 void SwiperPattern::NotifyParentScrollStart(float position)
3850 {
3851     auto parent = enableNestedScroll_ ? SearchParent() : nullptr;
3852     if (parent) {
3853         parent->OnScrollStartRecursive(position);
3854     }
3855     parent_ = parent;
3856 }
3857 
OnScrollEndRecursive(const std::optional<float> & velocity)3858 void SwiperPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
3859 {
3860     if (IsDisableSwipe()) {
3861         return;
3862     }
3863     // in case child didn't call swiper's HandleScrollVelocity
3864     if (!AnimationRunning()) {
3865         HandleDragEnd(velocity.value_or(0.0f));
3866     }
3867 
3868     childScrolling_ = false;
3869 }
3870 
NotifyParentScrollEnd()3871 void SwiperPattern::NotifyParentScrollEnd()
3872 {
3873     auto parent = parent_.Upgrade();
3874     if (parent && enableNestedScroll_) {
3875         parent->OnScrollEndRecursive(std::nullopt);
3876     }
3877 }
3878 
AnimationRunning() const3879 inline bool SwiperPattern::AnimationRunning() const
3880 {
3881     return (controller_ && controller_->IsRunning()) || (springAnimation_ && springAnimationIsRunning_) ||
3882            (fadeAnimation_ && fadeAnimationIsRunning_) || targetIndex_ || usePropertyAnimation_;
3883 }
3884 
HandleScrollVelocity(float velocity)3885 bool SwiperPattern::HandleScrollVelocity(float velocity)
3886 {
3887     if (IsDisableSwipe()) {
3888         return false;
3889     }
3890 
3891     // haven't reached edge
3892     if (GetDistanceToEdge() > 0.0f || IsLoop()) {
3893         HandleDragEnd(velocity);
3894         return true;
3895     }
3896 
3897     auto parent = parent_.Upgrade();
3898     if (parent && enableNestedScroll_) {
3899         // after reach end, parent handle velocity first
3900         if (parent->HandleScrollVelocity(velocity)) {
3901             return true;
3902         }
3903     }
3904     HandleDragEnd(velocity);
3905     // after reached end, NONE doesn't consume velocity, other edge effects do
3906     return GetEdgeEffect() != EdgeEffect::NONE;
3907 }
3908 
HandleScroll(float offset,int32_t source,NestedState state)3909 ScrollResult SwiperPattern::HandleScroll(float offset, int32_t source, NestedState state)
3910 {
3911     if (IsDisableSwipe()) {
3912         return { offset, false };
3913     }
3914 
3915     if (source == SCROLL_FROM_ANIMATION && AnimationRunning()) {
3916         // deny conflicting animation from child
3917         return { offset, false };
3918     }
3919     // mouse scroll triggers showNext / showPrev instead of updating offset
3920     if (source == SCROLL_FROM_AXIS) {
3921         auto targetBfr = targetIndex_;
3922         (offset > 0) ? ShowPrevious() : ShowNext();
3923         if (targetBfr == targetIndex_) {
3924             // unchanged targetIndex_ implies Swiper has reached the edge and the mouse scroll isn't consumed.
3925             return { offset, true };
3926         }
3927         return { 0.0f, false };
3928     }
3929     auto parent = parent_.Upgrade();
3930     if (!parent || !enableNestedScroll_) {
3931         if (IsOutOfBoundary(offset) && ChildFirst(state)) {
3932             CloseTheGap(offset);
3933             return { offset, true };
3934         }
3935         UpdateCurrentOffset(offset);
3936         return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
3937     }
3938     return HandleScrollSelfFirst(offset, source, state);
3939 }
3940 
HandleScrollSelfFirst(float offset,int32_t source,NestedState state)3941 ScrollResult SwiperPattern::HandleScrollSelfFirst(float offset, int32_t source, NestedState state)
3942 {
3943     // priority: self scroll > parent scroll > parent overScroll > self overScroll
3944     if (IsOutOfBoundary(offset)) {
3945         CloseTheGap(offset);
3946         // skip CHECK_NULL, already checked in HandleScroll
3947         auto parent = parent_.Upgrade();
3948 
3949         // reached edge, pass offset to parent
3950         auto res = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL);
3951         if (res.remain == 0.0f) {
3952             return { 0.0f, true };
3953         }
3954         // parent handle overScroll first
3955         if (res.reachEdge) {
3956             res = parent->HandleScroll(res.remain, source, NestedState::CHILD_OVER_SCROLL);
3957         }
3958 
3959         if (ChildFirst(state)) {
3960             return { res.remain, true };
3961         }
3962         if (res.remain != 0.0f) {
3963             // self overScroll
3964             UpdateCurrentOffset(res.remain);
3965         }
3966     } else {
3967         // regular scroll
3968         UpdateCurrentOffset(offset);
3969     }
3970     return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
3971 }
3972 
CloseTheGap(float offset)3973 void SwiperPattern::CloseTheGap(float offset)
3974 {
3975     float distanceToEdge = GetDistanceToEdge();
3976     if (distanceToEdge > 0.0f) {
3977         UpdateCurrentOffset(offset > 0 ? distanceToEdge : -distanceToEdge);
3978     }
3979 }
3980 
ChildFirst(NestedState state)3981 inline bool SwiperPattern::ChildFirst(NestedState state)
3982 {
3983     // SELF/CHILD priority: self scroll > child scroll > self overScroll > child overScroll
3984     return state == NestedState::CHILD_SCROLL // child hasn't reach edge
3985            || GetEdgeEffect() == EdgeEffect::NONE;
3986 }
3987 
DumpAdvanceInfo()3988 void SwiperPattern::DumpAdvanceInfo()
3989 {
3990     isLastIndicatorFocused_ ? DumpLog::GetInstance().AddDesc("isLastIndicatorFocused:true")
3991                             : DumpLog::GetInstance().AddDesc("isLastIndicatorFocused:false");
3992     moveDirection_ ? DumpLog::GetInstance().AddDesc("moveDirection:true")
3993                    : DumpLog::GetInstance().AddDesc("moveDirection:false");
3994     indicatorDoingAnimation_ ? DumpLog::GetInstance().AddDesc("indicatorDoingAnimation:true")
3995                              : DumpLog::GetInstance().AddDesc("indicatorDoingAnimation:false");
3996     hasVisibleChangeRegistered_ ? DumpLog::GetInstance().AddDesc("hasVisibleChangeRegistered:true")
3997                                 : DumpLog::GetInstance().AddDesc("hasVisibleChangeRegistered:false");
3998     isVisible_ ? DumpLog::GetInstance().AddDesc("isVisible:true") : DumpLog::GetInstance().AddDesc("isVisible:false");
3999     isVisibleArea_ ? DumpLog::GetInstance().AddDesc("isVisibleArea:true")
4000                    : DumpLog::GetInstance().AddDesc("isVisibleArea:false");
4001     isWindowShow_ ? DumpLog::GetInstance().AddDesc("isWindowShow:true")
4002                   : DumpLog::GetInstance().AddDesc("isWindowShow:false");
4003     IsCustomSize_ ? DumpLog::GetInstance().AddDesc("IsCustomSize:true")
4004                   : DumpLog::GetInstance().AddDesc("IsCustomSize:false");
4005     indicatorIsBoolean_ ? DumpLog::GetInstance().AddDesc("indicatorIsBoolean:true")
4006                         : DumpLog::GetInstance().AddDesc("indicatorIsBoolean:false");
4007     isAtHotRegion_ ? DumpLog::GetInstance().AddDesc("isAtHotRegion:true")
4008                    : DumpLog::GetInstance().AddDesc("isAtHotRegion:false");
4009     isDragging_ ? DumpLog::GetInstance().AddDesc("isDragging:true")
4010                 : DumpLog::GetInstance().AddDesc("isDragging:false");
4011     isTouchDown_ ? DumpLog::GetInstance().AddDesc("isTouchDown:true")
4012                  : DumpLog::GetInstance().AddDesc("isTouchDown:false");
4013     preLoop_.has_value() ? DumpLog::GetInstance().AddDesc("preLoop:" + std::to_string(preLoop_.value()))
4014                          : DumpLog::GetInstance().AddDesc("preLoop:null");
4015     indicatorId_.has_value() ? DumpLog::GetInstance().AddDesc("indicatorId:" + std::to_string(indicatorId_.value()))
4016                              : DumpLog::GetInstance().AddDesc("indicatorId:null");
4017     leftButtonId_.has_value() ? DumpLog::GetInstance().AddDesc("leftButtonId:" + std::to_string(leftButtonId_.value()))
4018                               : DumpLog::GetInstance().AddDesc("leftButtonId:null");
4019     rightButtonId_.has_value()
4020         ? DumpLog::GetInstance().AddDesc("rightButtonId:" + std::to_string(rightButtonId_.value()))
4021         : DumpLog::GetInstance().AddDesc("rightButtonId:null");
4022     crossMatchChild_ ? DumpLog::GetInstance().AddDesc("crossMatchChild:true")
4023                      : DumpLog::GetInstance().AddDesc("crossMatchChild:false");
4024     uiCastJumpIndex_.has_value()
4025         ? DumpLog::GetInstance().AddDesc("uiCastJumpIndex:" + std::to_string(uiCastJumpIndex_.value()))
4026         : DumpLog::GetInstance().AddDesc("uiCastJumpIndex:null");
4027     jumpIndex_.has_value() ? DumpLog::GetInstance().AddDesc("jumpIndex:" + std::to_string(jumpIndex_.value()))
4028                            : DumpLog::GetInstance().AddDesc("jumpIndex:null");
4029     targetIndex_.has_value() ? DumpLog::GetInstance().AddDesc("targetIndex:" + std::to_string(targetIndex_.value()))
4030                              : DumpLog::GetInstance().AddDesc("targetIndex:null");
4031     preTargetIndex_.has_value()
4032         ? DumpLog::GetInstance().AddDesc("preTargetIndex:" + std::to_string(preTargetIndex_.value()))
4033         : DumpLog::GetInstance().AddDesc("preTargetIndex:null");
4034     pauseTargetIndex_.has_value()
4035         ? DumpLog::GetInstance().AddDesc("pauseTargetIndex:" + std::to_string(pauseTargetIndex_.value()))
4036         : DumpLog::GetInstance().AddDesc("pauseTargetIndex:null");
4037     velocity_.has_value() ? DumpLog::GetInstance().AddDesc("velocity:" + std::to_string(velocity_.value()))
4038                           : DumpLog::GetInstance().AddDesc("velocity:null");
4039     isFinishAnimation_ ? DumpLog::GetInstance().AddDesc("isFinishAnimation:true")
4040                        : DumpLog::GetInstance().AddDesc("isFinishAnimation:false");
4041     mainSizeIsMeasured_ ? DumpLog::GetInstance().AddDesc("mainSizeIsMeasured:true")
4042                         : DumpLog::GetInstance().AddDesc("mainSizeIsMeasured:false");
4043     isNeedResetPrevMarginAndNextMargin_ ? DumpLog::GetInstance().AddDesc("isNeedResetPrevMarginAndNextMargin:true")
4044                                         : DumpLog::GetInstance().AddDesc("isNeedResetPrevMarginAndNextMargin:false");
4045     usePropertyAnimation_ ? DumpLog::GetInstance().AddDesc("usePropertyAnimation:true")
4046                           : DumpLog::GetInstance().AddDesc("usePropertyAnimation:false");
4047     isUserFinish_ ? DumpLog::GetInstance().AddDesc("isUserFinish:true")
4048                   : DumpLog::GetInstance().AddDesc("isUserFinish:false");
4049     isVoluntarilyClear_ ? DumpLog::GetInstance().AddDesc("isVoluntarilyClear:true")
4050                         : DumpLog::GetInstance().AddDesc("isVoluntarilyClear:false");
4051     isIndicatorLongPress_ ? DumpLog::GetInstance().AddDesc("isIndicatorLongPress:true")
4052                           : DumpLog::GetInstance().AddDesc("isIndicatorLongPress:false");
4053     stopIndicatorAnimation_ ? DumpLog::GetInstance().AddDesc("stopIndicatorAnimation:true")
4054                             : DumpLog::GetInstance().AddDesc("stopIndicatorAnimation:false");
4055     isTouchPad_ ? DumpLog::GetInstance().AddDesc("isTouchPad:true")
4056                 : DumpLog::GetInstance().AddDesc("isTouchPad:false");
4057     surfaceChangedCallbackId_.has_value()
4058         ? DumpLog::GetInstance().AddDesc(
4059               "surfaceChangedCallbackId:" + std::to_string(surfaceChangedCallbackId_.value()))
4060         : DumpLog::GetInstance().AddDesc("surfaceChangedCallbackId:null");
4061     if (lastSwiperIndicatorType_.has_value()) {
4062         switch (lastSwiperIndicatorType_.value()) {
4063             case SwiperIndicatorType::DOT: {
4064                 DumpLog::GetInstance().AddDesc("SwiperIndicatorType:DOT");
4065                 break;
4066             }
4067             case SwiperIndicatorType::DIGIT: {
4068                 DumpLog::GetInstance().AddDesc("SwiperIndicatorType:DIGIT");
4069                 break;
4070             }
4071             default: {
4072                 break;
4073             }
4074         }
4075     } else {
4076         DumpLog::GetInstance().AddDesc("lastSwiperIndicatorType:null");
4077     }
4078     DumpLog::GetInstance().AddDesc("currentIndex:" + std::to_string(currentIndex_));
4079     DumpLog::GetInstance().AddDesc("oldIndex:" + std::to_string(oldIndex_));
4080     DumpLog::GetInstance().AddDesc("currentOffset:" + std::to_string(currentOffset_));
4081     DumpLog::GetInstance().AddDesc("fadeOffset:" + std::to_string(fadeOffset_));
4082     DumpLog::GetInstance().AddDesc("touchBottomRate:" + std::to_string(touchBottomRate_));
4083     DumpLog::GetInstance().AddDesc("currentIndexOffset:" + std::to_string(currentIndexOffset_));
4084     DumpLog::GetInstance().AddDesc("gestureSwipeIndex:" + std::to_string(gestureSwipeIndex_));
4085     DumpLog::GetInstance().AddDesc("currentFirstIndex:" + std::to_string(currentFirstIndex_));
4086     DumpLog::GetInstance().AddDesc("startMainPos:" + std::to_string(startMainPos_));
4087     DumpLog::GetInstance().AddDesc("endMainPos:" + std::to_string(endMainPos_));
4088     DumpLog::GetInstance().AddDesc("contentMainSize:" + std::to_string(contentMainSize_));
4089     DumpLog::GetInstance().AddDesc("contentCrossSize:" + std::to_string(contentCrossSize_));
4090     DumpLog::GetInstance().AddDesc("currentDelta:" + std::to_string(currentDelta_));
4091     DumpLog::GetInstance().AddDesc("propertyAnimationIndex:" + std::to_string(propertyAnimationIndex_));
4092     DumpLog::GetInstance().AddDesc("mainDeltaSum:" + std::to_string(mainDeltaSum_));
4093     if (!itemPosition_.empty()) {
4094         DumpLog::GetInstance().AddDesc("-----------start print itemPosition------------");
4095         for (auto item : itemPosition_) {
4096             DumpLog::GetInstance().AddDesc(std::string("id:")
4097                                                .append(std::to_string(item.first))
4098                                                .append(",startPos:")
4099                                                .append(std::to_string(item.second.startPos))
4100                                                .append(",endPos:" + std::to_string(item.second.endPos)));
4101         }
4102         DumpLog::GetInstance().AddDesc("-----------end print itemPosition------------");
4103     }
4104     if (!itemPositionInAnimation_.empty()) {
4105         DumpLog::GetInstance().AddDesc("-----------start print itemPositionInAnimation------------");
4106 
4107         for (auto item : itemPositionInAnimation_) {
4108             DumpLog::GetInstance().AddDesc(std::string("id:")
4109                                                .append(std::to_string(item.first))
4110                                                .append(",startPos:")
4111                                                .append(std::to_string(item.second.startPos))
4112                                                .append(",endPos:")
4113                                                .append(std::to_string(item.second.endPos)));
4114         }
4115         DumpLog::GetInstance().AddDesc("-----------end print itemPositionInAnimation------------");
4116     }
4117     switch (panDirection_.type) {
4118         case PanDirection::NONE: {
4119             DumpLog::GetInstance().AddDesc("PanDirection:NONE");
4120             break;
4121         }
4122         case PanDirection::LEFT: {
4123             DumpLog::GetInstance().AddDesc("PanDirection:LEFT");
4124             break;
4125         }
4126         case PanDirection::RIGHT: {
4127             DumpLog::GetInstance().AddDesc("PanDirection:RIGHT");
4128             break;
4129         }
4130         case PanDirection::HORIZONTAL: {
4131             DumpLog::GetInstance().AddDesc("PanDirection:HORIZONTAL");
4132             break;
4133         }
4134         case PanDirection::UP: {
4135             DumpLog::GetInstance().AddDesc("PanDirection:UP");
4136             break;
4137         }
4138         case PanDirection::DOWN: {
4139             DumpLog::GetInstance().AddDesc("PanDirection:DOWN");
4140             break;
4141         }
4142         case PanDirection::VERTICAL: {
4143             DumpLog::GetInstance().AddDesc("PanDirection:VERTICAL");
4144             break;
4145         }
4146         case PanDirection::ALL: {
4147             DumpLog::GetInstance().AddDesc("PanDirection:ALL");
4148             break;
4149         }
4150         default: {
4151             break;
4152         }
4153     }
4154     switch (direction_) {
4155         case Axis::NONE: {
4156             DumpLog::GetInstance().AddDesc("Axis:NONE");
4157             break;
4158         }
4159         case Axis::HORIZONTAL: {
4160             DumpLog::GetInstance().AddDesc("Axis:HORIZONTAL");
4161             break;
4162         }
4163         case Axis::FREE: {
4164             DumpLog::GetInstance().AddDesc("Axis:FREE");
4165             break;
4166         }
4167         case Axis::VERTICAL: {
4168             DumpLog::GetInstance().AddDesc("Axis:VERTICAL");
4169             break;
4170         }
4171         default: {
4172             break;
4173         }
4174     }
4175 }
4176 
GetLoopIndex(int32_t index,int32_t childrenSize) const4177 int32_t SwiperPattern::GetLoopIndex(int32_t index, int32_t childrenSize) const
4178 {
4179     if (childrenSize <= 0) {
4180         return index;
4181     }
4182     auto loopIndex = index;
4183     while (loopIndex < 0) {
4184         loopIndex = loopIndex + childrenSize;
4185     }
4186     loopIndex %= childrenSize;
4187     return loopIndex;
4188 }
4189 
RegisterScrollingListener(const RefPtr<ScrollingListener> listener)4190 void SwiperPattern::RegisterScrollingListener(const RefPtr<ScrollingListener> listener)
4191 {
4192     CHECK_NULL_VOID(listener);
4193     scrollingListener_.emplace_back(listener);
4194 }
4195 
FireAndCleanScrollingListener()4196 void SwiperPattern::FireAndCleanScrollingListener()
4197 {
4198     for (auto listener : scrollingListener_) {
4199         CHECK_NULL_VOID(listener);
4200         listener->NotifyScrollingEvent();
4201     }
4202     scrollingListener_.clear();
4203 }
4204 
CleanScrollingListener()4205 void SwiperPattern::CleanScrollingListener()
4206 {
4207     scrollingListener_.clear();
4208 }
4209 
StopIndicatorAnimation()4210 void SwiperPattern::StopIndicatorAnimation()
4211 {
4212     AnimationUtils::StopAnimation(indicatorAnimation_);
4213 
4214     if (stopIndicatorAnimationFunc_) {
4215         stopIndicatorAnimationFunc_();
4216     }
4217 }
4218 
OnCustomContentTransition(int32_t toIndex)4219 void SwiperPattern::OnCustomContentTransition(int32_t toIndex)
4220 {
4221     if (!currentProxyInAnimation_ && toIndex == CurrentIndex()) {
4222         return;
4223     }
4224 
4225     customAnimationToIndex_ = toIndex;
4226     indexsInAnimation_.insert(toIndex);
4227     auto fromIndex = CurrentIndex();
4228     if (currentProxyInAnimation_) {
4229         fromIndex = currentProxyInAnimation_->GetToIndex();
4230 
4231         auto swiperEventHub = GetEventHub<SwiperEventHub>();
4232         CHECK_NULL_VOID(swiperEventHub);
4233         swiperEventHub->FireChangeEvent(fromIndex);
4234         swiperEventHub->FireIndicatorChangeEvent(fromIndex);
4235         swiperEventHub->FireChangeDoneEvent(moveDirection_);
4236 
4237         UpdateCurrentIndex(fromIndex);
4238         oldIndex_ = fromIndex;
4239 
4240         AnimationCallbackInfo info;
4241         info.currentOffset = GetCustomPropertyOffset();
4242         FireAnimationEndEvent(fromIndex, info);
4243 
4244         currentProxyInAnimation_->SetHasOnChanged(true);
4245     }
4246     auto pipelineContext = PipelineContext::GetCurrentContext();
4247     CHECK_NULL_VOID(pipelineContext);
4248 
4249     pipelineContext->AddAfterLayoutTask([weak = WeakClaim(this), fromIndex, toIndex]() {
4250         auto swiperPattern = weak.Upgrade();
4251         CHECK_NULL_VOID(swiperPattern);
4252         swiperPattern->TriggerCustomContentTransitionEvent(fromIndex, toIndex);
4253     });
4254 
4255     MarkDirtyNodeSelf();
4256 }
4257 
TriggerCustomContentTransitionEvent(int32_t fromIndex,int32_t toIndex)4258 void SwiperPattern::TriggerCustomContentTransitionEvent(int32_t fromIndex, int32_t toIndex)
4259 {
4260     CHECK_NULL_VOID(onCustomContentTransition_);
4261 
4262     auto tabContentAnimatedTransition = (*onCustomContentTransition_)(fromIndex, toIndex);
4263     auto transition = tabContentAnimatedTransition.transition;
4264 
4265     if (!transition) {
4266         OnCustomAnimationFinish(fromIndex, toIndex, false);
4267         return;
4268     }
4269 
4270     auto proxy = AceType::MakeRefPtr<TabContentTransitionProxy>();
4271     proxy->SetFromIndex(fromIndex);
4272     proxy->SetToIndex(toIndex);
4273     proxy->SetFinishTransitionEvent([weak = WeakClaim(this), fromIndex, toIndex](bool hasOnChanged) {
4274         auto swiperPattern = weak.Upgrade();
4275         CHECK_NULL_VOID(swiperPattern);
4276         swiperPattern->OnCustomAnimationFinish(fromIndex, toIndex, hasOnChanged);
4277     });
4278 
4279     transition(proxy);
4280     currentProxyInAnimation_ = proxy;
4281 
4282     AnimationCallbackInfo info;
4283     info.currentOffset = GetCustomPropertyOffset();
4284     info.targetOffset = GetCustomPropertyOffset();
4285     FireAnimationStartEvent(fromIndex, toIndex, info);
4286 
4287     auto pipeline = PipelineContext::GetCurrentContext();
4288     CHECK_NULL_VOID(pipeline);
4289     auto taskExecutor = pipeline->GetTaskExecutor();
4290     CHECK_NULL_VOID(taskExecutor);
4291 
4292     auto timeout = tabContentAnimatedTransition.timeout;
4293     auto timeoutTask = [weak = AceType::WeakClaim(AceType::RawPtr(proxy)), fromIndex, toIndex] {
4294         auto transitionProxy = weak.Upgrade();
4295         CHECK_NULL_VOID(transitionProxy);
4296         transitionProxy->FinishTransition();
4297     };
4298 
4299     taskExecutor->PostDelayedTask(timeoutTask, TaskExecutor::TaskType::UI, timeout);
4300 }
4301 
OnCustomAnimationFinish(int32_t fromIndex,int32_t toIndex,bool hasOnChanged)4302 void SwiperPattern::OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged)
4303 {
4304     customAnimationToIndex_.reset();
4305     needUnmountIndexs_.insert(fromIndex);
4306     indexsInAnimation_.erase(toIndex);
4307 
4308     if (!hasOnChanged) {
4309         auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
4310         CHECK_NULL_VOID(layoutProperty);
4311         layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(toIndex));
4312         oldIndex_ = fromIndex;
4313 
4314         AnimationCallbackInfo info;
4315         info.currentOffset = GetCustomPropertyOffset();
4316         FireAnimationEndEvent(toIndex, info);
4317     }
4318 
4319     if (indexsInAnimation_.empty()) {
4320         currentProxyInAnimation_ = nullptr;
4321     }
4322 
4323     auto host = GetHost();
4324     CHECK_NULL_VOID(host);
4325     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4326     auto pipeline = PipelineContext::GetCurrentContext();
4327     if (pipeline) {
4328         pipeline->FlushUITasks();
4329         pipeline->FlushMessages();
4330     }
4331 }
4332 
SetSwiperEventCallback(bool disableSwipe)4333 void SwiperPattern::SetSwiperEventCallback(bool disableSwipe)
4334 {
4335     CHECK_NULL_VOID(swiperController_);
4336     auto removeSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
4337         auto swiperPattern = weak.Upgrade();
4338         CHECK_NULL_VOID(swiperPattern);
4339         auto host = swiperPattern->GetHost();
4340         CHECK_NULL_VOID(host);
4341         auto hub = host->GetEventHub<EventHub>();
4342         CHECK_NULL_VOID(hub);
4343         auto gestureHub = hub->GetOrCreateGestureEventHub();
4344         CHECK_NULL_VOID(gestureHub);
4345         gestureHub->RemoveTouchEvent(swiperPattern->touchEvent_);
4346         if (!disableSwipe) {
4347             gestureHub->RemovePanEvent(swiperPattern->panEvent_);
4348         }
4349     };
4350     swiperController_->SetRemoveSwiperEventCallback(std::move(removeSwiperEventCallback));
4351 
4352     auto addSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
4353         auto swiperPattern = weak.Upgrade();
4354         CHECK_NULL_VOID(swiperPattern);
4355         auto host = swiperPattern->GetHost();
4356         CHECK_NULL_VOID(host);
4357         auto hub = host->GetEventHub<EventHub>();
4358         CHECK_NULL_VOID(hub);
4359         auto gestureHub = hub->GetOrCreateGestureEventHub();
4360         CHECK_NULL_VOID(gestureHub);
4361         gestureHub->AddTouchEvent(swiperPattern->touchEvent_);
4362         if (!disableSwipe) {
4363             gestureHub->AddPanEvent(swiperPattern->panEvent_, swiperPattern->panDirection_, 1, DEFAULT_PAN_DISTANCE);
4364         }
4365     };
4366     swiperController_->SetAddSwiperEventCallback(std::move(addSwiperEventCallback));
4367 }
4368 
UpdateSwiperPanEvent(bool disableSwipe)4369 void SwiperPattern::UpdateSwiperPanEvent(bool disableSwipe)
4370 {
4371     auto host = GetHost();
4372     CHECK_NULL_VOID(host);
4373     auto hub = host->GetEventHub<EventHub>();
4374     CHECK_NULL_VOID(hub);
4375     auto gestureHub = hub->GetOrCreateGestureEventHub();
4376     CHECK_NULL_VOID(gestureHub);
4377 
4378     if (!disableSwipe) {
4379         InitPanEvent(gestureHub);
4380     } else if (panEvent_) {
4381         gestureHub->RemovePanEvent(panEvent_);
4382         panEvent_.Reset();
4383         if (isDragging_) {
4384             HandleDragEnd(0.0);
4385         }
4386     }
4387 }
4388 
IsSwipeByGroup() const4389 bool SwiperPattern::IsSwipeByGroup() const
4390 {
4391     auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
4392     CHECK_NULL_RETURN(layoutProperty, false);
4393     return layoutProperty->GetSwipeByGroup().value_or(false);
4394 }
4395 
GetCurrentFrameNode(int32_t currentIndex) const4396 RefPtr<FrameNode> SwiperPattern::GetCurrentFrameNode(int32_t currentIndex) const
4397 {
4398     auto host = GetHost();
4399     CHECK_NULL_RETURN(host, nullptr);
4400     auto currentLayoutWrapper = host->GetChildByIndex(GetLoopIndex(currentIndex));
4401     CHECK_NULL_RETURN(currentLayoutWrapper, nullptr);
4402     return currentLayoutWrapper->GetHostNode();
4403 }
4404 
ProcessDelta(float & delta,float mainSize,float deltaSum)4405 void SwiperPattern::ProcessDelta(float& delta, float mainSize, float deltaSum)
4406 {
4407     if (std::abs(delta) > mainSize) {
4408         delta = delta > 0 ? mainSize : -mainSize;
4409     }
4410 
4411     if ((std::abs(deltaSum + delta)) > mainSize) {
4412         delta = GreatNotEqual((deltaSum + delta), 0) ? (mainSize - deltaSum) :
4413             (-deltaSum - mainSize);
4414     }
4415 }
4416 
ContentWillChange(int32_t comingIndex)4417 bool SwiperPattern::ContentWillChange(int32_t comingIndex)
4418 {
4419     return ContentWillChange(GetCurrentIndex(), comingIndex);
4420 }
4421 
ContentWillChange(int32_t currentIndex,int32_t comingIndex)4422 bool SwiperPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
4423 {
4424     auto host = GetHost();
4425     CHECK_NULL_RETURN(host, true);
4426     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
4427     CHECK_NULL_RETURN(tabsNode, true);
4428     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
4429     CHECK_NULL_RETURN(tabsPattern, true);
4430     if (tabsPattern->GetInterceptStatus()) {
4431         auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
4432         return ret.has_value() ? ret.value() : true;
4433     }
4434     return true;
4435 }
4436 
CheckSwiperPanEvent(const GestureEvent & info)4437 bool SwiperPattern::CheckSwiperPanEvent(const GestureEvent& info)
4438 {
4439     int32_t currentIndex = GetCurrentIndex();
4440     int32_t comingIndex = currentIndex;
4441     if (GreatNotEqual(info.GetMainDelta(), 0.0)) {
4442         comingIndex = comingIndex < 1 ? 0 : comingIndex - 1;
4443     } else if (LessNotEqual(info.GetMainDelta(), 0.0)) {
4444         comingIndex = comingIndex > TotalCount() - INDEX_DIFF_TWO ? TotalCount() - 1 : comingIndex + 1;
4445     }
4446 
4447     auto iter = indexCanChangeMap_.find(comingIndex);
4448     if (iter != indexCanChangeMap_.end()) {
4449         return iter->second;
4450     }
4451     bool ret = ContentWillChange(currentIndex, comingIndex);
4452     indexCanChangeMap_.emplace(comingIndex, ret);
4453     return ret;
4454 }
4455 } // namespace OHOS::Ace::NG
4456