• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/swiper/render_swiper.h"
17 
18 #include "base/ressched/ressched_report.h"
19 #include "base/utils/system_properties.h"
20 #include "base/utils/time_util.h"
21 #include "core/animation/curve_animation.h"
22 #include "core/animation/friction_motion.h"
23 #include "core/animation/keyframe.h"
24 #include "core/common/ace_application_info.h"
25 #include "core/common/frontend.h"
26 #include "core/components/align/render_align.h"
27 #include "core/components/display/render_display.h"
28 #include "core/components/swiper/swiper_component.h"
29 #include "core/event/ace_event_helper.h"
30 #include "core/pipeline/base/multi_child.h"
31 
32 namespace OHOS::Ace {
33 namespace {
34 
35 constexpr double MAX_VIEW_PORT_WIDTH = 1080.0;
36 constexpr int32_t LEAST_SLIDE_ITEM_COUNT = 2;
37 constexpr uint8_t MAX_OPACITY = 255;
38 constexpr double CUR_START_TRANSLATE_TIME = 0.0;
39 constexpr double CUR_END_TRANSLATE_TIME = 1.0;
40 constexpr double CUR_START_OPACITY_TIME = 0.0;
41 constexpr uint8_t CUR_START_OPACITY_VALUE = 255;
42 constexpr uint8_t CUR_END_OPACITY_VALUE = 0;
43 constexpr double CUR_END_OPACITY_TIME = 0.5;
44 constexpr double TARGET_START_TRANSLATE_TIME = 0.0;
45 constexpr double TARGET_END_TRANSLATE_TIME = 1.0;
46 constexpr double TARGET_START_OPACITY_TIME = 0.3;
47 constexpr double TARGET_END_OPACITY_TIME = 1.0;
48 constexpr uint8_t TARGET_START_OPACITY_VALUE = 0;
49 constexpr uint8_t TARGET_END_OPACITY_VALUE = 255;
50 constexpr uint8_t TRANSLATE_RATIO = 10;
51 constexpr int32_t COMPONENT_CHANGE_END_LISTENER_KEY = 1001;
52 constexpr double MIN_SCROLL_OFFSET = 0.5;
53 constexpr int32_t DEFAULT_SHOWING_COUNT = 1;
54 constexpr int32_t SIZE_RATIO_NORMAL = 2;
55 constexpr int32_t SIZE_RATIO_LARGE = 4;
56 
57 // for watch rotation const param
58 constexpr double ROTATION_SENSITIVITY_NORMAL = 1.4;
59 constexpr uint64_t ROTATION_INTERVAL_MS = 200;
60 
61 // for indicator animation const param
62 constexpr double SPRING_MASS = 1.0;
63 constexpr double SPRING_STIFF = 700.0;
64 constexpr double SPRING_DAMP = 22.0;
65 constexpr double SPRING_DAMP_INC = 5.0;
66 constexpr double DRAG_CALC_STRETCH_STEP = 0.01;
67 constexpr int32_t DRAG_CALC_STRETCH_STEP_INT = 1;   // 100*DRAG_CALC_STRETCH_STEP
68 constexpr int32_t DRAG_CALC_STRETCH_STEP_MAX = 100; // 100*DRAG_CALC_STRETCH_STEP_INT
69 constexpr double DRAG_OFFSET_START_DP = 4.0;
70 constexpr double DRAG_OFFSET_SWITCH_DP = 14.0;
71 constexpr double DRAG_STRETCH_LONGEST_DP = 80.0;
72 constexpr double DRAG_STRETCH_BASE_WIDTH = 1.0;
73 constexpr double DRAG_STRETCH_BASE_HIGH = 1.0;
74 constexpr double DRAG_STRETCH_MAX_WIDTH = 1.2;
75 constexpr double DRAG_STRETCH_MAX_HIGH = 0.8;
76 constexpr double DRAG_OFFSET_MIN = 0.0;
77 constexpr double DRAG_OFFSET_MAX = 1.0;
78 constexpr double ZOOM_MIN = 0.0;
79 constexpr double ZOOM_MAX = 1.0;
80 constexpr double OPACITY_MIN = 0.0;
81 constexpr double OPACITY_MAX = 0.1;
82 constexpr double ZOOM_DOT_MIN = 0.0;
83 constexpr double ZOOM_DOT_MAX = 1.0;
84 constexpr double ZOOM_HOTZONE_MAX_RATE = 1.33;
85 constexpr double INDICATOR_DIRECT_FORWARD = 1.0;
86 constexpr double INDICATOR_DIRECT_BACKWARD = -1.0;
87 constexpr int32_t VIBRATE_DURATION = 30;
88 constexpr int32_t ZOOM_IN_DURATION = 250;
89 constexpr int32_t ZOOM_OUT_DURATION = 250;
90 constexpr int32_t ZOOM_OUT_HOVER_DURATION = 250;
91 constexpr int32_t ZOOM_IN_DOT_DURATION = 100;
92 constexpr int32_t ZOOM_OUT_DOT_DURATION = 150;
93 constexpr int32_t DRAG_RETRETION_DURATION = 250;
94 
95 // indicator animation curve
96 const RefPtr<CubicCurve> INDICATOR_FOCUS_HEAD = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.0f, 1.0f, 1.0f);
97 const RefPtr<CubicCurve> INDICATOR_FOCUS_TAIL = AceType::MakeRefPtr<CubicCurve>(1.0f, 0.0f, 1.0f, 1.0f);
98 const RefPtr<CubicCurve> INDICATOR_NORMAL_POINT = AceType::MakeRefPtr<CubicCurve>(0.4f, 0.0f, 1.0f, 1.0f);
99 const RefPtr<CubicCurve> INDICATOR_ZONE_STRETCH = AceType::MakeRefPtr<CubicCurve>(0.1f, 0.2f, 0.48f, 1.0f);
100 
101 // for indicator
102 constexpr double DELAY_TIME_DEFAULT = 250;
103 constexpr int32_t MICROSEC_TO_NANOSEC = 1000;
104 constexpr int32_t INDICATOR_INVALID_HOVER_INDEX = -1;
105 constexpr Dimension INDICATOR_PADDING_TOP_DEFAULT = 9.0_vp;
106 constexpr Dimension INDICATOR_DIGITAL_PADDING = 8.0_vp;
107 constexpr Dimension INDICATOR_FOCUS_DEL_OFFSET = 4.0_vp;
108 constexpr Dimension INDICATOR_FOCUS_DEL_SIZE = 8.0_vp;
109 constexpr Dimension INDICATOR_FOCUS_RADIUS_DEL_SIZE = 3.0_vp;
110 constexpr int32_t INDICATOR_FOCUS_COLOR = 0x0a59f7;
111 
112 constexpr Dimension MIN_TURN_PAGE_VELOCITY = 400.0_vp;
113 constexpr Dimension MIN_DRAG_DISTANCE = 25.0_vp;
114 
115 } // namespace
116 
GetTickCount()117 int64_t GetTickCount()
118 {
119     struct timespec ts;
120     clock_gettime(CLOCK_MONOTONIC, &ts);
121     return (ts.tv_sec * MICROSEC_TO_NANOSEC + ts.tv_nsec / (MICROSEC_TO_NANOSEC * MICROSEC_TO_NANOSEC));
122 }
123 
~RenderSwiper()124 RenderSwiper::~RenderSwiper()
125 {
126     if (autoPlay_ && scheduler_ && scheduler_->IsActive()) {
127         scheduler_->Stop();
128     }
129 
130     auto context = context_.Upgrade();
131     if (!context || callbackId_ <= 0) {
132         return;
133     }
134     context->UnregisterSurfaceChangedCallback(callbackId_);
135 }
136 
Update(const RefPtr<Component> & component)137 void RenderSwiper::Update(const RefPtr<Component>& component)
138 {
139     const RefPtr<SwiperComponent> swiper = AceType::DynamicCast<SwiperComponent>(component);
140     if (!swiper) {
141         LOGW("swiper component is null");
142         return;
143     }
144     auto context = context_.Upgrade();
145     ACE_DCHECK(context);
146 
147     if (context && callbackId_ <= 0) {
148         callbackId_ = context->RegisterSurfaceChangedCallback(
149             [weak = WeakClaim(this)](int32_t width, int32_t height, int32_t oldWidth, int32_t oldHeight) {
150                 auto swiper = weak.Upgrade();
151                 if (swiper) {
152                     swiper->OnSurfaceChanged();
153                 }
154             });
155     }
156 
157     if (swiper->GetUpdateType() == UpdateType::STYLE) {
158         // only update indicator when update style
159         indicator_ = swiper->GetIndicator();
160         MarkNeedRender();
161         return;
162     }
163 
164     displayMode_ = swiper->GetDisplayMode();
165     displayCount_ = swiper->GetDisplayCount();
166     edgeEffect_ = swiper->GetEdgeEffect();
167     const auto& swiperController = swiper->GetSwiperController();
168     if (swiperController) {
169         auto weak = AceType::WeakClaim(this);
170         swiperController->SetSwipeToImpl([weak](int32_t index, bool reverse) {
171             auto swiper = weak.Upgrade();
172             if (swiper) {
173                 swiper->SwipeTo(index, reverse);
174             }
175         });
176         swiperController->SetShowPrevImpl([weak]() {
177             auto swiper = weak.Upgrade();
178             if (swiper) {
179                 swiper->ShowPrevious();
180             }
181         });
182         swiperController->SetShowNextImpl([weak]() {
183             auto swiper = weak.Upgrade();
184             if (swiper) {
185                 swiper->ShowNext();
186             }
187         });
188         swiperController->SetFinishImpl([weak]() {
189             auto swiper = weak.Upgrade();
190             if (swiper) {
191                 swiper->FinishAllSwipeAnimation(true);
192             }
193         });
194     }
195 
196     const auto& rotationController = swiper->GetRotationController();
197     if (rotationController) {
198         auto weak = AceType::WeakClaim(this);
199         rotationController->SetRequestRotationImpl(weak, context_);
200     }
201 
202     changeEvent_ =
203         AceAsyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::Create(swiper->GetChangeEventId(), context_);
204     animationFinishEvent_ = AceAsyncEvent<void()>::Create(swiper->GetAnimationFinishEventId(), context_);
205     animationStartEvent_ = AceAsyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::Create(
206         swiper->GetAnimationStartEventId(), context_);
207     animationEndEvent_ = AceAsyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::Create(
208         swiper->GetAnimationEndEventId(), context_);
209     rotationEvent_ = AceAsyncEvent<void(const std::string&)>::Create(swiper->GetRotationEventId(), context_);
210     auto clickId = swiper->GetClickEventId();
211     catchMode_ = true;
212     if (!clickId.IsEmpty()) {
213         catchMode_ = clickId.GetCatchMode();
214     }
215     clickEvent_ = AceAsyncEvent<void(const std::shared_ptr<ClickInfo>&)>::Create(clickId, context_);
216     remoteMessageEvent_ = AceAsyncEvent<void(const std::shared_ptr<ClickInfo>&)>::Create(
217         swiper->GetRemoteMessageEventId(), context_);
218     RegisterChangeEndListener(COMPONENT_CHANGE_END_LISTENER_KEY, swiper->GetChangeEndListener());
219     auto lazyComponent = swiper->GetLazyForEachComponent();
220     if (swiper && swiper_ && (*swiper == *swiper_) &&
221         currentIndex_ == static_cast<int32_t>(swiper->GetIndex()) && lazyComponent) {
222         LOGI("swiper not changed");
223         swiper_ = swiper;
224         return;
225     }
226     fadeColor_ = swiper->GetFadeColor();
227     if (context) {
228         scale_ = context->GetDipScale();
229     }
230 
231     curve_ = swiper->GetCurve();
232     if (curve_) {
233         curveRender_ = Curves::ToString(curve_);
234     }
235 
236     // Get item count of swiper
237     const auto& children = swiper->GetChildren();
238     itemCount_ = static_cast<int32_t>(children.size());
239     for (const auto& child : children) {
240         auto multiChild = AceType::DynamicCast<MultiChild>(child);
241         if (multiChild) {
242             --itemCount_;
243             itemCount_ += static_cast<int32_t>(multiChild->Count());
244         }
245     }
246 
247     indicator_ = swiper->GetIndicator();
248     mainSwiperSize_ = swiper->GetMainSwiperSize();
249     digitalIndicator_ = swiper->GetDigitalIndicator();
250     show_ = swiper->IsShow();
251     axis_ = swiper->GetAxis();
252     needReverse_ = (swiper->GetTextDirection() == TextDirection::RTL) && (axis_ == Axis::HORIZONTAL);
253     disableSwipe_ = swiper->GetDisableSwipe();
254     disableRotation_ = swiper->GetDisableRotation();
255     itemSpace_ = swiper->GetItemSpace();
256     autoPlay_ = !(context && context->IsJsCard()) && swiper->IsAutoPlay();
257     autoPlayInterval_ = swiper->GetAutoPlayInterval();
258     loop_ = swiper->IsLoop();
259     animationOpacity_ = swiper->IsAnimationOpacity();
260     duration_ = swiper->GetDuration();
261     showIndicator_ = swiper->IsShowIndicator();
262     cachedCount_ = swiper->GetCachedSize();
263     lazyLoadCacheSize_ = swiper->GetCachedSize() * 2 + swiper->GetDisplayCount();
264     UpdateItemCount(lazyComponent ? static_cast<int32_t>(lazyComponent->TotalCount()) : itemCount_);
265     ClearItems(lazyComponent, static_cast<int32_t>(swiper->GetIndex()));
266 
267     if (itemCount_ < LEAST_SLIDE_ITEM_COUNT) {
268         LOGD("swiper item is less than least slide count");
269         swiper_ = swiper;
270         index_ = 0;
271         return;
272     }
273     UpdateIndex(swiper->GetIndex());
274 
275     ApplyRestoreInfo();
276     Initialize(GetContext(), catchMode_);
277     swiper_ = swiper; // must after UpdateIndex
278 }
279 
RefuseUpdatePosition(int32_t index)280 bool RenderSwiper::RefuseUpdatePosition(int32_t index)
281 {
282     if ((isIndicatorAnimationStart_ && !quickTurnItem_) && (index == currentIndex_ || index == targetIndex_)) {
283         return true;
284     }
285     return false;
286 }
287 
PerformLayout()288 void RenderSwiper::PerformLayout()
289 {
290     LoadItems();
291     // get the prevMargin_ and nextMargin_, and make sure that prevMargin_ + nextMargin_ <= maxLength
292     prevMargin_ = swiper_ ? NormalizePercentToPx(swiper_->GetPreviousMargin(), axis_ == Axis::VERTICAL, true) : 0.0;
293     nextMargin_ = swiper_ ? NormalizePercentToPx(swiper_->GetNextMargin(), axis_ == Axis::VERTICAL, true) : 0.0;
294     Size swiperSize = GetLayoutSize();
295     if (GreatNotEqual(swiperSize.Width(), 0) && GreatNotEqual(swiperSize.Height(), 0)) {
296         double maxLength = (axis_ == Axis::HORIZONTAL ? swiperSize.Width() : swiperSize.Height()) - 1.0f;
297         if (LessOrEqual(prevMargin_, 0.0)) {
298             prevMargin_ = 0.0;
299         }
300         if (LessOrEqual(nextMargin_, 0.0)) {
301             nextMargin_ = 0.0;
302         }
303 
304         if (GreatOrEqual(prevMargin_, maxLength)) {
305             prevMargin_ = maxLength;
306         }
307         if (GreatOrEqual(nextMargin_, maxLength - prevMargin_)) {
308             nextMargin_ = maxLength - prevMargin_;
309         }
310     }
311 
312     LayoutParam innerLayout = GetLayoutParam();
313     Size minSize = GetLayoutParam().GetMinSize();
314     Size maxSize = GetLayoutParam().GetMaxSize();
315     Size maxSizeChild = maxSize;
316     auto showingCount = swiper_ ? swiper_->GetDisplayCount() : 1;
317     double intervalSpace = swiper_ ? NormalizeToPx(swiper_->GetItemSpace()) : 0.0;
318     if (axis_ == Axis::HORIZONTAL) {
319         maxSizeChild.SetWidth(
320             (maxSize.Width() - intervalSpace * (showingCount - 1)) / showingCount - prevMargin_ - nextMargin_);
321     } else {
322         maxSizeChild.SetHeight(
323             (maxSize.Height() - intervalSpace * (showingCount - 1)) / showingCount - prevMargin_ - nextMargin_);
324     }
325     innerLayout.SetMaxSize(maxSizeChild);
326 
327     bool isLinearLayout = swiper_ ? swiper_->GetDisplayMode() == SwiperDisplayMode::AUTO_LINEAR : false;
328     double maxWidth = minSize.Width();
329     double maxHeight = minSize.Height();
330     if (mainSwiperSize_ == MainSwiperSize::MAX) {
331         maxWidth = (axis_ == Axis::HORIZONTAL && isLinearLayout) ? 0.0 : maxSize.Width();
332         maxHeight = (axis_ == Axis::VERTICAL && isLinearLayout) ? 0.0 : maxSize.Height();
333     } else if (mainSwiperSize_ == MainSwiperSize::MIN) {
334         maxWidth = 0.0;
335         maxHeight = 0.0;
336     } else if (mainSwiperSize_ == MainSwiperSize::MAX_X) {
337         maxWidth = (axis_ == Axis::HORIZONTAL && isLinearLayout) ? 0.0 : maxSize.Width();
338         maxHeight = 0.0;
339     } else if (mainSwiperSize_ == MainSwiperSize::MAX_Y) {
340         maxWidth = 0.0;
341         maxHeight = (axis_ == Axis::VERTICAL && isLinearLayout) ? 0.0 : maxSize.Height();
342     } else if (mainSwiperSize_ == MainSwiperSize::AUTO) {
343         LOGD("Use default MainSwiperSize");
344     } else {
345         LOGE("input wrong MainSwiperSize");
346     }
347 
348     if (axis_ == Axis::HORIZONTAL) {
349         maxWidth = (showingCount > DEFAULT_SHOWING_COUNT) ? innerLayout.GetMaxSize().Width() : maxWidth;
350     } else {
351         maxHeight = (showingCount > DEFAULT_SHOWING_COUNT) ? innerLayout.GetMaxSize().Height() : maxHeight;
352     }
353 
354     for (auto iter = items_.begin(); iter != items_.end(); iter++) {
355         const auto& childItem = iter->second;
356         if (!childItem) {
357             continue;
358         }
359         childItem->Layout(innerLayout);
360         maxWidth = std::max(maxWidth, childItem->GetLayoutSize().Width());
361         maxHeight = std::max(maxHeight, childItem->GetLayoutSize().Height());
362     }
363 
364     Size size = Size(maxWidth, maxHeight);
365     if (showingCount > DEFAULT_SHOWING_COUNT) {
366         if (axis_ == Axis::HORIZONTAL) {
367             size.SetWidth(maxSize.Width());
368         } else {
369             size.SetHeight(maxSize.Height());
370         }
371     }
372     if (mainSwiperSize_ == MainSwiperSize::AUTO) {
373         SetLayoutSize(maxSize.IsInfinite() ? size : maxSize);
374     } else {
375         SetLayoutSize(isLinearLayout ? maxSize : size);
376     }
377 
378     Size layoutSize = GetLayoutSize();
379     double halfSpace = swiper_ ? NormalizeToPx(swiper_->GetItemSpace()) / 2.0 : 0.0;
380     if (showingCount > DEFAULT_SHOWING_COUNT) {
381         swiperWidth_ = (axis_ == Axis::HORIZONTAL) ? maxWidth + halfSpace : maxWidth;
382         swiperHeight_ = (axis_ == Axis::HORIZONTAL) ? maxHeight : maxHeight + halfSpace;
383     } else {
384         swiperWidth_ = (isLinearLayout ? maxWidth : layoutSize.Width());
385         swiperHeight_ = (isLinearLayout ? maxHeight : layoutSize.Height());
386         if (axis_ == Axis::HORIZONTAL) {
387             swiperWidth_ += 2.0 * halfSpace;
388         } else {
389             swiperHeight_ += 2.0 * halfSpace;
390         }
391     }
392 
393     if (isLinearLayout) {
394         prevItemOffset_ = axis_ == Axis::HORIZONTAL
395                               ? (needReverse_ ? swiperWidth_ + halfSpace : -swiperWidth_ - halfSpace)
396                               : -swiperHeight_;
397     } else {
398         prevItemOffset_ = axis_ == Axis::HORIZONTAL
399                               ? (needReverse_ ? swiperWidth_ - prevMargin_ - nextMargin_
400                                               : -swiperWidth_ + prevMargin_ + nextMargin_)
401                               : -swiperHeight_ + prevMargin_ + nextMargin_;
402     }
403     nextItemOffset_ = -prevItemOffset_;
404     auto childPosition = NearZero(nextItemOffset_) ? nextItemOffset_ : std::fmod(scrollOffset_, nextItemOffset_);
405     UpdateChildPosition(childPosition, currentIndex_, true);
406     quickTurnItem_ = false;
407 
408     // layout indicator, indicator style in tv is different.
409     if (SystemProperties::GetDeviceType() != DeviceType::TV) {
410         LayoutIndicator(swiperIndicatorData_);
411     } else {
412         UpdateIndicator();
413     }
414 
415     if (swipeToIndex_ != -1) {
416         SwipeTo(swipeToIndex_, false);
417         swipeToIndex_ = -1;
418     }
419 }
420 
IsUseOnly()421 bool RenderSwiper::IsUseOnly()
422 {
423     return true;
424 }
425 
Initialize(const WeakPtr<PipelineContext> & context,bool catchMode)426 void RenderSwiper::Initialize(const WeakPtr<PipelineContext>& context, bool catchMode)
427 {
428     if (!disableSwipe_) {
429         if (axis_ == Axis::VERTICAL) {
430             dragDetector_ = AceType::MakeRefPtr<VerticalDragRecognizer>();
431         } else {
432             dragDetector_ = AceType::MakeRefPtr<HorizontalDragRecognizer>();
433         }
434     }
435     if (!controller_) {
436         controller_ = AceType::MakeRefPtr<Animator>(context);
437     } else {
438         StopSwipeAnimation();
439     }
440     if (!swipeToController_) {
441         swipeToController_ = AceType::MakeRefPtr<Animator>(context);
442     }
443 
444     InitIndicatorAnimation(context);
445     InitRecognizer(catchMode);
446     InitAccessibilityEventListener();
447 
448     // for autoplay
449     auto weak = AceType::WeakClaim(this);
450     if (!scheduler_) {
451         auto&& callback = [weak](uint64_t duration) {
452             auto swiper = weak.Upgrade();
453             if (swiper) {
454                 swiper->Tick(duration);
455             } else {
456                 LOGW("empty swiper, skip tick callback.");
457             }
458         };
459         scheduler_ = SchedulerBuilder::Build(callback, context);
460     } else if (scheduler_->IsActive()) {
461         LOGD("stop autoplay");
462         scheduler_->Stop();
463     }
464 
465     if (autoPlay_ && !scheduler_->IsActive() && show_ && !IsDisabled()) {
466         LOGD("start autoplay");
467         scheduler_->Start();
468     }
469 }
470 
InitRecognizer(bool catchMode)471 void RenderSwiper::InitRecognizer(bool catchMode)
472 {
473     if (!clickRecognizer_) {
474         auto weak = AceType::WeakClaim(this);
475         clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
476         clickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
477             auto client = weak.Upgrade();
478             if (client) {
479                 client->HandleClick(info);
480             }
481         });
482         clickRecognizer_->SetRemoteMessage([weak](const ClickInfo& info) {
483             auto client = weak.Upgrade();
484             if (client) {
485                 client->HandleRemoteMessage(info);
486             }
487         });
488         static const int32_t bubbleModeVersion = 6;
489         auto pipeline = context_.Upgrade();
490         if (!catchMode && pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
491             clickRecognizer_->SetUseCatchMode(false);
492         } else if (!showIndicator_) {
493             clickRecognizer_->SetUseCatchMode(false);
494         } else {
495             clickRecognizer_->SetUseCatchMode(true);
496         }
497     }
498     auto context = context_.Upgrade();
499     if (context && context->IsJsCard()) {
500         return;
501     }
502     InitDragRecognizer();
503     InitRawDragRecognizer();
504 }
505 
InitRawDragRecognizer()506 void RenderSwiper::InitRawDragRecognizer()
507 {
508     if (!rawRecognizer_) {
509         rawRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
510         auto weak = AceType::WeakClaim(this);
511         rawRecognizer_->SetOnTouchDown([weak](const TouchEventInfo& info) {
512             auto client = weak.Upgrade();
513             if (client) {
514                 client->HandleTouchDown(info);
515             }
516         });
517         rawRecognizer_->SetOnTouchUp([weak](const TouchEventInfo& info) {
518             auto client = weak.Upgrade();
519             if (client) {
520                 client->HandleTouchUp(info);
521             }
522         });
523         rawRecognizer_->SetOnTouchMove([weak](const TouchEventInfo& info) {
524             auto client = weak.Upgrade();
525             if (client) {
526                 client->HandleTouchMove(info);
527             }
528         });
529         rawRecognizer_->SetOnTouchCancel([weak](const TouchEventInfo& info) {
530             auto client = weak.Upgrade();
531             if (client) {
532                 client->HandleTouchCancel(info);
533             }
534         });
535     }
536 }
537 
InitDragRecognizer()538 void RenderSwiper::InitDragRecognizer()
539 {
540     auto weak = AceType::WeakClaim(this);
541     if (!dragDetector_) {
542         return;
543     }
544     dragDetector_->SetOnDragStart([weak](const DragStartInfo& info) {
545         auto client = weak.Upgrade();
546         if (client) {
547             client->HandleDragStart(info);
548         }
549     });
550     dragDetector_->SetOnDragUpdate([weak](const DragUpdateInfo& info) {
551         auto client = weak.Upgrade();
552         if (client) {
553             client->HandleDragUpdate(info);
554         }
555     });
556     dragDetector_->SetOnDragEnd([weak](const DragEndInfo& info) {
557         auto client = weak.Upgrade();
558         if (client) {
559             client->HandleDragEnd(info);
560         }
561     });
562 }
563 
InitAccessibilityEventListener()564 void RenderSwiper::InitAccessibilityEventListener()
565 {
566     auto refNode = accessibilityNode_.Upgrade();
567     if (!refNode) {
568         return;
569     }
570     refNode->AddSupportAction(AceAction::ACTION_SCROLL_FORWARD);
571     refNode->AddSupportAction(AceAction::ACTION_SCROLL_BACKWARD);
572 
573     auto weakPtr = AceType::WeakClaim(this);
574     refNode->SetActionScrollForward([weakPtr]() {
575         auto swiper = weakPtr.Upgrade();
576         if (swiper) {
577             swiper->ShowPrevious();
578             return true;
579         }
580         return false;
581     });
582     refNode->SetActionScrollBackward([weakPtr]() {
583         auto swiper = weakPtr.Upgrade();
584         if (swiper) {
585             swiper->ShowNext();
586             return true;
587         }
588         return false;
589     });
590 }
591 
UpdateIndex(int32_t index)592 void RenderSwiper::UpdateIndex(int32_t index)
593 {
594     // can't change index when stretch indicator, as stretch direct is single.
595     if (index >= 0 && NearEqual(stretchRate_, 0.0)) {
596         if (index >= itemCount_) {
597             index = itemCount_ - 1;
598         }
599         if (swiper_ && !swiper_->GetLazyForEachComponent()) {
600             if (index_ != index) {
601                 swipeToIndex_ = index; // swipe to animation need to start after perform layout
602                 index_ = index;
603             }
604         } else {
605             // render node first update index
606             currentIndex_ = index;
607             LOGI("update index to: %{public}d", index);
608         }
609     }
610 }
611 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)612 void RenderSwiper::OnTouchTestHit(
613     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
614 {
615     if (IsDisabled()) {
616         return;
617     }
618     if (dragDetector_ && !disableSwipe_) {
619         dragDetector_->SetCoordinateOffset(coordinateOffset);
620         result.emplace_back(dragDetector_);
621     }
622     if (rawRecognizer_) {
623         rawRecognizer_->SetCoordinateOffset(coordinateOffset);
624         result.emplace_back(rawRecognizer_);
625     }
626     if (clickRecognizer_) {
627         clickRecognizer_->SetCoordinateOffset(coordinateOffset);
628         result.emplace_back(clickRecognizer_);
629     }
630 }
631 
HandleTouchDown(const TouchEventInfo & info)632 void RenderSwiper::HandleTouchDown(const TouchEventInfo& info)
633 {
634     if (info.GetTouches().empty()) {
635         return;
636     }
637     const auto& locationInfo = info.GetTouches().front();
638     Point touchPoint = Point(locationInfo.GetGlobalLocation().GetX(), locationInfo.GetGlobalLocation().GetY());
639     if (fingerId_ >= 0 && locationInfo.GetFingerId() != fingerId_) {
640         return;
641     }
642 
643     fingerId_ = locationInfo.GetFingerId();
644     GetIndicatorCurrentRect(swiperIndicatorData_);
645     if (indicatorRect_.IsInRegion(touchPoint)) {
646         startTimeStamp_ = GetTickCount();
647         if (isIndicatorAnimationStart_) {
648             touchContentType_ = TouchContentType::TOUCH_NONE;
649             return;
650         }
651         touchContentType_ = TouchContentType::TOUCH_INDICATOR;
652     } else {
653         touchContentType_ = TouchContentType::TOUCH_CONTENT;
654         if (controller_ && hasDragAction_ && swiper_->GetSlideContinue()) {
655             controller_->Finish();
656             return;
657         }
658         // when is in item moving animation, touch event will break animation and stop in current position
659         StopSwipeAnimation();
660         StopIndicatorAnimation();
661         if (autoPlay_ && scheduler_) {
662             scheduler_->Stop();
663         }
664     }
665     StopIndicatorSpringAnimation();
666 }
667 
668 // touch up event before than click event
HandleTouchUp(const TouchEventInfo & info)669 void RenderSwiper::HandleTouchUp(const TouchEventInfo& info)
670 {
671     // for indicator
672     startTimeStamp_ = 0;
673     int32_t fingerId = -1;
674     if (!info.GetTouches().empty()) {
675         fingerId = info.GetTouches().front().GetFingerId();
676     } else if (!info.GetChangedTouches().empty()) {
677         fingerId = info.GetChangedTouches().front().GetFingerId();
678     }
679     if ((fingerId_ >= 0 && fingerId != fingerId_) || fingerId_ == -1) {
680         return;
681     }
682 
683     fingerId_ = -1;
684     // indicator zone
685     if (touchContentType_ == TouchContentType::TOUCH_NONE) {
686         LOGD(" touch content type is none");
687         return;
688     } else if (touchContentType_ == TouchContentType::TOUCH_INDICATOR) {
689         if (swiperIndicatorData_.isPressed) {
690             if (isDragStart_) {
691                 // reset flag of isPressed by function of HandleDragEnd.
692                 isDragStart_ = false;
693                 return;
694             }
695             if (IsZoomOutAnimationStopped()) {
696                 // reset flag of isPressed after zoom out animation
697                 StartZoomOutAnimation();
698             }
699         }
700         return;
701     }
702 
703     // content zone
704     if (swiper_->GetSlideContinue()) {
705         return;
706     }
707     if (hasDragAction_) {
708         hasDragAction_ = false;
709         return;
710     }
711     if (isIndicatorAnimationStart_) {
712         return;
713     }
714     // restore the item position that slides to half stopped by a touch event during autoplay
715     scrollOffset_ = fmod(scrollOffset_, nextItemOffset_);
716     if (!NearZero(scrollOffset_)) {
717         MoveItems(0.0);
718     } else {
719         // restore autoplay which break by a touch event
720         RestoreAutoPlay();
721     }
722 }
723 
HandleTouchMove(const TouchEventInfo & info)724 void RenderSwiper::HandleTouchMove(const TouchEventInfo& info)
725 {
726     // for indicator
727     if (!indicator_ || indicator_->GetIndicatorDisabled() || swiperIndicatorData_.isDigital) {
728         return;
729     }
730 
731     if (info.GetTouches().empty()) {
732         return;
733     }
734 
735     if (touchContentType_ != TouchContentType::TOUCH_INDICATOR) {
736         return;
737     }
738 
739     const auto& locationInfo = info.GetTouches().front();
740     Point touchPoint = Point(locationInfo.GetGlobalLocation().GetX(), locationInfo.GetGlobalLocation().GetY());
741     GetIndicatorCurrentRect(swiperIndicatorData_);
742     if (indicatorRect_.IsInRegion(touchPoint)) {
743         if (autoPlay_ && scheduler_ && scheduler_->IsActive()) {
744             // forbid indicator operation on auto play period.
745             return;
746         }
747         if (!swiperIndicatorData_.isHovered) {
748             int64_t endStartTime = GetTickCount();
749             if (startTimeStamp_ == 0) {
750                 // move into indicator rage
751                 startTimeStamp_ = endStartTime;
752                 return;
753             }
754             auto delayTime = static_cast<double>(endStartTime - startTimeStamp_);
755             if (!swiperIndicatorData_.isPressed && delayTime >= DELAY_TIME_DEFAULT) {
756                 swiperIndicatorData_.isPressed = true;
757                 StartZoomInAnimation();
758             }
759         }
760     }
761 }
762 
763 // TouchCancel event is triggered by Input, it is similar to touchUp event.
HandleTouchCancel(const TouchEventInfo & info)764 void RenderSwiper::HandleTouchCancel(const TouchEventInfo& info)
765 {
766     LOGI("Handle touchCancel start.");
767     // TouchCancel is same to touchUp.
768     HandleTouchUp(info);
769 }
770 
HandleClick(const ClickInfo & clickInfo)771 void RenderSwiper::HandleClick(const ClickInfo& clickInfo)
772 {
773     if (clickEvent_) {
774         clickEvent_(std::make_shared<ClickInfo>(clickInfo));
775     }
776     std::string accessibilityEventType = "click";
777     SendAccessibilityEvent(accessibilityEventType);
778     // for indicator
779     if (!indicator_ || swiperIndicatorData_.isDigital) {
780         return;
781     }
782 
783     if (swiperIndicatorData_.isHovered || swiperIndicatorData_.isPressed) {
784         if (currentHoverIndex_ != INDICATOR_INVALID_HOVER_INDEX) {
785             auto toIndex = needReverse_ ? (itemCount_ - currentHoverIndex_ - 1) : currentHoverIndex_;
786             StartIndicatorAnimation(currentIndex_, toIndex);
787             return;
788         }
789         // refuse click event
790         LOGD("drop click event on press and hover status, otherwise exist hover index.");
791         return;
792     }
793 
794     // handle operation not support when indicator disabled.
795     if (indicator_->GetIndicatorDisabled()) {
796         return;
797     }
798     Point clickPoint = Point(clickInfo.GetGlobalLocation().GetX(), clickInfo.GetGlobalLocation().GetY());
799     GetIndicatorCurrentRect(swiperIndicatorData_);
800     if (!indicatorRect_.IsInRegion(clickPoint)) {
801         return;
802     }
803     if (autoPlay_ && scheduler_ && scheduler_->IsActive()) {
804         // forbid indicator operation on auto play period.
805         return;
806     }
807     if (fingerId_ >= 0 && clickInfo.GetFingerId() != fingerId_) {
808         return;
809     }
810 
811     Offset offset;
812     Size size;
813     Rect itemRect;
814     if (axis_ == Axis::HORIZONTAL) {
815         int currentIndex = needReverse_ ? (itemCount_ - currentIndex_ - 1) : currentIndex_;
816         offset = indicatorRect_.GetOffset() + Offset(
817             swiperIndicatorData_.indicatorItemData[currentIndex].position.GetX(), 0);
818         size = Size(swiperIndicatorData_.indicatorItemData[currentIndex].width,
819             swiperIndicatorData_.indicatorPaintData.height);
820         itemRect = Rect(offset, size);
821         if (clickPoint.GetX() < itemRect.GetOffset().GetX()) {
822             if (needReverse_) {
823                 IndicatorSwipeNext();
824             } else {
825                 IndicatorSwipePrev();
826             }
827         } else if (clickPoint.GetX() > itemRect.Right()) {
828             if (needReverse_) {
829                 IndicatorSwipePrev();
830             } else {
831                 IndicatorSwipeNext();
832             }
833         }
834     } else {
835         offset = indicatorRect_.GetOffset() + Offset(0,
836             swiperIndicatorData_.indicatorItemData[currentIndex_].position.GetY());
837         size = Size(swiperIndicatorData_.indicatorPaintData.width,
838             swiperIndicatorData_.indicatorItemData[currentIndex_].height);
839         itemRect = Rect(offset, size);
840         if (clickPoint.GetY() < itemRect.GetOffset().GetY()) {
841             IndicatorSwipePrev();
842         } else if (clickPoint.GetY() > itemRect.Bottom()) {
843             IndicatorSwipeNext();
844         }
845     }
846 }
847 
HandleRemoteMessage(const ClickInfo & clickInfo)848 void RenderSwiper::HandleRemoteMessage(const ClickInfo& clickInfo)
849 {
850     if (remoteMessageEvent_) {
851         remoteMessageEvent_(std::make_shared<ClickInfo>(clickInfo));
852     }
853 }
854 
HandleDragStart(const DragStartInfo & info)855 void RenderSwiper::HandleDragStart(const DragStartInfo& info)
856 {
857     Point dragStartPoint = Point(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY());
858     GetIndicatorCurrentRect(swiperIndicatorData_);
859     if (indicatorRect_.IsInRegion(dragStartPoint)) {
860         return;
861     }
862     if (fingerId_ >= 0 && info.GetFingerId() != fingerId_) {
863         return;
864     }
865 #ifdef OHOS_PLATFORM
866     // Increase the cpu frequency when sliding.
867     ResSchedReport::GetInstance().ResSchedDataReport("slide_on");
868 #endif
869     // for swiper item
870     hasDragAction_ = true;
871     scrollOffset_ = fmod(scrollOffset_, nextItemOffset_);
872     if (onFocus_) {
873         auto context = GetContext().Upgrade();
874         if (context) {
875             context->CancelFocusAnimation();
876         }
877     }
878     dragOffset_ = 0;
879 }
880 
CalculateFriction(double gamma)881 double RenderSwiper::CalculateFriction(double gamma)
882 {
883     constexpr double SCROLL_RATIO = 0.72;
884     if (GreatOrEqual(gamma, 1.0)) {
885         gamma = 1.0;
886     }
887     return SCROLL_RATIO * std::pow(1.0 - gamma, SQUARE);
888 }
889 
HandleDragUpdate(const DragUpdateInfo & info)890 void RenderSwiper::HandleDragUpdate(const DragUpdateInfo& info)
891 {
892     GetIndicatorCurrentRect(swiperIndicatorData_);
893     if (swiperIndicatorData_.isPressed) {
894         if (swiperIndicatorData_.isDigital) {
895             return;
896         }
897         if (autoPlay_ && scheduler_ && scheduler_->IsActive()) {
898             // forbid indicator operation on auto play period.
899             return;
900         }
901         DragIndicator(std::clamp(info.GetMainDelta(), -MAX_VIEW_PORT_WIDTH, MAX_VIEW_PORT_WIDTH));
902         return;
903     }
904 
905     if (touchContentType_ == TouchContentType::TOUCH_CONTENT || rotationStatus_ == RotationStatus::ROTATION_UPDATE) {
906         EdgeEffect edgeEffect = swiper_->GetEdgeEffect();
907         if (edgeEffect == EdgeEffect::SPRING && (!loop_) && currentIndex_ == targetIndex_
908             && (currentIndex_ == 0 || currentIndex_ == itemCount_ - 1)) {
909             dragOffset_ += info.GetMainDelta();
910             double friction = CalculateFriction(std::abs(dragOffset_)
911                 / (axis_ == Axis::VERTICAL ? swiperHeight_ : swiperWidth_));
912             UpdateScrollPosition(friction * info.GetMainDelta());
913         } else {
914             UpdateScrollPosition(info.GetMainDelta());
915         }
916     }
917 }
918 
SpringItems(const DragEndInfo & info)919 bool RenderSwiper::SpringItems(const DragEndInfo& info)
920 {
921     EdgeEffect edgeEffect = swiper_->GetEdgeEffect();
922     if (edgeEffect == EdgeEffect::SPRING) {
923         int32_t toIndex = 0;
924         toIndex = GreatNotEqual(scrollOffset_, 0.0) ? GetPrevIndex() : GetNextIndex();
925 
926         if (currentIndex_ == toIndex) {
927             double minLeading = 0.0;
928             double maxTrainling = 0.0;
929             if (axis_ == Axis::VERTICAL) {
930                 minLeading = needReverse_ ? 0.0 : (GreatNotEqual(scrollOffset_, 0.0) ?
931                     (swiperHeight_ - std::abs(prevItemOffset_)) : -(swiperHeight_ - std::abs(prevItemOffset_)));
932                 maxTrainling = needReverse_ ? (GreatNotEqual(scrollOffset_, 0.0) ?
933                     -(swiperHeight_ - std::abs(prevItemOffset_)) : (swiperHeight_ - std::abs(prevItemOffset_))) : 0.0;
934             } else {
935                 minLeading = needReverse_ ? 0.0 : (GreatNotEqual(scrollOffset_, 0.0) ?
936                     (swiperWidth_ - std::abs(prevItemOffset_)) : -(swiperWidth_ - std::abs(prevItemOffset_)));
937                 maxTrainling = needReverse_ ? (GreatNotEqual(scrollOffset_, 0.0) ?
938                     -(swiperWidth_ - std::abs(prevItemOffset_)) : (swiperWidth_ - std::abs(prevItemOffset_))) : 0.0;
939             }
940             double friction = CalculateFriction(std::abs(dragOffset_) /
941                  (axis_ == Axis::VERTICAL ? swiperHeight_ : swiperWidth_));
942             StartSpringMotion(scrollOffset_, info.GetMainVelocity() * friction,
943                 GreatNotEqual(scrollOffset_, 0.0) ?
944                 ExtentPair(std::abs(minLeading), maxTrainling) : ExtentPair(0.0, 0.0),
945                 ExtentPair(std::abs(minLeading), maxTrainling));
946             return true;
947         }
948     }
949 
950     return false;
951 }
952 
HandleDragEnd(const DragEndInfo & info)953 void RenderSwiper::HandleDragEnd(const DragEndInfo& info)
954 {
955     if (swiperIndicatorData_.isPressed) {
956         DragIndicatorEnd();
957         return;
958     }
959 
960     if (touchContentType_ != TouchContentType::TOUCH_CONTENT && rotationStatus_ != RotationStatus::ROTATION_UPDATE) {
961         return;
962     }
963 
964     if (fingerId_ >= 0 && info.GetFingerId() != fingerId_) {
965         return;
966     }
967 
968 #ifdef OHOS_PLATFORM
969     ResSchedReport::GetInstance().ResSchedDataReport("slide_off");
970 #endif
971 
972     // for swiper item
973     scrollOffset_ = fmod(scrollOffset_, nextItemOffset_);
974     if (NearZero(scrollOffset_)) {
975         // restore autoplay which break by a touch event
976         RestoreAutoPlay();
977         return;
978     }
979     if (isPaintedFade_ && fadeController_) {
980         auto translate = AceType::MakeRefPtr<CurveAnimation<double>>(dragDelta_, 0, Curves::LINEAR);
981         auto weak = AceType::WeakClaim(this);
982         translate->AddListener(Animation<double>::ValueCallback([weak](double value) {
983             auto swiper = weak.Upgrade();
984             if (swiper) {
985                 swiper->dragDelta_ = value;
986                 swiper->MarkNeedRender();
987             }
988         }));
989 
990         fadeController_->ClearStopListeners();
991         // trigger the event after the animation ends.
992         fadeController_->AddStopListener([weak]() {
993             auto swiper = weak.Upgrade();
994             if (swiper) {
995                 swiper->isPaintedFade_ = false;
996             }
997         });
998         fadeController_->SetDuration(FADE_DURATION);
999         fadeController_->ClearInterpolators();
1000         fadeController_->AddInterpolator(translate);
1001         fadeController_->Play();
1002         MarkNeedRender();
1003         scrollOffset_ = 0.0;
1004         return;
1005     }
1006 
1007     if (SpringItems(info)) {
1008         return;
1009     }
1010 
1011     isIndicatorAnimationStart_ = false;
1012     MoveItems(info.GetMainVelocity());
1013 }
1014 
StartSpringMotion(double mainPosition,double mainVelocity,const ExtentPair & extent,const ExtentPair & initExtent)1015 void RenderSwiper::StartSpringMotion(double mainPosition, double mainVelocity,
1016     const ExtentPair& extent, const ExtentPair& initExtent)
1017 {
1018     if (!springController_) {
1019         return;
1020     }
1021 
1022     constexpr double SPRING_SCROLL_MASS = 0.5;
1023     constexpr double SPRING_SCROLL_STIFFNESS = 100.0;
1024     constexpr double SPRING_SCROLL_DAMPING = 15.55635;
1025     const RefPtr<SpringProperty> DEFAULT_OVER_SPRING_PROPERTY =
1026     AceType::MakeRefPtr<SpringProperty>(SPRING_SCROLL_MASS, SPRING_SCROLL_STIFFNESS, SPRING_SCROLL_DAMPING);
1027 
1028     if (isAnimationAlreadyAdded_ && controller_) {
1029         controller_->RemoveInterpolator(translate_);
1030         isAnimationAlreadyAdded_ = false;
1031     }
1032     scrollMotion_ = AceType::MakeRefPtr<ScrollMotion>(mainPosition, mainVelocity, extent,
1033         initExtent, DEFAULT_OVER_SPRING_PROPERTY);
1034     scrollMotion_->AddListener([weakScroll = AceType::WeakClaim(this)](double position) {
1035         auto swiper = weakScroll.Upgrade();
1036         if (swiper) {
1037             swiper->UpdateChildPosition(position, swiper->currentIndex_);
1038         }
1039     });
1040     springController_->ClearStartListeners();
1041     springController_->AddStartListener([weak = AceType::WeakClaim(this)]() {
1042         auto swiper = weak.Upgrade();
1043         if (swiper) {
1044             swiper->FireAnimationStart();
1045         }
1046     });
1047     springController_->ClearStopListeners();
1048     springController_->PlayMotion(scrollMotion_);
1049     springController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
1050         auto swiper = weak.Upgrade();
1051         if (swiper) {
1052             swiper->RestoreAutoPlay();
1053             swiper->ResetCachedChildren();
1054             swiper->UpdateOneItemOpacity(MAX_OPACITY, swiper->currentIndex_);
1055             swiper->UpdateOneItemOpacity(MAX_OPACITY, swiper->currentIndex_);
1056             swiper->ExecuteMoveCallback(swiper->currentIndex_);
1057             swiper->FireAnimationEnd();
1058             swiper->MarkNeedLayout(true);
1059         }
1060     });
1061 }
1062 
MoveItems(double dragVelocity)1063 void RenderSwiper::MoveItems(double dragVelocity)
1064 {
1065     if (isIndicatorAnimationStart_) {
1066         LOGE("item and indicator animation is processing.");
1067         return;
1068     }
1069 
1070     if (isAnimationAlreadyAdded_ && controller_) {
1071         controller_->RemoveInterpolator(translate_);
1072         isAnimationAlreadyAdded_ = false;
1073     }
1074 
1075     isIndicatorAnimationStart_ = true;
1076     double start = scrollOffset_;
1077     double end;
1078 
1079     bool needRestore = false;
1080     int32_t fromIndex = currentIndex_;
1081     int32_t toIndex = 0;
1082     // Adjust offset more than MIN_SCROLL_OFFSET at least
1083     double minOffset = 0.0;
1084     if (axis_ == Axis::VERTICAL) {
1085         minOffset = MIN_SCROLL_OFFSET * (swiperHeight_ - prevMargin_ - nextMargin_);
1086     } else {
1087         minOffset = MIN_SCROLL_OFFSET * (swiperWidth_ - prevMargin_ - nextMargin_);
1088     }
1089     auto nextItemOffset = needReverse_ ? -nextItemOffset_ : nextItemOffset_;
1090     auto prevItemOffset = needReverse_ ? -prevItemOffset_ : prevItemOffset_;
1091     if (std::abs(dragVelocity) > NormalizeToPx(MIN_TURN_PAGE_VELOCITY) &&
1092         std::abs(scrollOffset_) > NormalizeToPx(MIN_DRAG_DISTANCE)) {
1093         if (dragVelocity > 0.0) {
1094             toIndex = GetPrevIndex();
1095             end = currentIndex_ == toIndex ? 0.0 : (scrollOffset_ < 0.0 ? 0.0 : nextItemOffset);
1096             if (scrollOffset_ < 0.0) {
1097                 fromIndex = GetNextIndex();
1098                 start += nextItemOffset;
1099                 toIndex = currentIndex_;
1100                 end += nextItemOffset;
1101             }
1102         } else {
1103             toIndex = GetNextIndex();
1104             end = currentIndex_ == toIndex ? 0.0 : (scrollOffset_ > 0.0 ? 0.0 : prevItemOffset);
1105             if (scrollOffset_ > 0.0) {
1106                 fromIndex = GetPrevIndex();
1107                 start += prevItemOffset;
1108                 toIndex = currentIndex_;
1109                 end += prevItemOffset;
1110             }
1111         }
1112         targetIndex_ = toIndex;
1113         nextIndex_ = targetIndex_;
1114     } else if (std::abs(scrollOffset_) > minOffset) {
1115         if (scrollOffset_ > 0.0) {
1116             toIndex = GetPrevIndex();
1117             end = nextItemOffset;
1118         } else {
1119             toIndex = GetNextIndex();
1120             end = prevItemOffset;
1121         }
1122         targetIndex_ = toIndex;
1123         nextIndex_ = targetIndex_;
1124     } else {
1125         toIndex = scrollOffset_ > 0.0 ? GetPrevIndex() : GetNextIndex();
1126         end = 0.0;
1127         needRestore = true;
1128     }
1129     needRestore_ = needRestore;
1130     LOGI("translate animation, currentIndex: %{public}d, fromIndex: %{public}d, toIndex: %{public}d, \
1131         start: %{public}f, end: %{public}f", currentIndex_, fromIndex, toIndex, start, end);
1132     translate_ = AceType::MakeRefPtr<CurveAnimation<double>>(start, end, curve_);
1133     auto weak = AceType::WeakClaim(this);
1134     translate_->AddListener(Animation<double>::ValueCallback([weak, fromIndex, toIndex, start, end](double value) {
1135         auto swiper = weak.Upgrade();
1136         if (swiper) {
1137             if (value != start && value != end && start != end) {
1138                 double moveRate = Curves::EASE_OUT->MoveInternal((value - start) / (end - start));
1139                 value = start + (end - start) * moveRate;
1140             }
1141             swiper->UpdateChildPosition(value, fromIndex);
1142             swiper->MoveIndicator(toIndex, value, true);
1143         }
1144     }));
1145 
1146     if (controller_) {
1147         controller_->ClearStopListeners();
1148         controller_->ClearStartListeners();
1149         // trigger the event after the animation ends.
1150         controller_->AddStopListener([weak, fromIndex, toIndex, needRestore]() {
1151             LOGI("slide animation stop");
1152             // moving animation end, one drag and item move is complete
1153             auto swiper = weak.Upgrade();
1154             if (!swiper) {
1155                 return;
1156             }
1157             swiper->isIndicatorAnimationStart_ = false;
1158             if (!needRestore) {
1159                 if (toIndex != swiper->currentIndex_) {
1160                     swiper->LoadLazyItems((fromIndex + 1) % swiper->itemCount_ == toIndex);
1161                     swiper->currentIndex_ = toIndex;
1162                 }
1163                 swiper->outItemIndex_ = fromIndex;
1164             }
1165             swiper->RestoreAutoPlay();
1166             swiper->FireItemChangedEvent(!needRestore);
1167             swiper->ResetCachedChildren();
1168             swiper->ResetIndicatorPosition();
1169             swiper->UpdateOneItemOpacity(MAX_OPACITY, fromIndex);
1170             swiper->UpdateOneItemOpacity(MAX_OPACITY, toIndex);
1171             swiper->ExecuteMoveCallback(swiper->currentIndex_);
1172             swiper->FireAnimationEnd();
1173             swiper->MarkNeedLayout(true);
1174         });
1175 
1176         controller_->AddStartListener([weak]() {
1177             auto swiper = weak.Upgrade();
1178             if (swiper) {
1179                 swiper->FireAnimationStart();
1180             }
1181         });
1182 
1183         controller_->SetDuration(duration_);
1184         controller_->AddInterpolator(translate_);
1185         controller_->Play();
1186     }
1187     isAnimationAlreadyAdded_ = true;
1188     MarkNeedRender();
1189 }
1190 
FireItemChangedEvent(bool changed) const1191 void RenderSwiper::FireItemChangedEvent(bool changed) const
1192 {
1193     if (animationFinishEvent_) {
1194         LOGI("call animationFinishEvent_");
1195         animationFinishEvent_();
1196     }
1197 
1198     if (changeEvent_ && changed) {
1199         LOGI("call changeEvent_");
1200         changeEvent_(std::make_shared<SwiperChangeEvent>(currentIndex_));
1201     }
1202 
1203     for (const auto& [first, second] : changeEndListeners_) {
1204         if (second) {
1205             second(currentIndex_);
1206         }
1207     }
1208 }
1209 
FireAnimationStart()1210 void RenderSwiper::FireAnimationStart()
1211 {
1212     if (animationStartEvent_) {
1213         LOGI("call animationStartEvent_");
1214         animationStartEvent_(std::make_shared<SwiperChangeEvent>(currentIndex_));
1215     }
1216 }
1217 
FireAnimationEnd()1218 void RenderSwiper::FireAnimationEnd()
1219 {
1220     if (animationEndEvent_) {
1221         LOGI("call animationEndEvent_");
1222         animationEndEvent_(std::make_shared<SwiperChangeEvent>(currentIndex_));
1223     }
1224 }
1225 
SwipeTo(int32_t index,bool reverse)1226 void RenderSwiper::SwipeTo(int32_t index, bool reverse)
1227 {
1228     if (index >= itemCount_) {
1229         index = itemCount_ - 1;
1230     } else if (index < 0) {
1231         index = 0;
1232     }
1233     if (isIndicatorAnimationStart_) {
1234         RedoSwipeToAnimation(index, reverse);
1235     } else {
1236         StopIndicatorSpringAnimation();
1237         DoSwipeToAnimation(currentIndex_, index, reverse);
1238     }
1239 }
1240 
InitSwipeToAnimation(double start,double end)1241 void RenderSwiper::InitSwipeToAnimation(double start, double end)
1242 {
1243     auto animationCurve = swiper_->GetAnimationCurve();
1244     auto curStartTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(CUR_START_TRANSLATE_TIME, start);
1245     auto curEndTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(CUR_END_TRANSLATE_TIME, end);
1246     curEndTranslateKeyframe->SetCurve(
1247         animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1248     curTranslateAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<double>>();
1249     curTranslateAnimation_->AddKeyframe(curStartTranslateKeyframe);
1250     curTranslateAnimation_->AddKeyframe(curEndTranslateKeyframe);
1251 
1252     auto targetStartTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(TARGET_START_TRANSLATE_TIME, -end);
1253     auto targetEndTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(TARGET_END_TRANSLATE_TIME, start);
1254     targetEndTranslateKeyframe->SetCurve(
1255         animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1256     targetTranslateAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<double>>();
1257     targetTranslateAnimation_->AddKeyframe(targetStartTranslateKeyframe);
1258     targetTranslateAnimation_->AddKeyframe(targetEndTranslateKeyframe);
1259 
1260     if (animationOpacity_) {
1261         auto curStartOpacityKeyframe =
1262             AceType::MakeRefPtr<Keyframe<uint8_t>>(CUR_START_OPACITY_TIME, CUR_START_OPACITY_VALUE);
1263         auto curEndOpacityKeyframe =
1264             AceType::MakeRefPtr<Keyframe<uint8_t>>(CUR_END_OPACITY_TIME, CUR_END_OPACITY_VALUE);
1265         curEndOpacityKeyframe->SetCurve(
1266             animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1267         curOpacityAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<uint8_t>>();
1268         curOpacityAnimation_->AddKeyframe(curStartOpacityKeyframe);
1269         curOpacityAnimation_->AddKeyframe(curEndOpacityKeyframe);
1270 
1271         auto targetStartOpacityKeyframe =
1272             AceType::MakeRefPtr<Keyframe<uint8_t>>(TARGET_START_OPACITY_TIME, TARGET_START_OPACITY_VALUE);
1273         auto targetEndOpacityKeyframe =
1274             AceType::MakeRefPtr<Keyframe<uint8_t>>(TARGET_END_OPACITY_TIME, TARGET_END_OPACITY_VALUE);
1275         targetEndOpacityKeyframe->SetCurve(
1276             animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1277         targetOpacityAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<uint8_t>>();
1278         targetOpacityAnimation_->AddKeyframe(targetStartOpacityKeyframe);
1279         targetOpacityAnimation_->AddKeyframe(targetEndOpacityKeyframe);
1280     }
1281 }
1282 
AddSwipeToTranslateListener(int32_t fromIndex,int32_t toIndex)1283 void RenderSwiper::AddSwipeToTranslateListener(int32_t fromIndex, int32_t toIndex)
1284 {
1285     auto weak = AceType::WeakClaim(this);
1286     targetIndex_ = toIndex;
1287     nextIndex_ = toIndex;
1288     curTranslateAnimation_->AddListener([weak, fromIndex, toIndex](const double& value) {
1289         auto swiper = weak.Upgrade();
1290         if (swiper) {
1291             swiper->UpdateItemPosition(value, fromIndex, toIndex);
1292         }
1293     });
1294 
1295     targetTranslateAnimation_->AddListener([weak, fromIndex, toIndex](const double& value) {
1296         auto swiper = weak.Upgrade();
1297         if (swiper) {
1298             swiper->UpdateItemPosition(value, toIndex, fromIndex);
1299         }
1300     });
1301 }
1302 
AddSwipeToOpacityListener(int32_t fromIndex,int32_t toIndex)1303 void RenderSwiper::AddSwipeToOpacityListener(int32_t fromIndex, int32_t toIndex)
1304 {
1305     if (!animationOpacity_) {
1306         return;
1307     }
1308     auto weak = AceType::WeakClaim(this);
1309     curOpacityAnimation_->AddListener([weak, fromIndex, toIndex](const uint8_t& opacity) {
1310         auto swiper = weak.Upgrade();
1311         if (swiper) {
1312             swiper->UpdateItemOpacity(opacity, fromIndex, toIndex);
1313         }
1314     });
1315 
1316     targetOpacityAnimation_->AddListener([weak, fromIndex, toIndex](const uint8_t& opacity) {
1317         auto swiper = weak.Upgrade();
1318         if (swiper) {
1319             swiper->UpdateItemOpacity(opacity, toIndex, fromIndex);
1320         }
1321     });
1322 }
1323 
AddSwipeToIndicatorListener(int32_t fromIndex,int32_t toIndex)1324 void RenderSwiper::AddSwipeToIndicatorListener(int32_t fromIndex, int32_t toIndex)
1325 {
1326     indicatorAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(
1327         CUR_START_TRANSLATE_TIME, CUR_END_TRANSLATE_TIME, curve_);
1328     indicatorAnimation_->AddListener(
1329         [weak = AceType::WeakClaim(this), fromIndex, toIndex](const double value) {
1330         auto swiper = weak.Upgrade();
1331         if (swiper) {
1332             swiper->UpdateIndicatorOffset(fromIndex, toIndex, value);
1333         }
1334     });
1335     animationDirect_ = (fromIndex - toIndex <= 0) ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
1336     if (needReverse_) {
1337         animationDirect_ *= INDICATOR_DIRECT_BACKWARD;
1338     }
1339     targetIndex_ = toIndex;
1340     nextIndex_ = toIndex;
1341 }
1342 
CalculateEndOffset(int32_t fromIndex,int32_t toIndex,bool reverse)1343 double RenderSwiper::CalculateEndOffset(int32_t fromIndex, int32_t toIndex, bool reverse)
1344 {
1345     double end = 0.0;
1346     auto context = GetContext().Upgrade();
1347     double translateRatio = TRANSLATE_RATIO;
1348     if (context && context->GetIsDeclarative()) {
1349         translateRatio = 1.0;
1350     }
1351     if (fromIndex > toIndex) {
1352         // default move to back position, if need reverse direction move to front position.
1353         end = reverse ? prevItemOffset_ / translateRatio : nextItemOffset_ / translateRatio;
1354     } else {
1355         // default move to front position, if need reverse direction move to back position.
1356         end = reverse ? nextItemOffset_ / translateRatio : prevItemOffset_ / translateRatio;
1357     }
1358     if (context && context->IsJsCard()) {
1359         if (loop_) {
1360             end = reverse ? nextItemOffset_ : prevItemOffset_;
1361         } else {
1362             if (fromIndex > toIndex) {
1363                 end = reverse ? prevItemOffset_ : nextItemOffset_;
1364             } else {
1365                 end = reverse ? nextItemOffset_ : prevItemOffset_;
1366             }
1367         }
1368     }
1369     return end;
1370 }
1371 
ResetScrollOffset()1372 void RenderSwiper::ResetScrollOffset()
1373 {
1374     scrollOffset_ = 0.0;
1375 }
1376 
DoSwipeToAnimation(int32_t fromIndex,int32_t toIndex,bool reverse)1377 void RenderSwiper::DoSwipeToAnimation(int32_t fromIndex, int32_t toIndex, bool reverse)
1378 {
1379     if (!swipeToController_ || isIndicatorAnimationStart_ || fromIndex == toIndex) {
1380         return;
1381     }
1382     isIndicatorAnimationStart_ = true;
1383     double start = 0.0;
1384     moveStatus_ = true;
1385     if (onFocus_) {
1386         auto context = GetContext().Upgrade();
1387         if (context) {
1388             context->CancelFocusAnimation();
1389         }
1390     }
1391     double end = CalculateEndOffset(fromIndex, toIndex, reverse);
1392     swipeToController_->ClearStopListeners();
1393     if (isSwipeToAnimationAdded_) {
1394         swipeToController_->ClearInterpolators();
1395         isSwipeToAnimationAdded_ = false;
1396     }
1397     if (!swipeToController_->IsStopped()) {
1398         swipeToController_->Stop();
1399     }
1400 
1401     InitSwipeToAnimation(start, end);
1402     AddSwipeToTranslateListener(fromIndex, toIndex);
1403     AddSwipeToOpacityListener(fromIndex, toIndex);
1404     AddSwipeToIndicatorListener(fromIndex, toIndex);
1405 
1406     // trigger the event after the animation ends.
1407     auto weak = AceType::WeakClaim(this);
1408     swipeToController_->AddStopListener([weak, fromIndex, toIndex]() {
1409         auto swiper = weak.Upgrade();
1410         if (swiper) {
1411             swiper->LoadLazyItems((fromIndex + 1) % swiper->itemCount_ == toIndex);
1412             swiper->isIndicatorAnimationStart_ = false;
1413             swiper->outItemIndex_ = fromIndex;
1414             swiper->currentIndex_ = toIndex;
1415             swiper->moveStatus_ = false;
1416             swiper->ResetScrollOffset();
1417             swiper->UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
1418             swiper->UpdateOneItemOpacity(MAX_OPACITY, fromIndex);
1419             swiper->UpdateOneItemOpacity(MAX_OPACITY, toIndex);
1420             swiper->RestoreAutoPlay();
1421             swiper->FireItemChangedEvent(true);
1422             swiper->ResetCachedChildren();
1423             swiper->MarkNeedLayout(true);
1424         }
1425     });
1426     swipeToController_->SetDuration(duration_);
1427     swipeToController_->AddInterpolator(curTranslateAnimation_);
1428     swipeToController_->AddInterpolator(targetTranslateAnimation_);
1429     swipeToController_->AddInterpolator(curOpacityAnimation_);
1430     swipeToController_->AddInterpolator(targetOpacityAnimation_);
1431     swipeToController_->AddInterpolator(indicatorAnimation_);
1432     swipeToController_->SetFillMode(FillMode::FORWARDS);
1433     swipeToController_->Play();
1434     isSwipeToAnimationAdded_ = true;
1435 }
1436 
RedoSwipeToAnimation(int32_t toIndex,bool reverse)1437 void RenderSwiper::RedoSwipeToAnimation(int32_t toIndex, bool reverse)
1438 {
1439     if (toIndex == targetIndex_) {
1440         // continue move animation
1441         return;
1442     }
1443     // stop animation before update item position, otherwise the
1444     // animation callback will change the item position
1445     FinishAllSwipeAnimation();
1446     DoSwipeToAnimation(currentIndex_, toIndex, false);
1447 }
1448 
StopSwipeToAnimation()1449 void RenderSwiper::StopSwipeToAnimation()
1450 {
1451     if (swipeToController_ && !swipeToController_->IsStopped()) {
1452         swipeToController_->ClearStopListeners();
1453         swipeToController_->Stop();
1454         UpdateOneItemOpacity(MAX_OPACITY, currentIndex_);
1455         UpdateOneItemOpacity(MAX_OPACITY, targetIndex_);
1456         isIndicatorAnimationStart_ = false;
1457     }
1458 }
1459 
UpdateItemOpacity(uint8_t opacity,int32_t index,int32_t otherIndex)1460 void RenderSwiper::UpdateItemOpacity(uint8_t opacity, int32_t index, int32_t otherIndex)
1461 {
1462     UpdateOneItemOpacity(opacity, index);
1463 
1464     int32_t preIndex = GetPrevIndex(index);
1465     if (preIndex != index && preIndex != otherIndex) {
1466         UpdateOneItemOpacity(opacity, preIndex);
1467     }
1468     int32_t nextIndex = GetNextIndex(index);
1469     if (nextIndex != index && nextIndex != otherIndex) {
1470         UpdateOneItemOpacity(opacity, nextIndex);
1471     }
1472 }
1473 
UpdateOneItemOpacity(uint8_t opacity,int32_t index)1474 void RenderSwiper::UpdateOneItemOpacity(uint8_t opacity, int32_t index)
1475 {
1476     if (!animationOpacity_) {
1477         return;
1478     }
1479     auto iter = items_.find(index);
1480     if (iter == items_.end()) {
1481         return;
1482     }
1483     auto display = AceType::DynamicCast<RenderDisplay>(iter->second);
1484     if (!display) {
1485         return;
1486     }
1487     display->UpdateOpacity(opacity);
1488 }
1489 
UpdateItemPosition(double offset,int32_t index,int32_t otherIndex)1490 void RenderSwiper::UpdateItemPosition(double offset, int32_t index, int32_t otherIndex)
1491 {
1492     auto iter = items_.find(index);
1493     if (iter != items_.end()) {
1494         iter->second->SetPosition(GetMainAxisOffset(offset));
1495     }
1496     int32_t prevIndex = GetPrevIndex(index);
1497     if (prevIndex != index && prevIndex != otherIndex) {
1498         auto item = items_.find(prevIndex);
1499         if (item != items_.end()) {
1500             item->second->SetPosition(GetMainAxisOffset(offset + (needReverse_ ? nextItemOffset_ : prevItemOffset_)));
1501         }
1502     }
1503     int32_t nextIndex = GetNextIndex(index);
1504     if (nextIndex != index && nextIndex != otherIndex) {
1505         auto item = items_.find(nextIndex);
1506         if (item != items_.end()) {
1507             item->second->SetPosition(GetMainAxisOffset(offset + (needReverse_ ? prevItemOffset_ : nextItemOffset_)));
1508         }
1509     }
1510     MarkNeedRender();
1511 }
1512 
GetPrevIndex() const1513 int32_t RenderSwiper::GetPrevIndex() const
1514 {
1515     return GetPrevIndex(currentIndex_);
1516 }
1517 
GetPrevIndexOnAnimation() const1518 int32_t RenderSwiper::GetPrevIndexOnAnimation() const
1519 {
1520     return GetPrevIndex(targetIndex_);
1521 }
1522 
GetPrevIndex(int32_t index) const1523 int32_t RenderSwiper::GetPrevIndex(int32_t index) const
1524 {
1525     return GetIndex(index, !needReverse_);
1526 }
1527 
GetNextIndex() const1528 int32_t RenderSwiper::GetNextIndex() const
1529 {
1530     return GetNextIndex(currentIndex_);
1531 }
1532 
GetNextIndexOnAnimation() const1533 int32_t RenderSwiper::GetNextIndexOnAnimation() const
1534 {
1535     return GetNextIndex(targetIndex_);
1536 }
1537 
GetNextIndex(int32_t index) const1538 int32_t RenderSwiper::GetNextIndex(int32_t index) const
1539 {
1540     return GetIndex(index, needReverse_);
1541 }
1542 
GetIndex(int32_t index,bool leftOrTop) const1543 int32_t RenderSwiper::GetIndex(int32_t index, bool leftOrTop) const
1544 {
1545     if (leftOrTop) {
1546         if (--index < 0) {
1547             index = loop_ ? itemCount_ - 1 : 0;
1548         }
1549     } else {
1550         if (++index >= itemCount_) {
1551             index = loop_ ? 0 : itemCount_ - 1;
1552         }
1553     }
1554     return index;
1555 }
1556 
ShowPrevious()1557 void RenderSwiper::ShowPrevious()
1558 {
1559     int32_t index = 0;
1560     if (isIndicatorAnimationStart_) {
1561         if (needReverse_) {
1562             index = GetNextIndexOnAnimation();
1563         } else {
1564             index = GetPrevIndexOnAnimation();
1565         }
1566         RedoSwipeToAnimation(index, false);
1567     } else {
1568         if (needReverse_) {
1569             index = GetNextIndex();
1570         } else {
1571             index = GetPrevIndex();
1572         }
1573 
1574         StopIndicatorSpringAnimation();
1575         DoSwipeToAnimation(currentIndex_, index, false);
1576     }
1577 }
1578 
ShowNext()1579 void RenderSwiper::ShowNext()
1580 {
1581     int32_t index = 0;
1582     if (isIndicatorAnimationStart_) {
1583         if (needReverse_) {
1584             index = GetPrevIndexOnAnimation();
1585         } else {
1586             index = GetNextIndexOnAnimation();
1587         }
1588         RedoSwipeToAnimation(index, false);
1589     } else {
1590         if (needReverse_) {
1591             index = GetPrevIndex();
1592         } else {
1593             index = GetNextIndex();
1594         }
1595         StopIndicatorSpringAnimation();
1596         DoSwipeToAnimation(currentIndex_, index, false);
1597     }
1598 }
1599 
OnFocus()1600 void RenderSwiper::OnFocus()
1601 {
1602     if (autoPlay_) {
1603         LOGD("stop autoplay cause by on focus");
1604         if (scheduler_) {
1605             scheduler_->Stop();
1606         }
1607         StopSwipeAnimation();
1608         StopSwipeToAnimation();
1609         StopIndicatorAnimation();
1610         StopIndicatorSpringAnimation();
1611         ResetIndicatorPosition();
1612     }
1613 }
1614 
OnBlur()1615 void RenderSwiper::OnBlur()
1616 {
1617     RestoreAutoPlay();
1618 }
1619 
RegisterChangeEndListener(int32_t listenerId,const SwiperChangeEndListener & listener)1620 void RenderSwiper::RegisterChangeEndListener(int32_t listenerId, const SwiperChangeEndListener& listener)
1621 {
1622     if (listener) {
1623         changeEndListeners_[listenerId] = listener;
1624     }
1625 }
1626 
UnRegisterChangeEndListener(int32_t listenerId)1627 void RenderSwiper::UnRegisterChangeEndListener(int32_t listenerId)
1628 {
1629     changeEndListeners_.erase(listenerId);
1630 }
1631 
UpdateScrollPosition(double dragDelta)1632 void RenderSwiper::UpdateScrollPosition(double dragDelta)
1633 {
1634     auto limitDelta = std::clamp(dragDelta, -MAX_VIEW_PORT_WIDTH, MAX_VIEW_PORT_WIDTH);
1635     double newDragOffset = scrollOffset_ + limitDelta;
1636     int32_t toIndex = newDragOffset > 0 ? GetPrevIndex() : GetNextIndex();
1637     if (toIndex < 0 || toIndex >= itemCount_) {
1638         LOGD("toIndex is error %{public}d", toIndex);
1639         return;
1640     }
1641     if (currentIndex_ == toIndex) {
1642         targetIndex_ = toIndex;
1643         nextIndex_ = toIndex;
1644         SetSwiperEffect(newDragOffset);
1645         return;
1646     }
1647 
1648     if (std::fabs(newDragOffset) >= std::fabs(nextItemOffset_)) {
1649         scrollOffset_ = (newDragOffset >= nextItemOffset_) ? newDragOffset - nextItemOffset_
1650                                                            : newDragOffset - prevItemOffset_;
1651         LoadLazyItems((currentIndex_ + 1) % itemCount_ == toIndex);
1652         outItemIndex_ = currentIndex_;
1653         currentIndex_ = toIndex;
1654         FireItemChangedEvent(true);
1655         ResetCachedChildren();
1656         UpdateOneItemOpacity(MAX_OPACITY, outItemIndex_);
1657         UpdateOneItemOpacity(MAX_OPACITY, currentIndex_);
1658         ExecuteMoveCallback(currentIndex_);
1659         ResetIndicatorPosition();
1660         MarkNeedLayout(true);
1661         // drag length is greater than swiper's width, don't need to move position
1662         LOGD("scroll to next page index[%{public}d] from index[%{public}d], scroll offset:%{public}lf",
1663             currentIndex_, outItemIndex_, scrollOffset_);
1664         return;
1665     }
1666 
1667     bool dragReverse = (newDragOffset * scrollOffset_) < 0.0;
1668     if (dragReverse) {
1669         int32_t lastToIndex = 0;
1670         double toItemPosValue = 0.0;
1671         lastToIndex = scrollOffset_ > 0 ? GetPrevIndex() : GetNextIndex();
1672         toItemPosValue = scrollOffset_ > 0 ? prevItemOffset_ : nextItemOffset_;
1673 
1674         auto iter = items_.find(lastToIndex);
1675         if (iter != items_.end()) {
1676             iter->second->SetPosition(GetMainAxisOffset(toItemPosValue));
1677         }
1678     }
1679 
1680     UpdateChildPosition(newDragOffset, currentIndex_);
1681     MoveIndicator(toIndex, newDragOffset);
1682 }
1683 
SetSwiperEffect(double dragOffset)1684 void RenderSwiper::SetSwiperEffect(double dragOffset)
1685 {
1686     EdgeEffect edgeEffect = swiper_->GetEdgeEffect();
1687     bool isFade = edgeEffect == EdgeEffect::FADE;
1688     bool isSpring = edgeEffect == EdgeEffect::SPRING;
1689     if (!isFade && !isSpring && !loop_) {
1690         return;
1691     }
1692 
1693     if ((isFade && currentIndex_ == 0 && GreatOrEqual(dragOffset, 0.0)) ||
1694         (isFade && (currentIndex_ == itemCount_ - 1) && LessOrEqual(dragOffset, 0.0))) {
1695         isPaintedFade_ = true;
1696         scrollOffset_ = dragOffset;
1697         dragDelta_ = dragOffset;
1698         MarkNeedRender();
1699     } else if (isSpring) {
1700         isPaintedFade_ = false;
1701         UpdateChildPosition(dragOffset, currentIndex_);
1702     }
1703 }
1704 
UpdateChildPosition(double offset,int32_t fromIndex,bool inLayout)1705 void RenderSwiper::UpdateChildPosition(double offset, int32_t fromIndex, bool inLayout)
1706 {
1707     if (itemCount_ <= 0) {
1708         LOGD("No child in swiper. return.");
1709         return;
1710     }
1711     if (std::abs(currentIndex_ - fromIndex) == 1) {
1712         scrollOffset_ = offset + (currentIndex_ - fromIndex) * nextItemOffset_;
1713     } else { // for loop reversal
1714         if (fromIndex > currentIndex_) {
1715             scrollOffset_ = offset + nextItemOffset_;
1716         } else if (fromIndex < currentIndex_) {
1717             scrollOffset_ = offset - nextItemOffset_;
1718         } else {
1719             scrollOffset_ = offset;
1720         }
1721     }
1722     // move current item
1723     auto item = items_.find(fromIndex);
1724     if (item != items_.end() && !(RefuseUpdatePosition(fromIndex) && inLayout)) {
1725         item->second->SetPosition(GetMainAxisOffset(offset));
1726     }
1727 
1728     // calculate the num of prev item
1729     int32_t prevItemCount = 0;
1730     if (!loop_) {
1731         prevItemCount = needReverse_ ? (itemCount_ - 1 - fromIndex) : fromIndex;
1732     } else {
1733         prevItemCount = (offset + prevMargin_ + std::fabs(prevItemOffset_) - 1) / std::fabs(prevItemOffset_);
1734     }
1735     if (prevItemCount >= itemCount_ - 1) {
1736         prevItemCount = itemCount_ - 1;
1737     }
1738 
1739     // move prev item
1740     int32_t prevIndex = fromIndex;
1741     for (int32_t i = 0; i < prevItemCount; i++) {
1742         prevIndex = GetPrevIndex(prevIndex);
1743         if ((RefuseUpdatePosition(prevIndex) && inLayout) || (prevIndex == fromIndex)) {
1744             continue;
1745         }
1746         auto item = items_.find(prevIndex);
1747         if (item != items_.end()) {
1748             item->second->SetPosition(
1749                 GetMainAxisOffset(offset + (needReverse_ ? (i + 1) * nextItemOffset_ : (i + 1) * prevItemOffset_)));
1750         }
1751     }
1752 
1753     // calculate the num of next item
1754     int32_t maxNextItemCount = itemCount_ - 1 - prevItemCount;
1755     int32_t nextItemCount = 0;
1756     if (inLayout) {
1757         nextItemCount = maxNextItemCount;
1758     } else {
1759         double maxLength = (axis_ == Axis::HORIZONTAL ? GetLayoutSize().Width() : GetLayoutSize().Height());
1760 
1761         nextItemCount =
1762             (maxLength - offset - prevMargin_ + std::fabs(prevItemOffset_) - 1) / std::fabs(prevItemOffset_);
1763         if (nextItemCount > maxNextItemCount) {
1764             nextItemCount = maxNextItemCount;
1765         }
1766     }
1767 
1768     // move next item
1769     int32_t nextIndex = fromIndex;
1770     for (int32_t i = 0; i < nextItemCount; i++) {
1771         nextIndex = GetNextIndex(nextIndex);
1772         if ((RefuseUpdatePosition(nextIndex) && inLayout) || (nextIndex == fromIndex)) {
1773             continue;
1774         }
1775         auto item = items_.find(nextIndex);
1776         if (item != items_.end()) {
1777             item->second->SetPosition(
1778                 GetMainAxisOffset(offset + (needReverse_ ? (i + 1) * prevItemOffset_ : (i + 1) * nextItemOffset_)));
1779         }
1780     }
1781 
1782     MarkNeedRender();
1783 }
1784 
Tick(uint64_t duration)1785 void RenderSwiper::Tick(uint64_t duration)
1786 {
1787     elapsedTime_ += duration;
1788     if (elapsedTime_ >= autoPlayInterval_) {
1789         if (currentIndex_ >= itemCount_ - 1 && !loop_) {
1790             LOGD("already last one, stop auto play because not loop");
1791             if (scheduler_) {
1792                 scheduler_->Stop();
1793             }
1794         } else {
1795             if (swiperIndicatorData_.isPressed) {
1796                 // end drag operations on autoplay.
1797                 DragIndicatorEnd();
1798             }
1799             if (swiperIndicatorData_.isHovered) {
1800                 ResetHoverZoomDot();
1801                 StartZoomOutAnimation(true);
1802             }
1803             int32_t nextIndex = 0;
1804             if (needReverse_) {
1805                 nextIndex = GetPrevIndex();
1806             } else {
1807                 nextIndex = GetNextIndex();
1808             }
1809             StartIndicatorAnimation(currentIndex_, nextIndex, currentIndex_ > nextIndex);
1810         }
1811         elapsedTime_ = 0;
1812     }
1813 }
1814 
OnHiddenChanged(bool hidden)1815 void RenderSwiper::OnHiddenChanged(bool hidden)
1816 {
1817     if (hidden) {
1818         if (autoPlay_) {
1819             LOGD("stop autoplay cause by hidden");
1820             if (scheduler_) {
1821                 scheduler_->Stop();
1822             }
1823             StopSwipeAnimation();
1824         }
1825     } else {
1826         RestoreAutoPlay();
1827     }
1828 }
1829 
OnRotation(const RotationEvent & event)1830 bool RenderSwiper::OnRotation(const RotationEvent& event)
1831 {
1832     if (disableRotation_) {
1833         return false;
1834     }
1835     if (itemCount_ < LEAST_SLIDE_ITEM_COUNT) {
1836         LOGI("Rotation is not enabled when count is 1");
1837         return false;
1838     }
1839     // Clockwise rotation switches to the next one, counterclockwise rotation switches to the previous one.
1840     auto context = GetContext().Upgrade();
1841     if (!context) {
1842         LOGE("context is null!");
1843         return false;
1844     }
1845     double deltaPx = context->NormalizeToPx(Dimension(event.value, DimensionUnit::VP)) * ROTATION_SENSITIVITY_NORMAL;
1846     switch (rotationStatus_) {
1847         case RotationStatus::ROTATION_START:
1848         case RotationStatus::ROTATION_UPDATE:
1849             rotationStatus_ = RotationStatus::ROTATION_UPDATE;
1850             HandleRotationUpdate(deltaPx);
1851             break;
1852         case RotationStatus::ROTATION_END:
1853         default:
1854             rotationStatus_ = RotationStatus::ROTATION_START;
1855             HandleRotationStart();
1856     }
1857     ResetRotationEndListener();
1858     return true;
1859 }
1860 
OnStatusChanged(RenderStatus renderStatus)1861 void RenderSwiper::OnStatusChanged(RenderStatus renderStatus)
1862 {
1863     if (renderStatus == RenderStatus::FOCUS) {
1864         onFocus_ = true;
1865     } else if (renderStatus == RenderStatus::BLUR) {
1866         onFocus_ = false;
1867     }
1868 }
1869 
GetValidEdgeLength(double swiperLength,double indicatorLength,const Dimension & edge) const1870 double RenderSwiper::GetValidEdgeLength(double swiperLength, double indicatorLength, const Dimension& edge) const
1871 {
1872     double edgeLength = edge.Unit() == DimensionUnit::PERCENT ? swiperLength * edge.Value() : NormalizeToPx(edge);
1873     if (!NearZero(edgeLength) && edgeLength > swiperLength - indicatorLength) {
1874         edgeLength = swiperLength - indicatorLength;
1875     }
1876     if (edgeLength < 0.0) {
1877         edgeLength = 0.0;
1878     }
1879     return edgeLength;
1880 }
1881 
GetIndicatorCurrentRect(SwiperIndicatorData & indicatorData)1882 void RenderSwiper::GetIndicatorCurrentRect(SwiperIndicatorData& indicatorData)
1883 {
1884     if (!indicator_) {
1885         indicatorRect_ = Rect();
1886         return;
1887     }
1888     Offset offset = indicatorPosition_ + GetGlobalOffset();
1889     Size size = Size(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
1890     indicatorRect_ = Rect(offset, size);
1891 }
1892 
GetIndicatorWidth(SwiperIndicatorData & indicatorData)1893 double RenderSwiper::GetIndicatorWidth(SwiperIndicatorData& indicatorData)
1894 {
1895     double indicatorWidth = 0.0;
1896     double lastItemEdge = 0.0;
1897 
1898     if (currentHoverIndex_ == itemCount_ - 1) {
1899         double deltaPadding = 0.0;
1900         if (axis_ == Axis::HORIZONTAL) {
1901             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetX() +
1902                            NormalizeToPx(indicator_->GetPressSize()) / 2;
1903         } else {
1904             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetY() +
1905                            NormalizeToPx(indicator_->GetPressSize()) / 2;
1906         }
1907         if (currentIndex_ == itemCount_ - 1) {
1908             deltaPadding = NormalizeToPx(indicator_->GetPressSize()) / 2;
1909         }
1910         indicatorWidth = lastItemEdge + indicatorData.startEndPadding + deltaPadding;
1911     } else {
1912         if (axis_ == Axis::HORIZONTAL) {
1913             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetX() +
1914                            indicatorData.indicatorItemData[itemCount_ - 1].width / 2;
1915         } else {
1916             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetY() +
1917                            indicatorData.indicatorItemData[itemCount_ - 1].height / 2;
1918         }
1919         indicatorWidth = lastItemEdge + indicatorData.startEndPadding;
1920     }
1921     return indicatorWidth;
1922 }
1923 
LayoutIndicator(SwiperIndicatorData & indicatorData)1924 void RenderSwiper::LayoutIndicator(SwiperIndicatorData& indicatorData)
1925 {
1926     if (!indicator_) {
1927         return;
1928     }
1929 
1930     // calc real hot zone size by zoom and stretch
1931     if (NearZero(hotZoneMaxSize_) || NearZero(hotZoneMinSize_)) {
1932         hotZoneMaxSize_ = NormalizeToPx((indicator_->GetHotZoneSize()));
1933         hotZoneMinSize_ = hotZoneMaxSize_ / ZOOM_HOTZONE_MAX_RATE;
1934     }
1935     hotZoneRealSize_ = hotZoneMinSize_ + (hotZoneMaxSize_ - hotZoneMinSize_) * zoomValue_;
1936     hotZoneRealSize_ *= heightStretchRate_;
1937 
1938     // update indicator item paint data;
1939     indicatorData.isDigital = digitalIndicator_;
1940     if (!digitalIndicator_) {
1941         UpdateIndicatorItem(indicatorData);
1942     }
1943 
1944     // update Indicator paint data
1945     if (digitalIndicator_) {
1946         LayoutDigitalIndicator(indicatorData);
1947         Size digitalIndicatorSize = indicatorData.textBoxRender->GetLayoutSize();
1948         indicatorData.indicatorPaintData.width = digitalIndicatorSize.Width();
1949         indicatorData.indicatorPaintData.height = digitalIndicatorSize.Height();
1950     } else {
1951         if (axis_ == Axis::HORIZONTAL) {
1952             indicatorData.indicatorPaintData.width = GetIndicatorWidth(indicatorData);
1953             indicatorData.indicatorPaintData.height = hotZoneRealSize_; // influenced on zoom and stretch
1954         } else {
1955             indicatorData.indicatorPaintData.width = hotZoneRealSize_; // influenced on zoom and stretch
1956             indicatorData.indicatorPaintData.height = GetIndicatorWidth(indicatorData);
1957         }
1958     }
1959     indicatorData.indicatorPaintData.radius = hotZoneRealSize_ / 2; // influenced on zoom and stretch
1960     if (!digitalIndicator_ && (indicatorData.isHovered || indicatorData.isPressed)) {
1961         indicatorData.indicatorPaintData.color = indicator_->GetHotZoneColor();
1962     } else {
1963         indicatorData.indicatorPaintData.color = Color::WHITE;
1964     }
1965 
1966     // update position
1967     UpdateIndicatorPosition(indicatorData);
1968 }
1969 
InitDigitalIndicator(SwiperIndicatorData & indicatorData)1970 void RenderSwiper::InitDigitalIndicator(SwiperIndicatorData& indicatorData)
1971 {
1972     auto textBoxComponent = AceType::MakeRefPtr<BoxComponent>();
1973     double padding = NormalizeToPx(INDICATOR_DIGITAL_PADDING);
1974     Edge margin = (axis_ == Axis::HORIZONTAL) ?
1975                   Edge(padding, 0, padding, 0, DimensionUnit::PX) :
1976                   Edge(0, padding, 0, padding, DimensionUnit::PX);
1977     textBoxComponent->SetPadding(margin);
1978     indicatorData.textBoxRender = AceType::DynamicCast<RenderBox>(textBoxComponent->CreateRenderNode());
1979     indicatorData.textBoxRender->Attach(GetContext());
1980 
1981     // add flex
1982     FlexDirection direction = axis_ == Axis::HORIZONTAL ? FlexDirection::ROW : FlexDirection::COLUMN;
1983     indicatorData.flexComponent = AceType::MakeRefPtr<FlexComponent>(direction,
1984         FlexAlign::FLEX_END, FlexAlign::CENTER, std::list<RefPtr<Component>>());
1985     indicatorData.flexComponent->SetMainAxisSize(MainAxisSize::MIN);
1986     indicatorData.flexRender = AceType::DynamicCast<RenderFlex>(indicatorData.flexComponent->CreateRenderNode());
1987     indicatorData.textBoxRender->AddChild(indicatorData.flexRender);
1988     indicatorData.flexRender->Attach(GetContext());
1989     indicatorData.flexRender->Update(indicatorData.flexComponent);
1990 
1991     // add text
1992     indicatorData.textComponentPrev = AceType::MakeRefPtr<TextComponent>("");
1993     indicatorData.textRenderPrev = AceType::DynamicCast<RenderText>(
1994         indicatorData.textComponentPrev->CreateRenderNode());
1995     indicatorData.flexRender->AddChild(indicatorData.textRenderPrev);
1996     indicatorData.textRenderPrev->Attach(GetContext());
1997     indicatorData.textRenderPrev->Update(indicatorData.textComponentPrev);
1998 
1999     indicatorData.textComponentNext = AceType::MakeRefPtr<TextComponent>("");
2000     indicatorData.textRenderNext = AceType::DynamicCast<RenderText>(
2001         indicatorData.textComponentNext->CreateRenderNode());
2002     indicatorData.flexRender->AddChild(indicatorData.textRenderNext);
2003     indicatorData.textRenderNext->Attach(GetContext());
2004     indicatorData.textRenderNext->Update(indicatorData.textComponentNext);
2005 
2006     indicatorData.textBoxRender->Update(textBoxComponent);
2007 }
2008 
LayoutDigitalIndicator(SwiperIndicatorData & indicatorData)2009 void RenderSwiper::LayoutDigitalIndicator(SwiperIndicatorData& indicatorData)
2010 {
2011     InitDigitalIndicator(indicatorData);
2012 
2013     auto textStyle = indicator_->GetDigitalIndicatorTextStyle();
2014     Color normalTextColor = textStyle.GetTextColor();
2015     // update text prev
2016     std::string indicatorTextPrev = std::to_string(currentIndex_ + 1);
2017     if (indicatorIsFocus_) {
2018         textStyle.SetTextColor(indicator_->GetIndicatorTextFocusColor());
2019     } else {
2020         textStyle.SetTextColor(normalTextColor);
2021     }
2022     indicatorData.textComponentPrev->SetTextStyle(textStyle);
2023     indicatorData.textComponentPrev->SetData(indicatorTextPrev);
2024     indicatorData.textRenderPrev->Update(indicatorData.textComponentPrev);
2025 
2026     // update text next
2027     std::string indicatorTextNext = (axis_ == Axis::HORIZONTAL) ? std::string("/").append(std::to_string(itemCount_))
2028         : std::string("/\n").append(std::to_string(itemCount_));
2029     textStyle.SetTextColor(normalTextColor);
2030     indicatorData.textComponentNext->SetTextStyle(textStyle);
2031     indicatorData.textComponentNext->SetData(indicatorTextNext);
2032     indicatorData.textRenderNext->Update(indicatorData.textComponentNext);
2033 
2034     // update text box
2035     auto decoration = AceType::MakeRefPtr<Decoration>();
2036     decoration->SetBackgroundColor(Color::TRANSPARENT);
2037     Border border;
2038     border.SetBorderRadius(Radius(indicator_->GetHotZoneSize() / 2.0));
2039     decoration->SetBorder(border);
2040     indicatorData.textBoxRender->SetBackDecoration(decoration);
2041     if (axis_ == Axis::HORIZONTAL) {
2042         indicatorData.textBoxRender->SetHeight(NormalizeToPx(indicator_->GetHotZoneSize()));
2043     } else {
2044         indicatorData.textBoxRender->SetWidth(NormalizeToPx(indicator_->GetHotZoneSize()));
2045     }
2046 
2047     LayoutParam innerLayout;
2048     innerLayout.SetMaxSize(Size(swiperWidth_, swiperHeight_));
2049     indicatorData.textBoxRender->Layout(innerLayout);
2050 }
2051 
UpdateIndicatorPosition(SwiperIndicatorData & indicatorData)2052 void RenderSwiper::UpdateIndicatorPosition(SwiperIndicatorData& indicatorData)
2053 {
2054     Offset position;
2055     double indicatorWidth = indicatorData.indicatorPaintData.width;
2056     double indicatorHeight = indicatorData.indicatorPaintData.height;
2057     double stableOffset = NormalizeToPx(INDICATOR_PADDING_TOP_DEFAULT) + (hotZoneMaxSize_ + hotZoneRealSize_) * 0.5;
2058     auto layoutSize = GetLayoutSize();
2059 
2060     if (indicator_->GetLeft().Value() != SwiperIndicator::DEFAULT_POSITION) {
2061         int32_t left = GetValidEdgeLength(swiperWidth_, indicatorWidth, indicator_->GetLeft());
2062         swiperLeft_ = indicator_->GetLeft();
2063         position.SetX(left);
2064     } else if (indicator_->GetRight().Value() != SwiperIndicator::DEFAULT_POSITION) {
2065         int32_t right = GetValidEdgeLength(swiperWidth_, indicatorWidth, indicator_->GetRight());
2066         swiperRight_ = indicator_->GetRight();
2067         position.SetX(swiperWidth_ - indicatorWidth - right);
2068     } else {
2069         if (axis_ == Axis::HORIZONTAL) {
2070             position.SetX((layoutSize.Width() - indicatorWidth) / 2.0);
2071         } else {
2072             // horizontal line of indicator zone is stable.
2073             double currentX = swiperWidth_ - stableOffset;
2074             position.SetX(currentX);
2075         }
2076     }
2077 
2078     if (indicator_->GetTop().Value() != SwiperIndicator::DEFAULT_POSITION) {
2079         int32_t top = GetValidEdgeLength(swiperHeight_, indicatorHeight, indicator_->GetTop());
2080         swiperTop_ = indicator_->GetTop();
2081         position.SetY(top);
2082     } else if (indicator_->GetBottom().Value() != SwiperIndicator::DEFAULT_POSITION) {
2083         int32_t bottom = GetValidEdgeLength(swiperHeight_, indicatorHeight, indicator_->GetBottom());
2084         swiperBottom_ = indicator_->GetBottom();
2085         position.SetY(swiperHeight_ - indicatorHeight - bottom);
2086     } else {
2087         if (axis_ == Axis::HORIZONTAL) {
2088             // horizontal line of indicator zone is stable.
2089             double currentY = swiperHeight_ - stableOffset;
2090             position.SetY(currentY);
2091         } else {
2092             position.SetY((layoutSize.Height() - indicatorHeight) / 2.0);
2093         }
2094     }
2095 
2096     // update position on stretch or retract indicator zone
2097     UpdatePositionOnStretch(position, indicatorData);
2098 
2099     // update  position
2100     indicatorPosition_ = position;
2101     indicatorData.indicatorPaintData.position = position;
2102     indicatorData.indicatorPaintData.center = position + Offset(indicatorData.indicatorPaintData.width / 2,
2103         indicatorData.indicatorPaintData.height / 2);
2104 }
2105 
UpdateIndicatorItem(SwiperIndicatorData & indicatorData)2106 void RenderSwiper::UpdateIndicatorItem(SwiperIndicatorData& indicatorData)
2107 {
2108     // horizontal line of indicator zone is stable
2109     double hotZoneCenterPadding = hotZoneRealSize_ / 2.0;
2110     if (indicatorData.isHovered || indicatorData.isPressed) {
2111         indicatorData.startEndPadding = NormalizeToPx(indicator_->GetStartEndPadding() +
2112             (indicator_->GetPressPadding() - indicator_->GetStartEndPadding()) * zoomValue_);
2113     } else {
2114         indicatorData.startEndPadding = NormalizeToPx(indicator_->GetStartEndPadding());
2115     }
2116     Offset startCenterOffset = axis_ == Axis::HORIZONTAL ? Offset(indicatorData.startEndPadding, hotZoneCenterPadding) :
2117         Offset(hotZoneCenterPadding, indicatorData.startEndPadding);
2118     Offset centerOffset = startCenterOffset;
2119 
2120     double targetIndex = currentIndex_;
2121     double hoverIndex = currentHoverIndex_;
2122     if (needReverse_) {
2123         targetIndex = itemCount_ - currentIndex_ - 1;
2124     }
2125 
2126     double itemRadius = 0.0;
2127     for (int32_t i = 0; i < itemCount_; ++i) {
2128         swiperSize_ = indicator_->GetSize();
2129         bool isZoomInBackground = indicatorData.isHovered || indicatorData.isPressed;
2130         if (isZoomInBackground) {
2131             // indicator radius and point padding is dynamic changed on zoom and stretch
2132             itemRadius = NormalizeToPx(
2133                 indicator_->GetSize() + (indicator_->GetPressSize() - indicator_->GetSize()) * zoomValue_) / 2.0;
2134             indicatorData.pointPadding = NormalizeToPx(indicator_->GetIndicatorPointPadding() +
2135                 (indicator_->GetPressPointPadding() - indicator_->GetIndicatorPointPadding()) *
2136                 zoomValue_) * widthStretchRate_;
2137         } else {
2138             itemRadius = NormalizeToPx(indicator_->GetSize()) / 2.0;
2139             indicatorData.pointPadding = NormalizeToPx(indicator_->GetIndicatorPointPadding());
2140         }
2141 
2142         double itemStartEndPadding = 0.0;
2143         if (i == targetIndex) {
2144             itemStartEndPadding = itemRadius * 2;
2145             indicatorData.indicatorItemData[i].color = indicator_->GetSelectedColor();
2146             selectedColors_ = indicator_->GetSelectedColor();
2147         } else {
2148             itemStartEndPadding = itemRadius;
2149             indicatorData.indicatorItemData[i].color = indicator_->GetColor();
2150             colors_ = indicator_->GetColor();
2151         }
2152         Offset paddingStartOffset;
2153         Offset paddingEndOffset;
2154         if (axis_ == Axis::HORIZONTAL) {
2155             paddingStartOffset = Offset(itemStartEndPadding, 0);
2156             paddingEndOffset = Offset(itemStartEndPadding + indicatorData.pointPadding, 0);
2157         } else {
2158             paddingStartOffset = Offset(0, itemStartEndPadding);
2159             paddingEndOffset = Offset(0, itemStartEndPadding + indicatorData.pointPadding);
2160         }
2161 
2162         // update mouse hover radius
2163         if (isZoomInBackground && i == hoverIndex) {
2164             // point radius is dynamic changed on mouse hover
2165             itemRadius = NormalizeToPx(indicator_->GetPressSize() +
2166                                        (indicator_->GetHoverSize() - indicator_->GetPressSize()) * zoomDotValue_) / 2.0;
2167         }
2168         if (axis_ == Axis::HORIZONTAL) {
2169             indicatorData.indicatorItemData[i].height = itemRadius * SIZE_RATIO_NORMAL;
2170             indicatorData.indicatorItemData[i].width =
2171                 (i == targetIndex ? itemRadius * SIZE_RATIO_LARGE : itemRadius * SIZE_RATIO_NORMAL);
2172         } else {
2173             indicatorData.indicatorItemData[i].width = itemRadius * SIZE_RATIO_NORMAL;
2174             indicatorData.indicatorItemData[i].height =
2175                 (i == targetIndex ? itemRadius * SIZE_RATIO_LARGE : itemRadius * SIZE_RATIO_NORMAL);
2176         }
2177         indicatorData.indicatorItemData[i].radius = itemRadius;
2178 
2179         centerOffset += paddingStartOffset;
2180         indicatorData.indicatorItemData[i].center = centerOffset;
2181         indicatorData.indicatorItemData[i].position = centerOffset -
2182             Offset(indicatorData.indicatorItemData[i].width / SIZE_RATIO_NORMAL,
2183                 indicatorData.indicatorItemData[i].height / SIZE_RATIO_NORMAL);
2184         centerOffset += paddingEndOffset;
2185     }
2186 }
2187 
UpdatePositionOnStretch(Offset & position,const SwiperIndicatorData & indicatorData)2188 void RenderSwiper::UpdatePositionOnStretch(Offset& position, const SwiperIndicatorData& indicatorData)
2189 {
2190     double indicatorWidth = indicatorData.indicatorPaintData.width;
2191     double indicatorHeight = indicatorData.indicatorPaintData.height;
2192     if (widthStretchRate_ > DRAG_STRETCH_BASE_WIDTH) {
2193         if (zoomValue_ == ZOOM_MAX) {
2194             // stretch indicator and update start position
2195             if (axis_ == Axis::HORIZONTAL) {
2196                 auto currentIndex = needReverse_ ? (itemCount_ - currentIndex_ - 1) : currentIndex_;
2197                 if (currentIndex == itemCount_ - 1) {
2198                     position.SetX(indicatorZoomMaxPositionLT_.GetX());
2199                 } else if (currentIndex == 0) {
2200                     position.SetX(indicatorZoomMaxPositionRB_.GetX() - indicatorData.indicatorPaintData.width);
2201                 }
2202             } else {
2203                 if (currentIndex_ == itemCount_ - 1) {
2204                     position.SetY(indicatorZoomMaxPositionLT_.GetY());
2205                 } else if (currentIndex_ == 0) {
2206                     position.SetY(indicatorZoomMaxPositionRB_.GetY() - indicatorData.indicatorPaintData.height);
2207                 }
2208             }
2209         } else if (zoomValue_ > ZOOM_MIN) {
2210             // restract indicator and update start position
2211             if (axis_ == Axis::HORIZONTAL) {
2212                 auto currentIndex = needReverse_ ? (itemCount_ - currentIndex_ - 1) : currentIndex_;
2213                 if (currentIndex == itemCount_ - 1) {
2214                     position.SetX(indicatorZoomMinPositionLT_.GetX() -
2215                         (indicatorZoomMinPositionLT_.GetX() - indicatorZoomMaxPositionLT_.GetX()) * zoomValue_);
2216                 } else if (currentIndex == 0) {
2217                     position.SetX(indicatorZoomMinPositionRB_.GetX() - indicatorWidth +
2218                         (indicatorZoomMaxPositionRB_.GetX() - indicatorZoomMinPositionRB_.GetX()) * zoomValue_);
2219                 }
2220             } else {
2221                 if (currentIndex_ == itemCount_ - 1) {
2222                     position.SetY(indicatorZoomMinPositionLT_.GetY() -
2223                         (indicatorZoomMinPositionLT_.GetY() - indicatorZoomMaxPositionLT_.GetY()) * zoomValue_);
2224                 } else if (currentIndex_ == 0) {
2225                     position.SetY(indicatorZoomMinPositionRB_.GetY() - indicatorHeight +
2226                         (indicatorZoomMaxPositionRB_.GetY() - indicatorZoomMinPositionRB_.GetY()) * zoomValue_);
2227                 }
2228             }
2229         }
2230     }
2231 }
2232 
IndicatorSwipePrev()2233 void RenderSwiper::IndicatorSwipePrev()
2234 {
2235     auto toIndex = GetPrevIndex();
2236     StartIndicatorAnimation(currentIndex_, toIndex, currentIndex_ == 0);
2237 }
2238 
IndicatorSwipeNext()2239 void RenderSwiper::IndicatorSwipeNext()
2240 {
2241     auto toIndex = GetNextIndex();
2242     StartIndicatorAnimation(currentIndex_, toIndex, currentIndex_ == itemCount_ - 1);
2243 }
2244 
HandleMouseEvent(const MouseEvent & event)2245 bool RenderSwiper::HandleMouseEvent(const MouseEvent& event)
2246 {
2247     const Point point { event.x, event.y};
2248     MouseHoverTest(point);
2249     return false;
2250 }
2251 
MouseHoverTest(const Point & parentLocalPoint)2252 bool RenderSwiper::MouseHoverTest(const Point& parentLocalPoint)
2253 {
2254     auto context = context_.Upgrade();
2255     if (!context) {
2256         return false;
2257     }
2258     const auto localPoint = parentLocalPoint - GetPosition();
2259     const auto& children = GetChildren();
2260     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
2261         auto& child = *iter;
2262         child->MouseHoverTest(localPoint);
2263     }
2264     bool isInRegion = InTouchRectList(parentLocalPoint, GetTouchRectList());
2265     if (isInRegion) {
2266         context->AddToHoverList(AceType::WeakClaim(this).Upgrade());
2267     }
2268 
2269     // swiper indicator mouse hover
2270     if (!indicator_) {
2271         return isInRegion;
2272     }
2273     // indicator zone zoom animation should wait for indicator moving animation finished
2274     if (isIndicatorAnimationStart_) {
2275         return isInRegion;
2276     }
2277 
2278     // get absolute position
2279     Point hoverPoint = parentLocalPoint;
2280     GetIndicatorCurrentRect(swiperIndicatorData_);
2281     if (indicatorRect_.IsInRegion(hoverPoint)) {
2282         if (autoPlay_ && scheduler_ && scheduler_->IsActive()) {
2283             // forbid indicator operation on auto play period.
2284             return isInRegion;
2285         }
2286         if ((!swiperIndicatorData_.isHovered && !swiperIndicatorData_.isPressed) || !IsZoomOutAnimationStopped()) {
2287             // hover animation
2288             swiperIndicatorData_.isHovered = true;
2289             StartZoomInAnimation(true);
2290             return isInRegion;
2291         }
2292         // point zoom after indicator zone zoom.
2293         if (!IsZoomAnimationStopped()) {
2294             return isInRegion;
2295         }
2296         for (int32_t i = 0; i < itemCount_; i++) {
2297             Offset offset = swiperIndicatorData_.indicatorItemData[i].position + indicatorRect_.GetOffset();
2298             Size size = Size(swiperIndicatorData_.indicatorItemData[i].width,
2299                 swiperIndicatorData_.indicatorItemData[i].height);
2300             Rect itemRect = Rect(offset, size);
2301             if (itemRect.IsInRegion(hoverPoint)) {
2302                 if (currentHoverIndex_ != i) {
2303                     StartZoomInDotAnimation(i);
2304                 }
2305                 return isInRegion;
2306             }
2307         }
2308         if (currentHoverIndex_ != INDICATOR_INVALID_HOVER_INDEX && IsZoomOutDotAnimationStopped()) {
2309             StartZoomOutDotAnimation();
2310         }
2311     } else {
2312         if (swiperIndicatorData_.isHovered) {
2313             ResetHoverZoomDot();
2314             StartZoomOutAnimation(true);
2315         }
2316     }
2317     return isInRegion;
2318 }
2319 
IndicatorShowFocus(bool isFocus)2320 void RenderSwiper::IndicatorShowFocus(bool isFocus)
2321 {
2322     if (!indicator_) {
2323         return;
2324     }
2325     indicatorIsFocus_ = isFocus;
2326     auto context = context_.Upgrade();
2327     if (!context) {
2328         return;
2329     }
2330     Offset offset = swiperIndicatorData_.indicatorPaintData.position;
2331     Size size = Size(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
2332     Offset globalOffset = swiperIndicatorData_.indicatorPaintData.position + GetGlobalOffset();
2333     double radius = swiperIndicatorData_.indicatorPaintData.radius;
2334     if (isFocus) {
2335         offset += Offset(NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET), NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET));
2336         size -= Size(NormalizeToPx(INDICATOR_FOCUS_DEL_SIZE), NormalizeToPx(INDICATOR_FOCUS_DEL_SIZE));
2337         globalOffset += Offset(NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET), NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET));
2338         Radius focusRadius = Radius(radius) - Radius(NormalizeToPx(INDICATOR_FOCUS_RADIUS_DEL_SIZE));
2339         context->ShowFocusAnimation(RRect::MakeRRect(Rect(offset, size), focusRadius), Color(INDICATOR_FOCUS_COLOR),
2340             globalOffset);
2341     } else {
2342         context->CancelFocusAnimation();
2343     }
2344     MarkNeedLayout();
2345 }
2346 
UpdateIndicatorFocus(bool isFocus,bool reverse)2347 void RenderSwiper::UpdateIndicatorFocus(bool isFocus, bool reverse)
2348 {
2349     if (reverse) {
2350         IndicatorSwipePrev();
2351     } else {
2352         IndicatorSwipeNext();
2353     }
2354     IndicatorShowFocus(isFocus);
2355 }
2356 
VibrateIndicator()2357 void RenderSwiper::VibrateIndicator()
2358 {
2359     auto context = context_.Upgrade();
2360     if (!context) {
2361         LOGW("GetVibrator fail, context is null");
2362         return;
2363     }
2364 
2365     if (!vibrator_) {
2366         vibrator_ = VibratorProxy::GetInstance().GetVibrator(context->GetTaskExecutor());
2367     }
2368     if (vibrator_) {
2369         vibrator_->Vibrate(VIBRATE_DURATION);
2370     } else {
2371         LOGW("GetVibrator fail");
2372     }
2373 }
2374 
UpdateIndicatorSpringStatus(SpringStatus status)2375 void RenderSwiper::UpdateIndicatorSpringStatus(SpringStatus status)
2376 {
2377     if (indicatorSpringStatus_ == SpringStatus::SPRING_STOP &&
2378         status == SpringStatus::FOCUS_SWITCH) {
2379         return;
2380     }
2381     LOGD("UpdateIndicatorSpringStatus from[%{public}d] to[%{public}d]", indicatorSpringStatus_, status);
2382     indicatorSpringStatus_ = status;
2383 }
2384 
GetIndicatorSpringStatus() const2385 SpringStatus RenderSwiper::GetIndicatorSpringStatus() const
2386 {
2387     return indicatorSpringStatus_;
2388 }
2389 
ResetIndicatorSpringStatus()2390 void RenderSwiper::ResetIndicatorSpringStatus()
2391 {
2392     if (GetIndicatorSpringStatus() == SpringStatus::FOCUS_SWITCH) {
2393         UpdateIndicatorTailPosition(DRAG_OFFSET_MIN, DRAG_OFFSET_MIN);
2394     }
2395     UpdateIndicatorSpringStatus(SpringStatus::SPRING_STOP);
2396 }
2397 
ResetIndicatorPosition()2398 void RenderSwiper::ResetIndicatorPosition()
2399 {
2400     UpdateIndicatorHeadPosition(DRAG_OFFSET_MIN);
2401     UpdateIndicatorTailPosition(DRAG_OFFSET_MIN);
2402     UpdateIndicatorPointPosition(DRAG_OFFSET_MIN);
2403 }
2404 
ResetHoverZoomDot()2405 void RenderSwiper::ResetHoverZoomDot()
2406 {
2407     StopZoomDotAnimation();
2408     UpdateZoomDotValue(ZOOM_DOT_MIN);
2409     currentHoverIndex_ = INDICATOR_INVALID_HOVER_INDEX;
2410 }
2411 
MarkIndicatorPosition(bool isZoomMax)2412 void RenderSwiper::MarkIndicatorPosition(bool isZoomMax)
2413 {
2414     if (isZoomMax) {
2415         indicatorZoomMaxPositionLT_ = indicatorPosition_;
2416         indicatorZoomMaxPositionRB_ = indicatorZoomMaxPositionLT_ +
2417             Offset(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
2418     } else {
2419         indicatorZoomMinPositionLT_ = indicatorPosition_;
2420         indicatorZoomMinPositionRB_ = indicatorZoomMinPositionLT_ +
2421             Offset(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
2422     }
2423 }
2424 
StartIndicatorSpringAnimation(double start,double end)2425 void RenderSwiper::StartIndicatorSpringAnimation(double start, double end)
2426 {
2427     LOGD("StartIndicatorSpringAnimation(%{public}lf, %{public}lf)", start, end);
2428     if (!springController_) {
2429         return;
2430     }
2431     UpdateIndicatorSpringStatus(SpringStatus::SPRING_START);
2432     double dampInc = std::fabs(currentIndex_ - targetIndex_) * SPRING_DAMP_INC;
2433     auto springDescription = AceType::MakeRefPtr<SpringProperty>(SPRING_MASS, SPRING_STIFF, SPRING_DAMP + dampInc);
2434     if (!indicatorSpringMotion_) {
2435         indicatorSpringMotion_ = AceType::MakeRefPtr<SpringMotion>(start, end, 0.0, springDescription);
2436     } else {
2437         indicatorSpringMotion_->Reset(start, end, 0.0, springDescription);
2438     }
2439 
2440     indicatorSpringMotion_->ClearListeners();
2441     indicatorSpringMotion_->AddListener([weak = AceType::WeakClaim(this), end](double position) {
2442         auto swiper = weak.Upgrade();
2443         if (swiper) {
2444             double offset = position;
2445             double switchOffset = position - end;
2446             swiper->UpdateIndicatorTailPosition(offset, switchOffset);
2447         }
2448     });
2449 
2450     springController_->PlayMotion(indicatorSpringMotion_);
2451     springController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
2452         auto swiper = weak.Upgrade();
2453         if (swiper) {
2454             swiper->UpdateIndicatorSpringStatus(SpringStatus::SPRING_STOP);
2455             swiper->UpdateIndicatorTailPosition(DRAG_OFFSET_MIN);
2456         }
2457     });
2458 }
2459 
2460 // spring animation
StopIndicatorSpringAnimation()2461 void RenderSwiper::StopIndicatorSpringAnimation()
2462 {
2463     if (springController_ && !springController_->IsStopped()) {
2464         // clear stop listener before stop
2465         springController_->ClearStopListeners();
2466         springController_->Stop();
2467     }
2468     ResetIndicatorSpringStatus();
2469     LOGD("StopIndicatorSpringAnimation");
2470 }
2471 
CalMaxStretch()2472 void RenderSwiper::CalMaxStretch()
2473 {
2474     if (focusStretchMaxTime_ == DRAG_OFFSET_MIN) {
2475         double stretch = DRAG_OFFSET_MIN;
2476         double maxStretch = DRAG_OFFSET_MIN;
2477         const int32_t step = DRAG_CALC_STRETCH_STEP_INT;
2478         for (int32_t i = step; i <= DRAG_CALC_STRETCH_STEP_MAX; i += step) {
2479             double actualStep = i * DRAG_CALC_STRETCH_STEP / static_cast<double>(DRAG_CALC_STRETCH_STEP_INT);
2480             stretch = INDICATOR_FOCUS_HEAD->Move(actualStep) - INDICATOR_FOCUS_TAIL->Move(actualStep);
2481             if (stretch > maxStretch) {
2482                 maxStretch = stretch;
2483                 focusStretchMaxTime_ = actualStep;
2484             }
2485         }
2486         LOGD("CalMaxStretch(%{public}lf), time(%{public}lf)", maxStretch, focusStretchMaxTime_);
2487     }
2488 }
2489 
MoveIndicator(int32_t toIndex,double offset,bool isAuto)2490 void RenderSwiper::MoveIndicator(int32_t toIndex, double offset, bool isAuto)
2491 {
2492     if (toIndex == currentIndex_) {
2493         LOGW("MoveIndicator drop it for edge moving.");
2494         return;
2495     }
2496 
2497     double dragRange = ((axis_ == Axis::HORIZONTAL) ? swiperWidth_ : swiperHeight_) - prevMargin_ - nextMargin_;
2498     if (NearZero(dragRange)) {
2499         return;
2500     }
2501     double dragRate = offset / dragRange;
2502     animationDirect_ = (currentIndex_ <= toIndex) ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
2503     if (needReverse_) {
2504         animationDirect_ *= INDICATOR_DIRECT_BACKWARD;
2505     }
2506     dragRate = std::fabs(dragRate);
2507     if (dragRate >= DRAG_OFFSET_MAX) {
2508         // move to end, and index change
2509         UpdateIndicatorPointPosition(DRAG_OFFSET_MIN);
2510         UpdateIndicatorHeadPosition(DRAG_OFFSET_MIN);
2511         UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
2512         return;
2513     }
2514 
2515     targetIndex_ = toIndex;
2516     int32_t indicatorMoveNums = std::abs(currentIndex_ - toIndex);
2517     UpdateIndicatorPointPosition(INDICATOR_NORMAL_POINT->MoveInternal(dragRate));
2518     UpdateIndicatorHeadPosition(INDICATOR_FOCUS_HEAD->MoveInternal(dragRate) * indicatorMoveNums);
2519     if (!isAuto) {
2520         // move tails with hand
2521         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(dragRate) * indicatorMoveNums);
2522         return;
2523     }
2524 
2525     // animation
2526     if (dragRate < focusStretchMaxTime_) {
2527         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(dragRate) * indicatorMoveNums);
2528         return;
2529     }
2530 
2531     // curve sport into spring sport
2532     if (GetIndicatorSpringStatus() == SpringStatus::SPRING_STOP) {
2533         LOGD("indicator tail move end, start spring motion.");
2534         double springStart = INDICATOR_FOCUS_TAIL->MoveInternal(dragRate);
2535         UpdateIndicatorTailPosition(springStart * indicatorMoveNums);
2536         StartIndicatorSpringAnimation(springStart * indicatorMoveNums, DRAG_OFFSET_MAX * indicatorMoveNums);
2537     }
2538 }
2539 
DragIndicator(double offset)2540 void RenderSwiper::DragIndicator(double offset)
2541 {
2542     // start drag after zoom in completed.
2543     if (!IsZoomAnimationStopped()) {
2544         LOGD("zoom in is not completed");
2545         return;
2546     }
2547 
2548     const double longPressDragStart = DRAG_OFFSET_START_DP * scale_;
2549     const double longPressDragSwitchFocus = DRAG_OFFSET_SWITCH_DP * scale_;
2550     const double longPressDragMaxDiff = longPressDragSwitchFocus - longPressDragStart;
2551     if (!isDragStart_) {
2552         isDragStart_ = true;
2553         dragBaseOffset_ = offset;
2554         dragMoveOffset_ = offset;
2555         return;
2556     }
2557 
2558     dragMoveOffset_ += offset;
2559     double diffOffset = dragMoveOffset_ - dragBaseOffset_;
2560     double fabsOffset = std::fabs(diffOffset);
2561     if (fabsOffset <= longPressDragStart) {
2562         // indicator move when drag offset larger than 4 vp
2563         return;
2564     }
2565 
2566     animationDirect_ = diffOffset >= 0 ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
2567 
2568     if ((!needReverse_ && (currentIndex_ + animationDirect_ >= itemCount_ || currentIndex_ + animationDirect_ < 0)) ||
2569         (needReverse_ && (currentIndex_ - animationDirect_ >= itemCount_ || currentIndex_ - animationDirect_ < 0))) {
2570         // drag end and stretch background
2571         return DragEdgeStretch(fabsOffset);
2572     }
2573 
2574     if (fabsOffset >= longPressDragSwitchFocus) {
2575         // focus switch and vibrate
2576         VibrateIndicator();
2577         outItemIndex_ = currentIndex_;
2578         if (needReverse_) {
2579             currentIndex_ -= animationDirect_;
2580         } else {
2581             currentIndex_ += animationDirect_;
2582         }
2583         nextIndex_ = currentIndex_;
2584         dragBaseOffset_ += longPressDragSwitchFocus * animationDirect_;
2585         ResetIndicatorPosition();
2586         MarkNeedLayout();
2587         FireItemChangedEvent(true);
2588     } else {
2589         double dragRate = (fabsOffset - longPressDragStart) / longPressDragMaxDiff;
2590         UpdateIndicatorHeadPosition(INDICATOR_FOCUS_HEAD->MoveInternal(dragRate));
2591         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(dragRate));
2592         UpdateIndicatorPointPosition(INDICATOR_NORMAL_POINT->MoveInternal(dragRate));
2593     }
2594 }
2595 
DragIndicatorEnd()2596 void RenderSwiper::DragIndicatorEnd()
2597 {
2598     if ((currentIndex_ + animationDirect_ >= itemCount_ || currentIndex_ + animationDirect_ < 0) &&
2599         std::fabs(dragMoveOffset_ - dragBaseOffset_) > 0) {
2600         // drag than 80dp, play reset and zoom out animation
2601         LOGD("drag end and start restriction animation");
2602         StartDragRetractionAnimation();
2603         StartZoomOutAnimation();
2604     } else {
2605         ResetIndicatorPosition();
2606         UpdateEdgeStretchRate(DRAG_OFFSET_MIN);
2607         // only play zoom out animation
2608         LOGD("drag end and start mask zoom out animation");
2609         StartZoomOutAnimation();
2610     }
2611     dragBaseOffset_ = DRAG_OFFSET_MIN;
2612     dragMoveOffset_ = DRAG_OFFSET_MIN;
2613 }
2614 
DragEdgeStretch(double offset)2615 void RenderSwiper::DragEdgeStretch(double offset)
2616 {
2617     const double longPressDragStretchLongest = DRAG_STRETCH_LONGEST_DP * scale_;
2618     if (offset >= longPressDragStretchLongest) {
2619         UpdateEdgeStretchRate(DRAG_OFFSET_MAX);
2620     } else {
2621         UpdateEdgeStretchRate(offset / longPressDragStretchLongest);
2622     }
2623 }
2624 
StartZoomInAnimation(bool isMouseHover)2625 void RenderSwiper::StartZoomInAnimation(bool isMouseHover)
2626 {
2627     StopZoomAnimation();
2628     if (zoomValue_ == ZOOM_MIN) {
2629         MarkIndicatorPosition(false);
2630     }
2631     if (!zoomInController_) {
2632         return;
2633     }
2634     LOGD("startZoomInAnimation zoom[%{public}lf,%{public}lf], opacity[%{public}lf,%{public}lf], duration[%{public}d]",
2635         zoomValue_, ZOOM_MAX, opacityValue_, OPACITY_MAX, ZOOM_IN_DURATION);
2636     zoomInAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(zoomValue_, ZOOM_MAX, Curves::SHARP);
2637     zoomInAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2638         auto swiper = weak.Upgrade();
2639         if (swiper) {
2640             swiper->UpdateZoomValue(value);
2641             if (value == ZOOM_MAX) {
2642                 // record position zone of indicator zone for stretch when zoom in reach maximum value.
2643                 swiper->MarkIndicatorPosition();
2644             }
2645         }
2646     });
2647 
2648     opacityInAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(opacityValue_, OPACITY_MAX, Curves::SHARP);
2649     opacityInAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2650         auto swiper = weak.Upgrade();
2651         if (swiper) {
2652             swiper->UpdateMaskOpacity(value);
2653         }
2654     });
2655 
2656     zoomInController_->ClearInterpolators();
2657     zoomInController_->AddInterpolator(zoomInAnimation_);
2658     zoomInController_->AddInterpolator(opacityInAnimation_);
2659     zoomInController_->SetDuration(ZOOM_IN_DURATION);
2660     zoomInController_->Play();
2661 }
2662 
StartZoomOutAnimation(bool isMouseHover)2663 void RenderSwiper::StartZoomOutAnimation(bool isMouseHover)
2664 {
2665     StopZoomAnimation();
2666     if (!zoomOutController_) {
2667         return;
2668     }
2669     int duration = isMouseHover ? ZOOM_OUT_HOVER_DURATION : ZOOM_OUT_DURATION;
2670     LOGD("StartZoomOutAnimation zoom[%{public}lf,%{public}lf], opacity[%{public}lf,%{public}lf], duration[%{public}d]",
2671         zoomValue_, ZOOM_MIN, opacityValue_, OPACITY_MIN, duration);
2672     zoomOutAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(zoomValue_, ZOOM_MIN, Curves::SHARP);
2673     zoomOutAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2674         auto swiper = weak.Upgrade();
2675         if (swiper) {
2676             swiper->UpdateZoomValue(value);
2677         }
2678     });
2679     opacityOutAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(opacityValue_, OPACITY_MIN, Curves::SHARP);
2680     opacityOutAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2681         auto swiper = weak.Upgrade();
2682         if (swiper) {
2683             swiper->UpdateMaskOpacity(value);
2684         }
2685     });
2686     zoomOutController_->ClearInterpolators();
2687     zoomOutController_->AddInterpolator(zoomOutAnimation_);
2688     zoomOutController_->AddInterpolator(opacityOutAnimation_);
2689     zoomOutController_->SetDuration(duration);
2690     zoomOutController_->AddStopListener([weak = AceType::WeakClaim(this), isMouseHover]() {
2691         auto swiper = weak.Upgrade();
2692         if (swiper) {
2693             isMouseHover ? swiper->UpdateHoverStatus(false) : swiper->UpdatePressStatus(false);
2694         }
2695     });
2696     zoomOutController_->Play();
2697 }
2698 
StartZoomInDotAnimation(int32_t index)2699 void RenderSwiper::StartZoomInDotAnimation(int32_t index)
2700 {
2701     StopZoomDotAnimation(); // function will reset currentHoverIndex_. set it after stop zoom out dot.
2702     currentHoverIndex_ = index;
2703     if (!zoomInDotController_) {
2704         return;
2705     }
2706     LOGD("StartZoomInDotAnimation zoom[%{public}lf, %{public}lf], duration[%{public}d]",
2707         ZOOM_DOT_MIN, ZOOM_DOT_MAX, ZOOM_IN_DOT_DURATION);
2708     if (!zoomInDotAnimation_) {
2709         zoomInDotAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(ZOOM_DOT_MIN, ZOOM_DOT_MAX, Curves::SHARP);
2710         zoomInDotAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2711             auto swiper = weak.Upgrade();
2712             if (swiper) {
2713                 swiper->UpdateZoomDotValue(value);
2714             }
2715         });
2716     }
2717 
2718     zoomInDotController_->ClearInterpolators();
2719     zoomInDotController_->AddInterpolator(zoomInDotAnimation_);
2720     zoomInDotController_->SetDuration(ZOOM_IN_DOT_DURATION);
2721     zoomInDotController_->Play();
2722 }
2723 
StartZoomOutDotAnimation()2724 void RenderSwiper::StartZoomOutDotAnimation()
2725 {
2726     StopZoomDotAnimation();
2727     if (!zoomOutDotController_) {
2728         return;
2729     }
2730     LOGD("StartZoomOutDotAnimation zoom[%{public}lf, %{public}lf], duration[%{public}d]",
2731         ZOOM_DOT_MAX, ZOOM_DOT_MIN, ZOOM_OUT_DOT_DURATION);
2732     if (!zoomOutDotAnimation_) {
2733         zoomOutDotAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(ZOOM_DOT_MAX, ZOOM_DOT_MIN, Curves::SHARP);
2734         zoomOutDotAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2735             auto swiper = weak.Upgrade();
2736             if (swiper) {
2737                 swiper->UpdateZoomDotValue(value);
2738             }
2739         });
2740     }
2741     zoomOutDotController_->ClearInterpolators();
2742     zoomOutDotController_->AddInterpolator(zoomOutDotAnimation_);
2743     zoomOutDotController_->SetDuration(ZOOM_OUT_DOT_DURATION);
2744     zoomOutDotController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
2745         auto swiper = weak.Upgrade();
2746         if (swiper) {
2747             swiper->currentHoverIndex_ = INDICATOR_INVALID_HOVER_INDEX;
2748         }
2749     });
2750     zoomOutDotController_->Play();
2751 }
2752 
StopZoomAnimation()2753 void RenderSwiper::StopZoomAnimation()
2754 {
2755     LOGD("stopZoomAnimation");
2756     if (zoomInController_ && !zoomInController_->IsStopped()) {
2757         zoomInController_->ClearStopListeners();
2758         zoomInController_->Stop();
2759     }
2760     if (zoomOutController_ && !zoomOutController_->IsStopped()) {
2761         zoomOutController_->ClearStopListeners();
2762         zoomOutController_->Stop();
2763     }
2764 }
2765 
StopZoomDotAnimation()2766 void RenderSwiper::StopZoomDotAnimation()
2767 {
2768     LOGD("StopZoomDotAnimation");
2769     if (zoomInDotController_ && !zoomInDotController_->IsStopped()) {
2770         zoomInDotController_->ClearStopListeners();
2771         zoomInDotController_->Stop();
2772     }
2773     if (zoomOutDotController_ && !zoomOutDotController_->IsStopped()) {
2774         zoomOutDotController_->ClearStopListeners();
2775         zoomOutDotController_->Stop();
2776     }
2777 }
2778 
StartDragRetractionAnimation()2779 void RenderSwiper::StartDragRetractionAnimation()
2780 {
2781     if (!dragRetractionController_) {
2782         return;
2783     }
2784     StopDragRetractionAnimation();
2785     dragRetractionAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(
2786         stretchRate_, TARGET_START_TRANSLATE_TIME, INDICATOR_ZONE_STRETCH);
2787     dragRetractionAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2788         auto swiper = weak.Upgrade();
2789         if (swiper) {
2790             swiper->UpdateEdgeStretchRate(value);
2791         }
2792     });
2793 
2794     dragRetractionController_->ClearInterpolators();
2795     dragRetractionController_->AddInterpolator(dragRetractionAnimation_);
2796     dragRetractionController_->SetDuration(DRAG_RETRETION_DURATION);
2797     dragRetractionController_->Play();
2798 }
2799 
StopDragRetractionAnimation()2800 void RenderSwiper::StopDragRetractionAnimation()
2801 {
2802     if (dragRetractionController_ && !dragRetractionController_->IsStopped()) {
2803         dragRetractionController_->ClearStopListeners();
2804         dragRetractionController_->Stop();
2805     }
2806 }
2807 
FinishAllSwipeAnimation(bool useFinish,bool surfaceChanged)2808 void RenderSwiper::FinishAllSwipeAnimation(bool useFinish, bool surfaceChanged)
2809 {
2810     if (useFinish && IsAnimatorStopped()) {
2811         FireSwiperControllerFinishEvent();
2812         return;
2813     }
2814     if (useFinish) {
2815         FinishSwipeAnimation();
2816     } else {
2817         StopSwipeAnimation();
2818     }
2819 
2820     StopSwipeToAnimation();
2821     StopIndicatorAnimation();
2822     StopIndicatorSpringAnimation();
2823     ResetIndicatorPosition();
2824 
2825     if (surfaceChanged) {
2826         UpdateChildPosition(0.0, currentIndex_);
2827     } else {
2828         LoadLazyItems((currentIndex_ + 1) % itemCount_ == targetIndex_);
2829     }
2830     UpdateOneItemOpacity(MAX_OPACITY, currentIndex_);
2831     UpdateOneItemOpacity(MAX_OPACITY, targetIndex_);
2832     currentIndex_ = targetIndex_;
2833     if (useFinish) {
2834         FireSwiperControllerFinishEvent();
2835     }
2836     quickTurnItem_ = true;
2837     MarkNeedLayout(true);
2838 }
2839 
IsAnimatorStopped() const2840 bool RenderSwiper::IsAnimatorStopped() const
2841 {
2842     bool isControllerRunning = controller_ && controller_->IsRunning();
2843     bool isSwiperControllerRunning = swipeToController_ && swipeToController_->IsRunning();
2844     bool isIndicatorControllerRunning = indicatorController_ && indicatorController_->IsRunning();
2845     bool isSpringControllerRunning = springController_ && springController_->IsRunning();
2846     return !isControllerRunning && !isSwiperControllerRunning && !isIndicatorControllerRunning &&
2847            !isSpringControllerRunning;
2848 }
2849 
FireSwiperControllerFinishEvent()2850 void RenderSwiper::FireSwiperControllerFinishEvent()
2851 {
2852     if (swiper_ && swiper_->GetSwiperController() && swiper_->GetSwiperController()->GetFinishCallback()) {
2853         swiper_->GetSwiperController()->GetFinishCallback()();
2854     }
2855 }
2856 
IsZoomAnimationStopped()2857 bool RenderSwiper::IsZoomAnimationStopped()
2858 {
2859     bool result = true;
2860     if (zoomInController_ && !zoomInController_->IsStopped()) {
2861         result = false;
2862     }
2863     if (zoomOutController_ && !zoomOutController_->IsStopped()) {
2864         result = false;
2865     }
2866     return result;
2867 }
2868 
IsZoomOutAnimationStopped()2869 bool RenderSwiper::IsZoomOutAnimationStopped()
2870 {
2871     return zoomOutController_ ? zoomOutController_->IsStopped() : true;
2872 }
2873 
IsZoomOutDotAnimationStopped()2874 bool RenderSwiper::IsZoomOutDotAnimationStopped()
2875 {
2876     return zoomOutDotController_ ? zoomOutDotController_->IsStopped() : true;
2877 }
2878 
UpdateIndicatorLayout()2879 void RenderSwiper::UpdateIndicatorLayout()
2880 {
2881     LayoutIndicator(swiperIndicatorData_);
2882     MarkNeedRender();
2883 }
2884 
UpdateIndicatorOffset(int32_t fromIndex,int32_t toIndex,double value)2885 void RenderSwiper::UpdateIndicatorOffset(int32_t fromIndex, int32_t toIndex, double value)
2886 {
2887     int32_t indicatorMoveNums = std::abs(fromIndex - toIndex);
2888     if (value >= 1.0) {
2889         // move to end, and index change
2890         UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
2891         UpdateIndicatorPointPosition(DRAG_OFFSET_MIN);
2892         UpdateIndicatorHeadPosition(DRAG_OFFSET_MIN);
2893         return;
2894     }
2895 
2896     UpdateIndicatorPointPosition(INDICATOR_NORMAL_POINT->MoveInternal(value));
2897     UpdateIndicatorHeadPosition(INDICATOR_FOCUS_HEAD->MoveInternal(value) * indicatorMoveNums);
2898     if (value < focusStretchMaxTime_) {
2899         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(value) * indicatorMoveNums);
2900         return;
2901     }
2902 
2903     // curve sport into spring sport
2904     if (GetIndicatorSpringStatus() == SpringStatus::SPRING_STOP) {
2905         LOGD("indicator tail move end, start spring sport.");
2906         double springStart = INDICATOR_FOCUS_TAIL->MoveInternal(value) * indicatorMoveNums;
2907         UpdateIndicatorTailPosition(springStart);
2908         StartIndicatorSpringAnimation(springStart, indicatorMoveNums * DRAG_OFFSET_MAX);
2909     }
2910 }
2911 
UpdateIndicatorHeadPosition(double offset)2912 void RenderSwiper::UpdateIndicatorHeadPosition(double offset)
2913 {
2914     indicatorHeadOffset_ = offset * animationDirect_;
2915 }
2916 
UpdateIndicatorTailPosition(double offset,double switchOffset)2917 void RenderSwiper::UpdateIndicatorTailPosition(double offset, double switchOffset)
2918 {
2919     indicatorTailOffset_ = offset * animationDirect_;
2920     // if indicator switch to the next or last, tail offset will be different.
2921     indicatorSwitchTailOffset_ = switchOffset * animationDirect_;
2922     MarkNeedRender();
2923 }
2924 
UpdateIndicatorPointPosition(double offset)2925 void RenderSwiper::UpdateIndicatorPointPosition(double offset)
2926 {
2927     indicatorPointOffset_ = offset * animationDirect_;
2928     MarkNeedRender();
2929 }
2930 
UpdateMaskOpacity(double value)2931 void RenderSwiper::UpdateMaskOpacity(double value)
2932 {
2933     opacityValue_ = value;
2934     MarkNeedRender();
2935 }
2936 
UpdateZoomValue(double value)2937 void RenderSwiper::UpdateZoomValue(double value)
2938 {
2939     zoomValue_ = value;
2940     LayoutIndicator(swiperIndicatorData_);
2941     MarkNeedRender();
2942 }
2943 
UpdateZoomDotValue(double value)2944 void RenderSwiper::UpdateZoomDotValue(double value)
2945 {
2946     zoomDotValue_ = value;
2947     LayoutIndicator(swiperIndicatorData_);
2948     MarkNeedRender();
2949 }
2950 
UpdateEdgeStretchRate(double value)2951 void RenderSwiper::UpdateEdgeStretchRate(double value)
2952 {
2953     stretchRate_ = value;
2954     widthStretchRate_ = DRAG_STRETCH_BASE_WIDTH + (DRAG_STRETCH_MAX_WIDTH - DRAG_STRETCH_BASE_WIDTH) * value;
2955     heightStretchRate_ = DRAG_STRETCH_BASE_HIGH + (DRAG_STRETCH_MAX_HIGH - DRAG_STRETCH_BASE_HIGH) * value;
2956     LayoutIndicator(swiperIndicatorData_);
2957     MarkNeedRender();
2958 }
2959 
UpdatePressStatus(bool isPress)2960 void RenderSwiper::UpdatePressStatus(bool isPress)
2961 {
2962     swiperIndicatorData_.isPressed = isPress;
2963 }
2964 
UpdateHoverStatus(bool isHover)2965 void RenderSwiper::UpdateHoverStatus(bool isHover)
2966 {
2967     swiperIndicatorData_.isHovered = isHover;
2968 }
2969 
StartIndicatorAnimation(int32_t fromIndex,int32_t toIndex,bool isLoop)2970 void RenderSwiper::StartIndicatorAnimation(int32_t fromIndex, int32_t toIndex, bool isLoop)
2971 {
2972     LOGD("StartIndicatorAnimation");
2973     if (fromIndex == toIndex) {
2974         LOGD("from index is same to next index.");
2975         return;
2976     }
2977     if (isIndicatorAnimationStart_) {
2978         LOGE("indicator animation is processing.");
2979         return;
2980     }
2981 
2982     CalMaxStretch();
2983     StopIndicatorSpringAnimation();
2984     StopIndicatorAnimation();
2985     ResetHoverZoomDot();
2986     targetIndex_ = toIndex;
2987     nextIndex_ = toIndex;
2988     isIndicatorAnimationStart_ = true;
2989     animationDirect_ = (fromIndex - toIndex <= 0) ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
2990 
2991     // the start offset of swiper content zone.
2992     double contentOffset = (animationDirect_ == INDICATOR_DIRECT_FORWARD) ? (isLoop ? nextItemOffset_ : prevItemOffset_)
2993                                                                       : (isLoop ? prevItemOffset_ : nextItemOffset_);
2994     if (needReverse_) {
2995         animationDirect_ *= INDICATOR_DIRECT_BACKWARD;
2996     }
2997     indicatorAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(
2998         CUR_START_TRANSLATE_TIME, CUR_END_TRANSLATE_TIME, curve_);
2999     indicatorAnimation_->AddListener(
3000         [weak = AceType::WeakClaim(this), fromIndex, toIndex, contentOffset](const double value) {
3001         auto swiper = weak.Upgrade();
3002         if (swiper) {
3003             swiper->UpdateIndicatorOffset(fromIndex, toIndex, value);
3004             double itemOffset = (value == CUR_END_TRANSLATE_TIME) ? value : Curves::EASE_OUT->MoveInternal(value);
3005             swiper->UpdateChildPosition(itemOffset * contentOffset, fromIndex);
3006         }
3007     });
3008 
3009     if (indicatorController_) {
3010         indicatorController_->ClearInterpolators();
3011         indicatorController_->AddInterpolator(indicatorAnimation_);
3012         indicatorController_->SetDuration(duration_);
3013         indicatorController_->ClearStopListeners();
3014         indicatorController_->AddStopListener([weak = AceType::WeakClaim(this), fromIndex, toIndex]() {
3015             auto swiper = weak.Upgrade();
3016             if (swiper) {
3017                 swiper->LoadLazyItems((fromIndex + 1) % swiper->itemCount_ == toIndex);
3018                 swiper->isIndicatorAnimationStart_ = false;
3019                 swiper->outItemIndex_ = fromIndex;
3020                 swiper->currentIndex_ = toIndex;
3021                 swiper->FireItemChangedEvent(true);
3022                 swiper->UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
3023                 swiper->MarkNeedLayout(true);
3024             }
3025         });
3026         indicatorController_->Play();
3027     }
3028 }
3029 
StopIndicatorAnimation()3030 void RenderSwiper::StopIndicatorAnimation()
3031 {
3032     LOGD("stopZoomAnimation");
3033     if (indicatorController_ && !indicatorController_->IsStopped()) {
3034         indicatorController_->ClearStopListeners();
3035         indicatorController_->Stop();
3036         isIndicatorAnimationStart_ = false;
3037     }
3038 }
3039 
InitIndicatorAnimation(const WeakPtr<PipelineContext> & context)3040 void RenderSwiper::InitIndicatorAnimation(const WeakPtr<PipelineContext>& context)
3041 {
3042     if (!springController_) {
3043         springController_ = AceType::MakeRefPtr<Animator>(context);
3044     } else {
3045         StopIndicatorSpringAnimation();
3046     }
3047     if (!fadeController_) {
3048         fadeController_ = AceType::MakeRefPtr<Animator>(context);
3049     }
3050     if (!zoomInController_) {
3051         zoomInController_ = AceType::MakeRefPtr<Animator>(context);
3052     }
3053     if (!zoomOutController_) {
3054         zoomOutController_ = AceType::MakeRefPtr<Animator>(context);
3055     }
3056     if (!zoomInDotController_) {
3057         zoomInDotController_ = AceType::MakeRefPtr<Animator>(context);
3058     }
3059     if (!zoomOutDotController_) {
3060         zoomOutDotController_ = AceType::MakeRefPtr<Animator>(context);
3061     }
3062     if (!dragRetractionController_) {
3063         dragRetractionController_ = AceType::MakeRefPtr<Animator>(context);
3064     }
3065     if (!indicatorController_) {
3066         indicatorController_ = AceType::MakeRefPtr<Animator>(context);
3067     } else {
3068         StopIndicatorAnimation();
3069         ResetIndicatorPosition();
3070     }
3071     CalMaxStretch();
3072 }
3073 
HandleRotationStart()3074 void RenderSwiper::HandleRotationStart()
3075 {
3076     DragStartInfo info(0);
3077     info.SetGlobalLocation(Offset(0.0, 0.0));
3078     HandleDragStart(info);
3079 }
3080 
HandleRotationUpdate(double delta)3081 void RenderSwiper::HandleRotationUpdate(double delta)
3082 {
3083     DragUpdateInfo info(0);
3084     info.SetMainDelta(delta).SetGlobalLocation(Offset(0.0, 0.0));
3085     HandleDragUpdate(info);
3086     if (rotationEvent_) {
3087         std::string param =
3088             std::string(R"("rotation",{"value":)").append(std::to_string(delta).append("},null"));
3089         rotationEvent_(param);
3090     }
3091 }
3092 
HandleRotationEnd()3093 void RenderSwiper::HandleRotationEnd()
3094 {
3095     DragEndInfo info(0);
3096     HandleDragEnd(info);
3097     rotationStatus_ = RotationStatus::ROTATION_END;
3098 }
3099 
ResetRotationEndListener()3100 void RenderSwiper::ResetRotationEndListener()
3101 {
3102     auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
3103         auto swiper = weakPtr.Upgrade();
3104         if (swiper) {
3105             swiper->HandleRotationEnd();
3106         } else {
3107             LOGE("fail to set rotation listener due to swiper weakPtr is nullptr");
3108         }
3109     };
3110     rotationTimer_.Reset(callback);
3111     auto context = GetContext().Upgrade();
3112     if (context) {
3113         auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
3114         taskExecutor.PostDelayedTask(rotationTimer_, ROTATION_INTERVAL_MS);
3115     }
3116 }
3117 
UpdateItemCount(int32_t itemCount)3118 void RenderSwiper::UpdateItemCount(int32_t itemCount)
3119 {
3120     if ((itemCount_ <= 1) && (itemCount > 1)) {
3121         Initialize(GetContext(), catchMode_);
3122     }
3123     itemCount_ = itemCount;
3124     if (currentIndex_ >= itemCount_) {
3125         currentIndex_ = itemCount_ > 0 ? itemCount_ - 1 : 0;
3126         if (changeEvent_) {
3127             changeEvent_(std::make_shared<SwiperChangeEvent>(currentIndex_));
3128         }
3129     }
3130 }
3131 
BuildLazyItems()3132 void RenderSwiper::BuildLazyItems()
3133 {
3134     if (itemCount_ <= lazyLoadCacheSize_) {
3135         cacheStart_ = 0;
3136         cacheEnd_ = itemCount_;
3137     } else {
3138         int32_t halfLazy = lazyLoadCacheSize_ / 2;
3139         if (loop_) {
3140             cacheStart_ = (itemCount_ + currentIndex_ - halfLazy) % itemCount_;
3141             cacheEnd_ = (cacheStart_ + lazyLoadCacheSize_ - 1) % itemCount_;
3142         } else {
3143             if (currentIndex_ < halfLazy) {
3144                 cacheStart_ = 0;
3145                 cacheEnd_ = swiper_->GetCachedSize() + swiper_->GetDisplayCount() - 1;
3146             } else if (currentIndex_ >= itemCount_ - halfLazy - 1) {
3147                 cacheEnd_ = itemCount_ - 1;
3148                 cacheStart_ = cacheEnd_ - swiper_->GetCachedSize() - swiper_->GetDisplayCount();
3149             } else {
3150                 cacheStart_ = currentIndex_ - halfLazy;
3151                 cacheEnd_ = cacheStart_ + lazyLoadCacheSize_ - 1;
3152             }
3153         }
3154     }
3155     LOGI("currentIndex_ = %{public}d, init cached: %{public}d - %{public}d", currentIndex_, cacheStart_, cacheEnd_);
3156     if (cacheStart_ > cacheEnd_) { // CacheStart may greater than cacheEnd when enable loop.
3157         for (int32_t index = cacheStart_; index < itemCount_; ++index) {
3158             buildChildByIndex_(index);
3159         }
3160         for (int32_t index = 0; index <= cacheEnd_; ++index) {
3161             buildChildByIndex_(index);
3162         }
3163     } else {
3164         for (int32_t index = cacheStart_; index <= cacheEnd_; ++index) {
3165             buildChildByIndex_(index);
3166         }
3167     }
3168 
3169     if (swipeToIndex_ < cacheStart_ || swipeToIndex_ > cacheEnd_) {
3170         buildChildByIndex_(swipeToIndex_);
3171     }
3172 }
3173 
LoadItems()3174 void RenderSwiper::LoadItems()
3175 {
3176     if (!items_.empty()) {
3177         return;
3178     }
3179     if ((swiper_ && !swiper_->GetLazyForEachComponent()) || !swiper_) {
3180         auto children = GetChildren();
3181         int32_t index = 0;
3182         for (auto iter = children.begin(); iter != children.end(); ++iter, ++index) {
3183             items_.emplace(std::make_pair(index, *iter));
3184         }
3185         if (Container::IsCurrentUsePartialUpdate()) {
3186             itemCount_ = static_cast<int32_t>(children.size());
3187         }
3188     } else {
3189         BuildLazyItems(); // depend on currentIndex_ value which init when swiper first update
3190     }
3191 }
3192 
LoadLazyItems(bool swipeToNext)3193 void RenderSwiper::LoadLazyItems(bool swipeToNext)
3194 {
3195     if (!buildChildByIndex_) {
3196         // not lazy foreach case.
3197         return;
3198     }
3199     if (static_cast<int32_t>(items_.size()) == itemCount_) {
3200         // all item in caches
3201         return;
3202     }
3203     if (swipeToNext) {
3204         if (!loop_) {
3205             buildChildByIndex_(++cacheEnd_);
3206             if (cacheStart_ + cacheEnd_ >= lazyLoadCacheSize_) {
3207                 deleteChildByIndex_(cacheStart_++);
3208             }
3209         } else {
3210             if (++cacheEnd_ == itemCount_) {
3211                 cacheEnd_ = 0;
3212             }
3213             buildChildByIndex_(cacheEnd_);
3214             deleteChildByIndex_(cacheStart_);
3215             if (++cacheStart_ == itemCount_) {
3216                 cacheStart_ = 0;
3217             }
3218         }
3219     } else {
3220         if (!loop_) {
3221             if (cacheStart_ + cacheEnd_ >= lazyLoadCacheSize_) {
3222                 buildChildByIndex_(--cacheStart_);
3223             }
3224             if (currentIndex_ < (itemCount_ - 1)) {
3225                 deleteChildByIndex_(cacheEnd_--);
3226             }
3227         } else {
3228             if (--cacheStart_ < 0) {
3229                 cacheStart_ = itemCount_ - 1;
3230             }
3231             buildChildByIndex_(cacheStart_);
3232             deleteChildByIndex_(cacheEnd_);
3233             if (--cacheEnd_ < 0) {
3234                 cacheEnd_ = itemCount_ - 1;
3235             }
3236         }
3237     }
3238     LOGI("load lazy cached: %{public}d - %{public}d, current = %{public}d", cacheStart_, cacheEnd_, currentIndex_);
3239 }
3240 
AddChildByIndex(int32_t index,const RefPtr<RenderNode> & renderNode)3241 void RenderSwiper::AddChildByIndex(int32_t index, const RefPtr<RenderNode>& renderNode)
3242 {
3243     items_.try_emplace(index, renderNode);
3244 }
3245 
RemoveChildByIndex(int32_t index)3246 void RenderSwiper::RemoveChildByIndex(int32_t index)
3247 {
3248     auto item = items_.find(index);
3249     if (item != items_.end()) {
3250         items_.erase(item);
3251     }
3252 }
3253 
OnDataSourceUpdated(int32_t totalCount,int32_t startIndex)3254 void RenderSwiper::OnDataSourceUpdated(int32_t totalCount, int32_t startIndex)
3255 {
3256     decltype(items_) items(std::move(items_));
3257     for (auto&& item : items) {
3258         deleteChildByIndex_(item.first);
3259     }
3260     UpdateItemCount(totalCount);
3261     MarkNeedLayout(true);
3262 }
3263 
ClearItems(const RefPtr<Component> & lazyForEachComponent,int32_t index)3264 void RenderSwiper::ClearItems(const RefPtr<Component>& lazyForEachComponent, int32_t index)
3265 {
3266     if (lazyForEachComponent) {
3267         if (index != currentIndex_) {
3268             decltype(items_) items(std::move(items_));
3269             for (auto&& item : items) {
3270                 deleteChildByIndex_(item.first);
3271             }
3272         }
3273     } else {
3274         items_.clear();
3275     }
3276 }
3277 
ResetCachedChildren()3278 void RenderSwiper::ResetCachedChildren()
3279 {
3280     auto context = context_.Upgrade();
3281     if (!context) {
3282         LOGW("ResetCachedChildren fail, context is null");
3283         return;
3284     }
3285     if (context->GetIsDeclarative()) {
3286         return;
3287     }
3288 
3289     int32_t cachedSize = swiper_->GetCachedSize();
3290     int32_t childrenSize = itemCount_;
3291     int32_t forwardNum = 0;
3292     int32_t backNum = 0;
3293     if (cachedSize <= -1 || cachedSize >= childrenSize / 2) {
3294         for (const auto& item : items_) {
3295             const auto& childItem = item.second;
3296             if (!childItem) {
3297                 continue;
3298             }
3299             childItem->SetHidden(false);
3300         }
3301         return;
3302     } else if (cachedSize == 0) {
3303         cachedSize = 1;
3304         forwardNum = cachedSize;
3305         backNum = cachedSize;
3306     }
3307     if (loop_) {
3308         forwardNum = cachedSize;
3309         backNum = cachedSize;
3310     } else {
3311         if (currentIndex_ == 0) {
3312             forwardNum = 0;
3313             if (cachedSize < childrenSize / 2) {
3314                 backNum = 2 * cachedSize;
3315             }
3316         } else if (currentIndex_ != 0 && currentIndex_ < cachedSize) {
3317             forwardNum = currentIndex_;
3318             backNum = cachedSize + (cachedSize - forwardNum);
3319         } else if (currentIndex_ != 0 && currentIndex_ >= cachedSize) {
3320             forwardNum = cachedSize;
3321             if (cachedSize + currentIndex_ < childrenSize) { // smaller than size
3322                 backNum = cachedSize;
3323             } else if (currentIndex_ + cachedSize >= childrenSize) {
3324                 backNum = childrenSize - currentIndex_ - 1;
3325                 int32_t des = cachedSize - backNum;
3326                 forwardNum = des + cachedSize;
3327             }
3328         }
3329     }
3330     SetSwiperHidden(forwardNum, backNum);
3331 }
3332 
SetSwiperHidden(int32_t forwardNum,int32_t backNum)3333 void RenderSwiper::SetSwiperHidden(int32_t forwardNum, int32_t backNum)
3334 {
3335     int32_t childrenSize = itemCount_;
3336     int32_t fromIndex = currentIndex_ - forwardNum;
3337     int32_t toIndex = currentIndex_ + backNum;
3338     if (fromIndex >= 0 && toIndex < childrenSize) { // normal
3339         for (const auto& item : items_) {
3340             const auto& childItem = item.second;
3341             if (childItem) {
3342                 childItem->SetHidden(item.first >= fromIndex && item.first <= toIndex);
3343             }
3344         }
3345     }
3346     if (loop_) {
3347         if (fromIndex < 0) {
3348             for (const auto& item : items_) {
3349                 const auto& childItem = item.second;
3350                 if (childItem) {
3351                     childItem->SetHidden(item.first > toIndex && item.first < fromIndex + childrenSize);
3352                 }
3353             }
3354         } else if (toIndex >= childrenSize) {
3355             for (const auto& item : items_) {
3356                 const auto& childItem = item.second;
3357                 if (childItem) {
3358                     childItem->SetHidden(item.first > toIndex - childrenSize && item.first < fromIndex);
3359                 }
3360             }
3361         }
3362     }
3363 }
3364 
IsChildrenTouchEnable()3365 bool RenderSwiper::IsChildrenTouchEnable()
3366 {
3367     return !(controller_ && controller_->IsRunning());
3368 }
3369 
OnPaintFinish()3370 void RenderSwiper::OnPaintFinish()
3371 {
3372     if (!AceApplicationInfo::GetInstance().IsAccessibilityEnabled()) {
3373         return;
3374     }
3375 
3376     bool isDeclarative = true;
3377     auto context = GetContext().Upgrade();
3378     if (context) {
3379         isDeclarative = context->GetIsDeclarative();
3380     }
3381 
3382     Rect itemRect;
3383     Rect viewPortRect(GetGlobalOffset(), GetChildViewPort());
3384     RefPtr<OHOS::Ace::RenderNode> itemWithChildAccessibilityNode;
3385     for (const auto& item : GetChildren()) {
3386         // RenderSwiper's children are RenderDisplay who's accessibility node is the same with RenderSwiper in v2,
3387         // see SwiperComponent::AppendChild and RenderElement::SetAccessibilityNode
3388         if (isDeclarative) {
3389             itemWithChildAccessibilityNode = item->GetFirstChild();
3390         } else {
3391             itemWithChildAccessibilityNode = item;
3392         }
3393 
3394         if (!itemWithChildAccessibilityNode) {
3395             continue;
3396         }
3397 
3398         auto node = itemWithChildAccessibilityNode->GetAccessibilityNode().Upgrade();
3399         if (!node) {
3400             continue;
3401         }
3402         bool visible = GetVisible();
3403         if (visible) {
3404             itemRect.SetSize(itemWithChildAccessibilityNode->GetLayoutSize());
3405             itemRect.SetOffset(itemWithChildAccessibilityNode->GetGlobalOffset());
3406             visible = itemRect.IsIntersectWith(viewPortRect);
3407         }
3408         itemWithChildAccessibilityNode->SetAccessibilityVisible(visible);
3409         if (visible) {
3410             Rect clampRect = itemRect.Constrain(viewPortRect);
3411             if (clampRect != itemRect) {
3412                 itemWithChildAccessibilityNode->SetAccessibilityRect(clampRect);
3413             }
3414         } else {
3415             itemWithChildAccessibilityNode->NotifyPaintFinish();
3416         }
3417     }
3418 }
3419 
3420 // In case of partial update we get extra RenderNode children
3421 // without invoking RenderSwiper::Update, so we have to reset items_
3422 // SwiperComponent swiper_ not updated in that case and
3423 // it will still keep initial list of children.
OnChildAdded(const RefPtr<RenderNode> & child)3424 void RenderSwiper::OnChildAdded(const RefPtr<RenderNode>& child)
3425 {
3426     if (!Container::IsCurrentUsePartialUpdate()) {
3427         return;
3428     }
3429 
3430     if (!swiper_) {
3431         return; // Not done with Update call yet.
3432     }
3433     if (swiper_->GetLazyForEachComponent()) {
3434         return; // No partial update support for LazyForEach yet
3435     }
3436 
3437     // Later LoadItems will recreate items_ and update itemCount_
3438     ClearItems(nullptr, 0);
3439     ResetCachedChildren();
3440 }
3441 
OnChildRemoved(const RefPtr<RenderNode> & child)3442 void RenderSwiper::OnChildRemoved(const RefPtr<RenderNode>& child)
3443 {
3444     if (!Container::IsCurrentUsePartialUpdate()) {
3445         return;
3446     }
3447 
3448     if (!swiper_) {
3449         return; // Not done with Update call yet.
3450     }
3451     if (swiper_->GetLazyForEachComponent()) {
3452         return; // No partial update support for LazyForEach yet
3453     }
3454     ClearItems(nullptr, 0);
3455     ResetCachedChildren();
3456 }
3457 
OnSurfaceChanged()3458 void RenderSwiper::OnSurfaceChanged()
3459 {
3460     if(isIndicatorAnimationStart_ && !needRestore_) {
3461         FinishAllSwipeAnimation(true, true);
3462     }
3463 }
3464 
ProvideRestoreInfo()3465 std::string RenderSwiper::ProvideRestoreInfo()
3466 {
3467     auto jsonObj = JsonUtil::Create(true);
3468     jsonObj->Put("index", index_);
3469     jsonObj->Put("currentIndex", currentIndex_);
3470     jsonObj->Put("swipeToIndex", swipeToIndex_);
3471     return jsonObj->ToString();
3472 }
3473 
ApplyRestoreInfo()3474 void RenderSwiper::ApplyRestoreInfo()
3475 {
3476     if (GetRestoreInfo().empty()) {
3477         return;
3478     }
3479     auto info = JsonUtil::ParseJsonString(GetRestoreInfo());
3480     if (!info->IsValid() || !info->IsObject()) {
3481         LOGW("RenderSwiper:: restore info is invalid");
3482         return;
3483     }
3484 
3485     auto jsonIndex = info->GetValue("index");
3486     auto jsonCurrentIndex = info->GetValue("currentIndex");
3487     auto jsonSwipeToIndex = info->GetValue("swipeToIndex");
3488 
3489     index_ = jsonIndex->GetInt();
3490     currentIndex_ = jsonCurrentIndex->GetInt();
3491     swipeToIndex_ = jsonSwipeToIndex->GetInt();
3492     SetRestoreInfo("");
3493 }
3494 
GetPaintChildList()3495 std::list<RefPtr<RenderNode>> RenderSwiper::GetPaintChildList()
3496 {
3497     std::list<RefPtr<RenderNode>> childList;
3498     auto swiperGlobalRect = GetRectBasedWindowTopLeft();
3499     const auto& children = GetChildren();
3500     for (const auto& child : children) {
3501         auto childGlobalRect = child->GetRectBasedWindowTopLeft();
3502         if (swiperGlobalRect.IsIntersectByCommonSideWith(childGlobalRect)) {
3503             childList.emplace_back(child);
3504         }
3505     }
3506 
3507     return childList;
3508 }
3509 
3510 } // namespace OHOS::Ace
3511