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