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