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