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_->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_->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_->GetEdgeEffect();
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_->GetEdgeEffect();
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     auto animationCurve = swiper_->GetAnimationCurve();
1231     auto curStartTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(CUR_START_TRANSLATE_TIME, start);
1232     auto curEndTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(CUR_END_TRANSLATE_TIME, end);
1233     curEndTranslateKeyframe->SetCurve(
1234         animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1235     curTranslateAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<double>>();
1236     curTranslateAnimation_->AddKeyframe(curStartTranslateKeyframe);
1237     curTranslateAnimation_->AddKeyframe(curEndTranslateKeyframe);
1238 
1239     auto targetStartTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(TARGET_START_TRANSLATE_TIME, -end);
1240     auto targetEndTranslateKeyframe = AceType::MakeRefPtr<Keyframe<double>>(TARGET_END_TRANSLATE_TIME, start);
1241     targetEndTranslateKeyframe->SetCurve(
1242         animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1243     targetTranslateAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<double>>();
1244     targetTranslateAnimation_->AddKeyframe(targetStartTranslateKeyframe);
1245     targetTranslateAnimation_->AddKeyframe(targetEndTranslateKeyframe);
1246 
1247     if (animationOpacity_) {
1248         auto curStartOpacityKeyframe =
1249             AceType::MakeRefPtr<Keyframe<uint8_t>>(CUR_START_OPACITY_TIME, CUR_START_OPACITY_VALUE);
1250         auto curEndOpacityKeyframe =
1251             AceType::MakeRefPtr<Keyframe<uint8_t>>(CUR_END_OPACITY_TIME, CUR_END_OPACITY_VALUE);
1252         curEndOpacityKeyframe->SetCurve(
1253             animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1254         curOpacityAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<uint8_t>>();
1255         curOpacityAnimation_->AddKeyframe(curStartOpacityKeyframe);
1256         curOpacityAnimation_->AddKeyframe(curEndOpacityKeyframe);
1257 
1258         auto targetStartOpacityKeyframe =
1259             AceType::MakeRefPtr<Keyframe<uint8_t>>(TARGET_START_OPACITY_TIME, TARGET_START_OPACITY_VALUE);
1260         auto targetEndOpacityKeyframe =
1261             AceType::MakeRefPtr<Keyframe<uint8_t>>(TARGET_END_OPACITY_TIME, TARGET_END_OPACITY_VALUE);
1262         targetEndOpacityKeyframe->SetCurve(
1263             animationCurve == AnimationCurve::FRICTION ? Curves::FRICTION : Curves::FAST_OUT_SLOW_IN);
1264         targetOpacityAnimation_ = AceType::MakeRefPtr<KeyframeAnimation<uint8_t>>();
1265         targetOpacityAnimation_->AddKeyframe(targetStartOpacityKeyframe);
1266         targetOpacityAnimation_->AddKeyframe(targetEndOpacityKeyframe);
1267     }
1268 }
1269 
AddSwipeToTranslateListener(int32_t fromIndex,int32_t toIndex)1270 void RenderSwiper::AddSwipeToTranslateListener(int32_t fromIndex, int32_t toIndex)
1271 {
1272     auto weak = AceType::WeakClaim(this);
1273     targetIndex_ = toIndex;
1274     nextIndex_ = toIndex;
1275     curTranslateAnimation_->AddListener([weak, fromIndex, toIndex](const double& value) {
1276         auto swiper = weak.Upgrade();
1277         if (swiper) {
1278             swiper->UpdateItemPosition(value, fromIndex, toIndex);
1279         }
1280     });
1281 
1282     targetTranslateAnimation_->AddListener([weak, fromIndex, toIndex](const double& value) {
1283         auto swiper = weak.Upgrade();
1284         if (swiper) {
1285             swiper->UpdateItemPosition(value, toIndex, fromIndex);
1286         }
1287     });
1288 }
1289 
AddSwipeToOpacityListener(int32_t fromIndex,int32_t toIndex)1290 void RenderSwiper::AddSwipeToOpacityListener(int32_t fromIndex, int32_t toIndex)
1291 {
1292     if (!animationOpacity_) {
1293         return;
1294     }
1295     auto weak = AceType::WeakClaim(this);
1296     curOpacityAnimation_->AddListener([weak, fromIndex, toIndex](const uint8_t& opacity) {
1297         auto swiper = weak.Upgrade();
1298         if (swiper) {
1299             swiper->UpdateItemOpacity(opacity, fromIndex, toIndex);
1300         }
1301     });
1302 
1303     targetOpacityAnimation_->AddListener([weak, fromIndex, toIndex](const uint8_t& opacity) {
1304         auto swiper = weak.Upgrade();
1305         if (swiper) {
1306             swiper->UpdateItemOpacity(opacity, toIndex, fromIndex);
1307         }
1308     });
1309 }
1310 
AddSwipeToIndicatorListener(int32_t fromIndex,int32_t toIndex)1311 void RenderSwiper::AddSwipeToIndicatorListener(int32_t fromIndex, int32_t toIndex)
1312 {
1313     indicatorAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(
1314         CUR_START_TRANSLATE_TIME, CUR_END_TRANSLATE_TIME, curve_);
1315     indicatorAnimation_->AddListener(
1316         [weak = AceType::WeakClaim(this), fromIndex, toIndex](const double value) {
1317         auto swiper = weak.Upgrade();
1318         if (swiper) {
1319             swiper->UpdateIndicatorOffset(fromIndex, toIndex, value);
1320         }
1321     });
1322     animationDirect_ = (fromIndex - toIndex <= 0) ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
1323     if (needReverse_) {
1324         animationDirect_ *= INDICATOR_DIRECT_BACKWARD;
1325     }
1326     targetIndex_ = toIndex;
1327     nextIndex_ = toIndex;
1328 }
1329 
CalculateEndOffset(int32_t fromIndex,int32_t toIndex,bool reverse)1330 double RenderSwiper::CalculateEndOffset(int32_t fromIndex, int32_t toIndex, bool reverse)
1331 {
1332     double end = 0.0;
1333     auto context = GetContext().Upgrade();
1334     double translateRatio = TRANSLATE_RATIO;
1335     if (context && context->GetIsDeclarative()) {
1336         translateRatio = 1.0;
1337     }
1338     if (fromIndex > toIndex) {
1339         // default move to back position, if need reverse direction move to front position.
1340         end = reverse ? prevItemOffset_ / translateRatio : nextItemOffset_ / translateRatio;
1341     } else {
1342         // default move to front position, if need reverse direction move to back position.
1343         end = reverse ? nextItemOffset_ / translateRatio : prevItemOffset_ / translateRatio;
1344     }
1345     if (context && context->IsJsCard()) {
1346         if (loop_) {
1347             end = reverse ? nextItemOffset_ : prevItemOffset_;
1348         } else {
1349             if (fromIndex > toIndex) {
1350                 end = reverse ? prevItemOffset_ : nextItemOffset_;
1351             } else {
1352                 end = reverse ? nextItemOffset_ : prevItemOffset_;
1353             }
1354         }
1355     }
1356     return end;
1357 }
1358 
ResetScrollOffset()1359 void RenderSwiper::ResetScrollOffset()
1360 {
1361     scrollOffset_ = 0.0;
1362 }
1363 
DoSwipeToAnimation(int32_t fromIndex,int32_t toIndex,bool reverse)1364 void RenderSwiper::DoSwipeToAnimation(int32_t fromIndex, int32_t toIndex, bool reverse)
1365 {
1366     if (!swipeToController_ || isIndicatorAnimationStart_ || fromIndex == toIndex) {
1367         return;
1368     }
1369     isIndicatorAnimationStart_ = true;
1370     double start = 0.0;
1371     moveStatus_ = true;
1372     if (onFocus_) {
1373         auto context = GetContext().Upgrade();
1374         if (context) {
1375             context->CancelFocusAnimation();
1376         }
1377     }
1378     double end = CalculateEndOffset(fromIndex, toIndex, reverse);
1379     swipeToController_->ClearStopListeners();
1380     if (isSwipeToAnimationAdded_) {
1381         swipeToController_->ClearInterpolators();
1382         isSwipeToAnimationAdded_ = false;
1383     }
1384     if (!swipeToController_->IsStopped()) {
1385         swipeToController_->Stop();
1386     }
1387 
1388     InitSwipeToAnimation(start, end);
1389     AddSwipeToTranslateListener(fromIndex, toIndex);
1390     AddSwipeToOpacityListener(fromIndex, toIndex);
1391     AddSwipeToIndicatorListener(fromIndex, toIndex);
1392 
1393     // trigger the event after the animation ends.
1394     auto weak = AceType::WeakClaim(this);
1395     swipeToController_->AddStopListener([weak, fromIndex, toIndex]() {
1396         auto swiper = weak.Upgrade();
1397         if (swiper) {
1398             swiper->LoadLazyItems((fromIndex + 1) % swiper->itemCount_ == toIndex);
1399             swiper->isIndicatorAnimationStart_ = false;
1400             swiper->outItemIndex_ = fromIndex;
1401             swiper->currentIndex_ = toIndex;
1402             swiper->moveStatus_ = false;
1403             swiper->ResetScrollOffset();
1404             swiper->UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
1405             swiper->UpdateOneItemOpacity(MAX_OPACITY, fromIndex);
1406             swiper->UpdateOneItemOpacity(MAX_OPACITY, toIndex);
1407             swiper->RestoreAutoPlay();
1408             swiper->FireItemChangedEvent(true);
1409             swiper->ResetCachedChildren();
1410             swiper->MarkNeedLayout(true);
1411         }
1412     });
1413     swipeToController_->SetDuration(duration_);
1414     swipeToController_->AddInterpolator(curTranslateAnimation_);
1415     swipeToController_->AddInterpolator(targetTranslateAnimation_);
1416     swipeToController_->AddInterpolator(curOpacityAnimation_);
1417     swipeToController_->AddInterpolator(targetOpacityAnimation_);
1418     swipeToController_->AddInterpolator(indicatorAnimation_);
1419     swipeToController_->SetFillMode(FillMode::FORWARDS);
1420     swipeToController_->Play();
1421     isSwipeToAnimationAdded_ = true;
1422 }
1423 
RedoSwipeToAnimation(int32_t toIndex,bool reverse)1424 void RenderSwiper::RedoSwipeToAnimation(int32_t toIndex, bool reverse)
1425 {
1426     if (toIndex == targetIndex_) {
1427         // continue move animation
1428         return;
1429     }
1430     // stop animation before update item position, otherwise the
1431     // animation callback will change the item position
1432     FinishAllSwipeAnimation();
1433     DoSwipeToAnimation(currentIndex_, toIndex, false);
1434 }
1435 
StopSwipeToAnimation()1436 void RenderSwiper::StopSwipeToAnimation()
1437 {
1438     if (swipeToController_ && !swipeToController_->IsStopped()) {
1439         swipeToController_->ClearStopListeners();
1440         swipeToController_->Stop();
1441         UpdateOneItemOpacity(MAX_OPACITY, currentIndex_);
1442         UpdateOneItemOpacity(MAX_OPACITY, targetIndex_);
1443         isIndicatorAnimationStart_ = false;
1444     }
1445 }
1446 
UpdateItemOpacity(uint8_t opacity,int32_t index,int32_t otherIndex)1447 void RenderSwiper::UpdateItemOpacity(uint8_t opacity, int32_t index, int32_t otherIndex)
1448 {
1449     UpdateOneItemOpacity(opacity, index);
1450 
1451     int32_t preIndex = GetPrevIndex(index);
1452     if (preIndex != index && preIndex != otherIndex) {
1453         UpdateOneItemOpacity(opacity, preIndex);
1454     }
1455     int32_t nextIndex = GetNextIndex(index);
1456     if (nextIndex != index && nextIndex != otherIndex) {
1457         UpdateOneItemOpacity(opacity, nextIndex);
1458     }
1459 }
1460 
UpdateOneItemOpacity(uint8_t opacity,int32_t index)1461 void RenderSwiper::UpdateOneItemOpacity(uint8_t opacity, int32_t index)
1462 {
1463     if (!animationOpacity_) {
1464         return;
1465     }
1466     auto iter = items_.find(index);
1467     if (iter == items_.end()) {
1468         return;
1469     }
1470     auto display = AceType::DynamicCast<RenderDisplay>(iter->second);
1471     if (!display) {
1472         return;
1473     }
1474     display->UpdateOpacity(opacity);
1475 }
1476 
UpdateItemPosition(double offset,int32_t index,int32_t otherIndex)1477 void RenderSwiper::UpdateItemPosition(double offset, int32_t index, int32_t otherIndex)
1478 {
1479     auto iter = items_.find(index);
1480     if (iter != items_.end()) {
1481         iter->second->SetPosition(GetMainAxisOffset(offset));
1482     }
1483     int32_t prevIndex = GetPrevIndex(index);
1484     if (prevIndex != index && prevIndex != otherIndex) {
1485         auto item = items_.find(prevIndex);
1486         if (item != items_.end()) {
1487             item->second->SetPosition(GetMainAxisOffset(offset + (needReverse_ ? nextItemOffset_ : prevItemOffset_)));
1488         }
1489     }
1490     int32_t nextIndex = GetNextIndex(index);
1491     if (nextIndex != index && nextIndex != otherIndex) {
1492         auto item = items_.find(nextIndex);
1493         if (item != items_.end()) {
1494             item->second->SetPosition(GetMainAxisOffset(offset + (needReverse_ ? prevItemOffset_ : nextItemOffset_)));
1495         }
1496     }
1497     MarkNeedRender();
1498 }
1499 
GetPrevIndex() const1500 int32_t RenderSwiper::GetPrevIndex() const
1501 {
1502     return GetPrevIndex(currentIndex_);
1503 }
1504 
GetPrevIndexOnAnimation() const1505 int32_t RenderSwiper::GetPrevIndexOnAnimation() const
1506 {
1507     return GetPrevIndex(targetIndex_);
1508 }
1509 
GetPrevIndex(int32_t index) const1510 int32_t RenderSwiper::GetPrevIndex(int32_t index) const
1511 {
1512     return GetIndex(index, !needReverse_);
1513 }
1514 
GetNextIndex() const1515 int32_t RenderSwiper::GetNextIndex() const
1516 {
1517     return GetNextIndex(currentIndex_);
1518 }
1519 
GetNextIndexOnAnimation() const1520 int32_t RenderSwiper::GetNextIndexOnAnimation() const
1521 {
1522     return GetNextIndex(targetIndex_);
1523 }
1524 
GetNextIndex(int32_t index) const1525 int32_t RenderSwiper::GetNextIndex(int32_t index) const
1526 {
1527     return GetIndex(index, needReverse_);
1528 }
1529 
GetIndex(int32_t index,bool leftOrTop) const1530 int32_t RenderSwiper::GetIndex(int32_t index, bool leftOrTop) const
1531 {
1532     if (leftOrTop) {
1533         if (--index < 0) {
1534             index = loop_ ? itemCount_ - 1 : 0;
1535         }
1536     } else {
1537         if (++index >= itemCount_) {
1538             index = loop_ ? 0 : itemCount_ - 1;
1539         }
1540     }
1541     return index;
1542 }
1543 
ShowPrevious()1544 void RenderSwiper::ShowPrevious()
1545 {
1546     int32_t index = 0;
1547     if (isIndicatorAnimationStart_) {
1548         if (needReverse_) {
1549             index = GetNextIndexOnAnimation();
1550         } else {
1551             index = GetPrevIndexOnAnimation();
1552         }
1553         RedoSwipeToAnimation(index, false);
1554     } else {
1555         if (needReverse_) {
1556             index = GetNextIndex();
1557         } else {
1558             index = GetPrevIndex();
1559         }
1560 
1561         StopIndicatorSpringAnimation();
1562         DoSwipeToAnimation(currentIndex_, index, false);
1563     }
1564 }
1565 
ShowNext()1566 void RenderSwiper::ShowNext()
1567 {
1568     int32_t index = 0;
1569     if (isIndicatorAnimationStart_) {
1570         if (needReverse_) {
1571             index = GetPrevIndexOnAnimation();
1572         } else {
1573             index = GetNextIndexOnAnimation();
1574         }
1575         RedoSwipeToAnimation(index, false);
1576     } else {
1577         if (needReverse_) {
1578             index = GetPrevIndex();
1579         } else {
1580             index = GetNextIndex();
1581         }
1582         StopIndicatorSpringAnimation();
1583         DoSwipeToAnimation(currentIndex_, index, false);
1584     }
1585 }
1586 
OnFocus()1587 void RenderSwiper::OnFocus()
1588 {
1589     if (autoPlay_) {
1590         if (scheduler_) {
1591             scheduler_->Stop();
1592         }
1593         StopSwipeAnimation();
1594         StopSwipeToAnimation();
1595         StopIndicatorAnimation();
1596         StopIndicatorSpringAnimation();
1597         ResetIndicatorPosition();
1598     }
1599 }
1600 
OnBlur()1601 void RenderSwiper::OnBlur()
1602 {
1603     RestoreAutoPlay();
1604 }
1605 
RegisterChangeEndListener(int32_t listenerId,const SwiperChangeEndListener & listener)1606 void RenderSwiper::RegisterChangeEndListener(int32_t listenerId, const SwiperChangeEndListener& listener)
1607 {
1608     if (listener) {
1609         changeEndListeners_[listenerId] = listener;
1610     }
1611 }
1612 
UnRegisterChangeEndListener(int32_t listenerId)1613 void RenderSwiper::UnRegisterChangeEndListener(int32_t listenerId)
1614 {
1615     changeEndListeners_.erase(listenerId);
1616 }
1617 
UpdateScrollPosition(double dragDelta)1618 void RenderSwiper::UpdateScrollPosition(double dragDelta)
1619 {
1620     auto limitDelta = std::clamp(dragDelta, -MAX_VIEW_PORT_WIDTH, MAX_VIEW_PORT_WIDTH);
1621     double newDragOffset = scrollOffset_ + limitDelta;
1622     int32_t toIndex = newDragOffset > 0 ? GetPrevIndex() : GetNextIndex();
1623     if (toIndex < 0 || toIndex >= itemCount_) {
1624         return;
1625     }
1626     if (currentIndex_ == toIndex) {
1627         targetIndex_ = toIndex;
1628         nextIndex_ = toIndex;
1629         SetSwiperEffect(newDragOffset);
1630         return;
1631     }
1632 
1633     if (std::fabs(newDragOffset) >= std::fabs(nextItemOffset_)) {
1634         scrollOffset_ = (newDragOffset >= nextItemOffset_) ? newDragOffset - nextItemOffset_
1635                                                            : newDragOffset - prevItemOffset_;
1636         LoadLazyItems((currentIndex_ + 1) % itemCount_ == toIndex);
1637         outItemIndex_ = currentIndex_;
1638         currentIndex_ = toIndex;
1639         FireItemChangedEvent(true);
1640         ResetCachedChildren();
1641         UpdateOneItemOpacity(MAX_OPACITY, outItemIndex_);
1642         UpdateOneItemOpacity(MAX_OPACITY, currentIndex_);
1643         ExecuteMoveCallback(currentIndex_);
1644         ResetIndicatorPosition();
1645         MarkNeedLayout(true);
1646         // drag length is greater than swiper's width, don't need to move position
1647         return;
1648     }
1649 
1650     bool dragReverse = (newDragOffset * scrollOffset_) < 0.0;
1651     if (dragReverse) {
1652         int32_t lastToIndex = 0;
1653         double toItemPosValue = 0.0;
1654         lastToIndex = scrollOffset_ > 0 ? GetPrevIndex() : GetNextIndex();
1655         toItemPosValue = scrollOffset_ > 0 ? prevItemOffset_ : nextItemOffset_;
1656 
1657         auto iter = items_.find(lastToIndex);
1658         if (iter != items_.end()) {
1659             iter->second->SetPosition(GetMainAxisOffset(toItemPosValue));
1660         }
1661     }
1662 
1663     UpdateChildPosition(newDragOffset, currentIndex_);
1664     MoveIndicator(toIndex, newDragOffset);
1665 }
1666 
SetSwiperEffect(double dragOffset)1667 void RenderSwiper::SetSwiperEffect(double dragOffset)
1668 {
1669     EdgeEffect edgeEffect = swiper_->GetEdgeEffect();
1670     bool isFade = edgeEffect == EdgeEffect::FADE;
1671     bool isSpring = edgeEffect == EdgeEffect::SPRING;
1672     if (!isFade && !isSpring && !loop_) {
1673         return;
1674     }
1675 
1676     if ((isFade && currentIndex_ == 0 && GreatOrEqual(dragOffset, 0.0)) ||
1677         (isFade && (currentIndex_ == itemCount_ - 1) && LessOrEqual(dragOffset, 0.0))) {
1678         isPaintedFade_ = true;
1679         scrollOffset_ = dragOffset;
1680         dragDelta_ = dragOffset;
1681         MarkNeedRender();
1682     } else if (isSpring) {
1683         isPaintedFade_ = false;
1684         UpdateChildPosition(dragOffset, currentIndex_);
1685     }
1686 }
1687 
UpdateChildPosition(double offset,int32_t fromIndex,bool inLayout)1688 void RenderSwiper::UpdateChildPosition(double offset, int32_t fromIndex, bool inLayout)
1689 {
1690     if (itemCount_ <= 0) {
1691         return;
1692     }
1693     if (std::abs(currentIndex_ - fromIndex) == 1) {
1694         scrollOffset_ = offset + (currentIndex_ - fromIndex) * nextItemOffset_;
1695     } else { // for loop reversal
1696         if (fromIndex > currentIndex_) {
1697             scrollOffset_ = offset + nextItemOffset_;
1698         } else if (fromIndex < currentIndex_) {
1699             scrollOffset_ = offset - nextItemOffset_;
1700         } else {
1701             scrollOffset_ = offset;
1702         }
1703     }
1704     // move current item
1705     auto item = items_.find(fromIndex);
1706     if (item != items_.end() && !(RefuseUpdatePosition(fromIndex) && inLayout)) {
1707         item->second->SetPosition(GetMainAxisOffset(offset));
1708     }
1709 
1710     // calculate the num of prev item
1711     int32_t prevItemCount = 0;
1712     if (!loop_) {
1713         prevItemCount = needReverse_ ? (itemCount_ - 1 - fromIndex) : fromIndex;
1714     } else {
1715         prevItemCount = (offset + prevMargin_ + std::fabs(prevItemOffset_) - 1) / std::fabs(prevItemOffset_);
1716     }
1717     if (prevItemCount >= itemCount_ - 1) {
1718         prevItemCount = itemCount_ - 1;
1719     }
1720 
1721     // move prev item
1722     int32_t prevIndex = fromIndex;
1723     for (int32_t i = 0; i < prevItemCount; i++) {
1724         prevIndex = GetPrevIndex(prevIndex);
1725         if ((RefuseUpdatePosition(prevIndex) && inLayout) || (prevIndex == fromIndex)) {
1726             continue;
1727         }
1728         auto item = items_.find(prevIndex);
1729         if (item != items_.end()) {
1730             item->second->SetPosition(
1731                 GetMainAxisOffset(offset + (needReverse_ ? (i + 1) * nextItemOffset_ : (i + 1) * prevItemOffset_)));
1732         }
1733     }
1734 
1735     // calculate the num of next item
1736     int32_t maxNextItemCount = itemCount_ - 1 - prevItemCount;
1737     int32_t nextItemCount = 0;
1738     if (inLayout) {
1739         nextItemCount = maxNextItemCount;
1740     } else {
1741         double maxLength = (axis_ == Axis::HORIZONTAL ? GetLayoutSize().Width() : GetLayoutSize().Height());
1742 
1743         nextItemCount =
1744             (maxLength - offset - prevMargin_ + std::fabs(prevItemOffset_) - 1) / std::fabs(prevItemOffset_);
1745         if (nextItemCount > maxNextItemCount) {
1746             nextItemCount = maxNextItemCount;
1747         }
1748     }
1749 
1750     // move next item
1751     int32_t nextIndex = fromIndex;
1752     for (int32_t i = 0; i < nextItemCount; i++) {
1753         nextIndex = GetNextIndex(nextIndex);
1754         if ((RefuseUpdatePosition(nextIndex) && inLayout) || (nextIndex == fromIndex)) {
1755             continue;
1756         }
1757         auto item = items_.find(nextIndex);
1758         if (item != items_.end()) {
1759             item->second->SetPosition(
1760                 GetMainAxisOffset(offset + (needReverse_ ? (i + 1) * prevItemOffset_ : (i + 1) * nextItemOffset_)));
1761         }
1762     }
1763 
1764     MarkNeedRender();
1765 }
1766 
Tick(uint64_t duration)1767 void RenderSwiper::Tick(uint64_t duration)
1768 {
1769     elapsedTime_ += duration;
1770     if (elapsedTime_ >= autoPlayInterval_) {
1771         if (currentIndex_ >= itemCount_ - 1 && !loop_) {
1772             if (scheduler_) {
1773                 scheduler_->Stop();
1774             }
1775         } else {
1776             if (swiperIndicatorData_.isPressed) {
1777                 // end drag operations on autoplay.
1778                 DragIndicatorEnd();
1779             }
1780             if (swiperIndicatorData_.isHovered) {
1781                 ResetHoverZoomDot();
1782                 StartZoomOutAnimation(true);
1783             }
1784             int32_t nextIndex = 0;
1785             if (needReverse_) {
1786                 nextIndex = GetPrevIndex();
1787             } else {
1788                 nextIndex = GetNextIndex();
1789             }
1790             StartIndicatorAnimation(currentIndex_, nextIndex, currentIndex_ > nextIndex);
1791         }
1792         elapsedTime_ = 0;
1793     }
1794 }
1795 
OnHiddenChanged(bool hidden)1796 void RenderSwiper::OnHiddenChanged(bool hidden)
1797 {
1798     if (hidden) {
1799         if (autoPlay_) {
1800             if (scheduler_) {
1801                 scheduler_->Stop();
1802             }
1803             StopSwipeAnimation();
1804         }
1805     } else {
1806         RestoreAutoPlay();
1807     }
1808 }
1809 
OnRotation(const RotationEvent & event)1810 bool RenderSwiper::OnRotation(const RotationEvent& event)
1811 {
1812     if (disableRotation_) {
1813         return false;
1814     }
1815     if (itemCount_ < LEAST_SLIDE_ITEM_COUNT) {
1816         LOGI("Rotation is not enabled when count is 1");
1817         return false;
1818     }
1819     // Clockwise rotation switches to the next one, counterclockwise rotation switches to the previous one.
1820     auto context = GetContext().Upgrade();
1821     if (!context) {
1822         LOGE("context is null!");
1823         return false;
1824     }
1825     double deltaPx = context->NormalizeToPx(Dimension(event.value, DimensionUnit::VP)) * ROTATION_SENSITIVITY_NORMAL;
1826     switch (rotationStatus_) {
1827         case RotationStatus::ROTATION_START:
1828         case RotationStatus::ROTATION_UPDATE:
1829             rotationStatus_ = RotationStatus::ROTATION_UPDATE;
1830             HandleRotationUpdate(deltaPx);
1831             break;
1832         case RotationStatus::ROTATION_END:
1833         default:
1834             rotationStatus_ = RotationStatus::ROTATION_START;
1835             HandleRotationStart();
1836     }
1837     ResetRotationEndListener();
1838     return true;
1839 }
1840 
OnStatusChanged(RenderStatus renderStatus)1841 void RenderSwiper::OnStatusChanged(RenderStatus renderStatus)
1842 {
1843     if (renderStatus == RenderStatus::FOCUS) {
1844         onFocus_ = true;
1845     } else if (renderStatus == RenderStatus::BLUR) {
1846         onFocus_ = false;
1847     }
1848 }
1849 
GetValidEdgeLength(double swiperLength,double indicatorLength,const Dimension & edge) const1850 double RenderSwiper::GetValidEdgeLength(double swiperLength, double indicatorLength, const Dimension& edge) const
1851 {
1852     double edgeLength = edge.Unit() == DimensionUnit::PERCENT ? swiperLength * edge.Value() : NormalizeToPx(edge);
1853     if (!NearZero(edgeLength) && edgeLength > swiperLength - indicatorLength) {
1854         edgeLength = swiperLength - indicatorLength;
1855     }
1856     if (edgeLength < 0.0) {
1857         edgeLength = 0.0;
1858     }
1859     return edgeLength;
1860 }
1861 
GetIndicatorCurrentRect(SwiperIndicatorData & indicatorData)1862 void RenderSwiper::GetIndicatorCurrentRect(SwiperIndicatorData& indicatorData)
1863 {
1864     if (!indicator_) {
1865         indicatorRect_ = Rect();
1866         return;
1867     }
1868     Offset offset = indicatorPosition_ + GetGlobalOffset();
1869     Size size = Size(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
1870     indicatorRect_ = Rect(offset, size);
1871 }
1872 
GetIndicatorWidth(SwiperIndicatorData & indicatorData)1873 double RenderSwiper::GetIndicatorWidth(SwiperIndicatorData& indicatorData)
1874 {
1875     double indicatorWidth = 0.0;
1876     double lastItemEdge = 0.0;
1877 
1878     if (currentHoverIndex_ == itemCount_ - 1) {
1879         double deltaPadding = 0.0;
1880         if (axis_ == Axis::HORIZONTAL) {
1881             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetX() +
1882                            NormalizeToPx(indicator_->GetPressSize()) / 2;
1883         } else {
1884             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetY() +
1885                            NormalizeToPx(indicator_->GetPressSize()) / 2;
1886         }
1887         if (currentIndex_ == itemCount_ - 1) {
1888             deltaPadding = NormalizeToPx(indicator_->GetPressSize()) / 2;
1889         }
1890         indicatorWidth = lastItemEdge + indicatorData.startEndPadding + deltaPadding;
1891     } else {
1892         if (axis_ == Axis::HORIZONTAL) {
1893             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetX() +
1894                            indicatorData.indicatorItemData[itemCount_ - 1].width / 2;
1895         } else {
1896             lastItemEdge = indicatorData.indicatorItemData[itemCount_ - 1].center.GetY() +
1897                            indicatorData.indicatorItemData[itemCount_ - 1].height / 2;
1898         }
1899         indicatorWidth = lastItemEdge + indicatorData.startEndPadding;
1900     }
1901     return indicatorWidth;
1902 }
1903 
LayoutIndicator(SwiperIndicatorData & indicatorData)1904 void RenderSwiper::LayoutIndicator(SwiperIndicatorData& indicatorData)
1905 {
1906     if (!indicator_) {
1907         return;
1908     }
1909 
1910     // calc real hot zone size by zoom and stretch
1911     if (NearZero(hotZoneMaxSize_) || NearZero(hotZoneMinSize_)) {
1912         hotZoneMaxSize_ = NormalizeToPx((indicator_->GetHotZoneSize()));
1913         hotZoneMinSize_ = hotZoneMaxSize_ / ZOOM_HOTZONE_MAX_RATE;
1914     }
1915     hotZoneRealSize_ = hotZoneMinSize_ + (hotZoneMaxSize_ - hotZoneMinSize_) * zoomValue_;
1916     hotZoneRealSize_ *= heightStretchRate_;
1917 
1918     // update indicator item paint data;
1919     indicatorData.isDigital = digitalIndicator_;
1920     if (!digitalIndicator_) {
1921         UpdateIndicatorItem(indicatorData);
1922     }
1923 
1924     // update Indicator paint data
1925     if (digitalIndicator_) {
1926         LayoutDigitalIndicator(indicatorData);
1927         Size digitalIndicatorSize = indicatorData.textBoxRender->GetLayoutSize();
1928         indicatorData.indicatorPaintData.width = digitalIndicatorSize.Width();
1929         indicatorData.indicatorPaintData.height = digitalIndicatorSize.Height();
1930     } else {
1931         if (axis_ == Axis::HORIZONTAL) {
1932             indicatorData.indicatorPaintData.width = GetIndicatorWidth(indicatorData);
1933             indicatorData.indicatorPaintData.height = hotZoneRealSize_; // influenced on zoom and stretch
1934         } else {
1935             indicatorData.indicatorPaintData.width = hotZoneRealSize_; // influenced on zoom and stretch
1936             indicatorData.indicatorPaintData.height = GetIndicatorWidth(indicatorData);
1937         }
1938     }
1939     indicatorData.indicatorPaintData.radius = hotZoneRealSize_ / 2; // influenced on zoom and stretch
1940     if (!digitalIndicator_ && (indicatorData.isHovered || indicatorData.isPressed)) {
1941         indicatorData.indicatorPaintData.color = indicator_->GetHotZoneColor();
1942     } else {
1943         indicatorData.indicatorPaintData.color = Color::WHITE;
1944     }
1945 
1946     // update position
1947     UpdateIndicatorPosition(indicatorData);
1948 }
1949 
InitDigitalIndicator(SwiperIndicatorData & indicatorData)1950 void RenderSwiper::InitDigitalIndicator(SwiperIndicatorData& indicatorData)
1951 {
1952     auto textBoxComponent = AceType::MakeRefPtr<BoxComponent>();
1953     double padding = NormalizeToPx(INDICATOR_DIGITAL_PADDING);
1954     Edge margin = (axis_ == Axis::HORIZONTAL) ?
1955                   Edge(padding, 0, padding, 0, DimensionUnit::PX) :
1956                   Edge(0, padding, 0, padding, DimensionUnit::PX);
1957     textBoxComponent->SetPadding(margin);
1958     indicatorData.textBoxRender = AceType::DynamicCast<RenderBox>(textBoxComponent->CreateRenderNode());
1959     indicatorData.textBoxRender->Attach(GetContext());
1960 
1961     // add flex
1962     FlexDirection direction = axis_ == Axis::HORIZONTAL ? FlexDirection::ROW : FlexDirection::COLUMN;
1963     indicatorData.flexComponent = AceType::MakeRefPtr<FlexComponent>(direction,
1964         FlexAlign::FLEX_END, FlexAlign::CENTER, std::list<RefPtr<Component>>());
1965     indicatorData.flexComponent->SetMainAxisSize(MainAxisSize::MIN);
1966     indicatorData.flexRender = AceType::DynamicCast<RenderFlex>(indicatorData.flexComponent->CreateRenderNode());
1967     indicatorData.textBoxRender->AddChild(indicatorData.flexRender);
1968     indicatorData.flexRender->Attach(GetContext());
1969     indicatorData.flexRender->Update(indicatorData.flexComponent);
1970 
1971     // add text
1972     indicatorData.textComponentPrev = AceType::MakeRefPtr<TextComponent>("");
1973     indicatorData.textRenderPrev = AceType::DynamicCast<RenderText>(
1974         indicatorData.textComponentPrev->CreateRenderNode());
1975     indicatorData.flexRender->AddChild(indicatorData.textRenderPrev);
1976     indicatorData.textRenderPrev->Attach(GetContext());
1977     indicatorData.textRenderPrev->Update(indicatorData.textComponentPrev);
1978 
1979     indicatorData.textComponentNext = AceType::MakeRefPtr<TextComponent>("");
1980     indicatorData.textRenderNext = AceType::DynamicCast<RenderText>(
1981         indicatorData.textComponentNext->CreateRenderNode());
1982     indicatorData.flexRender->AddChild(indicatorData.textRenderNext);
1983     indicatorData.textRenderNext->Attach(GetContext());
1984     indicatorData.textRenderNext->Update(indicatorData.textComponentNext);
1985 
1986     indicatorData.textBoxRender->Update(textBoxComponent);
1987 }
1988 
LayoutDigitalIndicator(SwiperIndicatorData & indicatorData)1989 void RenderSwiper::LayoutDigitalIndicator(SwiperIndicatorData& indicatorData)
1990 {
1991     InitDigitalIndicator(indicatorData);
1992 
1993     auto textStyle = indicator_->GetDigitalIndicatorTextStyle();
1994     Color normalTextColor = textStyle.GetTextColor();
1995     // update text prev
1996     std::string indicatorTextPrev = std::to_string(currentIndex_ + 1);
1997     if (indicatorIsFocus_) {
1998         textStyle.SetTextColor(indicator_->GetIndicatorTextFocusColor());
1999     } else {
2000         textStyle.SetTextColor(normalTextColor);
2001     }
2002     indicatorData.textComponentPrev->SetTextStyle(textStyle);
2003     indicatorData.textComponentPrev->SetData(indicatorTextPrev);
2004     indicatorData.textRenderPrev->Update(indicatorData.textComponentPrev);
2005 
2006     // update text next
2007     std::string indicatorTextNext = (axis_ == Axis::HORIZONTAL) ? std::string("/").append(std::to_string(itemCount_))
2008         : std::string("/\n").append(std::to_string(itemCount_));
2009     textStyle.SetTextColor(normalTextColor);
2010     indicatorData.textComponentNext->SetTextStyle(textStyle);
2011     indicatorData.textComponentNext->SetData(indicatorTextNext);
2012     indicatorData.textRenderNext->Update(indicatorData.textComponentNext);
2013 
2014     // update text box
2015     auto decoration = AceType::MakeRefPtr<Decoration>();
2016     decoration->SetBackgroundColor(Color::TRANSPARENT);
2017     Border border;
2018     border.SetBorderRadius(Radius(indicator_->GetHotZoneSize() / 2.0));
2019     decoration->SetBorder(border);
2020     indicatorData.textBoxRender->SetBackDecoration(decoration);
2021     if (axis_ == Axis::HORIZONTAL) {
2022         indicatorData.textBoxRender->SetHeight(NormalizeToPx(indicator_->GetHotZoneSize()));
2023     } else {
2024         indicatorData.textBoxRender->SetWidth(NormalizeToPx(indicator_->GetHotZoneSize()));
2025     }
2026 
2027     LayoutParam innerLayout;
2028     innerLayout.SetMaxSize(Size(swiperWidth_, swiperHeight_));
2029     indicatorData.textBoxRender->Layout(innerLayout);
2030 }
2031 
UpdateIndicatorPosition(SwiperIndicatorData & indicatorData)2032 void RenderSwiper::UpdateIndicatorPosition(SwiperIndicatorData& indicatorData)
2033 {
2034     Offset position;
2035     double indicatorWidth = indicatorData.indicatorPaintData.width;
2036     double indicatorHeight = indicatorData.indicatorPaintData.height;
2037     double stableOffset = NormalizeToPx(INDICATOR_PADDING_TOP_DEFAULT) + (hotZoneMaxSize_ + hotZoneRealSize_) * 0.5;
2038     auto layoutSize = GetLayoutSize();
2039 
2040     if (indicator_->GetLeft().Value() != SwiperIndicator::DEFAULT_POSITION) {
2041         int32_t left = GetValidEdgeLength(swiperWidth_, indicatorWidth, indicator_->GetLeft());
2042         swiperLeft_ = indicator_->GetLeft();
2043         position.SetX(left);
2044     } else if (indicator_->GetRight().Value() != SwiperIndicator::DEFAULT_POSITION) {
2045         int32_t right = GetValidEdgeLength(swiperWidth_, indicatorWidth, indicator_->GetRight());
2046         swiperRight_ = indicator_->GetRight();
2047         position.SetX(swiperWidth_ - indicatorWidth - right);
2048     } else {
2049         if (axis_ == Axis::HORIZONTAL) {
2050             position.SetX((layoutSize.Width() - indicatorWidth) / 2.0);
2051         } else {
2052             // horizontal line of indicator zone is stable.
2053             double currentX = swiperWidth_ - stableOffset;
2054             position.SetX(currentX);
2055         }
2056     }
2057 
2058     if (indicator_->GetTop().Value() != SwiperIndicator::DEFAULT_POSITION) {
2059         int32_t top = GetValidEdgeLength(swiperHeight_, indicatorHeight, indicator_->GetTop());
2060         swiperTop_ = indicator_->GetTop();
2061         position.SetY(top);
2062     } else if (indicator_->GetBottom().Value() != SwiperIndicator::DEFAULT_POSITION) {
2063         int32_t bottom = GetValidEdgeLength(swiperHeight_, indicatorHeight, indicator_->GetBottom());
2064         swiperBottom_ = indicator_->GetBottom();
2065         position.SetY(swiperHeight_ - indicatorHeight - bottom);
2066     } else {
2067         if (axis_ == Axis::HORIZONTAL) {
2068             // horizontal line of indicator zone is stable.
2069             double currentY = swiperHeight_ - stableOffset;
2070             position.SetY(currentY);
2071         } else {
2072             position.SetY((layoutSize.Height() - indicatorHeight) / 2.0);
2073         }
2074     }
2075 
2076     // update position on stretch or retract indicator zone
2077     UpdatePositionOnStretch(position, indicatorData);
2078 
2079     // update position
2080     if (digitalIndicator_ && indicatorData.flexRender) {
2081         indicatorData.flexRender->SetPaintRect(indicatorData.flexRender->GetPaintRect() + position);
2082     }
2083     indicatorPosition_ = position;
2084     indicatorData.indicatorPaintData.position = position;
2085     indicatorData.indicatorPaintData.center = position + Offset(indicatorData.indicatorPaintData.width / 2,
2086         indicatorData.indicatorPaintData.height / 2);
2087 }
2088 
UpdateIndicatorItem(SwiperIndicatorData & indicatorData)2089 void RenderSwiper::UpdateIndicatorItem(SwiperIndicatorData& indicatorData)
2090 {
2091     // horizontal line of indicator zone is stable
2092     double hotZoneCenterPadding = hotZoneRealSize_ / 2.0;
2093     if (indicatorData.isHovered || indicatorData.isPressed) {
2094         indicatorData.startEndPadding = NormalizeToPx(indicator_->GetStartEndPadding() +
2095             (indicator_->GetPressPadding() - indicator_->GetStartEndPadding()) * zoomValue_);
2096     } else {
2097         indicatorData.startEndPadding = NormalizeToPx(indicator_->GetStartEndPadding());
2098     }
2099     Offset startCenterOffset = axis_ == Axis::HORIZONTAL ? Offset(indicatorData.startEndPadding, hotZoneCenterPadding) :
2100         Offset(hotZoneCenterPadding, indicatorData.startEndPadding);
2101     Offset centerOffset = startCenterOffset;
2102 
2103     double targetIndex = currentIndex_;
2104     double hoverIndex = currentHoverIndex_;
2105     if (needReverse_) {
2106         targetIndex = itemCount_ - currentIndex_ - 1;
2107     }
2108 
2109     double itemRadius = 0.0;
2110     for (int32_t i = 0; i < itemCount_; ++i) {
2111         swiperSize_ = indicator_->GetSize();
2112         bool isZoomInBackground = indicatorData.isHovered || indicatorData.isPressed;
2113         if (isZoomInBackground) {
2114             // indicator radius and point padding is dynamic changed on zoom and stretch
2115             itemRadius = NormalizeToPx(
2116                 indicator_->GetSize() + (indicator_->GetPressSize() - indicator_->GetSize()) * zoomValue_) / 2.0;
2117             indicatorData.pointPadding = NormalizeToPx(indicator_->GetIndicatorPointPadding() +
2118                 (indicator_->GetPressPointPadding() - indicator_->GetIndicatorPointPadding()) *
2119                 zoomValue_) * widthStretchRate_;
2120         } else {
2121             itemRadius = NormalizeToPx(indicator_->GetSize()) / 2.0;
2122             indicatorData.pointPadding = NormalizeToPx(indicator_->GetIndicatorPointPadding());
2123         }
2124 
2125         double itemStartEndPadding = 0.0;
2126         if (i == targetIndex) {
2127             itemStartEndPadding = itemRadius * 2;
2128             indicatorData.indicatorItemData[i].color = indicator_->GetSelectedColor();
2129             selectedColors_ = indicator_->GetSelectedColor();
2130         } else {
2131             itemStartEndPadding = itemRadius;
2132             indicatorData.indicatorItemData[i].color = indicator_->GetColor();
2133             colors_ = indicator_->GetColor();
2134         }
2135         Offset paddingStartOffset;
2136         Offset paddingEndOffset;
2137         if (axis_ == Axis::HORIZONTAL) {
2138             paddingStartOffset = Offset(itemStartEndPadding, 0);
2139             paddingEndOffset = Offset(itemStartEndPadding + indicatorData.pointPadding, 0);
2140         } else {
2141             paddingStartOffset = Offset(0, itemStartEndPadding);
2142             paddingEndOffset = Offset(0, itemStartEndPadding + indicatorData.pointPadding);
2143         }
2144 
2145         // update mouse hover radius
2146         if (isZoomInBackground && i == hoverIndex) {
2147             // point radius is dynamic changed on mouse hover
2148             itemRadius = NormalizeToPx(indicator_->GetPressSize() +
2149                                        (indicator_->GetHoverSize() - indicator_->GetPressSize()) * zoomDotValue_) / 2.0;
2150         }
2151         if (axis_ == Axis::HORIZONTAL) {
2152             indicatorData.indicatorItemData[i].height = itemRadius * SIZE_RATIO_NORMAL;
2153             indicatorData.indicatorItemData[i].width =
2154                 (i == targetIndex ? itemRadius * SIZE_RATIO_LARGE : itemRadius * SIZE_RATIO_NORMAL);
2155         } else {
2156             indicatorData.indicatorItemData[i].width = itemRadius * SIZE_RATIO_NORMAL;
2157             indicatorData.indicatorItemData[i].height =
2158                 (i == targetIndex ? itemRadius * SIZE_RATIO_LARGE : itemRadius * SIZE_RATIO_NORMAL);
2159         }
2160         indicatorData.indicatorItemData[i].radius = itemRadius;
2161 
2162         centerOffset += paddingStartOffset;
2163         indicatorData.indicatorItemData[i].center = centerOffset;
2164         indicatorData.indicatorItemData[i].position = centerOffset -
2165             Offset(indicatorData.indicatorItemData[i].width / SIZE_RATIO_NORMAL,
2166                 indicatorData.indicatorItemData[i].height / SIZE_RATIO_NORMAL);
2167         centerOffset += paddingEndOffset;
2168     }
2169 }
2170 
UpdatePositionOnStretch(Offset & position,const SwiperIndicatorData & indicatorData)2171 void RenderSwiper::UpdatePositionOnStretch(Offset& position, const SwiperIndicatorData& indicatorData)
2172 {
2173     double indicatorWidth = indicatorData.indicatorPaintData.width;
2174     double indicatorHeight = indicatorData.indicatorPaintData.height;
2175     if (widthStretchRate_ > DRAG_STRETCH_BASE_WIDTH) {
2176         if (zoomValue_ == ZOOM_MAX) {
2177             // stretch indicator and update start position
2178             if (axis_ == Axis::HORIZONTAL) {
2179                 auto currentIndex = needReverse_ ? (itemCount_ - currentIndex_ - 1) : currentIndex_;
2180                 if (currentIndex == itemCount_ - 1) {
2181                     position.SetX(indicatorZoomMaxPositionLT_.GetX());
2182                 } else if (currentIndex == 0) {
2183                     position.SetX(indicatorZoomMaxPositionRB_.GetX() - indicatorData.indicatorPaintData.width);
2184                 }
2185             } else {
2186                 if (currentIndex_ == itemCount_ - 1) {
2187                     position.SetY(indicatorZoomMaxPositionLT_.GetY());
2188                 } else if (currentIndex_ == 0) {
2189                     position.SetY(indicatorZoomMaxPositionRB_.GetY() - indicatorData.indicatorPaintData.height);
2190                 }
2191             }
2192         } else if (zoomValue_ > ZOOM_MIN) {
2193             // restract indicator and update start position
2194             if (axis_ == Axis::HORIZONTAL) {
2195                 auto currentIndex = needReverse_ ? (itemCount_ - currentIndex_ - 1) : currentIndex_;
2196                 if (currentIndex == itemCount_ - 1) {
2197                     position.SetX(indicatorZoomMinPositionLT_.GetX() -
2198                         (indicatorZoomMinPositionLT_.GetX() - indicatorZoomMaxPositionLT_.GetX()) * zoomValue_);
2199                 } else if (currentIndex == 0) {
2200                     position.SetX(indicatorZoomMinPositionRB_.GetX() - indicatorWidth +
2201                         (indicatorZoomMaxPositionRB_.GetX() - indicatorZoomMinPositionRB_.GetX()) * zoomValue_);
2202                 }
2203             } else {
2204                 if (currentIndex_ == itemCount_ - 1) {
2205                     position.SetY(indicatorZoomMinPositionLT_.GetY() -
2206                         (indicatorZoomMinPositionLT_.GetY() - indicatorZoomMaxPositionLT_.GetY()) * zoomValue_);
2207                 } else if (currentIndex_ == 0) {
2208                     position.SetY(indicatorZoomMinPositionRB_.GetY() - indicatorHeight +
2209                         (indicatorZoomMaxPositionRB_.GetY() - indicatorZoomMinPositionRB_.GetY()) * zoomValue_);
2210                 }
2211             }
2212         }
2213     }
2214 }
2215 
IndicatorSwipePrev()2216 void RenderSwiper::IndicatorSwipePrev()
2217 {
2218     auto toIndex = GetPrevIndex();
2219     StartIndicatorAnimation(currentIndex_, toIndex, currentIndex_ == 0);
2220 }
2221 
IndicatorSwipeNext()2222 void RenderSwiper::IndicatorSwipeNext()
2223 {
2224     auto toIndex = GetNextIndex();
2225     StartIndicatorAnimation(currentIndex_, toIndex, currentIndex_ == itemCount_ - 1);
2226 }
2227 
HandleMouseEvent(const MouseEvent & event)2228 bool RenderSwiper::HandleMouseEvent(const MouseEvent& event)
2229 {
2230     const Point point { event.x, event.y};
2231     MouseHoverTest(point);
2232     return false;
2233 }
2234 
MouseHoverTest(const Point & parentLocalPoint)2235 bool RenderSwiper::MouseHoverTest(const Point& parentLocalPoint)
2236 {
2237     auto context = context_.Upgrade();
2238     if (!context) {
2239         return false;
2240     }
2241     const auto localPoint = parentLocalPoint - GetPosition();
2242     const auto& children = GetChildren();
2243     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
2244         auto& child = *iter;
2245         child->MouseHoverTest(localPoint);
2246     }
2247     bool isInRegion = InTouchRectList(parentLocalPoint, GetTouchRectList());
2248     if (isInRegion) {
2249         context->AddToHoverList(AceType::WeakClaim(this).Upgrade());
2250     }
2251 
2252     // swiper indicator mouse hover
2253     if (!indicator_) {
2254         return isInRegion;
2255     }
2256     // indicator zone zoom animation should wait for indicator moving animation finished
2257     if (isIndicatorAnimationStart_) {
2258         return isInRegion;
2259     }
2260 
2261     // get absolute position
2262     Point hoverPoint = parentLocalPoint;
2263     GetIndicatorCurrentRect(swiperIndicatorData_);
2264     if (indicatorRect_.IsInRegion(hoverPoint)) {
2265         if (autoPlay_ && scheduler_ && scheduler_->IsActive()) {
2266             // forbid indicator operation on auto play period.
2267             return isInRegion;
2268         }
2269         if ((!swiperIndicatorData_.isHovered && !swiperIndicatorData_.isPressed) || !IsZoomOutAnimationStopped()) {
2270             // hover animation
2271             swiperIndicatorData_.isHovered = true;
2272             StartZoomInAnimation(true);
2273             return isInRegion;
2274         }
2275         // point zoom after indicator zone zoom.
2276         if (!IsZoomAnimationStopped()) {
2277             return isInRegion;
2278         }
2279         for (int32_t i = 0; i < itemCount_; i++) {
2280             Offset offset = swiperIndicatorData_.indicatorItemData[i].position + indicatorRect_.GetOffset();
2281             Size size = Size(swiperIndicatorData_.indicatorItemData[i].width,
2282                 swiperIndicatorData_.indicatorItemData[i].height);
2283             Rect itemRect = Rect(offset, size);
2284             if (itemRect.IsInRegion(hoverPoint)) {
2285                 if (currentHoverIndex_ != i) {
2286                     StartZoomInDotAnimation(i);
2287                 }
2288                 return isInRegion;
2289             }
2290         }
2291         if (currentHoverIndex_ != INDICATOR_INVALID_HOVER_INDEX && IsZoomOutDotAnimationStopped()) {
2292             StartZoomOutDotAnimation();
2293         }
2294     } else {
2295         if (swiperIndicatorData_.isHovered) {
2296             ResetHoverZoomDot();
2297             StartZoomOutAnimation(true);
2298         }
2299     }
2300     return isInRegion;
2301 }
2302 
IndicatorShowFocus(bool isFocus)2303 void RenderSwiper::IndicatorShowFocus(bool isFocus)
2304 {
2305     if (!indicator_) {
2306         return;
2307     }
2308     indicatorIsFocus_ = isFocus;
2309     auto context = context_.Upgrade();
2310     if (!context) {
2311         return;
2312     }
2313     Offset offset = swiperIndicatorData_.indicatorPaintData.position;
2314     Size size = Size(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
2315     Offset globalOffset = swiperIndicatorData_.indicatorPaintData.position + GetGlobalOffset();
2316     double radius = swiperIndicatorData_.indicatorPaintData.radius;
2317     if (isFocus) {
2318         offset += Offset(NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET), NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET));
2319         size -= Size(NormalizeToPx(INDICATOR_FOCUS_DEL_SIZE), NormalizeToPx(INDICATOR_FOCUS_DEL_SIZE));
2320         globalOffset += Offset(NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET), NormalizeToPx(INDICATOR_FOCUS_DEL_OFFSET));
2321         Radius focusRadius = Radius(radius) - Radius(NormalizeToPx(INDICATOR_FOCUS_RADIUS_DEL_SIZE));
2322         context->ShowFocusAnimation(RRect::MakeRRect(Rect(offset, size), focusRadius), Color(INDICATOR_FOCUS_COLOR),
2323             globalOffset);
2324     } else {
2325         context->CancelFocusAnimation();
2326     }
2327     MarkNeedLayout();
2328 }
2329 
UpdateIndicatorFocus(bool isFocus,bool reverse)2330 void RenderSwiper::UpdateIndicatorFocus(bool isFocus, bool reverse)
2331 {
2332     if (reverse) {
2333         IndicatorSwipePrev();
2334     } else {
2335         IndicatorSwipeNext();
2336     }
2337     IndicatorShowFocus(isFocus);
2338 }
2339 
VibrateIndicator()2340 void RenderSwiper::VibrateIndicator()
2341 {
2342     auto context = context_.Upgrade();
2343     if (!context) {
2344         LOGW("GetVibrator fail, context is null");
2345         return;
2346     }
2347 
2348     if (!vibrator_) {
2349         vibrator_ = VibratorProxy::GetInstance().GetVibrator(context->GetTaskExecutor());
2350     }
2351     if (vibrator_) {
2352         vibrator_->Vibrate(VIBRATE_DURATION);
2353     } else {
2354         LOGW("GetVibrator fail");
2355     }
2356 }
2357 
UpdateIndicatorSpringStatus(SpringStatus status)2358 void RenderSwiper::UpdateIndicatorSpringStatus(SpringStatus status)
2359 {
2360     if (indicatorSpringStatus_ == SpringStatus::SPRING_STOP &&
2361         status == SpringStatus::FOCUS_SWITCH) {
2362         return;
2363     }
2364     indicatorSpringStatus_ = status;
2365 }
2366 
GetIndicatorSpringStatus() const2367 SpringStatus RenderSwiper::GetIndicatorSpringStatus() const
2368 {
2369     return indicatorSpringStatus_;
2370 }
2371 
ResetIndicatorSpringStatus()2372 void RenderSwiper::ResetIndicatorSpringStatus()
2373 {
2374     if (GetIndicatorSpringStatus() == SpringStatus::FOCUS_SWITCH) {
2375         UpdateIndicatorTailPosition(DRAG_OFFSET_MIN, DRAG_OFFSET_MIN);
2376     }
2377     UpdateIndicatorSpringStatus(SpringStatus::SPRING_STOP);
2378 }
2379 
ResetIndicatorPosition()2380 void RenderSwiper::ResetIndicatorPosition()
2381 {
2382     UpdateIndicatorHeadPosition(DRAG_OFFSET_MIN);
2383     UpdateIndicatorTailPosition(DRAG_OFFSET_MIN);
2384     UpdateIndicatorPointPosition(DRAG_OFFSET_MIN);
2385 }
2386 
ResetHoverZoomDot()2387 void RenderSwiper::ResetHoverZoomDot()
2388 {
2389     StopZoomDotAnimation();
2390     UpdateZoomDotValue(ZOOM_DOT_MIN);
2391     currentHoverIndex_ = INDICATOR_INVALID_HOVER_INDEX;
2392 }
2393 
MarkIndicatorPosition(bool isZoomMax)2394 void RenderSwiper::MarkIndicatorPosition(bool isZoomMax)
2395 {
2396     if (isZoomMax) {
2397         indicatorZoomMaxPositionLT_ = indicatorPosition_;
2398         indicatorZoomMaxPositionRB_ = indicatorZoomMaxPositionLT_ +
2399             Offset(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
2400     } else {
2401         indicatorZoomMinPositionLT_ = indicatorPosition_;
2402         indicatorZoomMinPositionRB_ = indicatorZoomMinPositionLT_ +
2403             Offset(swiperIndicatorData_.indicatorPaintData.width, swiperIndicatorData_.indicatorPaintData.height);
2404     }
2405 }
2406 
StartIndicatorSpringAnimation(double start,double end)2407 void RenderSwiper::StartIndicatorSpringAnimation(double start, double end)
2408 {
2409     if (!springController_) {
2410         return;
2411     }
2412     UpdateIndicatorSpringStatus(SpringStatus::SPRING_START);
2413     double dampInc = std::fabs(currentIndex_ - targetIndex_) * SPRING_DAMP_INC;
2414     auto springDescription = AceType::MakeRefPtr<SpringProperty>(SPRING_MASS, SPRING_STIFF, SPRING_DAMP + dampInc);
2415     if (!indicatorSpringMotion_) {
2416         indicatorSpringMotion_ = AceType::MakeRefPtr<SpringMotion>(start, end, 0.0, springDescription);
2417     } else {
2418         indicatorSpringMotion_->Reset(start, end, 0.0, springDescription);
2419     }
2420 
2421     indicatorSpringMotion_->ClearListeners();
2422     indicatorSpringMotion_->AddListener([weak = AceType::WeakClaim(this), end](double position) {
2423         auto swiper = weak.Upgrade();
2424         if (swiper) {
2425             double offset = position;
2426             double switchOffset = position - end;
2427             swiper->UpdateIndicatorTailPosition(offset, switchOffset);
2428         }
2429     });
2430 
2431     springController_->PlayMotion(indicatorSpringMotion_);
2432     springController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
2433         auto swiper = weak.Upgrade();
2434         if (swiper) {
2435             swiper->UpdateIndicatorSpringStatus(SpringStatus::SPRING_STOP);
2436             swiper->UpdateIndicatorTailPosition(DRAG_OFFSET_MIN);
2437         }
2438     });
2439 }
2440 
2441 // spring animation
StopIndicatorSpringAnimation()2442 void RenderSwiper::StopIndicatorSpringAnimation()
2443 {
2444     if (springController_ && !springController_->IsStopped()) {
2445         // clear stop listener before stop
2446         springController_->ClearStopListeners();
2447         springController_->Stop();
2448     }
2449     ResetIndicatorSpringStatus();
2450 }
2451 
CalMaxStretch()2452 void RenderSwiper::CalMaxStretch()
2453 {
2454     if (focusStretchMaxTime_ == DRAG_OFFSET_MIN) {
2455         double stretch = DRAG_OFFSET_MIN;
2456         double maxStretch = DRAG_OFFSET_MIN;
2457         const int32_t step = DRAG_CALC_STRETCH_STEP_INT;
2458         for (int32_t i = step; i <= DRAG_CALC_STRETCH_STEP_MAX; i += step) {
2459             double actualStep = i * DRAG_CALC_STRETCH_STEP / static_cast<double>(DRAG_CALC_STRETCH_STEP_INT);
2460             stretch = INDICATOR_FOCUS_HEAD->Move(actualStep) - INDICATOR_FOCUS_TAIL->Move(actualStep);
2461             if (stretch > maxStretch) {
2462                 maxStretch = stretch;
2463                 focusStretchMaxTime_ = actualStep;
2464             }
2465         }
2466     }
2467 }
2468 
MoveIndicator(int32_t toIndex,double offset,bool isAuto)2469 void RenderSwiper::MoveIndicator(int32_t toIndex, double offset, bool isAuto)
2470 {
2471     if (toIndex == currentIndex_) {
2472         LOGW("MoveIndicator drop it for edge moving.");
2473         return;
2474     }
2475 
2476     double dragRange = ((axis_ == Axis::HORIZONTAL) ? swiperWidth_ : swiperHeight_) - prevMargin_ - nextMargin_;
2477     if (NearZero(dragRange)) {
2478         return;
2479     }
2480     double dragRate = offset / dragRange;
2481     animationDirect_ = (currentIndex_ <= toIndex) ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
2482     if (needReverse_) {
2483         animationDirect_ *= INDICATOR_DIRECT_BACKWARD;
2484     }
2485     dragRate = std::fabs(dragRate);
2486     if (dragRate >= DRAG_OFFSET_MAX) {
2487         // move to end, and index change
2488         UpdateIndicatorPointPosition(DRAG_OFFSET_MIN);
2489         UpdateIndicatorHeadPosition(DRAG_OFFSET_MIN);
2490         UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
2491         return;
2492     }
2493 
2494     targetIndex_ = toIndex;
2495     int32_t indicatorMoveNums = std::abs(currentIndex_ - toIndex);
2496     UpdateIndicatorPointPosition(INDICATOR_NORMAL_POINT->MoveInternal(dragRate));
2497     UpdateIndicatorHeadPosition(INDICATOR_FOCUS_HEAD->MoveInternal(dragRate) * indicatorMoveNums);
2498     if (!isAuto) {
2499         // move tails with hand
2500         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(dragRate) * indicatorMoveNums);
2501         return;
2502     }
2503 
2504     // animation
2505     if (dragRate < focusStretchMaxTime_) {
2506         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(dragRate) * indicatorMoveNums);
2507         return;
2508     }
2509 
2510     // curve sport into spring sport
2511     if (GetIndicatorSpringStatus() == SpringStatus::SPRING_STOP) {
2512         double springStart = INDICATOR_FOCUS_TAIL->MoveInternal(dragRate);
2513         UpdateIndicatorTailPosition(springStart * indicatorMoveNums);
2514         StartIndicatorSpringAnimation(springStart * indicatorMoveNums, DRAG_OFFSET_MAX * indicatorMoveNums);
2515     }
2516 }
2517 
DragIndicator(double offset)2518 void RenderSwiper::DragIndicator(double offset)
2519 {
2520     // start drag after zoom in completed.
2521     if (!IsZoomAnimationStopped()) {
2522         return;
2523     }
2524 
2525     const double longPressDragStart = DRAG_OFFSET_START_DP * scale_;
2526     const double longPressDragSwitchFocus = DRAG_OFFSET_SWITCH_DP * scale_;
2527     const double longPressDragMaxDiff = longPressDragSwitchFocus - longPressDragStart;
2528     if (!isDragStart_) {
2529         isDragStart_ = true;
2530         dragBaseOffset_ = offset;
2531         dragMoveOffset_ = offset;
2532         return;
2533     }
2534 
2535     dragMoveOffset_ += offset;
2536     double diffOffset = dragMoveOffset_ - dragBaseOffset_;
2537     double fabsOffset = std::fabs(diffOffset);
2538     if (fabsOffset <= longPressDragStart) {
2539         // indicator move when drag offset larger than 4 vp
2540         return;
2541     }
2542 
2543     animationDirect_ = diffOffset >= 0 ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
2544 
2545     if ((!needReverse_ && (currentIndex_ + animationDirect_ >= itemCount_ || currentIndex_ + animationDirect_ < 0)) ||
2546         (needReverse_ && (currentIndex_ - animationDirect_ >= itemCount_ || currentIndex_ - animationDirect_ < 0))) {
2547         // drag end and stretch background
2548         return DragEdgeStretch(fabsOffset);
2549     }
2550 
2551     if (fabsOffset >= longPressDragSwitchFocus) {
2552         // focus switch and vibrate
2553         VibrateIndicator();
2554         outItemIndex_ = currentIndex_;
2555         if (needReverse_) {
2556             currentIndex_ -= animationDirect_;
2557         } else {
2558             currentIndex_ += animationDirect_;
2559         }
2560         nextIndex_ = currentIndex_;
2561         dragBaseOffset_ += longPressDragSwitchFocus * animationDirect_;
2562         ResetIndicatorPosition();
2563         MarkNeedLayout();
2564         FireItemChangedEvent(true);
2565     } else {
2566         double dragRate = (fabsOffset - longPressDragStart) / longPressDragMaxDiff;
2567         UpdateIndicatorHeadPosition(INDICATOR_FOCUS_HEAD->MoveInternal(dragRate));
2568         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(dragRate));
2569         UpdateIndicatorPointPosition(INDICATOR_NORMAL_POINT->MoveInternal(dragRate));
2570     }
2571 }
2572 
DragIndicatorEnd()2573 void RenderSwiper::DragIndicatorEnd()
2574 {
2575     if ((currentIndex_ + animationDirect_ >= itemCount_ || currentIndex_ + animationDirect_ < 0) &&
2576         std::fabs(dragMoveOffset_ - dragBaseOffset_) > 0) {
2577         // drag than 80dp, play reset and zoom out animation
2578         StartDragRetractionAnimation();
2579         StartZoomOutAnimation();
2580     } else {
2581         ResetIndicatorPosition();
2582         UpdateEdgeStretchRate(DRAG_OFFSET_MIN);
2583         // only play zoom out animation
2584         StartZoomOutAnimation();
2585     }
2586     dragBaseOffset_ = DRAG_OFFSET_MIN;
2587     dragMoveOffset_ = DRAG_OFFSET_MIN;
2588 }
2589 
DragEdgeStretch(double offset)2590 void RenderSwiper::DragEdgeStretch(double offset)
2591 {
2592     const double longPressDragStretchLongest = DRAG_STRETCH_LONGEST_DP * scale_;
2593     if (offset >= longPressDragStretchLongest) {
2594         UpdateEdgeStretchRate(DRAG_OFFSET_MAX);
2595     } else {
2596         UpdateEdgeStretchRate(offset / longPressDragStretchLongest);
2597     }
2598 }
2599 
StartZoomInAnimation(bool isMouseHover)2600 void RenderSwiper::StartZoomInAnimation(bool isMouseHover)
2601 {
2602     StopZoomAnimation();
2603     if (zoomValue_ == ZOOM_MIN) {
2604         MarkIndicatorPosition(false);
2605     }
2606     if (!zoomInController_) {
2607         return;
2608     }
2609     zoomInAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(zoomValue_, ZOOM_MAX, Curves::SHARP);
2610     zoomInAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2611         auto swiper = weak.Upgrade();
2612         if (swiper) {
2613             swiper->UpdateZoomValue(value);
2614             if (value == ZOOM_MAX) {
2615                 // record position zone of indicator zone for stretch when zoom in reach maximum value.
2616                 swiper->MarkIndicatorPosition();
2617             }
2618         }
2619     });
2620 
2621     opacityInAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(opacityValue_, OPACITY_MAX, Curves::SHARP);
2622     opacityInAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2623         auto swiper = weak.Upgrade();
2624         if (swiper) {
2625             swiper->UpdateMaskOpacity(value);
2626         }
2627     });
2628 
2629     zoomInController_->ClearInterpolators();
2630     zoomInController_->AddInterpolator(zoomInAnimation_);
2631     zoomInController_->AddInterpolator(opacityInAnimation_);
2632     zoomInController_->SetDuration(ZOOM_IN_DURATION);
2633     zoomInController_->Play();
2634 }
2635 
StartZoomOutAnimation(bool isMouseHover)2636 void RenderSwiper::StartZoomOutAnimation(bool isMouseHover)
2637 {
2638     StopZoomAnimation();
2639     if (!zoomOutController_) {
2640         return;
2641     }
2642     int duration = isMouseHover ? ZOOM_OUT_HOVER_DURATION : ZOOM_OUT_DURATION;
2643     zoomOutAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(zoomValue_, ZOOM_MIN, Curves::SHARP);
2644     zoomOutAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2645         auto swiper = weak.Upgrade();
2646         if (swiper) {
2647             swiper->UpdateZoomValue(value);
2648         }
2649     });
2650     opacityOutAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(opacityValue_, OPACITY_MIN, Curves::SHARP);
2651     opacityOutAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2652         auto swiper = weak.Upgrade();
2653         if (swiper) {
2654             swiper->UpdateMaskOpacity(value);
2655         }
2656     });
2657     zoomOutController_->ClearInterpolators();
2658     zoomOutController_->AddInterpolator(zoomOutAnimation_);
2659     zoomOutController_->AddInterpolator(opacityOutAnimation_);
2660     zoomOutController_->SetDuration(duration);
2661     zoomOutController_->AddStopListener([weak = AceType::WeakClaim(this), isMouseHover]() {
2662         auto swiper = weak.Upgrade();
2663         if (swiper) {
2664             isMouseHover ? swiper->UpdateHoverStatus(false) : swiper->UpdatePressStatus(false);
2665         }
2666     });
2667     zoomOutController_->Play();
2668 }
2669 
StartZoomInDotAnimation(int32_t index)2670 void RenderSwiper::StartZoomInDotAnimation(int32_t index)
2671 {
2672     StopZoomDotAnimation(); // function will reset currentHoverIndex_. set it after stop zoom out dot.
2673     currentHoverIndex_ = index;
2674     if (!zoomInDotController_) {
2675         return;
2676     }
2677     if (!zoomInDotAnimation_) {
2678         zoomInDotAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(ZOOM_DOT_MIN, ZOOM_DOT_MAX, Curves::SHARP);
2679         zoomInDotAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2680             auto swiper = weak.Upgrade();
2681             if (swiper) {
2682                 swiper->UpdateZoomDotValue(value);
2683             }
2684         });
2685     }
2686 
2687     zoomInDotController_->ClearInterpolators();
2688     zoomInDotController_->AddInterpolator(zoomInDotAnimation_);
2689     zoomInDotController_->SetDuration(ZOOM_IN_DOT_DURATION);
2690     zoomInDotController_->Play();
2691 }
2692 
StartZoomOutDotAnimation()2693 void RenderSwiper::StartZoomOutDotAnimation()
2694 {
2695     StopZoomDotAnimation();
2696     if (!zoomOutDotController_) {
2697         return;
2698     }
2699     if (!zoomOutDotAnimation_) {
2700         zoomOutDotAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(ZOOM_DOT_MAX, ZOOM_DOT_MIN, Curves::SHARP);
2701         zoomOutDotAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2702             auto swiper = weak.Upgrade();
2703             if (swiper) {
2704                 swiper->UpdateZoomDotValue(value);
2705             }
2706         });
2707     }
2708     zoomOutDotController_->ClearInterpolators();
2709     zoomOutDotController_->AddInterpolator(zoomOutDotAnimation_);
2710     zoomOutDotController_->SetDuration(ZOOM_OUT_DOT_DURATION);
2711     zoomOutDotController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
2712         auto swiper = weak.Upgrade();
2713         if (swiper) {
2714             swiper->currentHoverIndex_ = INDICATOR_INVALID_HOVER_INDEX;
2715         }
2716     });
2717     zoomOutDotController_->Play();
2718 }
2719 
StopZoomAnimation()2720 void RenderSwiper::StopZoomAnimation()
2721 {
2722     if (zoomInController_ && !zoomInController_->IsStopped()) {
2723         zoomInController_->ClearStopListeners();
2724         zoomInController_->Stop();
2725     }
2726     if (zoomOutController_ && !zoomOutController_->IsStopped()) {
2727         zoomOutController_->ClearStopListeners();
2728         zoomOutController_->Stop();
2729     }
2730 }
2731 
StopZoomDotAnimation()2732 void RenderSwiper::StopZoomDotAnimation()
2733 {
2734     if (zoomInDotController_ && !zoomInDotController_->IsStopped()) {
2735         zoomInDotController_->ClearStopListeners();
2736         zoomInDotController_->Stop();
2737     }
2738     if (zoomOutDotController_ && !zoomOutDotController_->IsStopped()) {
2739         zoomOutDotController_->ClearStopListeners();
2740         zoomOutDotController_->Stop();
2741     }
2742 }
2743 
StartDragRetractionAnimation()2744 void RenderSwiper::StartDragRetractionAnimation()
2745 {
2746     if (!dragRetractionController_) {
2747         return;
2748     }
2749     StopDragRetractionAnimation();
2750     dragRetractionAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(
2751         stretchRate_, TARGET_START_TRANSLATE_TIME, INDICATOR_ZONE_STRETCH);
2752     dragRetractionAnimation_->AddListener([weak = AceType::WeakClaim(this)](const double value) {
2753         auto swiper = weak.Upgrade();
2754         if (swiper) {
2755             swiper->UpdateEdgeStretchRate(value);
2756         }
2757     });
2758 
2759     dragRetractionController_->ClearInterpolators();
2760     dragRetractionController_->AddInterpolator(dragRetractionAnimation_);
2761     dragRetractionController_->SetDuration(DRAG_RETRETION_DURATION);
2762     dragRetractionController_->Play();
2763 }
2764 
StopDragRetractionAnimation()2765 void RenderSwiper::StopDragRetractionAnimation()
2766 {
2767     if (dragRetractionController_ && !dragRetractionController_->IsStopped()) {
2768         dragRetractionController_->ClearStopListeners();
2769         dragRetractionController_->Stop();
2770     }
2771 }
2772 
FinishAllSwipeAnimation(bool useFinish,bool surfaceChanged)2773 void RenderSwiper::FinishAllSwipeAnimation(bool useFinish, bool surfaceChanged)
2774 {
2775     if (useFinish && IsAnimatorStopped()) {
2776         FireSwiperControllerFinishEvent();
2777         return;
2778     }
2779     if (useFinish) {
2780         FinishSwipeAnimation();
2781     } else {
2782         StopSwipeAnimation();
2783     }
2784 
2785     StopSwipeToAnimation();
2786     StopIndicatorAnimation();
2787     StopIndicatorSpringAnimation();
2788     ResetIndicatorPosition();
2789 
2790     if (surfaceChanged) {
2791         UpdateChildPosition(0.0, currentIndex_);
2792     } else {
2793         LoadLazyItems((currentIndex_ + 1) % itemCount_ == targetIndex_);
2794     }
2795     UpdateOneItemOpacity(MAX_OPACITY, currentIndex_);
2796     UpdateOneItemOpacity(MAX_OPACITY, targetIndex_);
2797     currentIndex_ = targetIndex_;
2798     if (useFinish) {
2799         FireSwiperControllerFinishEvent();
2800     }
2801     quickTurnItem_ = true;
2802     MarkNeedLayout(true);
2803 }
2804 
IsAnimatorStopped() const2805 bool RenderSwiper::IsAnimatorStopped() const
2806 {
2807     bool isControllerRunning = controller_ && controller_->IsRunning();
2808     bool isSwiperControllerRunning = swipeToController_ && swipeToController_->IsRunning();
2809     bool isIndicatorControllerRunning = indicatorController_ && indicatorController_->IsRunning();
2810     bool isSpringControllerRunning = springController_ && springController_->IsRunning();
2811     return !isControllerRunning && !isSwiperControllerRunning && !isIndicatorControllerRunning &&
2812            !isSpringControllerRunning;
2813 }
2814 
FireSwiperControllerFinishEvent()2815 void RenderSwiper::FireSwiperControllerFinishEvent()
2816 {
2817     if (swiper_ && swiper_->GetSwiperController() && swiper_->GetSwiperController()->GetFinishCallback()) {
2818         swiper_->GetSwiperController()->GetFinishCallback()();
2819     }
2820 }
2821 
IsZoomAnimationStopped()2822 bool RenderSwiper::IsZoomAnimationStopped()
2823 {
2824     bool result = true;
2825     if (zoomInController_ && !zoomInController_->IsStopped()) {
2826         result = false;
2827     }
2828     if (zoomOutController_ && !zoomOutController_->IsStopped()) {
2829         result = false;
2830     }
2831     return result;
2832 }
2833 
IsZoomOutAnimationStopped()2834 bool RenderSwiper::IsZoomOutAnimationStopped()
2835 {
2836     return zoomOutController_ ? zoomOutController_->IsStopped() : true;
2837 }
2838 
IsZoomOutDotAnimationStopped()2839 bool RenderSwiper::IsZoomOutDotAnimationStopped()
2840 {
2841     return zoomOutDotController_ ? zoomOutDotController_->IsStopped() : true;
2842 }
2843 
UpdateIndicatorLayout()2844 void RenderSwiper::UpdateIndicatorLayout()
2845 {
2846     LayoutIndicator(swiperIndicatorData_);
2847     MarkNeedRender();
2848 }
2849 
UpdateIndicatorOffset(int32_t fromIndex,int32_t toIndex,double value)2850 void RenderSwiper::UpdateIndicatorOffset(int32_t fromIndex, int32_t toIndex, double value)
2851 {
2852     int32_t indicatorMoveNums = std::abs(fromIndex - toIndex);
2853     if (value >= 1.0) {
2854         // move to end, and index change
2855         UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
2856         UpdateIndicatorPointPosition(DRAG_OFFSET_MIN);
2857         UpdateIndicatorHeadPosition(DRAG_OFFSET_MIN);
2858         return;
2859     }
2860 
2861     UpdateIndicatorPointPosition(INDICATOR_NORMAL_POINT->MoveInternal(value));
2862     UpdateIndicatorHeadPosition(INDICATOR_FOCUS_HEAD->MoveInternal(value) * indicatorMoveNums);
2863     if (value < focusStretchMaxTime_) {
2864         UpdateIndicatorTailPosition(INDICATOR_FOCUS_TAIL->MoveInternal(value) * indicatorMoveNums);
2865         return;
2866     }
2867 
2868     // curve sport into spring sport
2869     if (GetIndicatorSpringStatus() == SpringStatus::SPRING_STOP) {
2870         double springStart = INDICATOR_FOCUS_TAIL->MoveInternal(value) * indicatorMoveNums;
2871         UpdateIndicatorTailPosition(springStart);
2872         StartIndicatorSpringAnimation(springStart, indicatorMoveNums * DRAG_OFFSET_MAX);
2873     }
2874 }
2875 
UpdateIndicatorHeadPosition(double offset)2876 void RenderSwiper::UpdateIndicatorHeadPosition(double offset)
2877 {
2878     indicatorHeadOffset_ = offset * animationDirect_;
2879 }
2880 
UpdateIndicatorTailPosition(double offset,double switchOffset)2881 void RenderSwiper::UpdateIndicatorTailPosition(double offset, double switchOffset)
2882 {
2883     indicatorTailOffset_ = offset * animationDirect_;
2884     // if indicator switch to the next or last, tail offset will be different.
2885     indicatorSwitchTailOffset_ = switchOffset * animationDirect_;
2886     MarkNeedRender();
2887 }
2888 
UpdateIndicatorPointPosition(double offset)2889 void RenderSwiper::UpdateIndicatorPointPosition(double offset)
2890 {
2891     indicatorPointOffset_ = offset * animationDirect_;
2892     MarkNeedRender();
2893 }
2894 
UpdateMaskOpacity(double value)2895 void RenderSwiper::UpdateMaskOpacity(double value)
2896 {
2897     opacityValue_ = value;
2898     MarkNeedRender();
2899 }
2900 
UpdateZoomValue(double value)2901 void RenderSwiper::UpdateZoomValue(double value)
2902 {
2903     zoomValue_ = value;
2904     LayoutIndicator(swiperIndicatorData_);
2905     MarkNeedRender();
2906 }
2907 
UpdateZoomDotValue(double value)2908 void RenderSwiper::UpdateZoomDotValue(double value)
2909 {
2910     zoomDotValue_ = value;
2911     LayoutIndicator(swiperIndicatorData_);
2912     MarkNeedRender();
2913 }
2914 
UpdateEdgeStretchRate(double value)2915 void RenderSwiper::UpdateEdgeStretchRate(double value)
2916 {
2917     stretchRate_ = value;
2918     widthStretchRate_ = DRAG_STRETCH_BASE_WIDTH + (DRAG_STRETCH_MAX_WIDTH - DRAG_STRETCH_BASE_WIDTH) * value;
2919     heightStretchRate_ = DRAG_STRETCH_BASE_HIGH + (DRAG_STRETCH_MAX_HIGH - DRAG_STRETCH_BASE_HIGH) * value;
2920     LayoutIndicator(swiperIndicatorData_);
2921     MarkNeedRender();
2922 }
2923 
UpdatePressStatus(bool isPress)2924 void RenderSwiper::UpdatePressStatus(bool isPress)
2925 {
2926     swiperIndicatorData_.isPressed = isPress;
2927 }
2928 
UpdateHoverStatus(bool isHover)2929 void RenderSwiper::UpdateHoverStatus(bool isHover)
2930 {
2931     swiperIndicatorData_.isHovered = isHover;
2932 }
2933 
StartIndicatorAnimation(int32_t fromIndex,int32_t toIndex,bool isLoop)2934 void RenderSwiper::StartIndicatorAnimation(int32_t fromIndex, int32_t toIndex, bool isLoop)
2935 {
2936     if (fromIndex == toIndex) {
2937         return;
2938     }
2939     if (isIndicatorAnimationStart_) {
2940         LOGE("indicator animation is processing.");
2941         return;
2942     }
2943 
2944     CalMaxStretch();
2945     StopIndicatorSpringAnimation();
2946     StopIndicatorAnimation();
2947     ResetHoverZoomDot();
2948     targetIndex_ = toIndex;
2949     nextIndex_ = toIndex;
2950     isIndicatorAnimationStart_ = true;
2951     animationDirect_ = (fromIndex - toIndex <= 0) ? INDICATOR_DIRECT_FORWARD : INDICATOR_DIRECT_BACKWARD;
2952 
2953     // the start offset of swiper content zone.
2954     double contentOffset = (animationDirect_ == INDICATOR_DIRECT_FORWARD) ? (isLoop ? nextItemOffset_ : prevItemOffset_)
2955                                                                       : (isLoop ? prevItemOffset_ : nextItemOffset_);
2956     if (needReverse_) {
2957         animationDirect_ *= INDICATOR_DIRECT_BACKWARD;
2958     }
2959     indicatorAnimation_ = AceType::MakeRefPtr<CurveAnimation<double>>(
2960         CUR_START_TRANSLATE_TIME, CUR_END_TRANSLATE_TIME, curve_);
2961     indicatorAnimation_->AddListener(
2962         [weak = AceType::WeakClaim(this), fromIndex, toIndex, contentOffset](const double value) {
2963         auto swiper = weak.Upgrade();
2964         if (swiper) {
2965             swiper->UpdateIndicatorOffset(fromIndex, toIndex, value);
2966             double itemOffset = (value == CUR_END_TRANSLATE_TIME) ? value : Curves::EASE_OUT->MoveInternal(value);
2967             swiper->UpdateChildPosition(itemOffset * contentOffset, fromIndex);
2968         }
2969     });
2970 
2971     if (indicatorController_) {
2972         indicatorController_->ClearInterpolators();
2973         indicatorController_->AddInterpolator(indicatorAnimation_);
2974         indicatorController_->SetDuration(duration_);
2975         indicatorController_->ClearStopListeners();
2976         indicatorController_->AddStopListener([weak = AceType::WeakClaim(this), fromIndex, toIndex]() {
2977             auto swiper = weak.Upgrade();
2978             if (swiper) {
2979                 swiper->LoadLazyItems((fromIndex + 1) % swiper->itemCount_ == toIndex);
2980                 swiper->isIndicatorAnimationStart_ = false;
2981                 swiper->outItemIndex_ = fromIndex;
2982                 swiper->currentIndex_ = toIndex;
2983                 swiper->FireItemChangedEvent(true);
2984                 swiper->UpdateIndicatorSpringStatus(SpringStatus::FOCUS_SWITCH);
2985                 swiper->MarkNeedLayout(true);
2986             }
2987         });
2988         indicatorController_->Play();
2989     }
2990 }
2991 
StopIndicatorAnimation()2992 void RenderSwiper::StopIndicatorAnimation()
2993 {
2994     if (indicatorController_ && !indicatorController_->IsStopped()) {
2995         indicatorController_->ClearStopListeners();
2996         indicatorController_->Stop();
2997         isIndicatorAnimationStart_ = false;
2998     }
2999 }
3000 
InitIndicatorAnimation(const WeakPtr<PipelineContext> & context)3001 void RenderSwiper::InitIndicatorAnimation(const WeakPtr<PipelineContext>& context)
3002 {
3003     if (!springController_) {
3004         springController_ = CREATE_ANIMATOR(context);
3005     } else {
3006         StopIndicatorSpringAnimation();
3007     }
3008     if (!fadeController_) {
3009         fadeController_ = CREATE_ANIMATOR(context);
3010     }
3011     if (!zoomInController_) {
3012         zoomInController_ = CREATE_ANIMATOR(context);
3013     }
3014     if (!zoomOutController_) {
3015         zoomOutController_ = CREATE_ANIMATOR(context);
3016     }
3017     if (!zoomInDotController_) {
3018         zoomInDotController_ = CREATE_ANIMATOR(context);
3019     }
3020     if (!zoomOutDotController_) {
3021         zoomOutDotController_ = CREATE_ANIMATOR(context);
3022     }
3023     if (!dragRetractionController_) {
3024         dragRetractionController_ = CREATE_ANIMATOR(context);
3025     }
3026     if (!indicatorController_) {
3027         indicatorController_ = CREATE_ANIMATOR(context);
3028     } else {
3029         StopIndicatorAnimation();
3030         ResetIndicatorPosition();
3031     }
3032     CalMaxStretch();
3033 }
3034 
HandleRotationStart()3035 void RenderSwiper::HandleRotationStart()
3036 {
3037     DragStartInfo info(0);
3038     info.SetGlobalLocation(Offset(0.0, 0.0));
3039     HandleDragStart(info);
3040 }
3041 
HandleRotationUpdate(double delta)3042 void RenderSwiper::HandleRotationUpdate(double delta)
3043 {
3044     DragUpdateInfo info(0);
3045     info.SetMainDelta(delta).SetGlobalLocation(Offset(0.0, 0.0));
3046     HandleDragUpdate(info);
3047     if (rotationEvent_) {
3048         std::string param =
3049             std::string(R"("rotation",{"value":)").append(std::to_string(delta).append("},null"));
3050         rotationEvent_(param);
3051     }
3052 }
3053 
HandleRotationEnd()3054 void RenderSwiper::HandleRotationEnd()
3055 {
3056     DragEndInfo info(0);
3057     HandleDragEnd(info);
3058     rotationStatus_ = RotationStatus::ROTATION_END;
3059 }
3060 
ResetRotationEndListener()3061 void RenderSwiper::ResetRotationEndListener()
3062 {
3063     auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
3064         auto swiper = weakPtr.Upgrade();
3065         if (swiper) {
3066             swiper->HandleRotationEnd();
3067         } else {
3068             LOGE("fail to set rotation listener due to swiper weakPtr is nullptr");
3069         }
3070     };
3071     rotationTimer_.Reset(callback);
3072     auto context = GetContext().Upgrade();
3073     if (context) {
3074         auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
3075         taskExecutor.PostDelayedTask(rotationTimer_, ROTATION_INTERVAL_MS, "ArkUISwiperResetRotationEndListener");
3076     }
3077 }
3078 
UpdateItemCount(int32_t itemCount)3079 void RenderSwiper::UpdateItemCount(int32_t itemCount)
3080 {
3081     if ((itemCount_ <= 1) && (itemCount > 1)) {
3082         Initialize(GetContext(), catchMode_);
3083     }
3084     itemCount_ = itemCount;
3085     if (currentIndex_ >= itemCount_) {
3086         currentIndex_ = itemCount_ > 0 ? itemCount_ - 1 : 0;
3087         if (changeEvent_) {
3088             changeEvent_(std::make_shared<SwiperChangeEvent>(currentIndex_));
3089         }
3090     }
3091 }
3092 
BuildLazyItems()3093 void RenderSwiper::BuildLazyItems()
3094 {
3095     if (itemCount_ <= lazyLoadCacheSize_) {
3096         cacheStart_ = 0;
3097         cacheEnd_ = itemCount_;
3098     } else {
3099         int32_t halfLazy = lazyLoadCacheSize_ / 2;
3100         if (loop_) {
3101             cacheStart_ = (itemCount_ + currentIndex_ - halfLazy) % itemCount_;
3102             cacheEnd_ = (cacheStart_ + lazyLoadCacheSize_ - 1) % itemCount_;
3103         } else {
3104             if (currentIndex_ < halfLazy) {
3105                 cacheStart_ = 0;
3106                 cacheEnd_ = swiper_->GetCachedSize() + swiper_->GetDisplayCount() - 1;
3107             } else if (currentIndex_ >= itemCount_ - halfLazy - 1) {
3108                 cacheEnd_ = itemCount_ - 1;
3109                 cacheStart_ = cacheEnd_ - swiper_->GetCachedSize() - swiper_->GetDisplayCount();
3110             } else {
3111                 cacheStart_ = currentIndex_ - halfLazy;
3112                 cacheEnd_ = cacheStart_ + lazyLoadCacheSize_ - 1;
3113             }
3114         }
3115     }
3116     LOGI("currentIndex_ = %{public}d, init cached: %{public}d - %{public}d", currentIndex_, cacheStart_, cacheEnd_);
3117     if (cacheStart_ > cacheEnd_) { // CacheStart may greater than cacheEnd when enable loop.
3118         for (int32_t index = cacheStart_; index < itemCount_; ++index) {
3119             buildChildByIndex_(index);
3120         }
3121         for (int32_t index = 0; index <= cacheEnd_; ++index) {
3122             buildChildByIndex_(index);
3123         }
3124     } else {
3125         for (int32_t index = cacheStart_; index <= cacheEnd_; ++index) {
3126             buildChildByIndex_(index);
3127         }
3128     }
3129 
3130     if (swipeToIndex_ < cacheStart_ || swipeToIndex_ > cacheEnd_) {
3131         buildChildByIndex_(swipeToIndex_);
3132     }
3133 }
3134 
LoadItems()3135 void RenderSwiper::LoadItems()
3136 {
3137     if (!items_.empty()) {
3138         return;
3139     }
3140     if ((swiper_ && !swiper_->GetLazyForEachComponent()) || !swiper_) {
3141         auto children = GetChildren();
3142         int32_t index = 0;
3143         for (auto iter = children.begin(); iter != children.end(); ++iter, ++index) {
3144             items_.emplace(std::make_pair(index, *iter));
3145         }
3146         if (Container::IsCurrentUsePartialUpdate()) {
3147             itemCount_ = static_cast<int32_t>(children.size());
3148         }
3149     } else {
3150         BuildLazyItems(); // depend on currentIndex_ value which init when swiper first update
3151     }
3152 }
3153 
LoadLazyItems(bool swipeToNext)3154 void RenderSwiper::LoadLazyItems(bool swipeToNext)
3155 {
3156     if (!buildChildByIndex_) {
3157         // not lazy foreach case.
3158         return;
3159     }
3160     if (static_cast<int32_t>(items_.size()) == itemCount_) {
3161         // all item in caches
3162         return;
3163     }
3164     if (swipeToNext) {
3165         if (!loop_) {
3166             buildChildByIndex_(++cacheEnd_);
3167             if (cacheStart_ + cacheEnd_ >= lazyLoadCacheSize_) {
3168                 deleteChildByIndex_(cacheStart_++);
3169             }
3170         } else {
3171             if (++cacheEnd_ == itemCount_) {
3172                 cacheEnd_ = 0;
3173             }
3174             buildChildByIndex_(cacheEnd_);
3175             deleteChildByIndex_(cacheStart_);
3176             if (++cacheStart_ == itemCount_) {
3177                 cacheStart_ = 0;
3178             }
3179         }
3180     } else {
3181         if (!loop_) {
3182             if (cacheStart_ + cacheEnd_ >= lazyLoadCacheSize_) {
3183                 buildChildByIndex_(--cacheStart_);
3184             }
3185             if (currentIndex_ < (itemCount_ - 1)) {
3186                 deleteChildByIndex_(cacheEnd_--);
3187             }
3188         } else {
3189             if (--cacheStart_ < 0) {
3190                 cacheStart_ = itemCount_ - 1;
3191             }
3192             buildChildByIndex_(cacheStart_);
3193             deleteChildByIndex_(cacheEnd_);
3194             if (--cacheEnd_ < 0) {
3195                 cacheEnd_ = itemCount_ - 1;
3196             }
3197         }
3198     }
3199     LOGI("load lazy cached: %{public}d - %{public}d, current = %{public}d", cacheStart_, cacheEnd_, currentIndex_);
3200 }
3201 
AddChildByIndex(int32_t index,const RefPtr<RenderNode> & renderNode)3202 void RenderSwiper::AddChildByIndex(int32_t index, const RefPtr<RenderNode>& renderNode)
3203 {
3204     items_.try_emplace(index, renderNode);
3205 }
3206 
RemoveChildByIndex(int32_t index)3207 void RenderSwiper::RemoveChildByIndex(int32_t index)
3208 {
3209     auto item = items_.find(index);
3210     if (item != items_.end()) {
3211         items_.erase(item);
3212     }
3213 }
3214 
OnDataSourceUpdated(int32_t totalCount,int32_t startIndex)3215 void RenderSwiper::OnDataSourceUpdated(int32_t totalCount, int32_t startIndex)
3216 {
3217     decltype(items_) items(std::move(items_));
3218     for (auto&& item : items) {
3219         deleteChildByIndex_(item.first);
3220     }
3221     UpdateItemCount(totalCount);
3222     MarkNeedLayout(true);
3223 }
3224 
ClearItems(const RefPtr<Component> & lazyForEachComponent,int32_t index)3225 void RenderSwiper::ClearItems(const RefPtr<Component>& lazyForEachComponent, int32_t index)
3226 {
3227     if (lazyForEachComponent) {
3228         if (index != currentIndex_) {
3229             decltype(items_) items(std::move(items_));
3230             for (auto&& item : items) {
3231                 deleteChildByIndex_(item.first);
3232             }
3233         }
3234     } else {
3235         items_.clear();
3236     }
3237 }
3238 
ResetCachedChildren()3239 void RenderSwiper::ResetCachedChildren()
3240 {
3241     auto context = context_.Upgrade();
3242     if (!context) {
3243         LOGW("ResetCachedChildren fail, context is null");
3244         return;
3245     }
3246     if (context->GetIsDeclarative()) {
3247         return;
3248     }
3249 
3250     int32_t cachedSize = swiper_->GetCachedSize();
3251     int32_t childrenSize = itemCount_;
3252     int32_t forwardNum = 0;
3253     int32_t backNum = 0;
3254     if (cachedSize <= -1 || cachedSize >= childrenSize / 2) {
3255         for (const auto& item : items_) {
3256             const auto& childItem = item.second;
3257             if (!childItem) {
3258                 continue;
3259             }
3260             childItem->SetHidden(false);
3261         }
3262         return;
3263     } else if (cachedSize == 0) {
3264         cachedSize = 1;
3265         forwardNum = cachedSize;
3266         backNum = cachedSize;
3267     }
3268     if (loop_) {
3269         forwardNum = cachedSize;
3270         backNum = cachedSize;
3271     } else {
3272         if (currentIndex_ == 0) {
3273             forwardNum = 0;
3274             if (cachedSize < childrenSize / 2) {
3275                 backNum = 2 * cachedSize;
3276             }
3277         } else if (currentIndex_ != 0 && currentIndex_ < cachedSize) {
3278             forwardNum = currentIndex_;
3279             backNum = cachedSize + (cachedSize - forwardNum);
3280         } else if (currentIndex_ != 0 && currentIndex_ >= cachedSize) {
3281             forwardNum = cachedSize;
3282             if (cachedSize + currentIndex_ < childrenSize) { // smaller than size
3283                 backNum = cachedSize;
3284             } else if (currentIndex_ + cachedSize >= childrenSize) {
3285                 backNum = childrenSize - currentIndex_ - 1;
3286                 int32_t des = cachedSize - backNum;
3287                 forwardNum = des + cachedSize;
3288             }
3289         }
3290     }
3291     SetSwiperHidden(forwardNum, backNum);
3292 }
3293 
SetSwiperHidden(int32_t forwardNum,int32_t backNum)3294 void RenderSwiper::SetSwiperHidden(int32_t forwardNum, int32_t backNum)
3295 {
3296     int32_t childrenSize = itemCount_;
3297     int32_t fromIndex = currentIndex_ - forwardNum;
3298     int32_t toIndex = currentIndex_ + backNum;
3299     if (fromIndex >= 0 && toIndex < childrenSize) { // normal
3300         for (const auto& item : items_) {
3301             const auto& childItem = item.second;
3302             if (childItem) {
3303                 childItem->SetHidden(item.first >= fromIndex && item.first <= toIndex);
3304             }
3305         }
3306     }
3307     if (loop_) {
3308         if (fromIndex < 0) {
3309             for (const auto& item : items_) {
3310                 const auto& childItem = item.second;
3311                 if (childItem) {
3312                     childItem->SetHidden(item.first > toIndex && item.first < fromIndex + childrenSize);
3313                 }
3314             }
3315         } else if (toIndex >= childrenSize) {
3316             for (const auto& item : items_) {
3317                 const auto& childItem = item.second;
3318                 if (childItem) {
3319                     childItem->SetHidden(item.first > toIndex - childrenSize && item.first < fromIndex);
3320                 }
3321             }
3322         }
3323     }
3324 }
3325 
IsChildrenTouchEnable()3326 bool RenderSwiper::IsChildrenTouchEnable()
3327 {
3328     return !(controller_ && controller_->IsRunning());
3329 }
3330 
OnPaintFinish()3331 void RenderSwiper::OnPaintFinish()
3332 {
3333     if (!AceApplicationInfo::GetInstance().IsAccessibilityEnabled()) {
3334         return;
3335     }
3336 
3337     bool isDeclarative = true;
3338     auto context = GetContext().Upgrade();
3339     if (context) {
3340         isDeclarative = context->GetIsDeclarative();
3341     }
3342 
3343     Rect itemRect;
3344     Rect viewPortRect(GetGlobalOffset(), GetChildViewPort());
3345     RefPtr<OHOS::Ace::RenderNode> itemWithChildAccessibilityNode;
3346     for (const auto& item : GetChildren()) {
3347         // RenderSwiper's children are RenderDisplay who's accessibility node is the same with RenderSwiper in v2,
3348         // see SwiperComponent::AppendChild and RenderElement::SetAccessibilityNode
3349         if (isDeclarative) {
3350             itemWithChildAccessibilityNode = item->GetFirstChild();
3351         } else {
3352             itemWithChildAccessibilityNode = item;
3353         }
3354 
3355         if (!itemWithChildAccessibilityNode) {
3356             continue;
3357         }
3358 
3359         auto node = itemWithChildAccessibilityNode->GetAccessibilityNode().Upgrade();
3360         if (!node) {
3361             continue;
3362         }
3363         bool visible = GetVisible();
3364         if (visible) {
3365             itemRect.SetSize(itemWithChildAccessibilityNode->GetLayoutSize());
3366             itemRect.SetOffset(itemWithChildAccessibilityNode->GetGlobalOffset());
3367             visible = itemRect.IsIntersectWith(viewPortRect);
3368         }
3369         itemWithChildAccessibilityNode->SetAccessibilityVisible(visible);
3370         if (visible) {
3371             Rect clampRect = itemRect.Constrain(viewPortRect);
3372             if (clampRect != itemRect) {
3373                 itemWithChildAccessibilityNode->SetAccessibilityRect(clampRect);
3374             }
3375         } else {
3376             itemWithChildAccessibilityNode->NotifyPaintFinish();
3377         }
3378     }
3379 }
3380 
3381 // In case of partial update we get extra RenderNode children
3382 // without invoking RenderSwiper::Update, so we have to reset items_
3383 // SwiperComponent swiper_ not updated in that case and
3384 // it will still keep initial list of children.
OnChildAdded(const RefPtr<RenderNode> & child)3385 void RenderSwiper::OnChildAdded(const RefPtr<RenderNode>& child)
3386 {
3387     if (!Container::IsCurrentUsePartialUpdate()) {
3388         return;
3389     }
3390 
3391     if (!swiper_) {
3392         return; // Not done with Update call yet.
3393     }
3394     if (swiper_->GetLazyForEachComponent()) {
3395         return; // No partial update support for LazyForEach yet
3396     }
3397 
3398     // Later LoadItems will recreate items_ and update itemCount_
3399     ClearItems(nullptr, 0);
3400     ResetCachedChildren();
3401 }
3402 
OnChildRemoved(const RefPtr<RenderNode> & child)3403 void RenderSwiper::OnChildRemoved(const RefPtr<RenderNode>& child)
3404 {
3405     if (!Container::IsCurrentUsePartialUpdate()) {
3406         return;
3407     }
3408 
3409     if (!swiper_) {
3410         return; // Not done with Update call yet.
3411     }
3412     if (swiper_->GetLazyForEachComponent()) {
3413         return; // No partial update support for LazyForEach yet
3414     }
3415     ClearItems(nullptr, 0);
3416     ResetCachedChildren();
3417 }
3418 
OnSurfaceChanged()3419 void RenderSwiper::OnSurfaceChanged()
3420 {
3421     if (isIndicatorAnimationStart_ && !needRestore_) {
3422         FinishAllSwipeAnimation(true, true);
3423     }
3424 }
3425 
ProvideRestoreInfo()3426 std::string RenderSwiper::ProvideRestoreInfo()
3427 {
3428     auto jsonObj = JsonUtil::Create(true);
3429     jsonObj->Put("index", index_);
3430     jsonObj->Put("currentIndex", currentIndex_);
3431     jsonObj->Put("swipeToIndex", swipeToIndex_);
3432     return jsonObj->ToString();
3433 }
3434 
ApplyRestoreInfo()3435 void RenderSwiper::ApplyRestoreInfo()
3436 {
3437     if (GetRestoreInfo().empty()) {
3438         return;
3439     }
3440     auto info = JsonUtil::ParseJsonString(GetRestoreInfo());
3441     if (!info->IsValid() || !info->IsObject()) {
3442         LOGW("RenderSwiper:: restore info is invalid");
3443         return;
3444     }
3445 
3446     auto jsonIndex = info->GetValue("index");
3447     auto jsonCurrentIndex = info->GetValue("currentIndex");
3448     auto jsonSwipeToIndex = info->GetValue("swipeToIndex");
3449 
3450     index_ = jsonIndex->GetInt();
3451     currentIndex_ = jsonCurrentIndex->GetInt();
3452     swipeToIndex_ = jsonSwipeToIndex->GetInt();
3453     SetRestoreInfo("");
3454 }
3455 
GetPaintChildList()3456 std::list<RefPtr<RenderNode>> RenderSwiper::GetPaintChildList()
3457 {
3458     std::list<RefPtr<RenderNode>> childList;
3459     auto swiperGlobalRect = GetRectBasedWindowTopLeft();
3460     const auto& children = GetChildren();
3461     for (const auto& child : children) {
3462         auto childGlobalRect = child->GetRectBasedWindowTopLeft();
3463         if (swiperGlobalRect.IsIntersectByCommonSideWith(childGlobalRect)) {
3464             childList.emplace_back(child);
3465         }
3466     }
3467 
3468     return childList;
3469 }
3470 
3471 } // namespace OHOS::Ace
3472