1 /*
2 * Copyright (c) 2022-2023 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_ng/pattern/swiper/swiper_pattern.h"
17
18 #include <algorithm>
19 #include <cmath>
20 #include <cstdint>
21 #include <optional>
22
23 #include "base/error/error_code.h"
24 #include "base/geometry/axis.h"
25 #include "base/geometry/dimension.h"
26 #include "base/geometry/ng/offset_t.h"
27 #include "base/log/dump_log.h"
28 #include "base/perfmonitor/perf_constants.h"
29 #include "base/perfmonitor/perf_monitor.h"
30 #include "base/ressched/ressched_report.h"
31 #include "base/utils/utils.h"
32 #include "core/animation/curve.h"
33 #include "core/animation/curves.h"
34 #include "core/animation/spring_curve.h"
35 #include "core/common/container_scope.h"
36 #include "core/common/recorder/node_data_cache.h"
37 #include "core/components/common/layout/constants.h"
38 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
39 #include "core/components_ng/pattern/swiper/swiper_layout_algorithm.h"
40 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
41 #include "core/components_ng/pattern/swiper/swiper_model.h"
42 #include "core/components_ng/pattern/swiper/swiper_paint_property.h"
43 #include "core/components_ng/pattern/swiper/swiper_utils.h"
44 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_arrow_pattern.h"
45 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_pattern.h"
46 #include "core/components_ng/pattern/tabs/tabs_node.h"
47 #include "core/components_ng/pattern/tabs/tabs_pattern.h"
48 #include "core/components_ng/property/measure_utils.h"
49 #include "core/components_ng/property/property.h"
50 #include "core/components_ng/syntax/for_each_node.h"
51 #include "core/components_ng/syntax/lazy_for_each_node.h"
52 #include "core/components_v2/inspector/inspector_constants.h"
53 #include "core/event/ace_events.h"
54 #include "core/event/touch_event.h"
55 #include "core/pipeline_ng/pipeline_context.h"
56
57 namespace OHOS::Ace::NG {
58 namespace {
59
60 // TODO use theme.
61 constexpr int32_t MIN_TURN_PAGE_VELOCITY = 1200;
62 constexpr int32_t NEW_MIN_TURN_PAGE_VELOCITY = 780;
63 constexpr Dimension INDICATOR_BORDER_RADIUS = 16.0_vp;
64
65 constexpr Dimension SWIPER_MARGIN = 16.0_vp;
66 constexpr Dimension SWIPER_GUTTER = 16.0_vp;
67 constexpr float PX_EPSILON = 0.01f;
68 constexpr float FADE_DURATION = 500.0f;
69 constexpr float SPRING_DURATION = 600.0f;
70 constexpr int32_t INDEX_DIFF_TWO = 2;
71 const std::string SWIPER_DRAG_SCENE = "swiper_drag_scene";
72 const std::string FADE_PROPERTY_NAME = "fade";
73 const std::string SPRING_PROPERTY_NAME = "spring";
74 const std::string INDICATOR_PROPERTY_NAME = "indicator";
75 // TODO define as common method
CalculateFriction(float gamma)76 float CalculateFriction(float gamma)
77 {
78 constexpr float SCROLL_RATIO = 0.72f;
79 if (GreatOrEqual(gamma, 1.0)) {
80 gamma = 1.0;
81 }
82 return SCROLL_RATIO * static_cast<float>(std::pow(1.0 - gamma, SQUARE));
83 }
84
85 } // namespace
86
SwiperPattern()87 SwiperPattern::SwiperPattern()
88 {
89 swiperController_ = MakeRefPtr<SwiperController>();
90 InitSwiperController();
91 }
92
OnAttachToFrameNode()93 void SwiperPattern::OnAttachToFrameNode()
94 {
95 auto host = GetHost();
96 CHECK_NULL_VOID(host);
97 host->GetRenderContext()->SetClipToFrame(true);
98 host->GetRenderContext()->SetClipToBounds(true);
99 host->GetRenderContext()->UpdateClipEdge(true);
100 InitSurfaceChangedCallback();
101 }
102
OnDetachFromFrameNode(FrameNode * node)103 void SwiperPattern::OnDetachFromFrameNode(FrameNode* node)
104 {
105 auto pipeline = PipelineContext::GetCurrentContext();
106 CHECK_NULL_VOID(pipeline);
107 if (HasSurfaceChangedCallback()) {
108 pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
109 }
110 pipeline->RemoveWindowStateChangedCallback(node->GetId());
111 }
112
CreateLayoutAlgorithm()113 RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
114 {
115 auto host = GetHost();
116 CHECK_NULL_RETURN(host, nullptr);
117 auto swiperLayoutProperty = host->GetLayoutProperty<SwiperLayoutProperty>();
118 CHECK_NULL_RETURN(swiperLayoutProperty, nullptr);
119
120 auto swiperLayoutAlgorithm = MakeRefPtr<SwiperLayoutAlgorithm>();
121 if (swiperLayoutProperty->GetIsCustomAnimation().value_or(false)) {
122 swiperLayoutAlgorithm->SetUseCustomAnimation(true);
123 swiperLayoutAlgorithm->SetCustomAnimationToIndex(customAnimationToIndex_);
124 swiperLayoutAlgorithm->SetIndexsInAnimation(indexsInAnimation_);
125 swiperLayoutAlgorithm->SetNeedUnmountIndexs(needUnmountIndexs_);
126 return swiperLayoutAlgorithm;
127 }
128
129 if (jumpIndex_) {
130 swiperLayoutAlgorithm->SetJumpIndex(jumpIndex_.value());
131 } else if (targetIndex_) {
132 swiperLayoutAlgorithm->SetTargetIndex(targetIndex_.value());
133 }
134 swiperLayoutAlgorithm->SetContentCrossSize(contentCrossSize_);
135 swiperLayoutAlgorithm->SetMainSizeIsMeasured(mainSizeIsMeasured_);
136 swiperLayoutAlgorithm->SetContentMainSize(contentMainSize_);
137 swiperLayoutAlgorithm->SetCurrentDelta(currentDelta_);
138 swiperLayoutAlgorithm->SetItemsPosition(itemPosition_);
139 swiperLayoutAlgorithm->SetIsNeedResetPrevMarginAndNextMargin();
140 if (IsOutOfBoundary() && !IsLoop()) {
141 swiperLayoutAlgorithm->SetOverScrollFeature();
142 }
143 swiperLayoutAlgorithm->SetTotalItemCount(TotalCount());
144 swiperLayoutAlgorithm->SetIsLoop(IsLoop());
145 swiperLayoutAlgorithm->SetSwipeByGroup(IsSwipeByGroup());
146 swiperLayoutAlgorithm->SetRealTotalCount(RealTotalCount());
147 swiperLayoutAlgorithm->SetPlaceItemWidth(placeItemWidth_);
148
149 auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
150 CHECK_NULL_RETURN(host, nullptr);
151 auto effect = swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
152 bool canOverScroll = effect == EdgeEffect::SPRING;
153 swiperLayoutAlgorithm->SetCanOverScroll(canOverScroll);
154 return swiperLayoutAlgorithm;
155 }
156
OnIndexChange()157 void SwiperPattern::OnIndexChange()
158 {
159 auto totalCount = TotalCount();
160 if (NonPositive(totalCount)) {
161 return;
162 }
163
164 auto oldIndex = GetLoopIndex(oldIndex_);
165 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != totalCount) {
166 oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
167 oldChildrenSize_ = totalCount;
168 }
169
170 auto targetIndex = GetLoopIndex(CurrentIndex());
171 if (oldIndex != targetIndex) {
172 auto swiperEventHub = GetEventHub<SwiperEventHub>();
173 CHECK_NULL_VOID(swiperEventHub);
174 swiperEventHub->FireChangeEvent(targetIndex);
175 swiperEventHub->FireIndicatorChangeEvent(targetIndex);
176 swiperEventHub->FireChangeDoneEvent(moveDirection_);
177 // lazyBuild feature.
178 SetLazyLoadFeature(true);
179 }
180 }
181
StopAndResetSpringAnimation()182 void SwiperPattern::StopAndResetSpringAnimation()
183 {
184 if (springAnimationIsRunning_) {
185 AnimationUtils::StopAnimation(springAnimation_);
186 currentDelta_ = 0.0f;
187 itemPosition_.clear();
188 isVoluntarilyClear_ = true;
189 jumpIndex_ = currentIndex_;
190 springAnimationIsRunning_ = false;
191 }
192 }
193
OnLoopChange()194 void SwiperPattern::OnLoopChange()
195 {
196 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
197 CHECK_NULL_VOID(layoutProperty);
198
199 if (!preLoop_.has_value()) {
200 preLoop_ = layoutProperty->GetLoop().value_or(true);
201 return;
202 }
203
204 if (preLoop_.value() != layoutProperty->GetLoop().value_or(true) &&
205 (layoutProperty->GetPrevMargin().has_value() || layoutProperty->GetNextMargin().has_value())) {
206 jumpIndex_ = GetLoopIndex(currentIndex_);
207 preLoop_ = layoutProperty->GetLoop().value_or(true);
208 }
209 }
210
AdjustCurrentIndexOnSwipePage(int32_t index)211 void SwiperPattern::AdjustCurrentIndexOnSwipePage(int32_t index)
212 {
213 auto adjustIndex = SwiperUtils::ComputePageIndex(index, GetDisplayCount());
214 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
215 CHECK_NULL_VOID(layoutProperty);
216 layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(adjustIndex));
217 currentIndex_ = GetLoopIndex(adjustIndex);
218 }
219
OnModifyDone()220 void SwiperPattern::OnModifyDone()
221 {
222 currentOffset_ = 0.0f;
223 Pattern::OnModifyDone();
224 auto host = GetHost();
225 CHECK_NULL_VOID(host);
226 auto hub = host->GetEventHub<EventHub>();
227 CHECK_NULL_VOID(hub);
228 auto gestureHub = hub->GetOrCreateGestureEventHub();
229 CHECK_NULL_VOID(gestureHub);
230 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
231 CHECK_NULL_VOID(layoutProperty);
232
233 InitIndicator();
234 InitArrow();
235 SetLazyLoadIsLoop();
236 RegisterVisibleAreaChange();
237 InitTouchEvent(gestureHub);
238 InitHoverMouseEvent();
239 StopAndResetSpringAnimation();
240 OnLoopChange();
241 if ((layoutProperty->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) {
242 StopPropertyTranslateAnimation(isFinishAnimation_);
243 StopTranslateAnimation();
244 StopSpringAnimation();
245 StopFadeAnimation();
246 StopIndicatorAnimation();
247 currentOffset_ = 0.0f;
248 mainSizeIsMeasured_ = false;
249 itemPosition_.clear();
250 isVoluntarilyClear_ = true;
251 jumpIndex_ = currentIndex_;
252 for (const auto& child : host->GetChildren()) {
253 if (child->GetTag() == V2::JS_LAZY_FOR_EACH_ETS_TAG) {
254 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(child);
255 CHECK_NULL_VOID(lazyForEachNode);
256 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
257 }
258 }
259 }
260 bool disableSwipe = IsDisableSwipe();
261 UpdateSwiperPanEvent(disableSwipe);
262
263 auto focusHub = host->GetFocusHub();
264 if (focusHub) {
265 InitOnKeyEvent(focusHub);
266 InitOnFocusInternal(focusHub);
267 }
268
269 SetSwiperEventCallback(disableSwipe);
270
271 auto updateCubicCurveCallback = [weak = WeakClaim(this)]() {
272 auto swiperPattern = weak.Upgrade();
273 CHECK_NULL_VOID(swiperPattern);
274 auto host = swiperPattern->GetHost();
275 CHECK_NULL_VOID(host);
276 auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
277 CHECK_NULL_VOID(swiperPaintProperty);
278 auto curve = MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
279 swiperPaintProperty->UpdateCurve(curve);
280 };
281 swiperController_->SetUpdateCubicCurveCallback(std::move(updateCubicCurveCallback));
282
283 if (IsAutoPlay()) {
284 StartAutoPlay();
285 } else {
286 translateTask_.Cancel();
287 }
288
289 SetAccessibilityAction();
290 placeItemWidth_.reset();
291
292 if (IsSwipeByGroup()) {
293 needAdjustIndex_ = true;
294 }
295 }
296
OnAfterModifyDone()297 void SwiperPattern::OnAfterModifyDone()
298 {
299 auto host = GetHost();
300 CHECK_NULL_VOID(host);
301 auto inspectorId = host->GetInspectorId().value_or("");
302 if (!inspectorId.empty()) {
303 Recorder::NodeDataCache::Get().PutInt(inspectorId, CurrentIndex());
304 }
305 }
306
BeforeCreateLayoutWrapper()307 void SwiperPattern::BeforeCreateLayoutWrapper()
308 {
309 auto host = GetHost();
310 CHECK_NULL_VOID(host);
311 if (host->GetChildrenUpdated() != -1 && NeedAutoPlay() && !translateTask_) {
312 StartAutoPlay();
313 host->ChildrenUpdatedFrom(-1);
314 }
315
316 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
317 CHECK_NULL_VOID(layoutProperty);
318 oldIndex_ = currentIndex_;
319 auto userSetCurrentIndex = CurrentIndex();
320 auto oldIndex = GetLoopIndex(oldIndex_);
321 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != TotalCount()) {
322 oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
323 if (HasIndicatorNode()) {
324 StopIndicatorAnimation();
325 auto host = GetHost();
326 CHECK_NULL_VOID(host);
327 auto indicatorNode = DynamicCast<FrameNode>(
328 host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
329 if (indicatorNode && indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
330 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
331 }
332 }
333 }
334 if (userSetCurrentIndex < 0 || userSetCurrentIndex >= TotalCount()) {
335 currentIndex_ = 0;
336 layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
337 } else {
338 if (oldIndex != userSetCurrentIndex) {
339 currentIndex_ = userSetCurrentIndex;
340 propertyAnimationIndex_ = GetLoopIndex(propertyAnimationIndex_);
341 }
342 }
343
344 if (IsSwipeByGroup() && needAdjustIndex_) {
345 AdjustCurrentIndexOnSwipePage(CurrentIndex());
346 needAdjustIndex_ = false;
347 }
348
349 if (oldIndex_ != currentIndex_ || (itemPosition_.empty() && !isVoluntarilyClear_)) {
350 jumpIndex_ = GetLoopIndex(currentIndex_);
351 currentFirstIndex_ = jumpIndex_.value_or(0);
352 turnPageRate_ = 0.0f;
353 }
354 isVoluntarilyClear_ = false;
355 if (jumpIndex_) {
356 if ((jumpIndex_.value() < 0 || jumpIndex_.value() >= TotalCount()) && !IsLoop()) {
357 jumpIndex_ = 0;
358 }
359 targetIndex_.reset();
360 if (usePropertyAnimation_) {
361 StopPropertyTranslateAnimation(false, true);
362 currentDelta_ = 0.0f;
363 StopIndicatorAnimation();
364 }
365 }
366 if (mainSizeIsMeasured_ && isNeedResetPrevMarginAndNextMargin_) {
367 layoutProperty->UpdatePrevMarginWithoutMeasure(0.0_px);
368 layoutProperty->UpdateNextMarginWithoutMeasure(0.0_px);
369 }
370 }
371
InitSurfaceChangedCallback()372 void SwiperPattern::InitSurfaceChangedCallback()
373 {
374 auto host = GetHost();
375 CHECK_NULL_VOID(host);
376 auto pipeline = host->GetContext();
377 CHECK_NULL_VOID(pipeline);
378 if (!HasSurfaceChangedCallback()) {
379 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
380 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
381 WindowSizeChangeReason type) {
382 if (type == WindowSizeChangeReason::UNDEFINED) {
383 return;
384 }
385 auto swiper = weak.Upgrade();
386 if (!swiper) {
387 return;
388 }
389
390 if (type == WindowSizeChangeReason::ROTATION) {
391 swiper->windowSizeChangeReason_ = type;
392 swiper->StopAutoPlay();
393 }
394
395 swiper->StopPropertyTranslateAnimation(swiper->isFinishAnimation_);
396 swiper->StopTranslateAnimation();
397 swiper->StopSpringAnimation();
398 swiper->StopFadeAnimation();
399 swiper->StopIndicatorAnimation();
400
401 const auto& surfaceChangeCallback = swiper->swiperController_->GetSurfaceChangeCallback();
402 if (surfaceChangeCallback) {
403 surfaceChangeCallback();
404 }
405 swiper->currentOffset_ = 0.0f;
406 swiper->itemPosition_.clear();
407 swiper->isVoluntarilyClear_ = true;
408 swiper->jumpIndex_ = swiper->currentIndex_;
409 swiper->MarkDirtyNodeSelf();
410 auto swiperNode = swiper->GetHost();
411 CHECK_NULL_VOID(swiperNode);
412 for (const auto& child : swiperNode->GetChildren()) {
413 if (child->GetTag() == V2::JS_LAZY_FOR_EACH_ETS_TAG) {
414 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(child);
415 CHECK_NULL_VOID(lazyForEachNode);
416 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
417 }
418 }
419 });
420 UpdateSurfaceChangedCallbackId(callbackId);
421 }
422 }
423
FlushFocus(const RefPtr<FrameNode> & curShowFrame)424 void SwiperPattern::FlushFocus(const RefPtr<FrameNode>& curShowFrame)
425 {
426 CHECK_NULL_VOID(curShowFrame);
427 auto swiperHost = GetHost();
428 CHECK_NULL_VOID(swiperHost);
429 auto swiperFocusHub = swiperHost->GetFocusHub();
430 CHECK_NULL_VOID(swiperFocusHub);
431 auto showChildFocusHub = curShowFrame->GetFirstFocusHubChild();
432 CHECK_NULL_VOID(showChildFocusHub);
433 auto focusChildren = swiperFocusHub->GetChildren();
434 CHECK_NULL_VOID(!focusChildren.empty());
435 auto iter = focusChildren.rbegin();
436 if (IsShowIndicator()) {
437 ++iter;
438 }
439 if (HasLeftButtonNode()) {
440 ++iter;
441 }
442 if (HasRightButtonNode()) {
443 ++iter;
444 }
445 while (iter != focusChildren.rend()) {
446 auto child = *iter;
447 if (!child) {
448 ++iter;
449 continue;
450 }
451 if (child != showChildFocusHub) {
452 child->SetParentFocusable(false);
453 } else {
454 child->SetParentFocusable(true);
455 }
456 ++iter;
457 }
458
459 RefPtr<FocusHub> needFocusNode = showChildFocusHub;
460 if (IsShowIndicator() && isLastIndicatorFocused_) {
461 needFocusNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
462 }
463 CHECK_NULL_VOID(needFocusNode);
464 lastWeakShowNode_ = AceType::WeakClaim(AceType::RawPtr(curShowFrame));
465 if (swiperFocusHub->IsCurrentFocus()) {
466 needFocusNode->RequestFocusImmediately();
467 } else {
468 swiperFocusHub->SetLastWeakFocusNode(AceType::WeakClaim(AceType::RawPtr(needFocusNode)));
469 }
470 }
GetFocusHubChild(std::string childFrameName)471 RefPtr<FocusHub> SwiperPattern::GetFocusHubChild(std::string childFrameName)
472 {
473 auto swiperHost = GetHost();
474 CHECK_NULL_RETURN(swiperHost, nullptr);
475 auto swiperFocusHub = swiperHost->GetFocusHub();
476 CHECK_NULL_RETURN(swiperFocusHub, nullptr);
477 auto focusChildren = swiperFocusHub->GetChildren();
478 CHECK_NULL_RETURN(!focusChildren.empty(), nullptr);
479 for (const auto& child : focusChildren) {
480 CHECK_NULL_RETURN(child, nullptr);
481 if (child->GetFrameName() == childFrameName) {
482 return child;
483 }
484 }
485 return nullptr;
486 }
487
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)488 WeakPtr<FocusHub> SwiperPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
489 {
490 auto curFocusNode = currentFocusNode.Upgrade();
491 CHECK_NULL_RETURN(curFocusNode, nullptr);
492 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::UP) ||
493 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::SHIFT_TAB) ||
494 (GetDirection() == Axis::VERTICAL && step == FocusStep::LEFT)) {
495 return PreviousFocus(curFocusNode);
496 }
497 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
498 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::TAB) ||
499 (GetDirection() == Axis::VERTICAL && step == FocusStep::RIGHT)) {
500 return NextFocus(curFocusNode);
501 }
502 return nullptr;
503 }
504
PreviousFocus(const RefPtr<FocusHub> & curFocusNode)505 WeakPtr<FocusHub> SwiperPattern::PreviousFocus(const RefPtr<FocusHub>& curFocusNode)
506 {
507 CHECK_NULL_RETURN(curFocusNode, nullptr);
508 RefPtr<FocusHub> indicatorNode;
509 RefPtr<FocusHub> leftArrowNode;
510 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
511 CHECK_NULL_RETURN(layoutProperty, nullptr);
512 if (HasLeftButtonNode()) {
513 leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
514 CHECK_NULL_RETURN(leftArrowNode, nullptr);
515 }
516 if (HasIndicatorNode()) {
517 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
518 CHECK_NULL_RETURN(indicatorNode, nullptr);
519 }
520 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
521 isLastIndicatorFocused_ = false;
522 (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ? curFocusNode->SetParentFocusable(false)
523 : curFocusNode->SetParentFocusable(true);
524 return nullptr;
525 }
526 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
527 if (!HasLeftButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ||
528 layoutProperty->GetHoverShowValue(false)) {
529 isLastIndicatorFocused_ = true;
530 curFocusNode->SetParentFocusable(true);
531 return nullptr;
532 }
533 isLastIndicatorFocused_ = false;
534 leftArrowNode->SetParentFocusable(true);
535 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
536 }
537 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
538 if (HasIndicatorNode()) {
539 isLastIndicatorFocused_ = true;
540 indicatorNode->SetParentFocusable(true);
541 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
542 }
543 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
544 curFocusNode->SetParentFocusable(true);
545 return nullptr;
546 }
547 isLastIndicatorFocused_ = true;
548 leftArrowNode->SetParentFocusable(true);
549 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
550 }
551 curFocusNode->SetParentFocusable(true);
552 return nullptr;
553 }
554
NextFocus(const RefPtr<FocusHub> & curFocusNode)555 WeakPtr<FocusHub> SwiperPattern::NextFocus(const RefPtr<FocusHub>& curFocusNode)
556 {
557 CHECK_NULL_RETURN(curFocusNode, nullptr);
558 RefPtr<FocusHub> indicatorNode;
559 RefPtr<FocusHub> rightArrowNode;
560 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
561 CHECK_NULL_RETURN(layoutProperty, nullptr);
562 if (HasIndicatorNode()) {
563 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
564 CHECK_NULL_RETURN(indicatorNode, nullptr);
565 }
566 if (HasRightButtonNode()) {
567 rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
568 CHECK_NULL_RETURN(rightArrowNode, nullptr);
569 }
570 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
571 if (HasIndicatorNode()) {
572 isLastIndicatorFocused_ = true;
573 indicatorNode->SetParentFocusable(true);
574 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
575 }
576 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
577 curFocusNode->SetParentFocusable(true);
578 return nullptr;
579 }
580 isLastIndicatorFocused_ = true;
581 rightArrowNode->SetParentFocusable(true);
582 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
583 }
584 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
585 if (!HasRightButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ||
586 layoutProperty->GetHoverShowValue(false)) {
587 isLastIndicatorFocused_ = true;
588 curFocusNode->SetParentFocusable(true);
589 return nullptr;
590 }
591 isLastIndicatorFocused_ = false;
592 rightArrowNode->SetParentFocusable(true);
593 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
594 }
595 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
596 isLastIndicatorFocused_ = false;
597 (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ? curFocusNode->SetParentFocusable(false)
598 : curFocusNode->SetParentFocusable(true);
599 return nullptr;
600 }
601 curFocusNode->SetParentFocusable(true);
602 return nullptr;
603 }
604
GetLoopIndex(int32_t originalIndex) const605 int32_t SwiperPattern::GetLoopIndex(int32_t originalIndex) const
606 {
607 if (TotalCount() <= 0) {
608 return originalIndex;
609 }
610 auto loopIndex = originalIndex;
611 while (loopIndex < 0) {
612 loopIndex = loopIndex + TotalCount();
613 }
614 loopIndex %= TotalCount();
615 return loopIndex;
616 }
617
AdjustCurrentFocusIndex()618 void SwiperPattern::AdjustCurrentFocusIndex()
619 {
620 if (GetDisplayCount() <= 1) {
621 currentFocusIndex_ = currentIndex_;
622 return;
623 }
624
625 if (currentFocusIndex_ >= currentIndex_ && currentFocusIndex_ < currentIndex_ + GetDisplayCount()) {
626 return;
627 }
628
629 currentFocusIndex_ = currentIndex_;
630 }
631
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)632 bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
633 {
634 if (!isDragging_) {
635 SetLazyLoadFeature(true);
636 }
637
638 auto isNotInit = true;
639 if (isInit_) {
640 isNotInit = false;
641 isInit_ = false;
642 // first load Swiper to preload page.
643 SetLazyLoadFeature(true);
644 } else {
645 OnIndexChange();
646 oldIndex_ = currentIndex_;
647 }
648
649 if (!IsAutoPlay() && config.skipMeasure && config.skipLayout) {
650 return false;
651 }
652
653 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
654 CHECK_NULL_RETURN(layoutProperty, false);
655 auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm();
656 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
657 auto swiperLayoutAlgorithm = DynamicCast<SwiperLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
658 CHECK_NULL_RETURN(swiperLayoutAlgorithm, false);
659
660 if (layoutProperty->GetIsCustomAnimation().value_or(false)) {
661 needUnmountIndexs_ = swiperLayoutAlgorithm->GetNeedUnmountIndexs();
662 return false;
663 }
664
665 autoLinearReachBoundary = false;
666 bool isJump = false;
667 itemPosition_ = std::move(swiperLayoutAlgorithm->GetItemPosition());
668 currentOffset_ -= swiperLayoutAlgorithm->GetCurrentOffset();
669 if (!itemPosition_.empty()) {
670 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
671 if (turnPageRateCallback && isDragging_ && !NearZero(GetTranslateLength())) {
672 turnPageRateCallback(
673 itemPosition_.begin()->first, -itemPosition_.begin()->second.startPos / GetTranslateLength());
674 }
675
676 placeItemWidth_ = itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
677 }
678 auto host = GetHost();
679 CHECK_NULL_RETURN(host, false);
680 if (!targetIndex_) {
681 CheckMarkDirtyNodeForRenderIndicator();
682 }
683
684 if (jumpIndex_) {
685 isJump = true;
686 UpdateCurrentIndex(swiperLayoutAlgorithm->GetCurrentIndex());
687 AdjustCurrentFocusIndex();
688 auto curChild = dirty->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_));
689 if (curChild) {
690 auto curChildFrame = curChild->GetHostNode();
691 CHECK_NULL_RETURN(curChildFrame, false);
692 FlushFocus(curChildFrame);
693 }
694 currentIndexOffset_ = 0.0f;
695 if (isNotInit) {
696 OnIndexChange();
697 }
698 jumpIndex_.reset();
699 auto delayTime = GetInterval() - GetDuration();
700 delayTime = std::clamp(delayTime, 0, delayTime);
701 if (NeedAutoPlay() && isUserFinish_) {
702 PostTranslateTask(delayTime);
703 }
704 } else if (targetIndex_) {
705 auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
706 auto iter = itemPosition_.find(targetIndexValue);
707 if (iter != itemPosition_.end()) {
708 float targetPos = 0.0f;
709 targetPos = iter->second.startPos;
710 auto context = PipelineContext::GetCurrentContext();
711 if (context) {
712 // displayCount is auto, loop is false, if the content width less than windows size
713 // need offset to keep right aligned
714 bool isNeedOffset = (GetLoopIndex(iter->first) == TotalCount() - 1)
715 && !layoutProperty->GetDisplayCount().has_value() && !IsLoop()
716 && LessNotEqual(iter->second.endPos - iter->second.startPos, CalculateVisibleSize());
717 float offset = isNeedOffset
718 ? CalculateVisibleSize() - iter->second.endPos + iter->second.startPos : 0.0;
719 targetPos -= offset;
720
721 auto nextIndex = iter->first;
722 auto stopAutoPlay = false;
723 if (AutoLinearAnimationNeedReset(targetPos)) {
724 auto firstItem = GetFirstItemInfoInVisibleArea();
725 nextIndex = firstItem.first;
726 targetPos = firstItem.second.startPos;
727 stopAutoPlay = true;
728 autoLinearReachBoundary = true;
729 }
730
731 context->AddAfterLayoutTask([weak = WeakClaim(this), targetPos, velocity = velocity_.value_or(0.0f),
732 nextIndex, stopAutoPlay]() {
733 auto swiper = weak.Upgrade();
734 CHECK_NULL_VOID(swiper);
735 swiper->PlayPropertyTranslateAnimation(-targetPos, nextIndex, velocity, stopAutoPlay);
736 swiper->PlayIndicatorTranslateAnimation(-targetPos);
737 });
738 } else {
739 PlayTranslateAnimation(
740 currentOffset_, currentOffset_ - targetPos, iter->first, false, velocity_.value_or(0.0f));
741 }
742 velocity_.reset();
743 }
744 pauseTargetIndex_ = targetIndex_;
745 }
746 mainSizeIsMeasured_ = swiperLayoutAlgorithm->GetMainSizeIsMeasured();
747 isNeedResetPrevMarginAndNextMargin_ = swiperLayoutAlgorithm->GetIsNeedResetPrevMarginAndNextMargin();
748 contentCrossSize_ = swiperLayoutAlgorithm->GetContentCrossSize();
749 currentDelta_ = 0.0f;
750 contentMainSize_ = swiperLayoutAlgorithm->GetContentMainSize();
751 startMainPos_ = swiperLayoutAlgorithm->GetStartPosition();
752 endMainPos_ = swiperLayoutAlgorithm->GetEndPosition();
753 startIndex_ = swiperLayoutAlgorithm->GetStartIndex();
754 endIndex_ = swiperLayoutAlgorithm->GetEndIndex();
755 crossMatchChild_ = swiperLayoutAlgorithm->IsCrossMatchChild();
756 oldIndex_ = currentIndex_;
757 oldChildrenSize_ = TotalCount();
758
759 if (windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION) {
760 StartAutoPlay();
761 windowSizeChangeReason_ = WindowSizeChangeReason::UNDEFINED;
762 }
763
764 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
765 return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
766 }
767
IsAutoLinear() const768 bool SwiperPattern::IsAutoLinear() const
769 {
770 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
771 CHECK_NULL_RETURN(swiperLayoutProperty, false);
772 return !SwiperUtils::IsStretch(swiperLayoutProperty);
773 }
774
AutoLinearAnimationNeedReset(float translate) const775 bool SwiperPattern::AutoLinearAnimationNeedReset(float translate) const
776 {
777 if (!IsAutoLinear()) {
778 return false;
779 }
780
781 if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
782 return false;
783 }
784
785 if (NonPositive(translate)) {
786 return false;
787 }
788
789 auto iter = itemPosition_.rbegin();
790 auto endPos = iter->second.endPos;
791 if (endPos - CalculateVisibleSize() < translate) {
792 return true;
793 }
794
795 return false;
796 }
797
OnAnimationTranslateZero(int32_t nextIndex,bool stopAutoPlay)798 void SwiperPattern::OnAnimationTranslateZero(int32_t nextIndex, bool stopAutoPlay)
799 {
800 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
801
802 if (!NeedAutoPlay() || !isUserFinish_) {
803 return;
804 }
805
806 if (stopAutoPlay) {
807 MarkDirtyNodeSelf();
808 } else {
809 auto delayTime = GetInterval() - GetDuration();
810 delayTime = std::clamp(delayTime, 0, delayTime);
811 PostTranslateTask(delayTime);
812 }
813 }
814
FireChangeEvent() const815 void SwiperPattern::FireChangeEvent() const
816 {
817 auto swiperEventHub = GetEventHub<SwiperEventHub>();
818 CHECK_NULL_VOID(swiperEventHub);
819 swiperEventHub->FireChangeEvent(GetLoopIndex(currentIndex_));
820 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
821 swiperEventHub->FireChangeDoneEvent(moveDirection_);
822 }
823
FireAnimationStartEvent(int32_t currentIndex,int32_t nextIndex,const AnimationCallbackInfo & info) const824 void SwiperPattern::FireAnimationStartEvent(
825 int32_t currentIndex, int32_t nextIndex, const AnimationCallbackInfo& info) const
826 {
827 auto swiperEventHub = GetEventHub<SwiperEventHub>();
828 CHECK_NULL_VOID(swiperEventHub);
829 swiperEventHub->FireAnimationStartEvent(currentIndex, nextIndex, info);
830 auto host = GetHost();
831 CHECK_NULL_VOID(host);
832 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
833 }
834
FireAnimationEndEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const835 void SwiperPattern::FireAnimationEndEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
836 {
837 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_FLING, false);
838 if (currentIndex == -1) {
839 return;
840 }
841 auto swiperEventHub = GetEventHub<SwiperEventHub>();
842 CHECK_NULL_VOID(swiperEventHub);
843 swiperEventHub->FireAnimationEndEvent(currentIndex, info);
844 }
845
FireGestureSwipeEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const846 void SwiperPattern::FireGestureSwipeEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
847 {
848 auto swiperEventHub = GetEventHub<SwiperEventHub>();
849 CHECK_NULL_VOID(swiperEventHub);
850 swiperEventHub->FireGestureSwipeEvent(currentIndex, info);
851 }
852
SwipeToWithoutAnimation(int32_t index)853 void SwiperPattern::SwipeToWithoutAnimation(int32_t index)
854 {
855 if (IsVisibleChildrenSizeLessThanSwiper()) {
856 return;
857 }
858
859 if (usePropertyAnimation_) {
860 StopPropertyTranslateAnimation(isFinishAnimation_);
861 }
862
863 StopFadeAnimation();
864 StopSpringAnimation();
865 jumpIndex_ = index;
866 uiCastJumpIndex_ = index;
867 MarkDirtyNodeSelf();
868 FireAndCleanScrollingListener();
869 }
870
StopSpringAnimationAndFlushImmediately()871 void SwiperPattern::StopSpringAnimationAndFlushImmediately()
872 {
873 if (springAnimationIsRunning_) {
874 AnimationUtils::StopAnimation(springAnimation_);
875 currentDelta_ = 0.0f;
876 itemPosition_.clear();
877 isVoluntarilyClear_ = true;
878 jumpIndex_ = currentIndex_;
879 springAnimationIsRunning_ = false;
880 MarkDirtyNodeSelf();
881 auto pipeline = PipelineContext::GetCurrentContext();
882 if (pipeline) {
883 pipeline->FlushUITasks();
884 }
885 }
886 }
887
IsUseCustomAnimation() const888 bool SwiperPattern::IsUseCustomAnimation() const
889 {
890 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
891 CHECK_NULL_RETURN(swiperLayoutProperty, false);
892 return swiperLayoutProperty->GetIsCustomAnimation().value_or(false);
893 }
894
SwipeTo(int32_t index)895 void SwiperPattern::SwipeTo(int32_t index)
896 {
897 auto targetIndex = IsLoop() ? index : (index < 0 || index > (TotalCount() - 1)) ? 0 : index;
898 targetIndex = IsLoop() ? targetIndex : std::clamp(targetIndex, 0, TotalCount() - GetDisplayCount());
899 if (!ContentWillChange(targetIndex)) {
900 return;
901 }
902
903 if (IsUseCustomAnimation()) {
904 OnCustomContentTransition(targetIndex);
905 MarkDirtyNodeSelf();
906 return;
907 }
908
909 if (IsVisibleChildrenSizeLessThanSwiper()) {
910 return;
911 }
912
913 // If targetIndex_ has a value, means animation is still running, stop it before play new animation.
914 if (currentIndex_ == targetIndex && !targetIndex_.has_value()) {
915 return;
916 }
917 StopFadeAnimation();
918 if (springAnimationIsRunning_) {
919 AnimationUtils::StopAnimation(springAnimation_);
920 jumpIndex_ = currentIndex_;
921 springAnimationIsRunning_ = false;
922 MarkDirtyNodeSelf();
923 auto pipeline = PipelineContext::GetCurrentContext();
924 if (pipeline) {
925 pipeline->FlushUITasks();
926 }
927 }
928 StopAutoPlay();
929 StopTranslateAnimation();
930 StopIndicatorAnimation();
931 if (usePropertyAnimation_) {
932 StopPropertyTranslateAnimation(isFinishAnimation_);
933 }
934
935 targetIndex_ = targetIndex;
936
937 if (GetDuration() == 0 || !isVisible_) {
938 SwipeToWithoutAnimation(index);
939 return;
940 }
941
942 MarkDirtyNodeSelf();
943 }
944
CheckTargetIndex(int32_t targetIndex,bool isForceBackward)945 int32_t SwiperPattern::CheckTargetIndex(int32_t targetIndex, bool isForceBackward)
946 {
947 if (!IsAutoLinear()) {
948 return targetIndex;
949 }
950 while (GetLoopIndex(targetIndex) != GetLoopIndex(currentIndex_)) {
951 auto currentFrameNode = GetCurrentFrameNode(GetLoopIndex(targetIndex));
952 CHECK_NULL_RETURN(currentFrameNode, targetIndex);
953 auto swiperLayoutProperty = currentFrameNode->GetLayoutProperty<LayoutProperty>();
954 CHECK_NULL_RETURN(swiperLayoutProperty, targetIndex);
955 if (swiperLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
956 return targetIndex;
957 }
958 if (isForceBackward || currentIndex_ < targetIndex) {
959 ++targetIndex;
960 } else {
961 --targetIndex;
962 }
963 if (!IsLoop() && (targetIndex < 0 || targetIndex >= TotalCount())) {
964 return currentIndex_;
965 }
966 }
967 return targetIndex;
968 }
969
ShowNext()970 void SwiperPattern::ShowNext()
971 {
972 if (IsVisibleChildrenSizeLessThanSwiper()) {
973 return;
974 }
975 indicatorDoingAnimation_ = false;
976 auto childrenSize = TotalCount();
977 std::optional<int32_t> preIndex;
978 if (preTargetIndex_.has_value()) {
979 if (GetLoopIndex(preTargetIndex_.value()) >= childrenSize - GetDisplayCount() && !IsLoop()) {
980 return;
981 }
982 preIndex = preTargetIndex_.value();
983 } else if (GetLoopIndex(currentIndex_) >= childrenSize - GetDisplayCount() && !IsLoop()) {
984 return;
985 }
986 if (childrenSize <= 0 || GetDisplayCount() == 0) {
987 return;
988 }
989 StopAutoPlay();
990 StopTranslateAnimation();
991
992 StopSpringAnimationAndFlushImmediately();
993 StopFadeAnimation();
994 StopIndicatorAnimation();
995 if (preIndex) {
996 isUserFinish_ = false;
997 FinishAnimation();
998 if (!ContentWillChange(currentIndex_ + 1)) {
999 return;
1000 }
1001 }
1002 moveDirection_ = true;
1003
1004 auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1005 if (isVisible_) {
1006 targetIndex_ = CheckTargetIndex(currentIndex_ + stepItems);
1007 preTargetIndex_ = targetIndex_;
1008 MarkDirtyNodeSelf();
1009 auto pipeline = PipelineContext::GetCurrentContext();
1010 if (pipeline) {
1011 pipeline->FlushUITasks();
1012 }
1013 } else {
1014 SwipeToWithoutAnimation(currentIndex_ + stepItems);
1015 }
1016 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1017 CHECK_NULL_VOID(swiperEventHub);
1018 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1019 }
1020
ShowPrevious()1021 void SwiperPattern::ShowPrevious()
1022 {
1023 if (IsVisibleChildrenSizeLessThanSwiper()) {
1024 return;
1025 }
1026
1027 if (IsAutoLinear() && static_cast<int32_t>(itemPosition_.size()) == TotalCount() && !autoLinearReachBoundary) {
1028 return;
1029 }
1030
1031 indicatorDoingAnimation_ = false;
1032 auto childrenSize = TotalCount();
1033 std::optional<int32_t> preIndex;
1034 if (preTargetIndex_.has_value()) {
1035 if (GetLoopIndex(preTargetIndex_.value()) <= 0 && !IsLoop()) {
1036 return;
1037 }
1038 preIndex = preTargetIndex_.value();
1039 } else if (GetLoopIndex(currentIndex_) <= 0 && !IsLoop()) {
1040 return;
1041 }
1042 if (childrenSize <= 0 || GetDisplayCount() == 0) {
1043 return;
1044 }
1045 StopAutoPlay();
1046 StopTranslateAnimation();
1047 StopSpringAnimationAndFlushImmediately();
1048 StopFadeAnimation();
1049 StopIndicatorAnimation();
1050
1051 if (preIndex) {
1052 isUserFinish_ = false;
1053 FinishAnimation();
1054 if (!ContentWillChange(currentIndex_ - 1)) {
1055 return;
1056 }
1057 }
1058 moveDirection_ = false;
1059
1060 auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1061 if (isVisible_) {
1062 targetIndex_ = CheckTargetIndex(currentIndex_ - stepItems);
1063 preTargetIndex_ = targetIndex_;
1064 MarkDirtyNodeSelf();
1065 auto pipeline = PipelineContext::GetCurrentContext();
1066 if (pipeline) {
1067 pipeline->FlushUITasks();
1068 }
1069 } else {
1070 SwipeToWithoutAnimation(currentIndex_ - stepItems);
1071 }
1072 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1073 CHECK_NULL_VOID(swiperEventHub);
1074 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1075 }
1076
FinishAnimation()1077 void SwiperPattern::FinishAnimation()
1078 {
1079 StopTranslateAnimation();
1080 StopSpringAnimation();
1081 StopFadeAnimation();
1082 StopIndicatorAnimation();
1083
1084 if (usePropertyAnimation_) {
1085 isFinishAnimation_ = true;
1086 StopPropertyTranslateAnimation(isFinishAnimation_);
1087 }
1088 if (isUserFinish_) {
1089 if (swiperController_ && swiperController_->GetFinishCallback()) {
1090 auto finishCallback = swiperController_->GetFinishCallback();
1091 finishCallback();
1092 swiperController_->SetFinishCallback(nullptr);
1093 }
1094 } else {
1095 isUserFinish_ = true;
1096 }
1097 }
1098
PreloadItems(const std::set<int32_t> & indexSet)1099 void SwiperPattern::PreloadItems(const std::set<int32_t>& indexSet)
1100 {
1101 std::set<int32_t> validIndexSet;
1102 auto childrenSize = RealTotalCount();
1103 auto errorCode = ERROR_CODE_NO_ERROR;
1104 for (const auto& index : indexSet) {
1105 if (index < 0 || index >= childrenSize) {
1106 errorCode = ERROR_CODE_PARAM_INVALID;
1107 break;
1108 }
1109
1110 validIndexSet.emplace(index);
1111 }
1112
1113 if (errorCode != ERROR_CODE_PARAM_INVALID) {
1114 DoPreloadItems(validIndexSet, errorCode);
1115 return;
1116 }
1117
1118 FirePreloadFinishEvent(errorCode);
1119 }
1120
FirePreloadFinishEvent(int32_t errorCode)1121 void SwiperPattern::FirePreloadFinishEvent(int32_t errorCode)
1122 {
1123 if (swiperController_ && swiperController_->GetPreloadFinishCallback()) {
1124 auto preloadFinishCallback = swiperController_->GetPreloadFinishCallback();
1125 swiperController_->SetPreloadFinishCallback(nullptr);
1126 preloadFinishCallback(errorCode);
1127 }
1128 }
1129
DoPreloadItems(const std::set<int32_t> & indexSet,int32_t errorCode)1130 void SwiperPattern::DoPreloadItems(const std::set<int32_t>& indexSet, int32_t errorCode)
1131 {
1132 if (indexSet.empty()) {
1133 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID);
1134 return;
1135 }
1136
1137 auto preloadTask = [weak = WeakClaim(this), indexSet, errorCode]() {
1138 auto swiperPattern = weak.Upgrade();
1139 CHECK_NULL_VOID(swiperPattern);
1140 auto host = swiperPattern->GetHost();
1141 CHECK_NULL_VOID(host);
1142 const auto& children = host->GetChildren();
1143 for (const auto& child : children) {
1144 if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG && child->GetTag() != V2::JS_LAZY_FOR_EACH_ETS_TAG) {
1145 continue;
1146 }
1147
1148 auto forEachNode = AceType::DynamicCast<ForEachNode>(child);
1149 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(child);
1150 for (auto index : indexSet) {
1151 if (forEachNode && forEachNode->GetChildAtIndex(index)) {
1152 forEachNode->GetChildAtIndex(index)->Build(nullptr);
1153 continue;
1154 }
1155
1156 if (lazyForEachNode) {
1157 lazyForEachNode->GetFrameChildByIndex(index, true);
1158 }
1159 }
1160 }
1161
1162 swiperPattern->FirePreloadFinishEvent(errorCode);
1163 };
1164 auto pipeline = PipelineContext::GetCurrentContext();
1165 CHECK_NULL_VOID(pipeline);
1166 auto taskExecutor = pipeline->GetTaskExecutor();
1167 CHECK_NULL_VOID(taskExecutor);
1168 taskExecutor->PostTask(preloadTask, TaskExecutor::TaskType::UI);
1169 }
1170
StopTranslateAnimation()1171 void SwiperPattern::StopTranslateAnimation()
1172 {
1173 if (controller_ && !controller_->IsStopped()) {
1174 isFinishAnimation_ = true;
1175 controller_->Stop();
1176 }
1177 }
1178
StopSpringAnimation()1179 void SwiperPattern::StopSpringAnimation()
1180 {
1181 AnimationUtils::StopAnimation(springAnimation_);
1182 if (springAnimationIsRunning_) {
1183 springAnimationIsRunning_ = false;
1184 }
1185 }
1186
StopFadeAnimation()1187 void SwiperPattern::StopFadeAnimation()
1188 {
1189 AnimationUtils::StopAnimation(fadeAnimation_);
1190 if (fadeAnimationIsRunning_) {
1191 fadeAnimationIsRunning_ = false;
1192 }
1193 }
1194
InitSwiperController()1195 void SwiperPattern::InitSwiperController()
1196 {
1197 swiperController_->SetSwipeToImpl([weak = WeakClaim(this)](int32_t index, bool reverse) {
1198 auto swiper = weak.Upgrade();
1199 if (swiper) {
1200 swiper->SwipeTo(index);
1201 }
1202 });
1203
1204 swiperController_->SetSwipeToWithoutAnimationImpl([weak = WeakClaim(this)](int32_t index) {
1205 auto swiper = weak.Upgrade();
1206 if (swiper) {
1207 swiper->SwipeToWithoutAnimation(index);
1208 }
1209 });
1210
1211 swiperController_->SetShowNextImpl([weak = WeakClaim(this)]() {
1212 auto swiper = weak.Upgrade();
1213 if (swiper) {
1214 auto swiperNode = swiper->GetHost();
1215 CHECK_NULL_VOID(swiperNode);
1216 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper ShowNext, id:%{public}d", swiperNode->GetId());
1217 swiper->ShowNext();
1218 }
1219 });
1220
1221 swiperController_->SetShowPrevImpl([weak = WeakClaim(this)]() {
1222 auto swiper = weak.Upgrade();
1223 if (swiper) {
1224 auto swiperNode = swiper->GetHost();
1225 CHECK_NULL_VOID(swiperNode);
1226 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper SetShowPrevImpl, id:%{public}d", swiperNode->GetId());
1227 swiper->ShowPrevious();
1228 }
1229 });
1230
1231 swiperController_->SetFinishImpl([weak = WeakClaim(this)]() {
1232 auto swiper = weak.Upgrade();
1233 if (swiper) {
1234 swiper->FinishAnimation();
1235 }
1236 });
1237
1238 swiperController_->SetPreloadItemsImpl([weak = WeakClaim(this)](const std::set<int32_t>& indexSet) {
1239 auto swiper = weak.Upgrade();
1240 if (swiper) {
1241 swiper->PreloadItems(indexSet);
1242 }
1243 });
1244 }
1245
InitIndicator()1246 void SwiperPattern::InitIndicator()
1247 {
1248 auto swiperNode = GetHost();
1249 CHECK_NULL_VOID(swiperNode);
1250 RefPtr<FrameNode> indicatorNode;
1251 if (!HasIndicatorNode()) {
1252 if (!IsShowIndicator()) {
1253 return;
1254 }
1255 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
1256 []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
1257 swiperNode->AddChild(indicatorNode);
1258 } else {
1259 indicatorNode =
1260 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetIndicatorId())));
1261 CHECK_NULL_VOID(indicatorNode);
1262 if (!IsShowIndicator()) {
1263 RemoveIndicatorNode();
1264 return;
1265 }
1266 if (GetIndicatorType() == SwiperIndicatorType::DIGIT && lastSwiperIndicatorType_ == SwiperIndicatorType::DOT) {
1267 RemoveIndicatorNode();
1268 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
1269 []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
1270 swiperNode->AddChild(indicatorNode);
1271 }
1272 }
1273 lastSwiperIndicatorType_ = GetIndicatorType();
1274 CHECK_NULL_VOID(indicatorNode);
1275 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
1276 CHECK_NULL_VOID(layoutProperty);
1277 if (layoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DOT) {
1278 SaveDotIndicatorProperty(indicatorNode);
1279 } else {
1280 SaveDigitIndicatorProperty(indicatorNode);
1281 }
1282
1283 auto renderContext = indicatorNode->GetRenderContext();
1284 CHECK_NULL_VOID(renderContext);
1285 BorderRadiusProperty radius;
1286 radius.SetRadius(INDICATOR_BORDER_RADIUS);
1287 renderContext->UpdateBorderRadius(radius);
1288
1289 indicatorNode->MarkModifyDone();
1290 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1291 }
1292
InitArrow()1293 void SwiperPattern::InitArrow()
1294 {
1295 auto swiperNode = GetHost();
1296 CHECK_NULL_VOID(swiperNode);
1297 RefPtr<FrameNode> leftArrow;
1298 RefPtr<FrameNode> rightArrow;
1299 if (!HasLeftButtonNode() && !HasRightButtonNode()) {
1300 if (!IsShowArrow()) {
1301 return;
1302 }
1303 leftArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_LEFT_ARROW_ETS_TAG, GetLeftButtonId(),
1304 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
1305 swiperNode->AddChild(leftArrow);
1306 rightArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_ARROW_ETS_TAG, GetRightButtonId(),
1307 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
1308 swiperNode->AddChild(rightArrow);
1309 } else {
1310 leftArrow =
1311 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
1312 CHECK_NULL_VOID(leftArrow);
1313 rightArrow =
1314 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
1315 CHECK_NULL_VOID(rightArrow);
1316 if (!IsShowArrow()) {
1317 RemoveLeftButtonNode();
1318 RemoveRightButtonNode();
1319 return;
1320 }
1321 }
1322
1323 SaveArrowProperty(leftArrow);
1324 SaveArrowProperty(rightArrow);
1325
1326 leftArrow->MarkModifyDone();
1327 rightArrow->MarkModifyDone();
1328 }
1329
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)1330 void SwiperPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1331 {
1332 if (direction_ == GetDirection() && panEvent_) {
1333 return;
1334 }
1335 direction_ = GetDirection();
1336
1337 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1338 auto pattern = weak.Upgrade();
1339 pattern->InitIndexCanChangeMap();
1340 if (pattern) {
1341 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1342 return;
1343 }
1344 pattern->FireAndCleanScrollingListener();
1345 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag start");
1346 pattern->HandleDragStart(info);
1347 // notify scrollStart upwards
1348 pattern->NotifyParentScrollStart(pattern->direction_ == Axis::HORIZONTAL ? info.GetGlobalLocation().GetX()
1349 : info.GetGlobalLocation().GetY());
1350 }
1351 };
1352
1353 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1354 auto pattern = weak.Upgrade();
1355 if (!pattern->CheckSwiperPanEvent(info)) {
1356 return;
1357 }
1358 if (pattern) {
1359 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1360 if (GreatNotEqual(info.GetMainDelta(), 0.0)) {
1361 pattern->ShowPrevious();
1362 } else if (LessNotEqual(info.GetMainDelta(), 0.0)) {
1363 pattern->ShowNext();
1364 }
1365 } else {
1366 pattern->HandleDragUpdate(info);
1367 }
1368 }
1369 };
1370
1371 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1372 auto pattern = weak.Upgrade();
1373 if (!pattern->CheckSwiperPanEvent(info)) {
1374 pattern->HandleDragEnd(0.0);
1375 return;
1376 }
1377 if (pattern) {
1378 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1379 return;
1380 }
1381 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag end. Velocity: %{public}f px/s", info.GetMainVelocity());
1382 pattern->HandleDragEnd(info.GetMainVelocity());
1383 }
1384 };
1385
1386 auto actionCancelTask = [weak = WeakClaim(this)]() {
1387 auto pattern = weak.Upgrade();
1388 if (pattern) {
1389 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag cancel");
1390 pattern->HandleDragEnd(0.0);
1391 }
1392 };
1393
1394 AddPanEvent(gestureHub, std::move(actionStartTask), std::move(actionUpdateTask),
1395 std::move(actionEndTask), std::move(actionCancelTask));
1396 }
1397
AddPanEvent(const RefPtr<GestureEventHub> & gestureHub,GestureEventFunc && actionStart,GestureEventFunc && actionUpdate,GestureEventFunc && actionEnd,GestureEventNoParameter && actionCancel)1398 void SwiperPattern::AddPanEvent(const RefPtr<GestureEventHub>& gestureHub, GestureEventFunc&& actionStart,
1399 GestureEventFunc&& actionUpdate, GestureEventFunc&& actionEnd, GestureEventNoParameter&& actionCancel)
1400 {
1401 if (GetDirection() == Axis::VERTICAL) {
1402 panDirection_.type = PanDirection::VERTICAL;
1403 } else {
1404 panDirection_.type = PanDirection::HORIZONTAL;
1405 }
1406 if (panEvent_) {
1407 gestureHub->RemovePanEvent(panEvent_);
1408 }
1409
1410 panEvent_ = MakeRefPtr<PanEvent>(
1411 std::move(actionStart), std::move(actionUpdate), std::move(actionEnd), std::move(actionCancel));
1412 gestureHub->AddPanEvent(panEvent_, panDirection_, 1, DEFAULT_PAN_DISTANCE);
1413 }
1414
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)1415 void SwiperPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
1416 {
1417 if (touchEvent_) {
1418 return;
1419 }
1420
1421 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
1422 auto pattern = weak.Upgrade();
1423 if (pattern) {
1424 pattern->HandleTouchEvent(info);
1425 }
1426 };
1427
1428 if (touchEvent_) {
1429 gestureHub->RemoveTouchEvent(touchEvent_);
1430 }
1431 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
1432 gestureHub->AddTouchEvent(touchEvent_);
1433 }
1434
InitOnFocusInternal(const RefPtr<FocusHub> & focusHub)1435 void SwiperPattern::InitOnFocusInternal(const RefPtr<FocusHub>& focusHub)
1436 {
1437 auto focusTask = [weak = WeakClaim(this)]() {
1438 auto pattern = weak.Upgrade();
1439 if (pattern) {
1440 pattern->HandleFocusInternal();
1441 }
1442 };
1443 focusHub->SetOnFocusInternal(std::move(focusTask));
1444 }
1445
HandleFocusInternal()1446 void SwiperPattern::HandleFocusInternal()
1447 {
1448 currentFocusIndex_ = currentIndex_;
1449 }
1450
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1451 void SwiperPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1452 {
1453 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1454 auto pattern = wp.Upgrade();
1455 if (pattern) {
1456 return pattern->OnKeyEvent(event);
1457 }
1458 return false;
1459 };
1460 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1461 }
1462
IsContentFocused()1463 bool SwiperPattern::IsContentFocused()
1464 {
1465 RefPtr<FocusHub> indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
1466 RefPtr<FocusHub> rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
1467 RefPtr<FocusHub> leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
1468
1469 return !((indicatorNode && indicatorNode->IsCurrentFocus()) ||
1470 (rightArrowNode && rightArrowNode->IsCurrentFocus()) ||
1471 (leftArrowNode && leftArrowNode->IsCurrentFocus()));
1472 }
1473
OnKeyEvent(const KeyEvent & event)1474 bool SwiperPattern::OnKeyEvent(const KeyEvent& event)
1475 {
1476 if (event.action != KeyAction::DOWN) {
1477 return false;
1478 }
1479 if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
1480 (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
1481 auto onlyFlushFocus = IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ > currentIndex_;
1482 if (onlyFlushFocus) {
1483 currentFocusIndex_ = IsLoop() ? currentFocusIndex_ - 1 :
1484 std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
1485 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
1486 } else {
1487 ShowPrevious();
1488 currentFocusIndex_ = IsLoop() ? currentFocusIndex_ - 1 :
1489 std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
1490 }
1491
1492 return true;
1493 }
1494 if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
1495 (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
1496 auto onlyFlushFocus =
1497 IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ < currentIndex_ + GetDisplayCount() - 1;
1498 if (onlyFlushFocus) {
1499 currentFocusIndex_ = IsLoop() ? currentFocusIndex_ + 1 :
1500 std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
1501 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
1502 } else {
1503 ShowNext();
1504 currentFocusIndex_ = IsLoop() ? currentFocusIndex_ + 1 :
1505 std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
1506 }
1507
1508 return true;
1509 }
1510 return false;
1511 }
1512
StopAutoPlay()1513 void SwiperPattern::StopAutoPlay()
1514 {
1515 if (IsAutoPlay()) {
1516 translateTask_.Cancel();
1517 }
1518 }
1519
StartAutoPlay()1520 void SwiperPattern::StartAutoPlay()
1521 {
1522 if (NeedAutoPlay()) {
1523 PostTranslateTask(GetInterval());
1524 }
1525 }
1526
OnVisibleChange(bool isVisible)1527 void SwiperPattern::OnVisibleChange(bool isVisible)
1528 {
1529 isVisible_ = isVisible;
1530 if (isInit_) {
1531 return;
1532 }
1533
1534 if (!isVisible_) {
1535 StopAutoPlay();
1536 return;
1537 }
1538
1539 if (NeedStartAutoPlay()) {
1540 StartAutoPlay();
1541 }
1542 }
1543
UpdateCurrentOffset(float offset)1544 void SwiperPattern::UpdateCurrentOffset(float offset)
1545 {
1546 if (itemPosition_.empty()) {
1547 MarkDirtyNodeSelf();
1548 return;
1549 }
1550 if (!IsLoop() && (isDragging_ || childScrolling_)) {
1551 // handle edge effects
1552 if (CheckOverScroll(offset)) {
1553 return;
1554 }
1555 }
1556 currentDelta_ = currentDelta_ - offset;
1557 currentIndexOffset_ += offset;
1558 if (isDragging_) {
1559 AnimationCallbackInfo callbackInfo;
1560 callbackInfo.currentOffset =
1561 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
1562 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
1563 }
1564 MarkDirtyNodeSelf();
1565 }
1566
CheckOverScroll(float offset)1567 bool SwiperPattern::CheckOverScroll(float offset)
1568 {
1569 switch (GetEdgeEffect()) {
1570 case EdgeEffect::SPRING:
1571 if (SpringOverScroll(offset)) {
1572 return true;
1573 }
1574 break;
1575 case EdgeEffect::FADE:
1576 if (FadeOverScroll(offset)) {
1577 return true;
1578 }
1579 break;
1580 case EdgeEffect::NONE:
1581 if (IsOutOfBoundary(offset)) {
1582 currentDelta_ = currentDelta_ - offset;
1583 MarkDirtyNodeSelf();
1584 return true;
1585 }
1586 break;
1587 }
1588 return false;
1589 }
1590
SpringOverScroll(float offset)1591 bool SwiperPattern::SpringOverScroll(float offset)
1592 {
1593 bool outOfBounds = isTouchPad_ ? IsOutOfBoundary(offset) : IsOutOfBoundary();
1594 if (!outOfBounds) {
1595 return false;
1596 }
1597 targetIndex_.reset();
1598
1599 auto visibleSize = CalculateVisibleSize();
1600 if (LessOrEqual(visibleSize, 0.0)) {
1601 return true;
1602 }
1603 auto friction = currentIndexOffset_ > 0
1604 ? CalculateFriction(itemPosition_.begin()->second.startPos / visibleSize)
1605 : CalculateFriction((visibleSize - itemPosition_.rbegin()->second.endPos) / visibleSize);
1606
1607 currentDelta_ = currentDelta_ - friction * offset;
1608 currentIndexOffset_ += friction * offset;
1609 AnimationCallbackInfo callbackInfo;
1610 callbackInfo.currentOffset =
1611 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
1612 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
1613 MarkDirtyNodeSelf();
1614 return true;
1615 }
1616
FadeOverScroll(float offset)1617 bool SwiperPattern::FadeOverScroll(float offset)
1618 {
1619 if (IsOutOfBoundary(fadeOffset_ + offset)) {
1620 auto onlyUpdateFadeOffset = (itemPosition_.begin()->first == 0 && offset < 0.0f) ||
1621 (itemPosition_.rbegin()->first == TotalCount() - 1 && offset > 0.0f);
1622 if (!IsVisibleChildrenSizeLessThanSwiper() && !onlyUpdateFadeOffset) {
1623 currentDelta_ = currentDelta_ - offset;
1624 }
1625 auto host = GetHost();
1626 CHECK_NULL_RETURN(host, false);
1627 if (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) {
1628 auto remainOffset = GetDistanceToEdge();
1629 fadeOffset_ += (offset - remainOffset);
1630 }
1631 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1632 MarkDirtyNodeSelf();
1633 return true;
1634 }
1635
1636 fadeOffset_ = 0.0f;
1637 return false;
1638 }
1639
HandleTouchBottomLoop()1640 void SwiperPattern::HandleTouchBottomLoop()
1641 {
1642 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
1643 auto currentIndex = GetLoopIndex(currentIndex_);
1644 bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
1645 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
1646 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
1647 if (followTouchBottom) {
1648 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
1649 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
1650 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
1651 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
1652 }
1653 return;
1654 }
1655 bool leftReleaseTouchBottom = (commTouchBottom && (currentIndex == 0 && gestureState_ ==
1656 GestureState::GESTURE_STATE_RELEASE_LEFT));
1657 bool rightReleaseTouchBottom = ((currentFirstIndex == 0) && (currentIndex == TotalCount() - 1) &&
1658 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT);
1659 if (leftReleaseTouchBottom || rightReleaseTouchBottom) {
1660 if (currentIndex == 0) {
1661 // left bottom
1662 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
1663 } else if (currentIndex == TotalCount() - 1) {
1664 // right bottom
1665 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
1666 }
1667 }
1668 return;
1669 }
1670
CalculateGestureState(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)1671 void SwiperPattern::CalculateGestureState(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
1672 {
1673 // Keep follow hand
1674 if ((preFirstIndex == 0 && currentFirstIndex_ == TotalCount() - 1) ||
1675 (preFirstIndex == TotalCount() - 1 && currentFirstIndex_ == 0)) {
1676 needTurn_ = true;
1677 }
1678
1679 if (GreatNotEqual(additionalOffset, 0.0f)) {
1680 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
1681 needTurn_ = false;
1682 } else if (LessNotEqual(additionalOffset, 0.0f)) {
1683 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
1684 needTurn_ = false;
1685 } else if (GetLoopIndex(currentFirstIndex_) >= GetLoopIndex(currentIndex_)) {
1686 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
1687 } else if (GetLoopIndex(currentFirstIndex_) < GetLoopIndex(currentIndex_)) {
1688 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
1689 }
1690 return;
1691 }
1692
UpdateNextValidIndex()1693 void SwiperPattern::UpdateNextValidIndex()
1694 {
1695 // item may be invalid in auto linear scene, mark next valid item
1696 if (IsAutoLinear()) {
1697 currentFirstIndex_ = CheckTargetIndex(currentFirstIndex_, true);
1698 nextValidIndex_ = GetLoopIndex(CheckTargetIndex(currentFirstIndex_ + 1, true));
1699 } else {
1700 nextValidIndex_ = -1;
1701 }
1702 }
1703
CheckMarkDirtyNodeForRenderIndicator(float additionalOffset)1704 void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset)
1705 {
1706 if (!indicatorId_.has_value()) {
1707 return;
1708 }
1709 auto host = GetHost();
1710 CHECK_NULL_VOID(host);
1711 auto child = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
1712 if (!child || child->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
1713 return;
1714 }
1715
1716 int32_t preFirstIndex = currentFirstIndex_;
1717 float currentTurnPageRate = FLT_MAX;
1718 for (const auto& iter : itemPosition_) {
1719 if (LessNotEqual((iter.second.startPos + additionalOffset), 0) &&
1720 LessNotEqual((iter.second.endPos + additionalOffset), 0)) {
1721 continue;
1722 }
1723 if (GreatOrEqual((iter.second.startPos + additionalOffset), 0) &&
1724 GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
1725 currentFirstIndex_ = iter.first;
1726 currentTurnPageRate = 0.0f;
1727 break;
1728 }
1729 if (GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
1730 currentFirstIndex_ = iter.first;
1731 currentTurnPageRate = (NearEqual(iter.second.endPos, iter.second.startPos) ? 0 :
1732 ((iter.second.startPos + additionalOffset) / (iter.second.endPos - iter.second.startPos)));
1733 break;
1734 }
1735 }
1736
1737 UpdateNextValidIndex();
1738 currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
1739 CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
1740 turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
1741
1742 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
1743 if (!IsLoop() && ((currentFirstIndex_ == 0 && GreatNotEqualCustomPrecision(turnPageRate_, 0.0f)) ||
1744 (currentFirstIndex_ == TotalCount() - 1 && LessNotEqualCustomPrecision(turnPageRate_, 0.0f)))) {
1745 return;
1746 }
1747 HandleTouchBottomLoop();
1748
1749 if (!indicatorDoingAnimation_) {
1750 child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1751 }
1752 if (GetLoopIndex(currentIndex_) != currentFirstIndex_) {
1753 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1754 CHECK_NULL_VOID(swiperEventHub);
1755 swiperEventHub->FireIndicatorChangeEvent(currentFirstIndex_);
1756 }
1757 }
1758
UpdateAnimationProperty(float velocity)1759 void SwiperPattern::UpdateAnimationProperty(float velocity)
1760 {
1761 if (isDragging_ || childScrolling_) {
1762 targetIndex_ = CheckTargetIndex(ComputeNextIndexByVelocity(velocity));
1763 velocity_ = velocity;
1764 } else {
1765 targetIndex_ = pauseTargetIndex_;
1766 velocity_ = velocity;
1767 }
1768
1769 MarkDirtyNodeSelf();
1770 moveDirection_ = velocity <= 0;
1771 }
1772
OnTouchTestHit(SourceType hitTestType)1773 void SwiperPattern::OnTouchTestHit(SourceType hitTestType)
1774 {
1775 // in mouse hover test case.
1776 if (hitTestType == SourceType::MOUSE) {
1777 return;
1778 }
1779 if (!isTouchDown_) {
1780 isTouchDown_ = true;
1781 }
1782 }
1783
HandleTouchEvent(const TouchEventInfo & info)1784 void SwiperPattern::HandleTouchEvent(const TouchEventInfo& info)
1785 {
1786 if (info.GetTouches().empty()) {
1787 return;
1788 }
1789 auto locationInfo = info.GetTouches().front();
1790 auto touchType = locationInfo.GetTouchType();
1791 if (touchType == TouchType::DOWN) {
1792 HandleTouchDown(locationInfo);
1793 } else if (touchType == TouchType::UP) {
1794 HandleTouchUp();
1795 } else if (touchType == TouchType::CANCEL) {
1796 HandleTouchUp();
1797 }
1798 }
1799
HandleTouchDown(const TouchLocationInfo & locationInfo)1800 void SwiperPattern::HandleTouchDown(const TouchLocationInfo& locationInfo)
1801 {
1802 isTouchDown_ = true;
1803 if (HasIndicatorNode()) {
1804 auto host = GetHost();
1805 CHECK_NULL_VOID(host);
1806 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
1807 CHECK_NULL_VOID(indicatorNode);
1808 if (indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
1809 auto geometryNode = indicatorNode->GetGeometryNode();
1810 CHECK_NULL_VOID(geometryNode);
1811 auto hotRegion = geometryNode->GetFrameRect();
1812 auto touchPoint = PointF(static_cast<float>(locationInfo.GetLocalLocation().GetX()),
1813 static_cast<float>(locationInfo.GetLocalLocation().GetY()));
1814 if (hotRegion.IsInRegion(touchPoint)) {
1815 return;
1816 }
1817 }
1818 }
1819
1820 if (childScrolling_) {
1821 // Even if the child fails to notify scrollEnd, we reset childScrolling_ flag on TouchDown to ensure its
1822 // value is correct.
1823 childScrolling_ = false;
1824 }
1825
1826 StopIndicatorAnimation();
1827 if (usePropertyAnimation_) {
1828 StopPropertyTranslateAnimation(isFinishAnimation_);
1829 }
1830
1831 indicatorDoingAnimation_ = false;
1832 // Stop translate animation when touch down.
1833 if (controller_ && controller_->IsRunning()) {
1834 controller_->Stop();
1835 }
1836
1837 AnimationUtils::PauseAnimation(springAnimation_);
1838 if (springAnimationIsRunning_) {
1839 isTouchDownSpringAnimation_ = true;
1840 springAnimationIsRunning_ = false;
1841 }
1842
1843 AnimationUtils::PauseAnimation(fadeAnimation_);
1844 if (fadeAnimationIsRunning_) {
1845 fadeAnimationIsRunning_ = false;
1846 }
1847
1848 // Stop auto play when touch down.
1849 StopAutoPlay();
1850 }
1851
HandleTouchUp()1852 void SwiperPattern::HandleTouchUp()
1853 {
1854 isTouchDown_ = false;
1855 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
1856 if (!isDragging_ && !childScrolling_ && !NearZero(firstItemInfoInVisibleArea.second.startPos)) {
1857 UpdateAnimationProperty(0.0);
1858 }
1859
1860 if (!springAnimationIsRunning_ && isTouchDownSpringAnimation_) {
1861 isTouchDownSpringAnimation_ = false;
1862 springAnimationIsRunning_ = true;
1863 AnimationUtils::ResumeAnimation(springAnimation_);
1864 }
1865
1866 if (!fadeAnimationIsRunning_) {
1867 fadeAnimationIsRunning_ = true;
1868 AnimationUtils::ResumeAnimation(fadeAnimation_);
1869 }
1870
1871 if (!isDragging_) {
1872 StartAutoPlay();
1873 }
1874 }
1875
HandleDragStart(const GestureEvent & info)1876 void SwiperPattern::HandleDragStart(const GestureEvent& info)
1877 {
1878 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_SCROLL, PerfActionType::FIRST_MOVE, "");
1879 UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::START);
1880
1881 StopAnimationOnScrollStart(
1882 info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD);
1883 StopAutoPlay();
1884
1885 const auto& tabBarFinishCallback = swiperController_->GetTabBarFinishCallback();
1886 if (tabBarFinishCallback) {
1887 tabBarFinishCallback();
1888 }
1889
1890 const auto& removeEventCallback = swiperController_->GetRemoveTabBarEventCallback();
1891 if (removeEventCallback) {
1892 removeEventCallback();
1893 }
1894 #ifdef OHOS_PLATFORM
1895 // Increase the cpu frequency when sliding.
1896 ResSchedReport::GetInstance().ResSchedDataReport("slide_on");
1897 #endif
1898
1899 gestureSwipeIndex_ = currentIndex_;
1900 isDragging_ = true;
1901 isTouchDown_ = true;
1902 mainDeltaSum_ = 0.0f;
1903 // in drag process, close lazy feature.
1904 SetLazyLoadFeature(false);
1905 StopFadeAnimation();
1906 }
1907
StopAnimationOnScrollStart(bool flushImmediately)1908 void SwiperPattern::StopAnimationOnScrollStart(bool flushImmediately)
1909 {
1910 if (usePropertyAnimation_) {
1911 StopPropertyTranslateAnimation(isFinishAnimation_);
1912 }
1913
1914 StopIndicatorAnimation();
1915 StopTranslateAnimation();
1916 if (flushImmediately) {
1917 StopSpringAnimationAndFlushImmediately();
1918 } else {
1919 StopSpringAnimation();
1920 }
1921 }
1922
HandleDragUpdate(const GestureEvent & info)1923 void SwiperPattern::HandleDragUpdate(const GestureEvent& info)
1924 {
1925 UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::RUNNING);
1926 auto mainDelta = static_cast<float>(info.GetMainDelta());
1927 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD) {
1928 isTouchPad_ = true;
1929 }
1930 auto mainSize = CalculateVisibleSize();
1931 ProcessDelta(mainDelta, mainSize, mainDeltaSum_);
1932 mainDeltaSum_ += mainDelta;
1933
1934 PointF dragPoint(static_cast<float>(info.GetGlobalLocation().GetX()),
1935 static_cast<float>(info.GetGlobalLocation().GetY()));
1936 NGGestureRecognizer::Transform(dragPoint, GetHost(), true);
1937 if (IsOutOfHotRegion(dragPoint)) {
1938 isTouchPad_ = false;
1939 return;
1940 }
1941
1942 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(static_cast<float>(mainDelta))) {
1943 return;
1944 }
1945
1946 HandleScroll(static_cast<float>(mainDelta), SCROLL_FROM_UPDATE, NestedState::GESTURE);
1947 UpdateItemRenderGroup(true);
1948 isTouchPad_ = false;
1949 }
1950
HandleDragEnd(double dragVelocity)1951 void SwiperPattern::HandleDragEnd(double dragVelocity)
1952 {
1953 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_SCROLL, false);
1954 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_FLING, PerfActionType::FIRST_MOVE, "");
1955 isTouchDown_ = false;
1956 UpdateDragFRCSceneInfo(dragVelocity, SceneStatus::END);
1957 const auto& addEventCallback = swiperController_->GetAddTabBarEventCallback();
1958 if (addEventCallback) {
1959 addEventCallback();
1960 }
1961
1962 auto pipeline = PipelineContext::GetCurrentContext();
1963 if (pipeline) {
1964 pipeline->FlushUITasks();
1965 }
1966 if (itemPosition_.empty()) {
1967 return;
1968 }
1969
1970 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(0.0f)) {
1971 return;
1972 }
1973
1974 auto edgeEffect = GetEdgeEffect();
1975 // edge effect is NONE and reached boundary
1976 bool noneOutOfBoundary = (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) &&
1977 NearZero(GetDistanceToEdge()) && edgeEffect == EdgeEffect::NONE;
1978 if (!IsLoop() && (IsOutOfBoundary() || !NearZero(fadeOffset_) || noneOutOfBoundary)) {
1979 isDragging_ = false;
1980
1981 if (edgeEffect == EdgeEffect::SPRING) {
1982 PlaySpringAnimation(dragVelocity);
1983 return;
1984 }
1985
1986 if (edgeEffect == EdgeEffect::FADE) {
1987 PlayFadeAnimation();
1988 return;
1989 }
1990
1991 auto nextIndex = ComputeNextIndexByVelocity(static_cast<float>(dragVelocity), true);
1992 if (currentIndex_ != nextIndex) {
1993 UpdateCurrentIndex(nextIndex);
1994 do {
1995 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
1996 if (!curChildFrame) {
1997 break;
1998 }
1999 FlushFocus(curChildFrame);
2000 currentFocusIndex_ = currentIndex_;
2001 } while (0);
2002 OnIndexChange();
2003 oldIndex_ = currentIndex_;
2004 }
2005
2006 if (edgeEffect == EdgeEffect::NONE) {
2007 auto parent = parent_.Upgrade();
2008 if (parent) {
2009 parent->HandleScrollVelocity(dragVelocity);
2010 }
2011 StartAutoPlay();
2012 UpdateItemRenderGroup(false);
2013 return;
2014 }
2015 }
2016
2017 #ifdef OHOS_PLATFORM
2018 ResSchedReport::GetInstance().ResSchedDataReport("slide_off");
2019 #endif
2020
2021 // nested and reached end, need to pass velocity to parent scrollable
2022 auto parent = parent_.Upgrade();
2023 if (!IsLoop() && parent && NearZero(GetDistanceToEdge())) {
2024 parent->HandleScrollVelocity(dragVelocity);
2025 StartAutoPlay();
2026 } else {
2027 UpdateAnimationProperty(static_cast<float>(dragVelocity));
2028 NotifyParentScrollEnd();
2029 }
2030 if (pipeline) {
2031 pipeline->FlushUITasks();
2032 }
2033
2034 isDragging_ = false;
2035 }
2036
UpdateCurrentIndex(int32_t index)2037 void SwiperPattern::UpdateCurrentIndex(int32_t index)
2038 {
2039 currentIndex_ = index;
2040 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2041 CHECK_NULL_VOID(layoutProperty);
2042 layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
2043 }
2044
ComputeSwipePageNextIndex(float velocity,bool onlyDistance) const2045 int32_t SwiperPattern::ComputeSwipePageNextIndex(float velocity, bool onlyDistance) const
2046 {
2047 auto swiperWidth = CalculateVisibleSize();
2048 if (LessOrEqual(swiperWidth, 0)) {
2049 return currentIndex_;
2050 }
2051
2052 auto iter = itemPosition_.find(currentIndex_);
2053 if (iter == itemPosition_.end()) {
2054 return currentIndex_;
2055 }
2056
2057 auto currentOffset = iter->second.startPos;
2058 auto direction = GreatNotEqual(velocity, 0.0);
2059 auto dragThresholdFlag = direction ? currentOffset > swiperWidth / 2 : -currentOffset > swiperWidth / 2;
2060 auto nextIndex = currentIndex_;
2061 auto displayCount = GetDisplayCount();
2062
2063 if (!IsLoop()) {
2064 if (GetLoopIndex(currentIndex_) == 0 && direction) {
2065 return nextIndex;
2066 }
2067
2068 auto currentPageIndex = SwiperUtils::ComputePageIndex(currentIndex_, displayCount);
2069 auto endPageIndex = SwiperUtils::ComputePageIndex(TotalCount() - 1, displayCount);
2070 if (!direction && currentPageIndex == endPageIndex) {
2071 return nextIndex;
2072 }
2073 }
2074
2075 if ((!onlyDistance && std::abs(velocity) > NEW_MIN_TURN_PAGE_VELOCITY) || dragThresholdFlag) {
2076 nextIndex = direction ? currentIndex_ - displayCount : currentIndex_ + displayCount;
2077 }
2078
2079 if (!IsAutoLinear() && nextIndex > currentIndex_ + displayCount) {
2080 nextIndex = currentIndex_ + displayCount;
2081 }
2082
2083 return nextIndex;
2084 }
2085
ComputeNextIndexByVelocity(float velocity,bool onlyDistance) const2086 int32_t SwiperPattern::ComputeNextIndexByVelocity(float velocity, bool onlyDistance) const
2087 {
2088 if (IsSwipeByGroup()) {
2089 return ComputeSwipePageNextIndex(velocity, onlyDistance);
2090 }
2091
2092 auto nextIndex = currentIndex_;
2093 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
2094 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
2095 if (LessOrEqual(firstItemLength, 0)) {
2096 return nextIndex;
2097 }
2098
2099 auto firstIndex = firstItemInfoInVisibleArea.first;
2100 auto dragDistance = firstItemInfoInVisibleArea.second.endPos;
2101 if (firstIndex == currentIndex_ && firstItemInfoInVisibleArea.second.startPos > 0) {
2102 firstIndex--;
2103 dragDistance = firstItemInfoInVisibleArea.second.startPos;
2104 }
2105 auto direction = GreatNotEqual(velocity, 0.0);
2106 auto dragThresholdFlag =
2107 direction ? dragDistance > firstItemLength / 2 : firstItemInfoInVisibleArea.second.endPos < firstItemLength / 2;
2108 auto turnVelocity = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_MIN_TURN_PAGE_VELOCITY
2109 : MIN_TURN_PAGE_VELOCITY;
2110 if ((!onlyDistance && std::abs(velocity) > turnVelocity) || dragThresholdFlag) {
2111 nextIndex = direction ? firstIndex : firstItemInfoInVisibleArea.first + 1;
2112 } else {
2113 nextIndex = direction ? firstIndex + 1 : firstItemInfoInVisibleArea.first;
2114 }
2115
2116 if (!IsAutoLinear() && nextIndex > currentIndex_ + GetDisplayCount()) {
2117 nextIndex = currentIndex_ + GetDisplayCount();
2118 }
2119
2120 if (!IsLoop()) {
2121 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - GetDisplayCount()));
2122 }
2123 return nextIndex;
2124 }
2125
PlayPropertyTranslateAnimation(float translate,int32_t nextIndex,float velocity,bool stopAutoPlay)2126 void SwiperPattern::PlayPropertyTranslateAnimation(
2127 float translate, int32_t nextIndex, float velocity, bool stopAutoPlay)
2128 {
2129 if (NearZero(translate)) {
2130 OnAnimationTranslateZero(nextIndex, stopAutoPlay);
2131 return;
2132 }
2133
2134 AnimationOption option;
2135 option.SetDuration(GetDuration());
2136 motionVelocity_ = velocity / translate;
2137 option.SetCurve(GetCurveIncludeMotion());
2138 option.SetFinishCallbackType(GetFinishCallbackType());
2139 OffsetF offset;
2140 if (GetDirection() == Axis::HORIZONTAL) {
2141 offset.AddX(translate);
2142 } else {
2143 offset.AddY(translate);
2144 }
2145 if (usePropertyAnimation_) {
2146 auto startNewAnimationFlag = false;
2147 if (itemPositionInAnimation_.empty()) {
2148 startNewAnimationFlag = true;
2149 }
2150 if (!startNewAnimationFlag) {
2151 for (const auto& animationItem : itemPositionInAnimation_) {
2152 auto iter = itemPosition_.find(animationItem.first);
2153 if (iter == itemPosition_.end()) {
2154 startNewAnimationFlag = true;
2155 break;
2156 }
2157 if (animationItem.second.finialOffset != offset ||
2158 !NearEqual(animationItem.second.startPos, iter->second.startPos) ||
2159 !NearEqual(animationItem.second.endPos, iter->second.endPos)) {
2160 startNewAnimationFlag = true;
2161 break;
2162 }
2163 }
2164 }
2165 if (!startNewAnimationFlag) {
2166 stopIndicatorAnimation_ = false;
2167 return;
2168 }
2169 std::optional<int32_t> targetIndex;
2170 if (targetIndex_) {
2171 targetIndex = targetIndex_;
2172 }
2173 StopPropertyTranslateAnimation(isFinishAnimation_);
2174 StopIndicatorAnimation();
2175
2176 if (targetIndex) {
2177 targetIndex_ = targetIndex;
2178 MarkDirtyNodeSelf();
2179 return;
2180 }
2181 }
2182 auto finishCallback = [weak = WeakClaim(this), offset]() {
2183 auto swiper = weak.Upgrade();
2184 CHECK_NULL_VOID(swiper);
2185 swiper->targetIndex_.reset();
2186 swiper->OnPropertyTranslateAnimationFinish(offset);
2187 };
2188 // initial translate info.
2189 for (auto& item : itemPosition_) {
2190 auto frameNode = item.second.node;
2191 if (frameNode) {
2192 frameNode->GetRenderContext()->UpdateTranslateInXY(item.second.finialOffset);
2193 }
2194 }
2195 // property callback will call immediately.
2196 auto propertyUpdateCallback = [swiper = WeakClaim(this), offset]() {
2197 auto swiperPattern = swiper.Upgrade();
2198 if (!swiperPattern) {
2199 return;
2200 }
2201 for (auto& item : swiperPattern->itemPosition_) {
2202 auto frameNode = item.second.node;
2203 if (frameNode) {
2204 frameNode->GetRenderContext()->UpdateTranslateInXY(offset);
2205 item.second.finialOffset = offset;
2206 }
2207 }
2208 swiperPattern->itemPositionInAnimation_ = swiperPattern->itemPosition_;
2209 };
2210 usePropertyAnimation_ = true;
2211 propertyAnimationIndex_ = nextIndex;
2212 ElementRegister::GetInstance()->ReSyncGeometryTransition(GetHost(), option);
2213 AnimationUtils::Animate(option, propertyUpdateCallback, finishCallback);
2214 AnimationCallbackInfo info;
2215 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
2216 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2217 info.targetOffset = GetCustomPropertyOffset() - Dimension(translate, DimensionUnit::PX).ConvertToVp();
2218
2219 auto pipeline = PipelineContext::GetCurrentContext();
2220 if (pipeline) {
2221 pipeline->AddAfterRenderTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
2222 auto swiper = weak.Upgrade();
2223 CHECK_NULL_VOID(swiper);
2224 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
2225 swiper->FireAndCleanScrollingListener();
2226 });
2227 }
2228
2229 // enable lazy load feature.
2230 SetLazyLoadFeature(true);
2231 UpdateItemRenderGroup(true);
2232 }
2233
UpdateOffsetAfterPropertyAnimation(float offset)2234 void SwiperPattern::UpdateOffsetAfterPropertyAnimation(float offset)
2235 {
2236 UpdateCurrentOffset(offset);
2237 auto pipeline = PipelineContext::GetCurrentContext();
2238 if (pipeline) {
2239 pipeline->FlushUITasks();
2240 }
2241 }
2242
OnPropertyTranslateAnimationFinish(const OffsetF & offset)2243 void SwiperPattern::OnPropertyTranslateAnimationFinish(const OffsetF& offset)
2244 {
2245 if (!usePropertyAnimation_) {
2246 // force stop.
2247 return;
2248 }
2249
2250 usePropertyAnimation_ = false;
2251 // reset translate.
2252 for (auto& item : itemPositionInAnimation_) {
2253 auto frameNode = item.second.node;
2254 if (frameNode) {
2255 frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
2256 }
2257 item.second.finialOffset = OffsetF();
2258 }
2259 itemPositionInAnimation_.clear();
2260 // update postion info.
2261 UpdateOffsetAfterPropertyAnimation(offset.GetMainOffset(GetDirection()));
2262 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
2263 }
2264
StopPropertyTranslateAnimation(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper)2265 void SwiperPattern::StopPropertyTranslateAnimation(bool isFinishAnimation, bool isBeforeCreateLayoutWrapper)
2266 {
2267 if (!usePropertyAnimation_) {
2268 return;
2269 }
2270 usePropertyAnimation_ = false;
2271
2272 // Stop CurrentAnimationProperty.
2273 AnimationOption option;
2274 option.SetDuration(0);
2275 option.SetCurve(Curves::LINEAR);
2276 auto propertyUpdateCallback = [weak = WeakClaim(this)]() {
2277 auto swiper = weak.Upgrade();
2278 CHECK_NULL_VOID(swiper);
2279 for (auto& item : swiper->itemPositionInAnimation_) {
2280 auto frameNode = item.second.node;
2281 if (!frameNode) {
2282 continue;
2283 }
2284 frameNode->GetRenderContext()->CancelTranslateXYAnimation();
2285 }
2286 };
2287 AnimationUtils::Animate(option, propertyUpdateCallback);
2288 OffsetF currentOffset;
2289 for (auto& item : itemPositionInAnimation_) {
2290 auto frameNode = item.second.node;
2291 if (!frameNode) {
2292 continue;
2293 }
2294 currentOffset = frameNode->GetRenderContext()->GetTranslateXYProperty();
2295 frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
2296 item.second.finialOffset = OffsetF();
2297 }
2298 itemPositionInAnimation_.clear();
2299 if (!isBeforeCreateLayoutWrapper) {
2300 UpdateOffsetAfterPropertyAnimation(currentOffset.GetMainOffset(GetDirection()));
2301 }
2302 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation, true);
2303 }
2304
GetCurveIncludeMotion()2305 RefPtr<Curve> SwiperPattern::GetCurveIncludeMotion()
2306 {
2307 auto curve = GetCurve();
2308 auto container = Container::Current();
2309 bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
2310 if (!curve && !isLauncherFeature) {
2311 curve = Curves::LINEAR;
2312 }
2313
2314 if (isLauncherFeature) {
2315 finishCallbackType_ = FinishCallbackType::LOGICALLY;
2316 }
2317
2318 if (curve) {
2319 if (InstanceOf<SpringCurve>(curve)) {
2320 auto springCurve = DynamicCast<SpringCurve>(curve);
2321 // check velocity to judge if this current velocity.
2322 if (springCurve->GetCurrentVelocity() < 0) {
2323 return AceType::MakeRefPtr<SpringCurve>(
2324 motionVelocity_, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
2325 }
2326 }
2327 if (InstanceOf<InterpolatingSpring>(curve)) {
2328 auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
2329 // check velocity to judge if this current velocity.
2330 if (interpolatingSpring->GetVelocity() < 0) {
2331 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, interpolatingSpring->GetMass(),
2332 interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
2333 }
2334 }
2335 return curve;
2336 }
2337 // use spring motion feature.
2338 // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
2339 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, 1, 328, 34);
2340 }
2341
PlayIndicatorTranslateAnimation(float translate)2342 void SwiperPattern::PlayIndicatorTranslateAnimation(float translate)
2343 {
2344 if (!stopIndicatorAnimation_) {
2345 stopIndicatorAnimation_ = true;
2346 return;
2347 }
2348 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
2349 if (!indicatorId_.has_value() && !turnPageRateCallback) {
2350 return;
2351 }
2352 CheckMarkDirtyNodeForRenderIndicator(translate);
2353 AnimationUtils::StopAnimation(indicatorAnimation_);
2354 indicatorAnimationIsRunning_ = false;
2355 if (itemPosition_.empty()) {
2356 return;
2357 }
2358
2359 auto host = GetHost();
2360 CHECK_NULL_VOID(host);
2361 auto weak = AceType::WeakClaim(this);
2362 host->CreateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0, [weak](float value) {
2363 auto swiper = weak.Upgrade();
2364 CHECK_NULL_VOID(swiper);
2365 auto currentContentOffset = -(swiper->itemPosition_.begin()->second.startPos);
2366 auto index = swiper->itemPosition_.begin()->first;
2367 const auto& turnPageRateCallback = swiper->swiperController_->GetTurnPageRateCallback();
2368 if (turnPageRateCallback && !NearZero(swiper->GetTranslateLength())) {
2369 turnPageRateCallback(index, (currentContentOffset - value) / swiper->GetTranslateLength());
2370 }
2371 });
2372
2373 AnimationOption option;
2374 option.SetDuration(GetDuration());
2375 option.SetCurve(Curves::LINEAR);
2376
2377 host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0);
2378 indicatorAnimationIsRunning_ = true;
2379 indicatorAnimation_ = AnimationUtils::StartAnimation(
2380 option, [host, translate]() { host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, translate); },
2381 [weak]() {
2382 auto swiperPattern = weak.Upgrade();
2383 CHECK_NULL_VOID(swiperPattern);
2384 swiperPattern->indicatorAnimationIsRunning_ = false;
2385 });
2386 }
2387
PlayTranslateAnimation(float startPos,float endPos,int32_t nextIndex,bool restartAutoPlay,float velocity)2388 void SwiperPattern::PlayTranslateAnimation(
2389 float startPos, float endPos, int32_t nextIndex, bool restartAutoPlay, float velocity)
2390 {
2391 auto host = GetHost();
2392 CHECK_NULL_VOID(host);
2393 auto curve = GetCurve();
2394
2395 // If animation is still running, stop it before play new animation.
2396 StopSpringAnimation();
2397 StopFadeAnimation();
2398 StopTranslateAnimation();
2399 StopAutoPlay();
2400
2401 SetLazyLoadFeature(false);
2402
2403 if (!controller_) {
2404 controller_ = CREATE_ANIMATOR(host->GetContext());
2405 }
2406 controller_->ClearStartListeners();
2407 controller_->ClearStopListeners();
2408 controller_->ClearInterpolators();
2409
2410 auto weak = WeakClaim(this);
2411 auto targetOffset = Dimension(startPos - endPos, DimensionUnit::PX).ConvertToVp();
2412 controller_->AddStartListener([weak, nextIndex, targetOffset, velocity]() {
2413 auto swiper = weak.Upgrade();
2414 CHECK_NULL_VOID(swiper);
2415 AnimationCallbackInfo info;
2416 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
2417 info.currentOffset =
2418 swiper->GetCustomPropertyOffset() + Dimension(swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2419 info.targetOffset = swiper->GetCustomPropertyOffset() + targetOffset;
2420 swiper->FireAnimationStartEvent(
2421 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex), info);
2422 });
2423
2424 auto container = Container::Current();
2425 bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
2426 if (!curve && !isLauncherFeature) {
2427 curve = Curves::LINEAR;
2428 }
2429
2430 if (curve) {
2431 auto currentIndexStartPos = currentIndexOffset_;
2432 auto translate = AceType::MakeRefPtr<CurveAnimation<double>>(startPos, endPos, curve);
2433 translate->AddListener(
2434 Animation<double>::ValueCallback([weak, startPos, endPos, currentIndexStartPos](double value) {
2435 auto swiper = weak.Upgrade();
2436 CHECK_NULL_VOID(swiper);
2437 if (!NearEqual(value, startPos) && !NearEqual(value, endPos) && !NearEqual(startPos, endPos)) {
2438 float moveRate =
2439 Curves::EASE_OUT->MoveInternal(static_cast<float>((value - startPos) / (endPos - startPos)));
2440 value = startPos + (endPos - startPos) * moveRate;
2441 auto moveOffset = (endPos - startPos) * moveRate;
2442 swiper->currentIndexOffset_ = currentIndexStartPos + moveOffset;
2443 }
2444 swiper->UpdateCurrentOffset(static_cast<float>(value - swiper->currentOffset_));
2445 }));
2446 controller_->AddStopListener([weak, nextIndex, restartAutoPlay]() {
2447 auto swiper = weak.Upgrade();
2448 CHECK_NULL_VOID(swiper);
2449 swiper->OnTranslateFinish(nextIndex, restartAutoPlay, swiper->isFinishAnimation_);
2450 });
2451 controller_->SetDuration(GetDuration());
2452 controller_->AddInterpolator(translate);
2453 controller_->Play();
2454 return;
2455 }
2456 // use spring motion feature.
2457 // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
2458 static const auto springProperty = AceType::MakeRefPtr<SpringProperty>(1, 328, 34);
2459 auto scrollMotion = AceType::MakeRefPtr<SpringMotion>(startPos, endPos, velocity, springProperty);
2460 scrollMotion->AddListener([weak](double value) {
2461 auto swiper = weak.Upgrade();
2462 if (swiper) {
2463 swiper->UpdateCurrentOffset(static_cast<float>(value) - swiper->currentOffset_);
2464 }
2465 });
2466 controller_->AddStopListener([weak, nextIndex, restartAutoPlay]() {
2467 auto swiper = weak.Upgrade();
2468 CHECK_NULL_VOID(swiper);
2469 swiper->OnTranslateFinish(nextIndex, restartAutoPlay, swiper->isFinishAnimation_);
2470 });
2471 controller_->PlayMotion(scrollMotion);
2472 }
2473
OnSpringAnimationStart(float velocity)2474 void SwiperPattern::OnSpringAnimationStart(float velocity)
2475 {
2476 AnimationCallbackInfo info;
2477 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
2478 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2479
2480 nextIndex_ = ComputeNextIndexByVelocity(velocity);
2481 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
2482 info.targetOffset = info.currentOffset;
2483 } else {
2484 auto iter = itemPosition_.find(nextIndex_);
2485 auto nextOffset = iter != itemPosition_.end() ? iter->second.startPos : 0.0f;
2486 info.targetOffset = GetCustomPropertyOffset() + Dimension(nextOffset, DimensionUnit::PX).ConvertToVp();
2487 }
2488
2489 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
2490 }
2491
OnSpringAndFadeAnimationFinish()2492 void SwiperPattern::OnSpringAndFadeAnimationFinish()
2493 {
2494 auto itemInfoInVisibleArea = std::make_pair(0, SwiperItemInfo {});
2495 if (!itemPosition_.empty()) {
2496 auto item = itemPosition_.find(nextIndex_);
2497 itemInfoInVisibleArea = std::make_pair(item->first,
2498 SwiperItemInfo { item->second.startPos, item->second.endPos });
2499 }
2500 if (GetLoopIndex(currentIndex_) != GetLoopIndex(nextIndex_)) {
2501 UpdateCurrentIndex(nextIndex_);
2502 do {
2503 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
2504 if (!curChildFrame) {
2505 break;
2506 }
2507 FlushFocus(curChildFrame);
2508 currentFocusIndex_ = currentIndex_;
2509 } while (0);
2510 OnIndexChange();
2511 oldIndex_ = currentIndex_;
2512 }
2513 AnimationCallbackInfo info;
2514 auto indexStartPos = itemInfoInVisibleArea.second.startPos;
2515 info.currentOffset = GetCustomPropertyOffset() + Dimension(indexStartPos, DimensionUnit::PX).ConvertToVp();
2516 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
2517 currentIndexOffset_ = indexStartPos;
2518 UpdateItemRenderGroup(false);
2519 NotifyParentScrollEnd();
2520 StartAutoPlay();
2521 fadeAnimationIsRunning_ = false;
2522 }
2523
OnFadeAnimationStart()2524 void SwiperPattern::OnFadeAnimationStart()
2525 {
2526 AnimationCallbackInfo info;
2527 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2528 nextIndex_ = ComputeNextIndexByVelocity(0.0);
2529 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
2530 info.targetOffset = info.currentOffset;
2531 } else {
2532 info.targetOffset = GetCustomPropertyOffset();
2533 }
2534
2535 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
2536 fadeAnimationIsRunning_ = true;
2537 }
2538
PlayFadeAnimation()2539 void SwiperPattern::PlayFadeAnimation()
2540 {
2541 if (NearZero(fadeOffset_)) {
2542 fadeAnimationIsRunning_ = false;
2543 return;
2544 }
2545
2546 auto host = GetHost();
2547 CHECK_NULL_VOID(host);
2548 auto weak = AceType::WeakClaim(this);
2549 host->CreateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0, Animation<double>::ValueCallback([weak](float value) {
2550 auto swiper = weak.Upgrade();
2551 if (swiper && swiper->GetHost() && !swiper->isTouchDown_) {
2552 swiper->fadeOffset_ = value;
2553 swiper->GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2554 }
2555 }));
2556
2557 AnimationOption option;
2558 option.SetDuration(FADE_DURATION);
2559 option.SetCurve(Curves::LINEAR);
2560
2561 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, fadeOffset_);
2562 constexpr float end = 0.0f;
2563 nextIndex_ = currentIndex_;
2564 fadeAnimation_ = AnimationUtils::StartAnimation(option,
2565 [weak, host, end]() {
2566 auto swiperPattern = weak.Upgrade();
2567 CHECK_NULL_VOID(swiperPattern);
2568 swiperPattern->OnFadeAnimationStart();
2569 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, end);
2570 },
2571 [weak]() {
2572 auto swiperPattern = weak.Upgrade();
2573 CHECK_NULL_VOID(swiperPattern);
2574 swiperPattern->OnSpringAndFadeAnimationFinish();
2575 });
2576 }
2577
PlaySpringAnimation(double dragVelocity)2578 void SwiperPattern::PlaySpringAnimation(double dragVelocity)
2579 {
2580 auto host = GetHost();
2581 CHECK_NULL_VOID(host);
2582
2583 auto mainSize = CalculateVisibleSize();
2584 if (LessOrEqual(mainSize, 0)) {
2585 return;
2586 }
2587 if (itemPosition_.empty()) {
2588 return;
2589 }
2590 childScrolling_ = false;
2591 auto leading = currentOffset_ + mainSize - itemPosition_.rbegin()->second.endPos;
2592 auto trailing = currentOffset_ - itemPosition_.begin()->second.startPos;
2593 ExtentPair extentPair = ExtentPair(leading, trailing);
2594
2595 host->CreateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, 0, [weak = AceType::WeakClaim(this)](float position) {
2596 auto swiper = weak.Upgrade();
2597 CHECK_NULL_VOID(swiper);
2598 if (!swiper->isTouchDown_) {
2599 swiper->UpdateCurrentOffset(static_cast<float>(position) - swiper->currentOffset_);
2600 }
2601 }, PropertyUnit::PIXEL_POSITION);
2602
2603 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, currentOffset_);
2604 auto delta = currentOffset_ < 0.0f ? extentPair.Leading() : extentPair.Trailing();
2605
2606 // spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
2607 auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
2608 AnimationOption option;
2609 option.SetCurve(springCurve);
2610 option.SetDuration(SPRING_DURATION);
2611
2612 nextIndex_ = currentIndex_;
2613 springAnimation_ = AnimationUtils::StartAnimation(
2614 option,
2615 [weak = AceType::WeakClaim(this), dragVelocity, host, delta]() {
2616 auto swiperPattern = weak.Upgrade();
2617 CHECK_NULL_VOID(swiperPattern);
2618 swiperPattern->springAnimationIsRunning_ = true;
2619 swiperPattern->OnSpringAnimationStart(static_cast<float>(dragVelocity));
2620 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, delta);
2621 },
2622 [weak = AceType::WeakClaim(this)]() {
2623 auto swiperPattern = weak.Upgrade();
2624 CHECK_NULL_VOID(swiperPattern);
2625 swiperPattern->springAnimationIsRunning_ = false;
2626 swiperPattern->isTouchDownSpringAnimation_ = false;
2627 swiperPattern->OnSpringAndFadeAnimationFinish();
2628 });
2629 }
2630
IsOutOfBoundary(float mainOffset) const2631 bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
2632 {
2633 if (IsLoop() || itemPosition_.empty()) {
2634 return false;
2635 }
2636
2637 auto startPos = itemPosition_.begin()->second.startPos;
2638 startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
2639 auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
2640
2641 auto visibleWindowSize = CalculateVisibleSize();
2642 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
2643 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
2644 auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
2645
2646 return isOutOfStart || isOutOfEnd;
2647 }
2648
AutoLinearIsOutOfBoundary(float mainOffset) const2649 bool SwiperPattern::AutoLinearIsOutOfBoundary(float mainOffset) const
2650 {
2651 if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
2652 return false;
2653 }
2654
2655 auto startPos = itemPosition_.begin()->second.startPos;
2656 auto isOutOfStart = GreatNotEqual(startPos + mainOffset, 0.0);
2657
2658 auto visibleWindowSize = CalculateVisibleSize();
2659 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
2660 auto isOutOfEnd = LessNotEqual(endPos, visibleWindowSize);
2661
2662 return isOutOfStart || isOutOfEnd;
2663 }
2664
GetDistanceToEdge() const2665 float SwiperPattern::GetDistanceToEdge() const
2666 {
2667 if (IsLoop() || itemPosition_.empty()) {
2668 return 0.0f;
2669 }
2670 if (itemPosition_.begin()->first == 0) {
2671 return -itemPosition_.begin()->second.startPos;
2672 }
2673 auto visibleWindowSize = CalculateVisibleSize();
2674 return itemPosition_.rbegin()->second.endPos - visibleWindowSize;
2675 }
2676
MainSize() const2677 float SwiperPattern::MainSize() const
2678 {
2679 auto host = GetHost();
2680 CHECK_NULL_RETURN(host, 0.0);
2681 auto geometryNode = host->GetGeometryNode();
2682 CHECK_NULL_RETURN(geometryNode, 0.0);
2683 return geometryNode->GetFrameSize().MainSize(GetDirection());
2684 }
2685
GetMainContentSize() const2686 float SwiperPattern::GetMainContentSize() const
2687 {
2688 auto host = GetHost();
2689 CHECK_NULL_RETURN(host, 0.0);
2690 auto geometryNode = host->GetGeometryNode();
2691 CHECK_NULL_RETURN(geometryNode, 0.0);
2692 return geometryNode->GetPaddingSize().Width();
2693 }
2694
CalculateVisibleSize() const2695 float SwiperPattern::CalculateVisibleSize() const
2696 {
2697 auto prevMargin = GetPrevMargin();
2698 auto nextMargin = GetNextMargin();
2699 auto itemSpace = GetItemSpace();
2700 auto host = GetHost();
2701 CHECK_NULL_RETURN(host, 0.0f);
2702 auto geometryNode = host->GetGeometryNode();
2703 CHECK_NULL_RETURN(geometryNode, 0.0);
2704 auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
2705 if (itemSpace > mainSize) {
2706 itemSpace = 0.0f;
2707 }
2708 if (prevMargin != 0.0f) {
2709 if (nextMargin != 0.0f) {
2710 return contentMainSize_ - prevMargin - nextMargin - 2 * itemSpace;
2711 }
2712 return contentMainSize_ - prevMargin - itemSpace;
2713 }
2714
2715 if (nextMargin != 0.0f) {
2716 return contentMainSize_ - nextMargin - itemSpace;
2717 }
2718 return contentMainSize_;
2719 }
2720
GetItemSpace() const2721 float SwiperPattern::GetItemSpace() const
2722 {
2723 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2724 CHECK_NULL_RETURN(swiperLayoutProperty, 0.0f);
2725 if (swiperLayoutProperty->IgnoreItemSpace()) {
2726 return 0.0f;
2727 }
2728 return ConvertToPx(swiperLayoutProperty->GetItemSpace().value_or(0.0_vp),
2729 swiperLayoutProperty->GetLayoutConstraint()->scaleProperty, 0.0f)
2730 .value_or(0.0f);
2731 }
2732
GetPrevMargin() const2733 float SwiperPattern::GetPrevMargin() const
2734 {
2735 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2736 CHECK_NULL_RETURN(swiperLayoutProperty, 0.0f);
2737 return SwiperUtils::IsStretch(swiperLayoutProperty) ?
2738 ConvertToPx(swiperLayoutProperty->GetPrevMargin().value_or(0.0_vp),
2739 swiperLayoutProperty->GetLayoutConstraint()->scaleProperty, 0).value_or(0) : 0.0f;
2740 }
2741
GetNextMargin() const2742 float SwiperPattern::GetNextMargin() const
2743 {
2744 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2745 CHECK_NULL_RETURN(swiperLayoutProperty, 0.0f);
2746 return SwiperUtils::IsStretch(swiperLayoutProperty) ?
2747 ConvertToPx(swiperLayoutProperty->GetNextMargin().value_or(0.0_vp),
2748 swiperLayoutProperty->GetLayoutConstraint()->scaleProperty, 0).value_or(0) : 0.0f;
2749 }
2750
GetDirection() const2751 Axis SwiperPattern::GetDirection() const
2752 {
2753 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2754 CHECK_NULL_RETURN(swiperLayoutProperty, Axis::HORIZONTAL);
2755 return swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
2756 }
2757
CurrentIndex() const2758 int32_t SwiperPattern::CurrentIndex() const
2759 {
2760 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2761 CHECK_NULL_RETURN(swiperLayoutProperty, 0);
2762 return swiperLayoutProperty->GetIndex().value_or(0);
2763 }
2764
GetDisplayCount() const2765 int32_t SwiperPattern::GetDisplayCount() const
2766 {
2767 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2768 CHECK_NULL_RETURN(swiperLayoutProperty, 1);
2769 auto displayCount = CalculateDisplayCount();
2770 return displayCount;
2771 }
2772
CalculateDisplayCount() const2773 int32_t SwiperPattern::CalculateDisplayCount() const
2774 {
2775 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2776 CHECK_NULL_RETURN(swiperLayoutProperty, 1);
2777 bool isAutoFill = IsAutoFill();
2778 if (isAutoFill) {
2779 auto minSize = swiperLayoutProperty->GetMinSize()->ConvertToPx();
2780 float contentWidth = GetMainContentSize();
2781 auto displayCount =
2782 CalculateCount(contentWidth, minSize, SWIPER_MARGIN.ConvertToPx(), SWIPER_GUTTER.ConvertToPx());
2783 if (LessOrEqual(minSize, 0)) {
2784 displayCount = 1;
2785 }
2786 displayCount = displayCount > 0 ? displayCount : 1;
2787 auto totalCount = TotalCount();
2788 displayCount = displayCount > totalCount ? totalCount : displayCount;
2789 auto displayCountProperty = swiperLayoutProperty->GetDisplayCount().value_or(1);
2790
2791 if (displayCountProperty != displayCount) {
2792 swiperLayoutProperty->UpdateDisplayCount(displayCount);
2793 auto host = GetHost();
2794 CHECK_NULL_RETURN(host, 1);
2795 host->MarkDirtyNode(
2796 (crossMatchChild_ ? PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD : PROPERTY_UPDATE_MEASURE_SELF) |
2797 PROPERTY_UPDATE_RENDER);
2798 }
2799 return displayCount;
2800 } else {
2801 return swiperLayoutProperty->GetDisplayCount().value_or(1);
2802 }
2803 }
2804
CalculateCount(float contentWidth,float minSize,float margin,float gutter,float swiperPadding) const2805 int32_t SwiperPattern::CalculateCount(
2806 float contentWidth, float minSize, float margin, float gutter, float swiperPadding) const
2807 {
2808 return static_cast<int32_t>(floor((contentWidth - 2 * margin + gutter - 2 * swiperPadding) / (minSize + gutter)));
2809 }
2810
IsAutoFill() const2811 bool SwiperPattern::IsAutoFill() const
2812 {
2813 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2814 CHECK_NULL_RETURN(swiperLayoutProperty, false);
2815 return swiperLayoutProperty->GetMinSize().has_value();
2816 }
2817
IsAutoPlay() const2818 bool SwiperPattern::IsAutoPlay() const
2819 {
2820 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2821 CHECK_NULL_RETURN(swiperPaintProperty, false);
2822 return swiperPaintProperty->GetAutoPlay().value_or(false);
2823 }
2824
GetDuration() const2825 int32_t SwiperPattern::GetDuration() const
2826 {
2827 const int32_t DEFAULT_DURATION = 400;
2828 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2829 CHECK_NULL_RETURN(swiperPaintProperty, DEFAULT_DURATION);
2830 return swiperPaintProperty->GetDuration().value_or(DEFAULT_DURATION);
2831 }
2832
GetInterval() const2833 int32_t SwiperPattern::GetInterval() const
2834 {
2835 const int32_t DEFAULT_INTERVAL = 3000;
2836 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2837 CHECK_NULL_RETURN(swiperPaintProperty, DEFAULT_INTERVAL);
2838 return swiperPaintProperty->GetAutoPlayInterval().value_or(DEFAULT_INTERVAL);
2839 }
2840
GetCurve() const2841 RefPtr<Curve> SwiperPattern::GetCurve() const
2842 {
2843 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2844 CHECK_NULL_RETURN(swiperPaintProperty, nullptr);
2845 return swiperPaintProperty->GetCurve().value_or(nullptr);
2846 }
2847
IsLoop() const2848 bool SwiperPattern::IsLoop() const
2849 {
2850 if (TotalDisPlayCount() >= TotalCount()) {
2851 return false;
2852 }
2853 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2854 CHECK_NULL_RETURN(swiperLayoutProperty, true);
2855 return swiperLayoutProperty->GetLoop().value_or(true);
2856 }
2857
IsEnabled() const2858 bool SwiperPattern::IsEnabled() const
2859 {
2860 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2861 CHECK_NULL_RETURN(swiperPaintProperty, true);
2862 return swiperPaintProperty->GetEnabled().value_or(true);
2863 }
2864
GetEdgeEffect() const2865 EdgeEffect SwiperPattern::GetEdgeEffect() const
2866 {
2867 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
2868 CHECK_NULL_RETURN(swiperPaintProperty, EdgeEffect::SPRING);
2869 return swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
2870 }
2871
IsDisableSwipe() const2872 bool SwiperPattern::IsDisableSwipe() const
2873 {
2874 auto props = GetLayoutProperty<SwiperLayoutProperty>();
2875 CHECK_NULL_RETURN(props, false);
2876 return props->GetDisableSwipe().value_or(false);
2877 }
2878
IsShowIndicator() const2879 bool SwiperPattern::IsShowIndicator() const
2880 {
2881 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2882 CHECK_NULL_RETURN(swiperLayoutProperty, true);
2883 return swiperLayoutProperty->GetShowIndicatorValue(true);
2884 }
2885
IsShowArrow() const2886 bool SwiperPattern::IsShowArrow() const
2887 {
2888 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2889 CHECK_NULL_RETURN(swiperLayoutProperty, true);
2890 return swiperLayoutProperty->GetDisplayArrowValue(false);
2891 }
2892
GetIndicatorType() const2893 SwiperIndicatorType SwiperPattern::GetIndicatorType() const
2894 {
2895 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2896 CHECK_NULL_RETURN(swiperLayoutProperty, SwiperIndicatorType::DOT);
2897 return swiperLayoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
2898 }
2899
GetSwiperParameters() const2900 std::shared_ptr<SwiperParameters> SwiperPattern::GetSwiperParameters() const
2901 {
2902 if (swiperParameters_ == nullptr) {
2903 swiperParameters_ = std::make_shared<SwiperParameters>();
2904 auto pipelineContext = PipelineBase::GetCurrentContext();
2905 CHECK_NULL_RETURN(pipelineContext, swiperParameters_);
2906 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
2907 swiperParameters_->itemWidth = swiperIndicatorTheme->GetSize();
2908 swiperParameters_->itemHeight = swiperIndicatorTheme->GetSize();
2909 swiperParameters_->selectedItemWidth = swiperIndicatorTheme->GetSize();
2910 swiperParameters_->selectedItemHeight = swiperIndicatorTheme->GetSize();
2911 swiperParameters_->maskValue = false;
2912 swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
2913 swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
2914 }
2915 return swiperParameters_;
2916 }
2917
GetSwiperDigitalParameters() const2918 std::shared_ptr<SwiperDigitalParameters> SwiperPattern::GetSwiperDigitalParameters() const
2919 {
2920 if (swiperDigitalParameters_ == nullptr) {
2921 swiperDigitalParameters_ = std::make_shared<SwiperDigitalParameters>();
2922 auto pipelineContext = PipelineBase::GetCurrentContext();
2923 CHECK_NULL_RETURN(pipelineContext, swiperDigitalParameters_);
2924 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
2925 swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
2926 swiperDigitalParameters_->selectedFontColor =
2927 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
2928 swiperDigitalParameters_->fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
2929 swiperDigitalParameters_->selectedFontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
2930 swiperDigitalParameters_->fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
2931 swiperDigitalParameters_->selectedFontWeight =
2932 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
2933 }
2934 return swiperDigitalParameters_;
2935 }
2936
TotalCount() const2937 int32_t SwiperPattern::TotalCount() const
2938 {
2939 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2940 CHECK_NULL_RETURN(layoutProperty, 1);
2941 auto displayCount = layoutProperty->GetDisplayCount().value_or(1);
2942 auto totalCount = RealTotalCount();
2943 if (IsSwipeByGroup() && displayCount != 0) {
2944 totalCount =
2945 static_cast<int32_t>(std::ceil(static_cast<float>(totalCount) / static_cast<float>(displayCount))) *
2946 displayCount;
2947 }
2948
2949 return totalCount;
2950 }
2951
RealTotalCount() const2952 int32_t SwiperPattern::RealTotalCount() const
2953 {
2954 auto host = GetHost();
2955 CHECK_NULL_RETURN(host, 0);
2956 // last child is swiper indicator
2957 int num = 0;
2958 if (IsShowIndicator()) {
2959 num += 1;
2960 }
2961 if (HasLeftButtonNode()) {
2962 num += 1;
2963 }
2964 if (HasRightButtonNode()) {
2965 num += 1;
2966 }
2967
2968 return host->TotalChildCount() - num;
2969 }
2970
GetTranslateLength() const2971 float SwiperPattern::GetTranslateLength() const
2972 {
2973 if (itemPosition_.empty()) {
2974 return 0.0f;
2975 }
2976 return itemPosition_.begin()->second.endPos - itemPosition_.begin()->second.startPos;
2977 }
2978
GetFirstItemInfoInVisibleArea() const2979 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetFirstItemInfoInVisibleArea() const
2980 {
2981 if (itemPosition_.empty()) {
2982 return std::make_pair(0, SwiperItemInfo {});
2983 }
2984 auto targetIndex = 0;
2985 if (GetPrevMargin() != 0.0f) {
2986 for (const auto& item : itemPosition_) {
2987 if (item.second.startPos < 0 && item.second.endPos < 0) {
2988 continue;
2989 }
2990 if (item.second.startPos <= 0 && item.second.endPos > 0) {
2991 targetIndex = item.first;
2992 return std::make_pair(targetIndex, SwiperItemInfo { item.second.startPos, item.second.endPos });
2993 }
2994 if (item.second.startPos > 0 && item.second.endPos > 0) {
2995 targetIndex = item.first;
2996 return std::make_pair(targetIndex, SwiperItemInfo { item.second.startPos, item.second.endPos });
2997 }
2998 }
2999 }
3000 return std::make_pair(itemPosition_.begin()->first,
3001 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
3002 }
3003
GetLastItemInfoInVisibleArea() const3004 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetLastItemInfoInVisibleArea() const
3005 {
3006 if (itemPosition_.empty()) {
3007 return std::make_pair(0, SwiperItemInfo {});
3008 }
3009 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3010 auto targetVisableIndex = firstItemInfoInVisibleArea.first;
3011 targetVisableIndex += GetDisplayCount() - 1;
3012 auto iter = itemPosition_.find(targetVisableIndex);
3013 if (iter != itemPosition_.end()) {
3014 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
3015 }
3016 return std::make_pair(itemPosition_.rbegin()->first,
3017 SwiperItemInfo { itemPosition_.rbegin()->second.startPos, itemPosition_.rbegin()->second.endPos });
3018 }
3019
GetSecondItemInfoInVisibleArea() const3020 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetSecondItemInfoInVisibleArea() const
3021 {
3022 if (itemPosition_.empty()) {
3023 return std::make_pair(0, SwiperItemInfo {});
3024 }
3025 auto targetIndex = itemPosition_.begin()->first;
3026 if (GetPrevMargin() != 0.0f) {
3027 for (const auto& item : itemPosition_) {
3028 if (item.second.startPos < 0 && item.second.endPos < 0) {
3029 continue;
3030 }
3031 if (item.second.startPos <= 0 && item.second.endPos > 0) {
3032 targetIndex = item.first;
3033 break;
3034 }
3035 if (item.second.startPos > 0 && item.second.endPos > 0) {
3036 targetIndex = item.first;
3037 break;
3038 }
3039 }
3040 }
3041
3042 targetIndex++;
3043 auto iter = itemPosition_.find(targetIndex);
3044 if (iter != itemPosition_.end()) {
3045 return std::make_pair(targetIndex, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
3046 }
3047 return std::make_pair(itemPosition_.begin()->first,
3048 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
3049 }
3050
IsOutOfHotRegion(const PointF & dragPoint) const3051 bool SwiperPattern::IsOutOfHotRegion(const PointF& dragPoint) const
3052 {
3053 auto host = GetHost();
3054 CHECK_NULL_RETURN(host, true);
3055 auto context = host->GetRenderContext();
3056 CHECK_NULL_RETURN(context, true);
3057
3058 auto hotRegion = context->GetPaintRectWithoutTransform();
3059 return !hotRegion.IsInRegion(dragPoint + OffsetF(hotRegion.GetX(), hotRegion.GetY()));
3060 }
3061
SaveDotIndicatorProperty(const RefPtr<FrameNode> & indicatorNode)3062 void SwiperPattern::SaveDotIndicatorProperty(const RefPtr<FrameNode>& indicatorNode)
3063 {
3064 CHECK_NULL_VOID(indicatorNode);
3065 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
3066 CHECK_NULL_VOID(indicatorPattern);
3067 auto layoutProperty = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
3068 CHECK_NULL_VOID(layoutProperty);
3069 auto paintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
3070 CHECK_NULL_VOID(paintProperty);
3071 auto pipelineContext = PipelineBase::GetCurrentContext();
3072 CHECK_NULL_VOID(pipelineContext);
3073 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
3074 CHECK_NULL_VOID(swiperIndicatorTheme);
3075 auto swiperParameters = GetSwiperParameters();
3076 CHECK_NULL_VOID(swiperParameters);
3077 layoutProperty->ResetIndicatorLayoutStyle();
3078 if (swiperParameters->dimLeft.has_value()) {
3079 layoutProperty->UpdateLeft(swiperParameters->dimLeft.value());
3080 }
3081 if (swiperParameters->dimTop.has_value()) {
3082 layoutProperty->UpdateTop(swiperParameters->dimTop.value());
3083 }
3084 if (swiperParameters->dimRight.has_value()) {
3085 layoutProperty->UpdateRight(swiperParameters->dimRight.value());
3086 }
3087 if (swiperParameters->dimBottom.has_value()) {
3088 layoutProperty->UpdateBottom(swiperParameters->dimBottom.value());
3089 }
3090 paintProperty->UpdateItemWidth(swiperParameters->itemWidth.value_or(swiperIndicatorTheme->GetSize()));
3091 paintProperty->UpdateItemHeight(swiperParameters->itemHeight.value_or(swiperIndicatorTheme->GetSize()));
3092 paintProperty->UpdateSelectedItemWidth(
3093 swiperParameters->selectedItemWidth.value_or(swiperIndicatorTheme->GetSize()));
3094 paintProperty->UpdateSelectedItemHeight(
3095 swiperParameters->selectedItemHeight.value_or(swiperIndicatorTheme->GetSize()));
3096 paintProperty->UpdateIndicatorMask(swiperParameters->maskValue.value_or(false));
3097 paintProperty->UpdateColor(swiperParameters->colorVal.value_or(swiperIndicatorTheme->GetColor()));
3098 paintProperty->UpdateSelectedColor(
3099 swiperParameters->selectedColorVal.value_or(swiperIndicatorTheme->GetSelectedColor()));
3100 paintProperty->UpdateIsCustomSize(IsCustomSize_);
3101
3102 MarkDirtyNodeSelf();
3103 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3104 }
3105
SaveDigitIndicatorProperty(const RefPtr<FrameNode> & indicatorNode)3106 void SwiperPattern::SaveDigitIndicatorProperty(const RefPtr<FrameNode>& indicatorNode)
3107 {
3108 CHECK_NULL_VOID(indicatorNode);
3109 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
3110 CHECK_NULL_VOID(indicatorPattern);
3111 auto layoutProperty = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
3112 CHECK_NULL_VOID(layoutProperty);
3113 auto pipelineContext = PipelineBase::GetCurrentContext();
3114 CHECK_NULL_VOID(pipelineContext);
3115 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
3116 auto swiperDigitalParameters = GetSwiperDigitalParameters();
3117 CHECK_NULL_VOID(swiperDigitalParameters);
3118 layoutProperty->ResetIndicatorLayoutStyle();
3119 if (swiperDigitalParameters->dimLeft.has_value()) {
3120 layoutProperty->UpdateLeft(swiperDigitalParameters->dimLeft.value());
3121 }
3122 if (swiperDigitalParameters->dimTop.has_value()) {
3123 layoutProperty->UpdateTop(swiperDigitalParameters->dimTop.value());
3124 }
3125 if (swiperDigitalParameters->dimRight.has_value()) {
3126 layoutProperty->UpdateRight(swiperDigitalParameters->dimRight.value());
3127 }
3128 if (swiperDigitalParameters->dimBottom.has_value()) {
3129 layoutProperty->UpdateBottom(swiperDigitalParameters->dimBottom.value());
3130 }
3131 layoutProperty->UpdateFontColor(swiperDigitalParameters->fontColor.value_or(
3132 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor()));
3133 layoutProperty->UpdateSelectedFontColor(swiperDigitalParameters->selectedFontColor.value_or(
3134 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor()));
3135 layoutProperty->UpdateFontSize(
3136 swiperDigitalParameters->fontSize.value_or(swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize()));
3137 layoutProperty->UpdateSelectedFontSize(swiperDigitalParameters->selectedFontSize.value_or(
3138 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize()));
3139 layoutProperty->UpdateFontWeight(swiperDigitalParameters->fontWeight.value_or(
3140 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight()));
3141 layoutProperty->UpdateSelectedFontWeight(swiperDigitalParameters->selectedFontWeight.value_or(
3142 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight()));
3143 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3144 CHECK_NULL_VOID(swiperLayoutProperty);
3145 swiperLayoutProperty->UpdateLeft(swiperDigitalParameters->dimLeft.value_or(0.0_vp));
3146 swiperLayoutProperty->UpdateTop(swiperDigitalParameters->dimTop.value_or(0.0_vp));
3147 swiperLayoutProperty->UpdateRight(swiperDigitalParameters->dimRight.value_or(0.0_vp));
3148 swiperLayoutProperty->UpdateBottom(swiperDigitalParameters->dimBottom.value_or(0.0_vp));
3149 }
3150
PostTranslateTask(uint32_t delayTime)3151 void SwiperPattern::PostTranslateTask(uint32_t delayTime)
3152 {
3153 auto pipeline = PipelineContext::GetCurrentContext();
3154 CHECK_NULL_VOID(pipeline);
3155 auto taskExecutor = pipeline->GetTaskExecutor();
3156 CHECK_NULL_VOID(taskExecutor);
3157
3158 if (translateTask_) {
3159 translateTask_.Cancel();
3160 }
3161
3162 auto weak = AceType::WeakClaim(this);
3163 translateTask_.Reset([weak, delayTime] {
3164 auto swiper = weak.Upgrade();
3165 if (swiper) {
3166 auto childrenSize = swiper->TotalCount();
3167 auto displayCount = swiper->GetDisplayCount();
3168 if (childrenSize <= 0 || displayCount <= 0 || swiper->itemPosition_.empty()) {
3169 return;
3170 }
3171 if (!swiper->IsLoop() && swiper->GetLoopIndex(swiper->currentIndex_) + 1 > (childrenSize - displayCount)) {
3172 return;
3173 }
3174 auto stepItems = swiper->IsSwipeByGroup() ? displayCount : 1;
3175 swiper->targetIndex_ = swiper->CheckTargetIndex(swiper->currentIndex_ + stepItems);
3176 swiper->MarkDirtyNodeSelf();
3177 auto pipeline = PipelineContext::GetCurrentContext();
3178 if (pipeline) {
3179 pipeline->FlushUITasks();
3180 }
3181 }
3182 });
3183
3184 taskExecutor->PostDelayedTask(translateTask_, TaskExecutor::TaskType::UI, delayTime);
3185 }
3186
RegisterVisibleAreaChange()3187 void SwiperPattern::RegisterVisibleAreaChange()
3188 {
3189 auto pipeline = PipelineContext::GetCurrentContext();
3190 CHECK_NULL_VOID(pipeline);
3191 auto host = GetHost();
3192 CHECK_NULL_VOID(host);
3193 pipeline->AddWindowStateChangedCallback(host->GetId());
3194
3195 if (hasVisibleChangeRegistered_ || !IsAutoPlay()) {
3196 return;
3197 }
3198
3199 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
3200 auto swiperPattern = weak.Upgrade();
3201 CHECK_NULL_VOID(swiperPattern);
3202 swiperPattern->isVisibleArea_ = visible;
3203 if (!visible) {
3204 swiperPattern->translateTask_.Cancel();
3205 return;
3206 }
3207
3208 if (swiperPattern->NeedStartAutoPlay()) {
3209 swiperPattern->StartAutoPlay();
3210 }
3211 };
3212 pipeline->RemoveVisibleAreaChangeNode(host->GetId());
3213 pipeline->AddVisibleAreaChangeNode(host, 0.0f, callback, false);
3214 hasVisibleChangeRegistered_ = true;
3215 }
3216
NeedAutoPlay() const3217 bool SwiperPattern::NeedAutoPlay() const
3218 {
3219 bool reachEnd = GetLoopIndex(CurrentIndex()) >= TotalCount() - 1 && !IsLoop();
3220 return IsAutoPlay() && !reachEnd && isVisible_ && !isIndicatorLongPress_;
3221 }
3222
TriggerAnimationEndOnSwipeToLeft()3223 void SwiperPattern::TriggerAnimationEndOnSwipeToLeft()
3224 {
3225 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3226 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3227 auto firstIndexStartPos = firstItemInfoInVisibleArea.second.startPos;
3228 if (std::abs(firstIndexStartPos) < (firstItemLength / 2)) {
3229 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
3230 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
3231 } else {
3232 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
3233 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
3234 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
3235 }
3236 }
3237
TriggerAnimationEndOnSwipeToRight()3238 void SwiperPattern::TriggerAnimationEndOnSwipeToRight()
3239 {
3240 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3241 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3242 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
3243 auto secondIndexStartPos = secondItemInfoInVisibleArea.second.startPos;
3244 if (std::abs(secondIndexStartPos) < (firstItemLength / 2)) {
3245 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
3246 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
3247 } else {
3248 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
3249 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
3250 }
3251 }
3252
UpdateIndexOnAnimationStop()3253 void SwiperPattern::UpdateIndexOnAnimationStop()
3254 {
3255 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3256 if (currentIndex_ == firstItemInfoInVisibleArea.first) {
3257 // swipe to left
3258 TriggerAnimationEndOnSwipeToLeft();
3259 } else {
3260 // swipe to right
3261 TriggerAnimationEndOnSwipeToRight();
3262 }
3263 }
3264
UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)3265 void SwiperPattern::UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)
3266 {
3267 auto iter = itemPosition_.find(currentIndex_);
3268 if (iter == itemPosition_.end()) {
3269 UpdateCurrentIndex(pauseTargetIndex);
3270 if (itemPosition_.find(pauseTargetIndex) != itemPosition_.end()) {
3271 currentIndexOffset_ = itemPosition_.find(pauseTargetIndex)->second.startPos;
3272 }
3273 return;
3274 }
3275
3276 auto swiperWidth = MainSize();
3277 auto currentOffset = iter->second.startPos;
3278 if (std::abs(currentOffset) < (swiperWidth / 2)) {
3279 return;
3280 }
3281
3282 if (currentOffset < 0.0f) {
3283 auto nextPageIndex = currentIndex_ + GetDisplayCount();
3284 auto nextIter = itemPosition_.find(nextPageIndex);
3285 if (nextIter == itemPosition_.end()) {
3286 return;
3287 }
3288
3289 auto nextPageOffset = nextIter->second.startPos;
3290 currentIndexOffset_ = nextPageOffset;
3291 UpdateCurrentIndex(nextPageIndex);
3292 } else {
3293 auto prevPageIndex = currentIndex_ - GetDisplayCount();
3294 auto prevIter = itemPosition_.find(prevPageIndex);
3295 if (prevIter == itemPosition_.end()) {
3296 return;
3297 }
3298
3299 auto prevPageOffset = prevIter->second.startPos;
3300 currentIndexOffset_ = prevPageOffset;
3301 UpdateCurrentIndex(prevPageIndex);
3302 }
3303 }
3304
TriggerAnimationEndOnForceStop()3305 void SwiperPattern::TriggerAnimationEndOnForceStop()
3306 {
3307 auto pauseTargetIndex = pauseTargetIndex_.has_value() ? pauseTargetIndex_.value() : currentIndex_;
3308 if (currentIndex_ != pauseTargetIndex) {
3309 if (IsSwipeByGroup()) {
3310 UpdateIndexOnSwipePageStop(pauseTargetIndex);
3311 } else {
3312 UpdateIndexOnAnimationStop();
3313 }
3314 do {
3315 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
3316 if (!curChildFrame) {
3317 break;
3318 }
3319 FlushFocus(curChildFrame);
3320 currentFocusIndex_ = currentIndex_;
3321 } while (0);
3322
3323 OnIndexChange();
3324 oldIndex_ = currentIndex_;
3325 }
3326 AnimationCallbackInfo info;
3327 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3328 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
3329 UpdateItemRenderGroup(false);
3330 }
3331
TriggerEventOnFinish(int32_t nextIndex)3332 void SwiperPattern::TriggerEventOnFinish(int32_t nextIndex)
3333 {
3334 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
3335
3336 AnimationCallbackInfo info;
3337 info.currentOffset = GetCustomPropertyOffset();
3338 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
3339 }
3340
GetCachedCount() const3341 int32_t SwiperPattern::GetCachedCount() const
3342 {
3343 auto host = GetHost();
3344 CHECK_NULL_RETURN(host, 1);
3345 auto layoutProperty = host->GetLayoutProperty<SwiperLayoutProperty>();
3346 CHECK_NULL_RETURN(layoutProperty, 1);
3347 auto cachedCount = layoutProperty->GetCachedCount().value_or(1);
3348
3349 if (IsSwipeByGroup()) {
3350 cachedCount *= GetDisplayCount();
3351 }
3352
3353 return cachedCount;
3354 }
3355
SetLazyLoadFeature(bool useLazyLoad) const3356 void SwiperPattern::SetLazyLoadFeature(bool useLazyLoad) const
3357 {
3358 SetLazyForEachLongPredict(useLazyLoad);
3359
3360 if (useLazyLoad) {
3361 auto cacheCount = GetCachedCount();
3362 std::set<int32_t> forEachIndexSet;
3363 for (auto count = 1; count <= cacheCount; count++) {
3364 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ + count));
3365 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ - count));
3366 }
3367 if (forEachIndexSet.empty()) {
3368 return;
3369 }
3370
3371 auto host = GetHost();
3372 CHECK_NULL_VOID(host);
3373 const auto& children = host->GetChildren();
3374 for (const auto& child : children) {
3375 if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
3376 continue;
3377 }
3378 auto pipeline = PipelineContext::GetCurrentContext();
3379 CHECK_NULL_VOID(pipeline);
3380 auto taskExecutor = pipeline->GetTaskExecutor();
3381 CHECK_NULL_VOID(taskExecutor);
3382 taskExecutor->PostTask(
3383 [weak = WeakClaim(RawPtr(child)), forEachIndexSet]() {
3384 auto node = weak.Upgrade();
3385 CHECK_NULL_VOID(node);
3386 auto forEachNode = AceType::DynamicCast<ForEachNode>(node);
3387 CHECK_NULL_VOID(forEachNode);
3388 for (auto index : forEachIndexSet) {
3389 auto childNode = forEachNode->GetChildAtIndex(index);
3390 CHECK_NULL_VOID(childNode);
3391 childNode->Build(nullptr);
3392 }
3393 },
3394 TaskExecutor::TaskType::UI);
3395 }
3396 }
3397 }
3398
SetLazyForEachLongPredict(bool useLazyLoad) const3399 void SwiperPattern::SetLazyForEachLongPredict(bool useLazyLoad) const
3400 {
3401 // lazyBuild feature.
3402 auto host = GetHost();
3403 CHECK_NULL_VOID(host);
3404 const auto& children = host->GetChildren();
3405 for (auto&& child : children) {
3406 auto lazyForEach = DynamicCast<LazyForEachNode>(child);
3407 if (lazyForEach) {
3408 lazyForEach->SetRequestLongPredict(useLazyLoad);
3409 }
3410 }
3411 }
3412
SetLazyLoadIsLoop() const3413 void SwiperPattern::SetLazyLoadIsLoop() const
3414 {
3415 auto host = GetHost();
3416 CHECK_NULL_VOID(host);
3417 const auto& children = host->GetChildren();
3418 for (auto&& child : children) {
3419 auto lazyForEach = DynamicCast<LazyForEachNode>(child);
3420 if (lazyForEach) {
3421 lazyForEach->SetIsLoop(IsLoop());
3422 }
3423 }
3424 }
3425
IsVisibleChildrenSizeLessThanSwiper()3426 bool SwiperPattern::IsVisibleChildrenSizeLessThanSwiper()
3427 {
3428 if (itemPosition_.empty()) {
3429 return true;
3430 }
3431 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3432 auto lastItemInfoInVisibleArea = GetLastItemInfoInVisibleArea();
3433 auto calcDisPlayCount = lastItemInfoInVisibleArea.first - firstItemInfoInVisibleArea.first + 1;
3434 if (Positive(TotalCount() - calcDisPlayCount)) {
3435 return false;
3436 }
3437 if (static_cast<int32_t>(itemPosition_.size()) == TotalCount()) {
3438 auto totalChildrenSize = lastItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3439 if (NonPositive(totalChildrenSize)) {
3440 return true;
3441 }
3442 auto prevMargin = GetPrevMargin();
3443 auto nextMargin = GetNextMargin();
3444 auto itemSpace = GetItemSpace();
3445 auto host = GetHost();
3446 CHECK_NULL_RETURN(host, true);
3447 auto geometryNode = host->GetGeometryNode();
3448 CHECK_NULL_RETURN(geometryNode, true);
3449 auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
3450 if (itemSpace > mainSize) {
3451 itemSpace = 0.0f;
3452 }
3453 auto prevMarginMontage = Positive(prevMargin) ? prevMargin + itemSpace : 0.0f;
3454 auto nextMarginMontage = Positive(nextMargin) ? nextMargin + itemSpace : 0.0f;
3455
3456 if (totalChildrenSize <= (contentMainSize_ - prevMarginMontage - nextMarginMontage)) {
3457 return true;
3458 }
3459 }
3460 return false;
3461 }
3462
UpdateItemRenderGroup(bool itemRenderGroup)3463 void SwiperPattern::UpdateItemRenderGroup(bool itemRenderGroup)
3464 {
3465 for (auto& item : itemPosition_) {
3466 if (auto frameNode = item.second.node) {
3467 auto context = frameNode->GetRenderContext();
3468 CHECK_NULL_VOID(context);
3469 context->UpdateSuggestedRenderGroup(itemRenderGroup);
3470 }
3471 }
3472 auto host = GetHost();
3473 CHECK_NULL_VOID(host);
3474 for (auto child : host->GetChildren()) {
3475 auto frameNode = DynamicCast<FrameNode>(child);
3476 if (!frameNode || child->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
3477 continue;
3478 }
3479 auto context = frameNode->GetRenderContext();
3480 CHECK_NULL_VOID(context);
3481 context->UpdateSuggestedRenderGroup(itemRenderGroup);
3482 }
3483 }
3484
OnTranslateFinish(int32_t nextIndex,bool restartAutoPlay,bool isFinishAnimation,bool forceStop)3485 void SwiperPattern::OnTranslateFinish(int32_t nextIndex, bool restartAutoPlay, bool isFinishAnimation, bool forceStop)
3486 {
3487 if (forceStop && !isFinishAnimation) {
3488 TriggerAnimationEndOnForceStop();
3489 } else {
3490 TriggerEventOnFinish(nextIndex);
3491 }
3492
3493 auto host = GetHost();
3494 CHECK_NULL_VOID(host);
3495 if (HasIndicatorNode()) {
3496 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
3497 CHECK_NULL_VOID(indicatorNode);
3498 if (indicatorNode->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
3499 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3500 MarkDirtyNodeSelf();
3501 }
3502 }
3503
3504 auto delayTime = GetInterval() - GetDuration();
3505 delayTime = std::clamp(delayTime, 0, delayTime);
3506 if (NeedAutoPlay() && isUserFinish_ && !forceStop) {
3507 PostTranslateTask(delayTime);
3508 }
3509 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
3510 UpdateItemRenderGroup(false);
3511 }
3512
OnWindowShow()3513 void SwiperPattern::OnWindowShow()
3514 {
3515 isWindowShow_ = true;
3516 if (NeedStartAutoPlay()) {
3517 StartAutoPlay();
3518 }
3519 }
3520
OnWindowHide()3521 void SwiperPattern::OnWindowHide()
3522 {
3523 isWindowShow_ = false;
3524 StopAutoPlay();
3525
3526 if (isDragging_) {
3527 HandleDragEnd(0.0);
3528 }
3529
3530 StopSpringAnimationAndFlushImmediately();
3531 }
3532
ArrowHover(bool hoverFlag)3533 void SwiperPattern::ArrowHover(bool hoverFlag)
3534 {
3535 if (HasLeftButtonNode() && HasRightButtonNode()) {
3536 auto swiperNode = GetHost();
3537 CHECK_NULL_VOID(swiperNode);
3538 auto leftArrowNode =
3539 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
3540 CHECK_NULL_VOID(leftArrowNode);
3541 auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
3542 CHECK_NULL_VOID(leftArrowPattern);
3543 leftArrowPattern->SetButtonVisible(hoverFlag);
3544 auto rightArrowNode =
3545 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
3546 CHECK_NULL_VOID(rightArrowNode);
3547 auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
3548 CHECK_NULL_VOID(rightArrowPattern);
3549 rightArrowPattern->SetButtonVisible(hoverFlag);
3550 }
3551 }
3552
SaveArrowProperty(const RefPtr<FrameNode> & arrowNode)3553 void SwiperPattern::SaveArrowProperty(const RefPtr<FrameNode>& arrowNode)
3554 {
3555 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3556 CHECK_NULL_VOID(layoutProperty);
3557 auto swiperPaintProperty = GetPaintProperty<SwiperPaintProperty>();
3558 CHECK_NULL_VOID(swiperPaintProperty);
3559 auto arrowLayoutProperty = arrowNode->GetLayoutProperty<SwiperArrowLayoutProperty>();
3560 CHECK_NULL_VOID(arrowLayoutProperty);
3561 arrowLayoutProperty->UpdateDirection(layoutProperty->GetDirection().value_or(Axis::HORIZONTAL));
3562 arrowLayoutProperty->UpdateIndex(layoutProperty->GetIndex().value_or(0));
3563 arrowLayoutProperty->UpdateLoop(layoutProperty->GetLoop().value_or(true));
3564 arrowLayoutProperty->UpdateEnabled(swiperPaintProperty->GetEnabled().value_or(true));
3565 arrowLayoutProperty->UpdateDisplayArrow(layoutProperty->GetDisplayArrowValue());
3566 arrowLayoutProperty->UpdateHoverShow(layoutProperty->GetHoverShowValue());
3567 arrowLayoutProperty->UpdateIsShowBackground(layoutProperty->GetIsShowBackgroundValue());
3568 arrowLayoutProperty->UpdateBackgroundSize(layoutProperty->GetBackgroundSizeValue());
3569 arrowLayoutProperty->UpdateBackgroundColor(layoutProperty->GetBackgroundColorValue());
3570 arrowLayoutProperty->UpdateArrowSize(layoutProperty->GetArrowSizeValue());
3571 arrowLayoutProperty->UpdateArrowColor(layoutProperty->GetArrowColorValue());
3572 arrowLayoutProperty->UpdateIsSidebarMiddle(layoutProperty->GetIsSidebarMiddleValue());
3573 }
3574
SetAccessibilityAction()3575 void SwiperPattern::SetAccessibilityAction()
3576 {
3577 auto host = GetHost();
3578 CHECK_NULL_VOID(host);
3579 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
3580 CHECK_NULL_VOID(accessibilityProperty);
3581 accessibilityProperty->SetActionScrollForward(
3582 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
3583 const auto& pattern = weakPtr.Upgrade();
3584 CHECK_NULL_VOID(pattern);
3585 const auto& accessibilityProperty = accessibility.Upgrade();
3586 CHECK_NULL_VOID(accessibilityProperty);
3587 if (!accessibilityProperty->IsScrollable()) {
3588 return;
3589 }
3590 pattern->ShowNext();
3591 });
3592
3593 accessibilityProperty->SetActionScrollBackward(
3594 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
3595 const auto& pattern = weakPtr.Upgrade();
3596 CHECK_NULL_VOID(pattern);
3597 const auto& accessibilityProperty = accessibility.Upgrade();
3598 CHECK_NULL_VOID(accessibilityProperty);
3599 if (!accessibilityProperty->IsScrollable()) {
3600 return;
3601 }
3602 pattern->ShowPrevious();
3603 });
3604 }
3605
NeedStartAutoPlay() const3606 bool SwiperPattern::NeedStartAutoPlay() const
3607 {
3608 return isWindowShow_ && isVisibleArea_ && isVisible_;
3609 }
3610
ProvideRestoreInfo()3611 std::string SwiperPattern::ProvideRestoreInfo()
3612 {
3613 auto jsonObj = JsonUtil::Create(true);
3614 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3615 CHECK_NULL_RETURN(swiperLayoutProperty, "");
3616 jsonObj->Put("Index", swiperLayoutProperty->GetIndex().value_or(0));
3617 return jsonObj->ToString();
3618 }
3619
OnRestoreInfo(const std::string & restoreInfo)3620 void SwiperPattern::OnRestoreInfo(const std::string& restoreInfo)
3621 {
3622 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3623 CHECK_NULL_VOID(swiperLayoutProperty);
3624 auto info = JsonUtil::ParseJsonString(restoreInfo);
3625 if (!info->IsValid() || !info->IsObject()) {
3626 return;
3627 }
3628 auto jsonIsOn = info->GetValue("Index");
3629 swiperLayoutProperty->UpdateIndex(jsonIsOn->GetInt());
3630 OnModifyDone();
3631 }
3632
InitHoverMouseEvent()3633 void SwiperPattern::InitHoverMouseEvent()
3634 {
3635 auto host = GetHost();
3636 CHECK_NULL_VOID(host);
3637 auto eventHub = host->GetEventHub<EventHub>();
3638 CHECK_NULL_VOID(eventHub);
3639 auto inputHub = eventHub->GetOrCreateInputEventHub();
3640 CHECK_NULL_VOID(inputHub);
3641
3642 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
3643 auto pattern = weak.Upgrade();
3644 CHECK_NULL_VOID(pattern);
3645 if (!pattern->IsShowIndicator()) {
3646 pattern->ArrowHover(isHover);
3647 }
3648 };
3649
3650 if (!hoverEvent_) {
3651 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
3652 inputHub->AddOnHoverEvent(hoverEvent_);
3653 }
3654
3655 auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
3656 auto pattern = weak.Upgrade();
3657 if (pattern) {
3658 pattern->HandleMouseEvent(info);
3659 }
3660 };
3661 if (mouseEvent_) {
3662 inputHub->RemoveOnMouseEvent(mouseEvent_);
3663 }
3664 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
3665 inputHub->AddOnMouseEvent(mouseEvent_);
3666 }
3667
HandleMouseEvent(const MouseInfo & info)3668 void SwiperPattern::HandleMouseEvent(const MouseInfo& info)
3669 {
3670 auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
3671 auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
3672 auto mousePoint = PointF(mouseOffsetX, mouseOffsetY);
3673 if (IsShowIndicator()) {
3674 CheckAndSetArrowHoverState(mousePoint);
3675 }
3676 }
3677
CheckAndSetArrowHoverState(const PointF & mousePoint)3678 void SwiperPattern::CheckAndSetArrowHoverState(const PointF& mousePoint)
3679 {
3680 if (!HasLeftButtonNode() || !HasRightButtonNode() || !HasIndicatorNode()) {
3681 return;
3682 }
3683
3684 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3685 CHECK_NULL_VOID(layoutProperty);
3686 if (layoutProperty->GetIsSidebarMiddleValue(false)) {
3687 return;
3688 }
3689
3690 RectF leftNodeRect;
3691 RectF rightNodeRect;
3692
3693 leftNodeRect = GetArrowFrameRect(GetLeftButtonId());
3694 rightNodeRect = GetArrowFrameRect(GetRightButtonId());
3695
3696 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
3697 leftNodeRect = GetArrowFrameRect(GetIndicatorId());
3698 }
3699
3700 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
3701 rightNodeRect = GetArrowFrameRect(GetIndicatorId());
3702 }
3703 RectF newNodeRect;
3704 if (GetDirection() == Axis::HORIZONTAL) {
3705 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(), rightNodeRect.Right() - leftNodeRect.Left(),
3706 std::min(rightNodeRect.Height(), leftNodeRect.Height()));
3707 } else {
3708 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(),
3709 std::min(rightNodeRect.Width(), leftNodeRect.Width()), rightNodeRect.Bottom() - leftNodeRect.Top());
3710 }
3711
3712 isAtHotRegion_ = newNodeRect.IsInRegion(mousePoint);
3713 ArrowHover(isAtHotRegion_);
3714 }
3715
GetArrowFrameRect(const int32_t index) const3716 RectF SwiperPattern::GetArrowFrameRect(const int32_t index) const
3717 {
3718 auto swiperNode = GetHost();
3719 CHECK_NULL_RETURN(swiperNode, RectF(0, 0, 0, 0));
3720 auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(index)));
3721 CHECK_NULL_RETURN(arrowNode, RectF(0, 0, 0, 0));
3722 auto arrowGeometryNode = arrowNode->GetGeometryNode();
3723 CHECK_NULL_RETURN(arrowGeometryNode, RectF(0, 0, 0, 0));
3724 return arrowGeometryNode->GetFrameRect();
3725 }
3726
GetCustomPropertyOffset() const3727 float SwiperPattern::GetCustomPropertyOffset() const
3728 {
3729 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3730 CHECK_NULL_RETURN(layoutProperty, 0.0);
3731 auto paddingAndBorder = layoutProperty->CreatePaddingAndBorder();
3732 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
3733 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
3734 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
3735
3736 auto preMarginPX = GetPrevMargin();
3737 if (layoutProperty->GetPrevMargin().has_value() && preMarginPX > 0.0) {
3738 preMarginPX += GetItemSpace();
3739 }
3740
3741 return Dimension(paddingAndBorderValue + preMarginPX, DimensionUnit::PX).ConvertToVp();
3742 }
3743
GetCurrentFirstIndexStartPos() const3744 float SwiperPattern::GetCurrentFirstIndexStartPos() const
3745 {
3746 if (itemPosition_.empty()) {
3747 return 0.0;
3748 }
3749
3750 return itemPosition_.begin()->second.startPos;
3751 }
3752
TotalDisPlayCount() const3753 int32_t SwiperPattern::TotalDisPlayCount() const
3754 {
3755 auto swiperLayoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
3756 CHECK_NULL_RETURN(swiperLayoutProperty, 1);
3757 auto displayCount = GetDisplayCount();
3758 if (SwiperUtils::IsStretch(swiperLayoutProperty)) {
3759 if (Positive(swiperLayoutProperty->GetPrevMarginValue(0.0_px).ConvertToPx())) {
3760 displayCount++;
3761 }
3762 if (Positive(swiperLayoutProperty->GetNextMarginValue(0.0_px).ConvertToPx())) {
3763 displayCount++;
3764 }
3765 }
3766 return displayCount;
3767 }
3768
MarkDirtyNodeSelf()3769 void SwiperPattern::MarkDirtyNodeSelf()
3770 {
3771 auto host = GetHost();
3772 CHECK_NULL_VOID(host);
3773 if (!crossMatchChild_) {
3774 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3775 } else {
3776 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
3777 }
3778 }
3779
ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)3780 void SwiperPattern::ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)
3781 {
3782 auto host = GetHost();
3783 CHECK_NULL_VOID(host);
3784 targetIndex_.reset();
3785 if (preTargetIndex_.has_value()) {
3786 preTargetIndex_.reset();
3787 }
3788
3789 if (currentIndex_ == nextIndex) {
3790 return;
3791 }
3792
3793 if (isFinishAnimation_) {
3794 currentDelta_ = 0.0f;
3795 itemPosition_.clear();
3796 isVoluntarilyClear_ = true;
3797 jumpIndex_ = nextIndex;
3798 MarkDirtyNodeSelf();
3799 auto pipeline = PipelineContext::GetCurrentContext();
3800 if (pipeline) {
3801 pipeline->FlushUITasks();
3802 }
3803 isFinishAnimation_ = false;
3804 } else {
3805 UpdateCurrentIndex(nextIndex);
3806 if (currentFocusIndex_ < currentIndex_ || currentFocusIndex_ >= currentIndex_ + GetDisplayCount()) {
3807 currentFocusIndex_ = currentIndex_;
3808 }
3809 do {
3810 auto curChildFrame = GetCurrentFrameNode(currentFocusIndex_);
3811 if (!curChildFrame) {
3812 break;
3813 }
3814 FlushFocus(curChildFrame);
3815 } while (0);
3816 oldIndex_ = nextIndex;
3817 currentFirstIndex_ = GetLoopIndex(nextIndex);
3818 turnPageRate_ = 0.0f;
3819 currentIndexOffset_ = 0.0f;
3820 auto pipeline = PipelineContext::GetCurrentContext();
3821 if (pipeline) {
3822 pipeline->FlushUITasks();
3823 pipeline->FlushMessages();
3824 }
3825 FireChangeEvent();
3826 // lazyBuild feature.
3827 SetLazyLoadFeature(true);
3828 }
3829 }
3830
UpdateDragFRCSceneInfo(float speed,SceneStatus sceneStatus)3831 void SwiperPattern::UpdateDragFRCSceneInfo(float speed, SceneStatus sceneStatus)
3832 {
3833 auto host = GetHost();
3834 CHECK_NULL_VOID(host);
3835 host->AddFRCSceneInfo(SWIPER_DRAG_SCENE, speed, sceneStatus);
3836 }
3837
OnScrollStartRecursive(float position)3838 void SwiperPattern::OnScrollStartRecursive(float position)
3839 {
3840 if (IsDisableSwipe()) {
3841 return;
3842 }
3843 childScrolling_ = true;
3844 gestureSwipeIndex_ = currentIndex_;
3845 StopAnimationOnScrollStart(false);
3846 NotifyParentScrollStart(position);
3847 }
3848
NotifyParentScrollStart(float position)3849 void SwiperPattern::NotifyParentScrollStart(float position)
3850 {
3851 auto parent = enableNestedScroll_ ? SearchParent() : nullptr;
3852 if (parent) {
3853 parent->OnScrollStartRecursive(position);
3854 }
3855 parent_ = parent;
3856 }
3857
OnScrollEndRecursive(const std::optional<float> & velocity)3858 void SwiperPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
3859 {
3860 if (IsDisableSwipe()) {
3861 return;
3862 }
3863 // in case child didn't call swiper's HandleScrollVelocity
3864 if (!AnimationRunning()) {
3865 HandleDragEnd(velocity.value_or(0.0f));
3866 }
3867
3868 childScrolling_ = false;
3869 }
3870
NotifyParentScrollEnd()3871 void SwiperPattern::NotifyParentScrollEnd()
3872 {
3873 auto parent = parent_.Upgrade();
3874 if (parent && enableNestedScroll_) {
3875 parent->OnScrollEndRecursive(std::nullopt);
3876 }
3877 }
3878
AnimationRunning() const3879 inline bool SwiperPattern::AnimationRunning() const
3880 {
3881 return (controller_ && controller_->IsRunning()) || (springAnimation_ && springAnimationIsRunning_) ||
3882 (fadeAnimation_ && fadeAnimationIsRunning_) || targetIndex_ || usePropertyAnimation_;
3883 }
3884
HandleScrollVelocity(float velocity)3885 bool SwiperPattern::HandleScrollVelocity(float velocity)
3886 {
3887 if (IsDisableSwipe()) {
3888 return false;
3889 }
3890
3891 // haven't reached edge
3892 if (GetDistanceToEdge() > 0.0f || IsLoop()) {
3893 HandleDragEnd(velocity);
3894 return true;
3895 }
3896
3897 auto parent = parent_.Upgrade();
3898 if (parent && enableNestedScroll_) {
3899 // after reach end, parent handle velocity first
3900 if (parent->HandleScrollVelocity(velocity)) {
3901 return true;
3902 }
3903 }
3904 HandleDragEnd(velocity);
3905 // after reached end, NONE doesn't consume velocity, other edge effects do
3906 return GetEdgeEffect() != EdgeEffect::NONE;
3907 }
3908
HandleScroll(float offset,int32_t source,NestedState state)3909 ScrollResult SwiperPattern::HandleScroll(float offset, int32_t source, NestedState state)
3910 {
3911 if (IsDisableSwipe()) {
3912 return { offset, false };
3913 }
3914
3915 if (source == SCROLL_FROM_ANIMATION && AnimationRunning()) {
3916 // deny conflicting animation from child
3917 return { offset, false };
3918 }
3919 // mouse scroll triggers showNext / showPrev instead of updating offset
3920 if (source == SCROLL_FROM_AXIS) {
3921 auto targetBfr = targetIndex_;
3922 (offset > 0) ? ShowPrevious() : ShowNext();
3923 if (targetBfr == targetIndex_) {
3924 // unchanged targetIndex_ implies Swiper has reached the edge and the mouse scroll isn't consumed.
3925 return { offset, true };
3926 }
3927 return { 0.0f, false };
3928 }
3929 auto parent = parent_.Upgrade();
3930 if (!parent || !enableNestedScroll_) {
3931 if (IsOutOfBoundary(offset) && ChildFirst(state)) {
3932 CloseTheGap(offset);
3933 return { offset, true };
3934 }
3935 UpdateCurrentOffset(offset);
3936 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
3937 }
3938 return HandleScrollSelfFirst(offset, source, state);
3939 }
3940
HandleScrollSelfFirst(float offset,int32_t source,NestedState state)3941 ScrollResult SwiperPattern::HandleScrollSelfFirst(float offset, int32_t source, NestedState state)
3942 {
3943 // priority: self scroll > parent scroll > parent overScroll > self overScroll
3944 if (IsOutOfBoundary(offset)) {
3945 CloseTheGap(offset);
3946 // skip CHECK_NULL, already checked in HandleScroll
3947 auto parent = parent_.Upgrade();
3948
3949 // reached edge, pass offset to parent
3950 auto res = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL);
3951 if (res.remain == 0.0f) {
3952 return { 0.0f, true };
3953 }
3954 // parent handle overScroll first
3955 if (res.reachEdge) {
3956 res = parent->HandleScroll(res.remain, source, NestedState::CHILD_OVER_SCROLL);
3957 }
3958
3959 if (ChildFirst(state)) {
3960 return { res.remain, true };
3961 }
3962 if (res.remain != 0.0f) {
3963 // self overScroll
3964 UpdateCurrentOffset(res.remain);
3965 }
3966 } else {
3967 // regular scroll
3968 UpdateCurrentOffset(offset);
3969 }
3970 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
3971 }
3972
CloseTheGap(float offset)3973 void SwiperPattern::CloseTheGap(float offset)
3974 {
3975 float distanceToEdge = GetDistanceToEdge();
3976 if (distanceToEdge > 0.0f) {
3977 UpdateCurrentOffset(offset > 0 ? distanceToEdge : -distanceToEdge);
3978 }
3979 }
3980
ChildFirst(NestedState state)3981 inline bool SwiperPattern::ChildFirst(NestedState state)
3982 {
3983 // SELF/CHILD priority: self scroll > child scroll > self overScroll > child overScroll
3984 return state == NestedState::CHILD_SCROLL // child hasn't reach edge
3985 || GetEdgeEffect() == EdgeEffect::NONE;
3986 }
3987
DumpAdvanceInfo()3988 void SwiperPattern::DumpAdvanceInfo()
3989 {
3990 isLastIndicatorFocused_ ? DumpLog::GetInstance().AddDesc("isLastIndicatorFocused:true")
3991 : DumpLog::GetInstance().AddDesc("isLastIndicatorFocused:false");
3992 moveDirection_ ? DumpLog::GetInstance().AddDesc("moveDirection:true")
3993 : DumpLog::GetInstance().AddDesc("moveDirection:false");
3994 indicatorDoingAnimation_ ? DumpLog::GetInstance().AddDesc("indicatorDoingAnimation:true")
3995 : DumpLog::GetInstance().AddDesc("indicatorDoingAnimation:false");
3996 hasVisibleChangeRegistered_ ? DumpLog::GetInstance().AddDesc("hasVisibleChangeRegistered:true")
3997 : DumpLog::GetInstance().AddDesc("hasVisibleChangeRegistered:false");
3998 isVisible_ ? DumpLog::GetInstance().AddDesc("isVisible:true") : DumpLog::GetInstance().AddDesc("isVisible:false");
3999 isVisibleArea_ ? DumpLog::GetInstance().AddDesc("isVisibleArea:true")
4000 : DumpLog::GetInstance().AddDesc("isVisibleArea:false");
4001 isWindowShow_ ? DumpLog::GetInstance().AddDesc("isWindowShow:true")
4002 : DumpLog::GetInstance().AddDesc("isWindowShow:false");
4003 IsCustomSize_ ? DumpLog::GetInstance().AddDesc("IsCustomSize:true")
4004 : DumpLog::GetInstance().AddDesc("IsCustomSize:false");
4005 indicatorIsBoolean_ ? DumpLog::GetInstance().AddDesc("indicatorIsBoolean:true")
4006 : DumpLog::GetInstance().AddDesc("indicatorIsBoolean:false");
4007 isAtHotRegion_ ? DumpLog::GetInstance().AddDesc("isAtHotRegion:true")
4008 : DumpLog::GetInstance().AddDesc("isAtHotRegion:false");
4009 isDragging_ ? DumpLog::GetInstance().AddDesc("isDragging:true")
4010 : DumpLog::GetInstance().AddDesc("isDragging:false");
4011 isTouchDown_ ? DumpLog::GetInstance().AddDesc("isTouchDown:true")
4012 : DumpLog::GetInstance().AddDesc("isTouchDown:false");
4013 preLoop_.has_value() ? DumpLog::GetInstance().AddDesc("preLoop:" + std::to_string(preLoop_.value()))
4014 : DumpLog::GetInstance().AddDesc("preLoop:null");
4015 indicatorId_.has_value() ? DumpLog::GetInstance().AddDesc("indicatorId:" + std::to_string(indicatorId_.value()))
4016 : DumpLog::GetInstance().AddDesc("indicatorId:null");
4017 leftButtonId_.has_value() ? DumpLog::GetInstance().AddDesc("leftButtonId:" + std::to_string(leftButtonId_.value()))
4018 : DumpLog::GetInstance().AddDesc("leftButtonId:null");
4019 rightButtonId_.has_value()
4020 ? DumpLog::GetInstance().AddDesc("rightButtonId:" + std::to_string(rightButtonId_.value()))
4021 : DumpLog::GetInstance().AddDesc("rightButtonId:null");
4022 crossMatchChild_ ? DumpLog::GetInstance().AddDesc("crossMatchChild:true")
4023 : DumpLog::GetInstance().AddDesc("crossMatchChild:false");
4024 uiCastJumpIndex_.has_value()
4025 ? DumpLog::GetInstance().AddDesc("uiCastJumpIndex:" + std::to_string(uiCastJumpIndex_.value()))
4026 : DumpLog::GetInstance().AddDesc("uiCastJumpIndex:null");
4027 jumpIndex_.has_value() ? DumpLog::GetInstance().AddDesc("jumpIndex:" + std::to_string(jumpIndex_.value()))
4028 : DumpLog::GetInstance().AddDesc("jumpIndex:null");
4029 targetIndex_.has_value() ? DumpLog::GetInstance().AddDesc("targetIndex:" + std::to_string(targetIndex_.value()))
4030 : DumpLog::GetInstance().AddDesc("targetIndex:null");
4031 preTargetIndex_.has_value()
4032 ? DumpLog::GetInstance().AddDesc("preTargetIndex:" + std::to_string(preTargetIndex_.value()))
4033 : DumpLog::GetInstance().AddDesc("preTargetIndex:null");
4034 pauseTargetIndex_.has_value()
4035 ? DumpLog::GetInstance().AddDesc("pauseTargetIndex:" + std::to_string(pauseTargetIndex_.value()))
4036 : DumpLog::GetInstance().AddDesc("pauseTargetIndex:null");
4037 velocity_.has_value() ? DumpLog::GetInstance().AddDesc("velocity:" + std::to_string(velocity_.value()))
4038 : DumpLog::GetInstance().AddDesc("velocity:null");
4039 isFinishAnimation_ ? DumpLog::GetInstance().AddDesc("isFinishAnimation:true")
4040 : DumpLog::GetInstance().AddDesc("isFinishAnimation:false");
4041 mainSizeIsMeasured_ ? DumpLog::GetInstance().AddDesc("mainSizeIsMeasured:true")
4042 : DumpLog::GetInstance().AddDesc("mainSizeIsMeasured:false");
4043 isNeedResetPrevMarginAndNextMargin_ ? DumpLog::GetInstance().AddDesc("isNeedResetPrevMarginAndNextMargin:true")
4044 : DumpLog::GetInstance().AddDesc("isNeedResetPrevMarginAndNextMargin:false");
4045 usePropertyAnimation_ ? DumpLog::GetInstance().AddDesc("usePropertyAnimation:true")
4046 : DumpLog::GetInstance().AddDesc("usePropertyAnimation:false");
4047 isUserFinish_ ? DumpLog::GetInstance().AddDesc("isUserFinish:true")
4048 : DumpLog::GetInstance().AddDesc("isUserFinish:false");
4049 isVoluntarilyClear_ ? DumpLog::GetInstance().AddDesc("isVoluntarilyClear:true")
4050 : DumpLog::GetInstance().AddDesc("isVoluntarilyClear:false");
4051 isIndicatorLongPress_ ? DumpLog::GetInstance().AddDesc("isIndicatorLongPress:true")
4052 : DumpLog::GetInstance().AddDesc("isIndicatorLongPress:false");
4053 stopIndicatorAnimation_ ? DumpLog::GetInstance().AddDesc("stopIndicatorAnimation:true")
4054 : DumpLog::GetInstance().AddDesc("stopIndicatorAnimation:false");
4055 isTouchPad_ ? DumpLog::GetInstance().AddDesc("isTouchPad:true")
4056 : DumpLog::GetInstance().AddDesc("isTouchPad:false");
4057 surfaceChangedCallbackId_.has_value()
4058 ? DumpLog::GetInstance().AddDesc(
4059 "surfaceChangedCallbackId:" + std::to_string(surfaceChangedCallbackId_.value()))
4060 : DumpLog::GetInstance().AddDesc("surfaceChangedCallbackId:null");
4061 if (lastSwiperIndicatorType_.has_value()) {
4062 switch (lastSwiperIndicatorType_.value()) {
4063 case SwiperIndicatorType::DOT: {
4064 DumpLog::GetInstance().AddDesc("SwiperIndicatorType:DOT");
4065 break;
4066 }
4067 case SwiperIndicatorType::DIGIT: {
4068 DumpLog::GetInstance().AddDesc("SwiperIndicatorType:DIGIT");
4069 break;
4070 }
4071 default: {
4072 break;
4073 }
4074 }
4075 } else {
4076 DumpLog::GetInstance().AddDesc("lastSwiperIndicatorType:null");
4077 }
4078 DumpLog::GetInstance().AddDesc("currentIndex:" + std::to_string(currentIndex_));
4079 DumpLog::GetInstance().AddDesc("oldIndex:" + std::to_string(oldIndex_));
4080 DumpLog::GetInstance().AddDesc("currentOffset:" + std::to_string(currentOffset_));
4081 DumpLog::GetInstance().AddDesc("fadeOffset:" + std::to_string(fadeOffset_));
4082 DumpLog::GetInstance().AddDesc("touchBottomRate:" + std::to_string(touchBottomRate_));
4083 DumpLog::GetInstance().AddDesc("currentIndexOffset:" + std::to_string(currentIndexOffset_));
4084 DumpLog::GetInstance().AddDesc("gestureSwipeIndex:" + std::to_string(gestureSwipeIndex_));
4085 DumpLog::GetInstance().AddDesc("currentFirstIndex:" + std::to_string(currentFirstIndex_));
4086 DumpLog::GetInstance().AddDesc("startMainPos:" + std::to_string(startMainPos_));
4087 DumpLog::GetInstance().AddDesc("endMainPos:" + std::to_string(endMainPos_));
4088 DumpLog::GetInstance().AddDesc("contentMainSize:" + std::to_string(contentMainSize_));
4089 DumpLog::GetInstance().AddDesc("contentCrossSize:" + std::to_string(contentCrossSize_));
4090 DumpLog::GetInstance().AddDesc("currentDelta:" + std::to_string(currentDelta_));
4091 DumpLog::GetInstance().AddDesc("propertyAnimationIndex:" + std::to_string(propertyAnimationIndex_));
4092 DumpLog::GetInstance().AddDesc("mainDeltaSum:" + std::to_string(mainDeltaSum_));
4093 if (!itemPosition_.empty()) {
4094 DumpLog::GetInstance().AddDesc("-----------start print itemPosition------------");
4095 for (auto item : itemPosition_) {
4096 DumpLog::GetInstance().AddDesc(std::string("id:")
4097 .append(std::to_string(item.first))
4098 .append(",startPos:")
4099 .append(std::to_string(item.second.startPos))
4100 .append(",endPos:" + std::to_string(item.second.endPos)));
4101 }
4102 DumpLog::GetInstance().AddDesc("-----------end print itemPosition------------");
4103 }
4104 if (!itemPositionInAnimation_.empty()) {
4105 DumpLog::GetInstance().AddDesc("-----------start print itemPositionInAnimation------------");
4106
4107 for (auto item : itemPositionInAnimation_) {
4108 DumpLog::GetInstance().AddDesc(std::string("id:")
4109 .append(std::to_string(item.first))
4110 .append(",startPos:")
4111 .append(std::to_string(item.second.startPos))
4112 .append(",endPos:")
4113 .append(std::to_string(item.second.endPos)));
4114 }
4115 DumpLog::GetInstance().AddDesc("-----------end print itemPositionInAnimation------------");
4116 }
4117 switch (panDirection_.type) {
4118 case PanDirection::NONE: {
4119 DumpLog::GetInstance().AddDesc("PanDirection:NONE");
4120 break;
4121 }
4122 case PanDirection::LEFT: {
4123 DumpLog::GetInstance().AddDesc("PanDirection:LEFT");
4124 break;
4125 }
4126 case PanDirection::RIGHT: {
4127 DumpLog::GetInstance().AddDesc("PanDirection:RIGHT");
4128 break;
4129 }
4130 case PanDirection::HORIZONTAL: {
4131 DumpLog::GetInstance().AddDesc("PanDirection:HORIZONTAL");
4132 break;
4133 }
4134 case PanDirection::UP: {
4135 DumpLog::GetInstance().AddDesc("PanDirection:UP");
4136 break;
4137 }
4138 case PanDirection::DOWN: {
4139 DumpLog::GetInstance().AddDesc("PanDirection:DOWN");
4140 break;
4141 }
4142 case PanDirection::VERTICAL: {
4143 DumpLog::GetInstance().AddDesc("PanDirection:VERTICAL");
4144 break;
4145 }
4146 case PanDirection::ALL: {
4147 DumpLog::GetInstance().AddDesc("PanDirection:ALL");
4148 break;
4149 }
4150 default: {
4151 break;
4152 }
4153 }
4154 switch (direction_) {
4155 case Axis::NONE: {
4156 DumpLog::GetInstance().AddDesc("Axis:NONE");
4157 break;
4158 }
4159 case Axis::HORIZONTAL: {
4160 DumpLog::GetInstance().AddDesc("Axis:HORIZONTAL");
4161 break;
4162 }
4163 case Axis::FREE: {
4164 DumpLog::GetInstance().AddDesc("Axis:FREE");
4165 break;
4166 }
4167 case Axis::VERTICAL: {
4168 DumpLog::GetInstance().AddDesc("Axis:VERTICAL");
4169 break;
4170 }
4171 default: {
4172 break;
4173 }
4174 }
4175 }
4176
GetLoopIndex(int32_t index,int32_t childrenSize) const4177 int32_t SwiperPattern::GetLoopIndex(int32_t index, int32_t childrenSize) const
4178 {
4179 if (childrenSize <= 0) {
4180 return index;
4181 }
4182 auto loopIndex = index;
4183 while (loopIndex < 0) {
4184 loopIndex = loopIndex + childrenSize;
4185 }
4186 loopIndex %= childrenSize;
4187 return loopIndex;
4188 }
4189
RegisterScrollingListener(const RefPtr<ScrollingListener> listener)4190 void SwiperPattern::RegisterScrollingListener(const RefPtr<ScrollingListener> listener)
4191 {
4192 CHECK_NULL_VOID(listener);
4193 scrollingListener_.emplace_back(listener);
4194 }
4195
FireAndCleanScrollingListener()4196 void SwiperPattern::FireAndCleanScrollingListener()
4197 {
4198 for (auto listener : scrollingListener_) {
4199 CHECK_NULL_VOID(listener);
4200 listener->NotifyScrollingEvent();
4201 }
4202 scrollingListener_.clear();
4203 }
4204
CleanScrollingListener()4205 void SwiperPattern::CleanScrollingListener()
4206 {
4207 scrollingListener_.clear();
4208 }
4209
StopIndicatorAnimation()4210 void SwiperPattern::StopIndicatorAnimation()
4211 {
4212 AnimationUtils::StopAnimation(indicatorAnimation_);
4213
4214 if (stopIndicatorAnimationFunc_) {
4215 stopIndicatorAnimationFunc_();
4216 }
4217 }
4218
OnCustomContentTransition(int32_t toIndex)4219 void SwiperPattern::OnCustomContentTransition(int32_t toIndex)
4220 {
4221 if (!currentProxyInAnimation_ && toIndex == CurrentIndex()) {
4222 return;
4223 }
4224
4225 customAnimationToIndex_ = toIndex;
4226 indexsInAnimation_.insert(toIndex);
4227 auto fromIndex = CurrentIndex();
4228 if (currentProxyInAnimation_) {
4229 fromIndex = currentProxyInAnimation_->GetToIndex();
4230
4231 auto swiperEventHub = GetEventHub<SwiperEventHub>();
4232 CHECK_NULL_VOID(swiperEventHub);
4233 swiperEventHub->FireChangeEvent(fromIndex);
4234 swiperEventHub->FireIndicatorChangeEvent(fromIndex);
4235 swiperEventHub->FireChangeDoneEvent(moveDirection_);
4236
4237 UpdateCurrentIndex(fromIndex);
4238 oldIndex_ = fromIndex;
4239
4240 AnimationCallbackInfo info;
4241 info.currentOffset = GetCustomPropertyOffset();
4242 FireAnimationEndEvent(fromIndex, info);
4243
4244 currentProxyInAnimation_->SetHasOnChanged(true);
4245 }
4246 auto pipelineContext = PipelineContext::GetCurrentContext();
4247 CHECK_NULL_VOID(pipelineContext);
4248
4249 pipelineContext->AddAfterLayoutTask([weak = WeakClaim(this), fromIndex, toIndex]() {
4250 auto swiperPattern = weak.Upgrade();
4251 CHECK_NULL_VOID(swiperPattern);
4252 swiperPattern->TriggerCustomContentTransitionEvent(fromIndex, toIndex);
4253 });
4254
4255 MarkDirtyNodeSelf();
4256 }
4257
TriggerCustomContentTransitionEvent(int32_t fromIndex,int32_t toIndex)4258 void SwiperPattern::TriggerCustomContentTransitionEvent(int32_t fromIndex, int32_t toIndex)
4259 {
4260 CHECK_NULL_VOID(onCustomContentTransition_);
4261
4262 auto tabContentAnimatedTransition = (*onCustomContentTransition_)(fromIndex, toIndex);
4263 auto transition = tabContentAnimatedTransition.transition;
4264
4265 if (!transition) {
4266 OnCustomAnimationFinish(fromIndex, toIndex, false);
4267 return;
4268 }
4269
4270 auto proxy = AceType::MakeRefPtr<TabContentTransitionProxy>();
4271 proxy->SetFromIndex(fromIndex);
4272 proxy->SetToIndex(toIndex);
4273 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), fromIndex, toIndex](bool hasOnChanged) {
4274 auto swiperPattern = weak.Upgrade();
4275 CHECK_NULL_VOID(swiperPattern);
4276 swiperPattern->OnCustomAnimationFinish(fromIndex, toIndex, hasOnChanged);
4277 });
4278
4279 transition(proxy);
4280 currentProxyInAnimation_ = proxy;
4281
4282 AnimationCallbackInfo info;
4283 info.currentOffset = GetCustomPropertyOffset();
4284 info.targetOffset = GetCustomPropertyOffset();
4285 FireAnimationStartEvent(fromIndex, toIndex, info);
4286
4287 auto pipeline = PipelineContext::GetCurrentContext();
4288 CHECK_NULL_VOID(pipeline);
4289 auto taskExecutor = pipeline->GetTaskExecutor();
4290 CHECK_NULL_VOID(taskExecutor);
4291
4292 auto timeout = tabContentAnimatedTransition.timeout;
4293 auto timeoutTask = [weak = AceType::WeakClaim(AceType::RawPtr(proxy)), fromIndex, toIndex] {
4294 auto transitionProxy = weak.Upgrade();
4295 CHECK_NULL_VOID(transitionProxy);
4296 transitionProxy->FinishTransition();
4297 };
4298
4299 taskExecutor->PostDelayedTask(timeoutTask, TaskExecutor::TaskType::UI, timeout);
4300 }
4301
OnCustomAnimationFinish(int32_t fromIndex,int32_t toIndex,bool hasOnChanged)4302 void SwiperPattern::OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged)
4303 {
4304 customAnimationToIndex_.reset();
4305 needUnmountIndexs_.insert(fromIndex);
4306 indexsInAnimation_.erase(toIndex);
4307
4308 if (!hasOnChanged) {
4309 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
4310 CHECK_NULL_VOID(layoutProperty);
4311 layoutProperty->UpdateIndexWithoutMeasure(GetLoopIndex(toIndex));
4312 oldIndex_ = fromIndex;
4313
4314 AnimationCallbackInfo info;
4315 info.currentOffset = GetCustomPropertyOffset();
4316 FireAnimationEndEvent(toIndex, info);
4317 }
4318
4319 if (indexsInAnimation_.empty()) {
4320 currentProxyInAnimation_ = nullptr;
4321 }
4322
4323 auto host = GetHost();
4324 CHECK_NULL_VOID(host);
4325 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4326 auto pipeline = PipelineContext::GetCurrentContext();
4327 if (pipeline) {
4328 pipeline->FlushUITasks();
4329 pipeline->FlushMessages();
4330 }
4331 }
4332
SetSwiperEventCallback(bool disableSwipe)4333 void SwiperPattern::SetSwiperEventCallback(bool disableSwipe)
4334 {
4335 CHECK_NULL_VOID(swiperController_);
4336 auto removeSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
4337 auto swiperPattern = weak.Upgrade();
4338 CHECK_NULL_VOID(swiperPattern);
4339 auto host = swiperPattern->GetHost();
4340 CHECK_NULL_VOID(host);
4341 auto hub = host->GetEventHub<EventHub>();
4342 CHECK_NULL_VOID(hub);
4343 auto gestureHub = hub->GetOrCreateGestureEventHub();
4344 CHECK_NULL_VOID(gestureHub);
4345 gestureHub->RemoveTouchEvent(swiperPattern->touchEvent_);
4346 if (!disableSwipe) {
4347 gestureHub->RemovePanEvent(swiperPattern->panEvent_);
4348 }
4349 };
4350 swiperController_->SetRemoveSwiperEventCallback(std::move(removeSwiperEventCallback));
4351
4352 auto addSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
4353 auto swiperPattern = weak.Upgrade();
4354 CHECK_NULL_VOID(swiperPattern);
4355 auto host = swiperPattern->GetHost();
4356 CHECK_NULL_VOID(host);
4357 auto hub = host->GetEventHub<EventHub>();
4358 CHECK_NULL_VOID(hub);
4359 auto gestureHub = hub->GetOrCreateGestureEventHub();
4360 CHECK_NULL_VOID(gestureHub);
4361 gestureHub->AddTouchEvent(swiperPattern->touchEvent_);
4362 if (!disableSwipe) {
4363 gestureHub->AddPanEvent(swiperPattern->panEvent_, swiperPattern->panDirection_, 1, DEFAULT_PAN_DISTANCE);
4364 }
4365 };
4366 swiperController_->SetAddSwiperEventCallback(std::move(addSwiperEventCallback));
4367 }
4368
UpdateSwiperPanEvent(bool disableSwipe)4369 void SwiperPattern::UpdateSwiperPanEvent(bool disableSwipe)
4370 {
4371 auto host = GetHost();
4372 CHECK_NULL_VOID(host);
4373 auto hub = host->GetEventHub<EventHub>();
4374 CHECK_NULL_VOID(hub);
4375 auto gestureHub = hub->GetOrCreateGestureEventHub();
4376 CHECK_NULL_VOID(gestureHub);
4377
4378 if (!disableSwipe) {
4379 InitPanEvent(gestureHub);
4380 } else if (panEvent_) {
4381 gestureHub->RemovePanEvent(panEvent_);
4382 panEvent_.Reset();
4383 if (isDragging_) {
4384 HandleDragEnd(0.0);
4385 }
4386 }
4387 }
4388
IsSwipeByGroup() const4389 bool SwiperPattern::IsSwipeByGroup() const
4390 {
4391 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
4392 CHECK_NULL_RETURN(layoutProperty, false);
4393 return layoutProperty->GetSwipeByGroup().value_or(false);
4394 }
4395
GetCurrentFrameNode(int32_t currentIndex) const4396 RefPtr<FrameNode> SwiperPattern::GetCurrentFrameNode(int32_t currentIndex) const
4397 {
4398 auto host = GetHost();
4399 CHECK_NULL_RETURN(host, nullptr);
4400 auto currentLayoutWrapper = host->GetChildByIndex(GetLoopIndex(currentIndex));
4401 CHECK_NULL_RETURN(currentLayoutWrapper, nullptr);
4402 return currentLayoutWrapper->GetHostNode();
4403 }
4404
ProcessDelta(float & delta,float mainSize,float deltaSum)4405 void SwiperPattern::ProcessDelta(float& delta, float mainSize, float deltaSum)
4406 {
4407 if (std::abs(delta) > mainSize) {
4408 delta = delta > 0 ? mainSize : -mainSize;
4409 }
4410
4411 if ((std::abs(deltaSum + delta)) > mainSize) {
4412 delta = GreatNotEqual((deltaSum + delta), 0) ? (mainSize - deltaSum) :
4413 (-deltaSum - mainSize);
4414 }
4415 }
4416
ContentWillChange(int32_t comingIndex)4417 bool SwiperPattern::ContentWillChange(int32_t comingIndex)
4418 {
4419 return ContentWillChange(GetCurrentIndex(), comingIndex);
4420 }
4421
ContentWillChange(int32_t currentIndex,int32_t comingIndex)4422 bool SwiperPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
4423 {
4424 auto host = GetHost();
4425 CHECK_NULL_RETURN(host, true);
4426 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
4427 CHECK_NULL_RETURN(tabsNode, true);
4428 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
4429 CHECK_NULL_RETURN(tabsPattern, true);
4430 if (tabsPattern->GetInterceptStatus()) {
4431 auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
4432 return ret.has_value() ? ret.value() : true;
4433 }
4434 return true;
4435 }
4436
CheckSwiperPanEvent(const GestureEvent & info)4437 bool SwiperPattern::CheckSwiperPanEvent(const GestureEvent& info)
4438 {
4439 int32_t currentIndex = GetCurrentIndex();
4440 int32_t comingIndex = currentIndex;
4441 if (GreatNotEqual(info.GetMainDelta(), 0.0)) {
4442 comingIndex = comingIndex < 1 ? 0 : comingIndex - 1;
4443 } else if (LessNotEqual(info.GetMainDelta(), 0.0)) {
4444 comingIndex = comingIndex > TotalCount() - INDEX_DIFF_TWO ? TotalCount() - 1 : comingIndex + 1;
4445 }
4446
4447 auto iter = indexCanChangeMap_.find(comingIndex);
4448 if (iter != indexCanChangeMap_.end()) {
4449 return iter->second;
4450 }
4451 bool ret = ContentWillChange(currentIndex, comingIndex);
4452 indexCanChangeMap_.emplace(comingIndex, ret);
4453 return ret;
4454 }
4455 } // namespace OHOS::Ace::NG
4456