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