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