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