1 /*
2 * Copyright (c) 2022-2025 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/ace_trace.h"
28 #include "base/log/event_report.h"
29 #include "base/log/log_wrapper.h"
30 #include "base/perfmonitor/perf_constants.h"
31 #include "base/perfmonitor/perf_monitor.h"
32 #include "base/ressched/ressched_report.h"
33 #include "base/utils/multi_thread.h"
34 #include "base/utils/utils.h"
35 #include "core/animation/curve.h"
36 #include "core/animation/curves.h"
37 #include "core/animation/spring_curve.h"
38 #include "core/common/container_scope.h"
39 #include "core/common/recorder/node_data_cache.h"
40 #include "core/components/common/layout/constants.h"
41 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
42 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
43 #include "core/components_ng/pattern/swiper/swiper_helper.h"
44 #include "core/components_ng/pattern/swiper/swiper_node.h"
45 #include "core/components_ng/pattern/swiper/swiper_paint_method.h"
46 #include "core/components_ng/pattern/swiper/swiper_theme.h"
47 #include "core/components_ng/pattern/swiper_indicator/indicator_common/arc_swiper_indicator_pattern.h"
48 #include "core/components_ng/pattern/swiper_indicator/indicator_common/indicator_pattern.h"
49 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_arrow_pattern.h"
50 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_pattern.h"
51 #include "core/components_ng/pattern/tabs/tab_content_node.h"
52 #include "core/components_ng/pattern/tabs/tab_content_pattern.h"
53 #include "core/components_ng/pattern/tabs/tabs_node.h"
54 #include "core/components_ng/render/adapter/component_snapshot.h"
55 #include "core/components_ng/syntax/for_each_node.h"
56 #include "core/components_ng/syntax/lazy_for_each_node.h"
57 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
58 #include "core/components_ng/syntax/repeat_virtual_scroll_2_node.h"
59
60 namespace OHOS::Ace::NG {
61 namespace {
62
63 // TODO use theme.
64 constexpr int32_t MAX_DISPLAY_COUNT_MIN = 6;
65 constexpr int32_t MAX_DISPLAY_COUNT_MAX = 9;
66 constexpr int32_t MIN_TURN_PAGE_VELOCITY = 1200;
67 constexpr Dimension INDICATOR_BORDER_RADIUS = 16.0_vp;
68
69 constexpr float PX_EPSILON = 0.01f;
70 constexpr float FADE_DURATION = 500.0f;
71 constexpr float SPRING_DURATION = 600.0f;
72 constexpr float DEFAULT_MINIMUM_AMPLITUDE_PX = 1.0f;
73 constexpr int32_t INDEX_DIFF_TWO = 2;
74 constexpr int32_t FIRST_CAPTURE_DELAY_TIME = 30;
75 const std::string SWIPER_DRAG_SCENE = "swiper_drag_scene";
76 const std::string FADE_PROPERTY_NAME = "fade";
77 const std::string SPRING_PROPERTY_NAME = "spring";
78 const std::string INDICATOR_PROPERTY_NAME = "indicator";
79 const std::string TRANSLATE_PROPERTY_NAME = "translate";
80 constexpr uint16_t CAPTURE_PIXEL_ROUND_VALUE = static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_START) |
81 static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
82 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_END) |
83 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM);
84 constexpr int32_t CAPTURE_COUNT = 2;
85 constexpr char APP_SWIPER_NO_ANIMATION_SWITCH[] = "APP_SWIPER_NO_ANIMATION_SWITCH";
86 constexpr char APP_SWIPER_FRAME_ANIMATION[] = "APP_SWIPER_FRAME_ANIMATION";
87 constexpr char APP_TABS_FLING[] = "APP_TABS_FLING";
88 constexpr char APP_TABS_SCROLL[] = "APP_TABS_SCROLL";
89 constexpr char APP_TABS_NO_ANIMATION_SWITCH[] = "APP_TABS_NO_ANIMATION_SWITCH";
90 constexpr char APP_TABS_FRAME_ANIMATION[] = "APP_TABS_FRAME_ANIMATION";
91
92 constexpr int32_t COMPONENT_SWIPER_FLING = 1;
93 constexpr int32_t PAGE_FLIP_MODE_SIZE = 2;
94 const RefPtr<FrameRateRange> SWIPER_DEFAULT_FRAME_RATE =
95 AceType::MakeRefPtr<FrameRateRange>(0, 0, 0, COMPONENT_SWIPER_FLING);
96
97 constexpr int32_t JUMP_NEAR_VALUE = 3;
98 constexpr int32_t MIN_DUMP_VELOCITY_THRESHOLD = 500;
99 constexpr float MAX_INDICATOR_VELOCITY = 1200.0f;
100 constexpr Dimension DEFAULT_INDICATOR_HEAD_DISTANCE = 14.0_vp;
101
GetKeyMoveStep(const KeyEvent & event,Axis axis,bool isRtl)102 MoveStep GetKeyMoveStep(const KeyEvent& event, Axis axis, bool isRtl)
103 {
104 if ((axis == Axis::HORIZONTAL && event.code == (isRtl ? KeyCode::KEY_DPAD_RIGHT : KeyCode::KEY_DPAD_LEFT)) ||
105 (axis == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
106 return MoveStep::PREV;
107 }
108 if ((axis == Axis::HORIZONTAL && event.code == (isRtl ? KeyCode::KEY_DPAD_LEFT : KeyCode::KEY_DPAD_RIGHT)) ||
109 (axis == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
110 return MoveStep::NEXT;
111 }
112 return MoveStep::NONE;
113 }
114 } // namespace
115
SwiperPattern()116 SwiperPattern::SwiperPattern()
117 {
118 swiperController_ = MakeRefPtr<SwiperController>();
119 SwiperHelper::InitSwiperController(swiperController_, WeakClaim(this));
120 }
121
OnAttachToFrameNode()122 void SwiperPattern::OnAttachToFrameNode()
123 {
124 auto host = GetHost();
125 THREAD_SAFE_NODE_CHECK(host, OnAttachToFrameNode);
126 CHECK_NULL_VOID(host);
127 auto renderContext = host->GetRenderContext();
128 CHECK_NULL_VOID(renderContext);
129 renderContext->SetClipToFrame(true);
130 renderContext->SetClipToBounds(true);
131 auto pipeline = host->GetContext();
132 CHECK_NULL_VOID(pipeline);
133 auto indicatorTheme = pipeline->GetTheme<SwiperIndicatorTheme>();
134 CHECK_NULL_VOID(indicatorTheme);
135 renderContext->UpdateClipEdge(indicatorTheme->GetClipEdge());
136 InitSurfaceChangedCallback();
137 }
138
OnDetachFromFrameNode(FrameNode * node)139 void SwiperPattern::OnDetachFromFrameNode(FrameNode* node)
140 {
141 THREAD_SAFE_NODE_CHECK(node, OnDetachFromFrameNode, node);
142 CHECK_NULL_VOID(node);
143 auto pipeline = node->GetContext();
144 CHECK_NULL_VOID(pipeline);
145 if (HasSurfaceChangedCallback()) {
146 pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
147 }
148 pipeline->RemoveWindowStateChangedCallback(node->GetId());
149 }
150
OnAttachToMainTree()151 void SwiperPattern::OnAttachToMainTree()
152 {
153 auto host = GetHost();
154 THREAD_SAFE_NODE_CHECK(host, OnAttachToMainTree);
155 if (!isInit_) {
156 SetOnHiddenChangeForParent();
157 }
158 }
159
OnDetachFromMainTree()160 void SwiperPattern::OnDetachFromMainTree()
161 {
162 auto host = GetHost();
163 THREAD_SAFE_NODE_CHECK(host, OnDetachFromMainTree);
164 RemoveOnHiddenChange();
165 }
166
CreateLayoutAlgorithm()167 RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
168 {
169 auto host = GetHost();
170 CHECK_NULL_RETURN(host, nullptr);
171 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
172 CHECK_NULL_RETURN(props, nullptr);
173
174 auto algo = MakeRefPtr<SwiperLayoutAlgorithm>();
175 if (props->GetIsCustomAnimation().value_or(false)) {
176 algo->SetUseCustomAnimation(true);
177 algo->SetCustomAnimationToIndex(customAnimationToIndex_);
178 algo->SetIndexsInAnimation(indexsInAnimation_);
179 algo->SetNeedUnmountIndexs(needUnmountIndexs_);
180 return algo;
181 }
182 if (SupportSwiperCustomAnimation()) {
183 algo->SetNeedUnmountIndexs(needUnmountIndexs_);
184 algo->SetItemsPositionInAnimation(itemPositionInAnimation_);
185 }
186
187 if (jumpIndex_) {
188 algo->SetJumpIndex(jumpIndex_.value());
189 } else if (targetIndex_) {
190 algo->SetTargetIndex(targetIndex_.value());
191 }
192 algo->SetCachedShow(IsCachedShow());
193 algo->SetCurrentIndex(currentIndex_);
194 algo->SetMainSizeIsMeasured(mainSizeIsMeasured_);
195 oldContentMainSize_ = contentMainSize_;
196 algo->SetContentMainSize(contentMainSize_);
197 algo->SetDuringInteraction(isDragging_ || RunningTranslateAnimation());
198 if (!propertyAnimationIsRunning_) {
199 algo->SetCurrentDelta(currentDelta_);
200 }
201 algo->SetItemsPosition(itemPosition_);
202 if (IsOutOfBoundary() && !IsLoop()) {
203 algo->SetOverScrollFeature();
204 }
205 algo->SetTotalItemCount(TotalCount());
206 algo->SetIsLoop(IsLoop());
207 algo->SetSwipeByGroup(IsSwipeByGroup());
208 algo->SetRealTotalCount(RealTotalCount());
209 algo->SetPlaceItemWidth(placeItemWidth_);
210 algo->SetIsFrameAnimation(translateAnimationIsRunning_);
211
212 auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
213 const auto effect = swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
214 algo->SetCanOverScroll(effect == EdgeEffect::SPRING);
215 algo->SetHasCachedCapture(hasCachedCapture_);
216 algo->SetIsCaptureReverse(isCaptureReverse_);
217 algo->SetCachedCount(GetCachedCount());
218 algo->SetIgnoreBlankOffset(ignoreBlankOffset_);
219 return algo;
220 }
221
OnIndexChange(bool isInLayout)222 void SwiperPattern::OnIndexChange(bool isInLayout)
223 {
224 auto totalCount = TotalCount();
225 if (NonPositive(totalCount)) {
226 return;
227 }
228 auto oldIndex = GetLoopIndex(oldIndex_);
229 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != totalCount) {
230 oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
231 oldChildrenSize_ = totalCount;
232 }
233
234 auto targetIndex = GetLoopIndex(CurrentIndex());
235 if (oldIndex != targetIndex) {
236 FireChangeEvent(oldIndex, targetIndex, isInLayout);
237 FireSelectedEvent(oldIndex, targetIndex);
238 FireUnselectedEvent(oldIndex, targetIndex);
239 // lazyBuild feature.
240 SetLazyLoadFeature(true);
241 }
242 // interrupt FAST_ANIMATION and end in JUMP_NEAR_VALUE Page
243 if (oldIndex == targetIndex && fastAnimationRunning_) {
244 fastAnimationChange_ = true;
245 unselectedIndex_ = -1;
246 FireSelectedEvent(oldIndex, targetIndex);
247 }
248 if (fastAnimationChange_ && !fastAnimationRunning_) {
249 fastAnimationChange_ = false;
250 FireChangeEvent(oldIndex, targetIndex, isInLayout);
251 }
252 }
253
StopAndResetSpringAnimation()254 void SwiperPattern::StopAndResetSpringAnimation()
255 {
256 if (springAnimationIsRunning_ && !isTouchDownSpringAnimation_) {
257 StopSpringAnimation();
258 currentDelta_ = 0.0f;
259 itemPosition_.clear();
260 isVoluntarilyClear_ = true;
261 jumpIndex_ = currentIndex_;
262 MarkDirtyNodeSelf();
263 }
264 UpdateItemRenderGroup(false);
265 }
266
CheckLoopChange()267 void SwiperPattern::CheckLoopChange()
268 {
269 auto props = GetLayoutProperty<SwiperLayoutProperty>();
270 CHECK_NULL_VOID(props);
271 auto currentLoopValue = props->GetLoop().value_or(true);
272 if (!preLoop_.has_value()) {
273 preLoop_ = currentLoopValue;
274 return;
275 }
276
277 if (preLoop_.value() != currentLoopValue) {
278 currentIndex_ =
279 GetLoopIndex(currentIndex_, oldChildrenSize_.has_value() ? oldChildrenSize_.value() : TotalCount());
280 if (props->GetPrevMargin().has_value() || props->GetNextMargin().has_value()) {
281 jumpIndex_ = jumpIndex_.value_or(currentIndex_);
282 StopIndicatorAnimation(true);
283 }
284 preLoop_ = currentLoopValue;
285 }
286 }
287
AdjustCurrentIndexOnSwipePage(int32_t index)288 void SwiperPattern::AdjustCurrentIndexOnSwipePage(int32_t index)
289 {
290 auto adjustIndex = SwiperUtils::ComputePageIndex(index, GetDisplayCount());
291 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
292 CHECK_NULL_VOID(props);
293 props->UpdateIndexWithoutMeasure(GetLoopIndex(adjustIndex));
294 currentIndex_ = GetLoopIndex(adjustIndex);
295 }
296
InitCapture()297 void SwiperPattern::InitCapture()
298 {
299 auto host = GetHost();
300 CHECK_NULL_VOID(host);
301 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
302 CHECK_NULL_VOID(props);
303 bool hasCachedCapture = SwiperUtils::IsStretch(props) && props->GetLoop().value_or(true) && !IsSwipeByGroup() &&
304 GetDisplayCount() == TotalCount() - 1 &&
305 (Positive(props->GetPrevMarginValue(0.0_px).ConvertToPx()) ||
306 Positive(props->GetNextMarginValue(0.0_px).ConvertToPx()));
307 if (hasCachedCapture) {
308 leftCaptureIndex_ = std::nullopt;
309 rightCaptureIndex_ = std::nullopt;
310 }
311
312 if (!hasCachedCapture_ && hasCachedCapture) {
313 // Screenshot nodes need to be added at the forefront of all special nodes to display at the bottom
314 uint32_t number = static_cast<uint32_t>(indicatorId_.has_value()) + static_cast<uint32_t>(HasLeftButtonNode()) +
315 static_cast<uint32_t>(HasRightButtonNode()) + 1;
316 auto leftCaptureNode = FrameNode::GetOrCreateFrameNode(
317 V2::SWIPER_LEFT_CAPTURE_ETS_TAG, GetLeftCaptureId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
318 auto imageLayoutProperty = leftCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
319 CHECK_NULL_VOID(imageLayoutProperty);
320 imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
321 leftCaptureNode->MarkModifyDone();
322 host->AddChild(leftCaptureNode, -number);
323
324 auto rightCaptureNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_CAPTURE_ETS_TAG, GetRightCaptureId(),
325 []() { return AceType::MakeRefPtr<ImagePattern>(); });
326 imageLayoutProperty = rightCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
327 CHECK_NULL_VOID(imageLayoutProperty);
328 imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
329 rightCaptureNode->MarkModifyDone();
330 host->AddChild(rightCaptureNode, -number);
331 }
332 if (hasCachedCapture_ && !hasCachedCapture) {
333 RemoveAllCaptureNode();
334 }
335 if (SupportSwiperCustomAnimation() && hasCachedCapture) {
336 needUnmountIndexs_.clear();
337 itemPositionInAnimation_.clear();
338 }
339 hasCachedCapture_ = hasCachedCapture;
340 }
341
SetLazyForEachFlag() const342 void SwiperPattern::SetLazyForEachFlag() const
343 {
344 auto host = GetHost();
345 CHECK_NULL_VOID(host);
346 auto targetNode = FindLazyForEachNode(host);
347 if (targetNode.has_value()) {
348 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
349 CHECK_NULL_VOID(lazyForEachNode);
350 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
351 }
352 }
353
ResetOnForceMeasure()354 void SwiperPattern::ResetOnForceMeasure()
355 {
356 hoverFlag_ = HOVER_NONE;
357 resetLayoutTask_.Cancel();
358 StopPropertyTranslateAnimation(isFinishAnimation_, false, true);
359 StopTranslateAnimation();
360 StopSpringAnimationImmediately();
361 StopFadeAnimation();
362 StopIndicatorAnimation(true);
363 currentOffset_ = 0.0f;
364 mainSizeIsMeasured_ = false;
365 currentDelta_ = 0.0f;
366 itemPosition_.clear();
367 isVoluntarilyClear_ = true;
368 jumpIndex_ = jumpIndex_.value_or(
369 GetLoopIndex(currentIndex_, oldChildrenSize_.has_value() ? oldChildrenSize_.value() : TotalCount()));
370 SetLazyForEachFlag();
371 ResetTabBar();
372 MarkDirtyNodeSelf();
373 }
374
ResetTabBar()375 void SwiperPattern::ResetTabBar()
376 {
377 auto host = GetHost();
378 CHECK_NULL_VOID(host);
379 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
380 CHECK_NULL_VOID(tabsNode);
381 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
382 CHECK_NULL_VOID(tabBarNode);
383 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
384 CHECK_NULL_VOID(tabBarPattern);
385 tabBarPattern->ResetOnForceMeasure(jumpIndex_.value_or(currentIndex_));
386 }
387
GetTabBarAnimationCurve(const RefPtr<Curve> & curve)388 const RefPtr<Curve> SwiperPattern::GetTabBarAnimationCurve(const RefPtr<Curve>& curve)
389 {
390 auto host = GetHost();
391 CHECK_NULL_RETURN(host, curve);
392 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
393 CHECK_NULL_RETURN(tabsNode, curve);
394 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
395 CHECK_NULL_RETURN(tabBarNode, curve);
396 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
397 CHECK_NULL_RETURN(tabBarPattern, curve);
398 return tabBarPattern->GetAnimationCurve(curve);
399 }
400
UpdateTabBarIndicatorCurve()401 void SwiperPattern::UpdateTabBarIndicatorCurve()
402 {
403 CHECK_NULL_VOID(swiperController_);
404 auto updateCubicCurveCallback = [weak = WeakClaim(this)]() {
405 auto swiperPattern = weak.Upgrade();
406 CHECK_NULL_VOID(swiperPattern);
407 auto host = swiperPattern->GetHost();
408 CHECK_NULL_VOID(host);
409 auto props = host->GetPaintProperty<SwiperPaintProperty>();
410 CHECK_NULL_VOID(props);
411 auto curve = MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
412 props->UpdateCurve(swiperPattern->GetTabBarAnimationCurve(curve));
413 };
414 swiperController_->SetUpdateCubicCurveCallback(std::move(updateCubicCurveCallback));
415 }
416
NeedForceMeasure() const417 bool SwiperPattern::NeedForceMeasure() const
418 {
419 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
420 CHECK_NULL_RETURN(props, false);
421
422 return ((props->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
423 (isSwipeByGroup_.has_value() && isSwipeByGroup_.value() != IsSwipeByGroup());
424 }
425
MarkDirtyBindIndicatorNode() const426 void SwiperPattern::MarkDirtyBindIndicatorNode() const
427 {
428 auto indicatorNode = GetIndicatorNode();
429 CHECK_NULL_VOID(indicatorNode);
430 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
431 }
432
GetIndicatorController()433 Framework::JSIndicatorController* SwiperPattern::GetIndicatorController()
434 {
435 return indicatorController_;
436 }
437
SetIndicatorController(Framework::JSIndicatorController * controller)438 void SwiperPattern::SetIndicatorController(Framework::JSIndicatorController* controller)
439 {
440 indicatorController_ = controller;
441 }
442
OnModifyDone()443 void SwiperPattern::OnModifyDone()
444 {
445 Pattern::OnModifyDone();
446 auto host = GetHost();
447 CHECK_NULL_VOID(host);
448 swiperId_ = host->GetId();
449 auto hub = host->GetOrCreateEventHub<SwiperEventHub>();
450 CHECK_NULL_VOID(hub);
451 hub->SetSwiperId(swiperId_);
452 auto gestureHub = hub->GetOrCreateGestureEventHub();
453 CHECK_NULL_VOID(gestureHub);
454
455 auto index = CurrentIndex();
456 if (currentIndex_ != index && index >= 0) {
457 AceAsyncTraceBeginCommercial(
458 0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
459 }
460
461 if (!isBindIndicator_) {
462 InitIndicator();
463 } else if (NeedForceMeasure()) {
464 MarkDirtyBindIndicatorNode();
465 }
466 InitArrow();
467 InitCapture();
468 CheckSpecialItemCount();
469 SetLazyLoadIsLoop();
470 RegisterVisibleAreaChange();
471 InitTouchEvent(gestureHub);
472 InitHoverMouseEvent();
473 StopAndResetSpringAnimation();
474
475 if (NeedForceMeasure()) {
476 ResetOnForceMeasure();
477 }
478
479 isSwipeByGroup_ = IsSwipeByGroup();
480
481 bool disableSwipe = IsDisableSwipe();
482 UpdateSwiperPanEvent(disableSwipe);
483
484 auto focusHub = host->GetFocusHub();
485 if (focusHub) {
486 InitOnKeyEvent(focusHub);
487 InitOnFocusInternal(focusHub);
488 }
489 #ifdef SUPPORT_DIGITAL_CROWN
490 InitOnCrownEventInternal(focusHub);
491 #endif
492
493 SetSwiperEventCallback(disableSwipe);
494 UpdateTabBarIndicatorCurve();
495
496 if (IsAutoPlay()) {
497 StartAutoPlay();
498 } else {
499 translateTask_.Cancel();
500 isInAutoPlay_ = false;
501 }
502
503 SetAccessibilityAction();
504 placeItemWidth_.reset();
505
506 if (IsSwipeByGroup()) {
507 needAdjustIndex_ = true;
508 }
509
510 if (isBindIndicator_) {
511 auto frameNode = indicatorNode_.Upgrade();
512 CHECK_NULL_VOID(frameNode);
513 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
514 CHECK_NULL_VOID(indicatorPattern);
515 indicatorPattern->InitIndicatorEvent();
516 }
517 }
518
OnAfterModifyDone()519 void SwiperPattern::OnAfterModifyDone()
520 {
521 auto host = GetHost();
522 CHECK_NULL_VOID(host);
523 auto inspectorId = host->GetInspectorId().value_or("");
524 if (!inspectorId.empty()) {
525 Recorder::NodeDataCache::Get().PutInt(host, inspectorId, CurrentIndex());
526 }
527 }
528
CheckUserSetIndex(int32_t index)529 int32_t SwiperPattern::CheckUserSetIndex(int32_t index)
530 {
531 if (!IsAutoLinear()) {
532 return index;
533 }
534
535 if (index < 0 || index >= RealTotalCount()) {
536 index = 0;
537 UpdateCurrentIndex(index);
538 }
539
540 auto childNode = GetCurrentFrameNode(GetLoopIndex(index));
541 CHECK_NULL_RETURN(childNode, index);
542 auto childLayoutProperty = childNode->GetLayoutProperty<LayoutProperty>();
543 CHECK_NULL_RETURN(childLayoutProperty, index);
544 if (childLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
545 return index;
546 }
547
548 return CheckTargetIndex(index + 1);
549 }
550
UpdateIndicatorOnChildChange()551 void SwiperPattern::UpdateIndicatorOnChildChange()
552 {
553 if (HasIndicatorNode()) {
554 StopIndicatorAnimation();
555 auto host = GetHost();
556 CHECK_NULL_VOID(host);
557 auto indicatorNode = GetCommonIndicatorNode();
558 if (indicatorNode && IsIndicator(indicatorNode->GetTag())) {
559 indicatorNode->MarkModifyDone();
560 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
561 }
562 }
563 }
564
UpdateDigitalIndicator()565 void SwiperPattern::UpdateDigitalIndicator()
566 {
567 if (!HasIndicatorNode() || GetIndicatorType() != SwiperIndicatorType::DIGIT) {
568 return;
569 }
570
571 auto host = GetHost();
572 CHECK_NULL_VOID(host);
573 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
574 CHECK_NULL_VOID(indicatorNode);
575
576 if (indicatorNode->GetTag() != V2::SWIPER_INDICATOR_ETS_TAG) {
577 return;
578 }
579
580 indicatorNode->MarkModifyDone();
581 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
582 }
583
BeforeCreateLayoutWrapper()584 void SwiperPattern::BeforeCreateLayoutWrapper()
585 {
586 auto host = GetHost();
587 CHECK_NULL_VOID(host);
588 auto hadCachedCapture = hasCachedCapture_;
589 if (host->GetChildrenUpdated() != -1) {
590 InitCapture();
591 if (NeedAutoPlay() && !translateTask_) {
592 StartAutoPlay();
593 }
594 UpdateCurrentFocus();
595 host->ChildrenUpdatedFrom(-1);
596 }
597 CheckLoopChange();
598 SetLazyLoadIsLoop();
599 auto lastCurrentIndex = currentIndex_;
600 auto userSetCurrentIndex = CurrentIndex();
601 userSetCurrentIndex = CheckUserSetIndex(userSetCurrentIndex);
602 auto oldIndex = GetLoopIndex(lastCurrentIndex);
603 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != TotalCount()) {
604 oldIndex = GetLoopIndex(lastCurrentIndex, oldChildrenSize_.value());
605 UpdateIndicatorOnChildChange();
606 StartAutoPlay();
607 InitArrow();
608 if (IsLoop() && oldIndex != GetLoopIndex(currentIndex_)) {
609 currentIndex_ = oldIndex >= TotalCount() ? 0 : oldIndex;
610 }
611 } else if (oldRealTotalCount_ && oldRealTotalCount_.value() != RealTotalCount()) {
612 UpdateDigitalIndicator();
613 }
614 auto index = CheckIndexRange(userSetCurrentIndex);
615 if (index != userSetCurrentIndex) {
616 // The current index property is an outlier and has been corrected.
617 // It is necessary to determine whether the changindex interface has a set value.
618 if (userSetCurrentIndex >= TotalCount()) {
619 index = jumpIndexByUser_.value_or(index);
620 }
621 UpdateCurrentIndex(index);
622 } else if (oldIndex != userSetCurrentIndex) {
623 currentIndex_ = userSetCurrentIndex;
624 propertyAnimationIndex_ = GetLoopIndex(propertyAnimationIndex_);
625 }
626 jumpIndexByUser_.reset();
627
628 if (IsSwipeByGroup() && needAdjustIndex_) {
629 AdjustCurrentIndexOnSwipePage(CurrentIndex());
630 needAdjustIndex_ = false;
631 }
632
633 if (lastCurrentIndex != currentIndex_ || (itemPosition_.empty() && !isVoluntarilyClear_)
634 || hadCachedCapture != hasCachedCapture_) {
635 jumpIndex_ = (!isInit_ && GetMaintainVisibleContentPosition())
636 ? jumpIndex_.value_or(GetLoopIndex(currentIndex_))
637 : GetLoopIndex(currentIndex_);
638 currentFirstIndex_ = jumpIndex_.value_or(0);
639 turnPageRate_ = 0.0f;
640 SetIndicatorJumpIndex(jumpIndex_);
641 }
642 isVoluntarilyClear_ = false;
643 if (jumpIndex_) {
644 if ((jumpIndex_.value() < 0 || jumpIndex_.value() >= TotalCount()) && !IsLoop()) {
645 jumpIndex_ = 0;
646 }
647 targetIndex_.reset();
648 nextIndex_ = jumpIndex_.value();
649 StopAutoPlay();
650 StopTranslateAnimation();
651 StopFadeAnimation();
652 StopSpringAnimation();
653 if (propertyAnimationIsRunning_) {
654 StopPropertyTranslateAnimation(false, true);
655 StopIndicatorAnimation();
656 }
657 currentDelta_ = 0.0f;
658 }
659 if (isInit_) {
660 FireSelectedEvent(-1, currentIndex_);
661 }
662 if (lastCurrentIndex != currentIndex_ && !isInit_ && !IsUseCustomAnimation()) {
663 FireWillShowEvent(currentIndex_);
664 FireWillHideEvent(lastCurrentIndex);
665 }
666
667 UpdateItemsLatestSwitched();
668 UpdateIgnoreBlankOffsetWithIndex();
669 }
670
UpdateItemsLatestSwitched()671 void SwiperPattern::UpdateItemsLatestSwitched()
672 {
673 if (!hasTabsAncestor_) {
674 return;
675 }
676 auto host = GetHost();
677 CHECK_NULL_VOID(host);
678 auto tabsNode = AceType::DynamicCast<FrameNode>(host->GetParent());
679 CHECK_NULL_VOID(tabsNode);
680 auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
681 CHECK_NULL_VOID(tabsLayoutProperty);
682 auto cachedMaxCount = tabsLayoutProperty->GetCachedMaxCountValue(-1);
683 auto cacheMode = tabsLayoutProperty->GetCacheModeValue(TabsCacheMode::CACHE_BOTH_SIDE);
684 if (cachedMaxCount < 0 || cachedMaxCount >= RealTotalCount() || cacheMode != TabsCacheMode::CACHE_LATEST_SWITCHED) {
685 itemsLatestSwitched_.clear();
686 return;
687 }
688
689 auto props = GetLayoutProperty<SwiperLayoutProperty>();
690 CHECK_NULL_VOID(props);
691 auto currentIndex = props->GetIndexValue(0);
692 auto indexNeedInsert = -1;
693 if (IsUseCustomAnimation()) {
694 indexNeedInsert = customAnimationToIndex_.value_or(currentIndex);
695 } else if (jumpIndex_) {
696 indexNeedInsert = jumpIndex_.value();
697 } else if (targetIndex_) {
698 indexNeedInsert = targetIndex_.value();
699 } else if (itemsLatestSwitched_.empty()) {
700 indexNeedInsert = currentIndex;
701 }
702 if (indexNeedInsert < 0) {
703 return;
704 }
705
706 itemsLatestSwitched_.remove(indexNeedInsert);
707 itemsLatestSwitched_.push_back(indexNeedInsert);
708 if (static_cast<int32_t>(itemsLatestSwitched_.size()) > (cachedMaxCount + 1)) {
709 itemsLatestSwitched_.pop_front();
710 }
711 }
712
HandleTabsCachedMaxCount(int32_t startIndex,int32_t endIndex)713 void SwiperPattern::HandleTabsCachedMaxCount(int32_t startIndex, int32_t endIndex)
714 {
715 if (!hasTabsAncestor_) {
716 return;
717 }
718 itemsNeedClean_.clear();
719 auto host = GetHost();
720 CHECK_NULL_VOID(host);
721 auto tabsNode = AceType::DynamicCast<FrameNode>(host->GetParent());
722 CHECK_NULL_VOID(tabsNode);
723 auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
724 CHECK_NULL_VOID(tabsLayoutProperty);
725 auto realTotalCount = RealTotalCount();
726 auto cachedMaxCount = tabsLayoutProperty->GetCachedMaxCountValue(-1);
727 if (cachedMaxCount < 0 || cachedMaxCount >= realTotalCount) {
728 return;
729 }
730 auto cacheMode = tabsLayoutProperty->GetCacheModeValue(TabsCacheMode::CACHE_BOTH_SIDE);
731 auto useCustomAnimation = IsUseCustomAnimation();
732 for (int32_t index = 0; index < realTotalCount; ++index) {
733 if (cacheMode == TabsCacheMode::CACHE_BOTH_SIDE) {
734 if (useCustomAnimation && ((index >= startIndex - cachedMaxCount && index <= startIndex + cachedMaxCount) ||
735 (index >= endIndex - cachedMaxCount && index <= endIndex + cachedMaxCount))) {
736 continue;
737 } else if (startIndex > endIndex ||
738 (index >= startIndex - cachedMaxCount && index <= endIndex + cachedMaxCount)) {
739 continue;
740 }
741 } else if (cacheMode == TabsCacheMode::CACHE_LATEST_SWITCHED) {
742 if (std::find(itemsLatestSwitched_.begin(), itemsLatestSwitched_.end(), index) !=
743 itemsLatestSwitched_.end()) {
744 continue;
745 }
746 }
747
748 itemsNeedClean_.insert(index);
749 }
750
751 PostIdleTaskToCleanTabContent();
752 }
753
PostIdleTaskToCleanTabContent()754 void SwiperPattern::PostIdleTaskToCleanTabContent()
755 {
756 if (itemsNeedClean_.empty()) {
757 return;
758 }
759 auto pipelineContext = GetContext();
760 CHECK_NULL_VOID(pipelineContext);
761 pipelineContext->AddPredictTask([weak = WeakClaim(this)](int64_t deadline, bool canUseLongPredictTask) {
762 auto pattern = weak.Upgrade();
763 CHECK_NULL_VOID(pattern);
764 auto host = pattern->GetHost();
765 CHECK_NULL_VOID(host);
766
767 std::set<int32_t> itemsHasClean;
768 for (const auto& index : pattern->itemsNeedClean_) {
769 if (GetSysTimestamp() > deadline) {
770 break;
771 }
772 itemsHasClean.insert(index);
773 auto child = AceType::DynamicCast<FrameNode>(host->GetChildByIndex(index));
774 if (!child || child->IsActive()) {
775 continue;
776 }
777 auto tabContentPattern = AceType::DynamicCast<TabContentPattern>(child->GetPattern<TabContentPattern>());
778 if (tabContentPattern) {
779 tabContentPattern->CleanChildren();
780 }
781 }
782 for (const auto& index : itemsHasClean) {
783 pattern->itemsNeedClean_.erase(index);
784 }
785 if (!pattern->itemsNeedClean_.empty()) {
786 pattern->PostIdleTaskToCleanTabContent();
787 }
788 });
789 }
790
UpdateTargetCapture(bool forceUpdate)791 void SwiperPattern::UpdateTargetCapture(bool forceUpdate)
792 {
793 if (itemPosition_.empty()) {
794 return;
795 }
796 auto leftTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
797 auto rightTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
798 if (isCaptureReverse_) {
799 leftTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
800 rightTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
801 }
802 if (forceUpdate || !leftCaptureIndex_.has_value() || leftCaptureIndex_.value() != leftTargetIndex) {
803 CreateCaptureCallback(leftTargetIndex, GetLeftCaptureId(), forceUpdate);
804 leftCaptureIndex_ = leftTargetIndex;
805 }
806 if (forceUpdate || !rightCaptureIndex_.has_value() || rightCaptureIndex_.value() != rightTargetIndex) {
807 CreateCaptureCallback(rightTargetIndex, GetRightCaptureId(), forceUpdate);
808 rightCaptureIndex_ = rightTargetIndex;
809 }
810 }
811
CreateCaptureCallback(int32_t targetIndex,int32_t captureId,bool forceUpdate)812 void SwiperPattern::CreateCaptureCallback(int32_t targetIndex, int32_t captureId, bool forceUpdate)
813 {
814 auto host = GetHost();
815 CHECK_NULL_VOID(host);
816 auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
817 CHECK_NULL_VOID(targetNode);
818 auto callback = [weak = WeakClaim(this), captureId, targetIndex, hostInstanceId = GetHostInstanceId()](
819 std::shared_ptr<Media::PixelMap> pixelMap) {
820 ContainerScope scope(hostInstanceId);
821 auto swiper = weak.Upgrade();
822 CHECK_NULL_VOID(swiper);
823 auto piplineContext = swiper->GetContext();
824 CHECK_NULL_VOID(piplineContext);
825 auto taskExecutor = piplineContext->GetTaskExecutor();
826 CHECK_NULL_VOID(taskExecutor);
827 taskExecutor->PostTask(
828 [weak, pixelMap, captureId, targetIndex]() mutable {
829 auto swiper = weak.Upgrade();
830 CHECK_NULL_VOID(swiper);
831 swiper->UpdateCaptureSource(pixelMap, captureId, targetIndex);
832 },
833 TaskExecutor::TaskType::UI, "ArkUISwiperUpdateCaptureSource");
834 };
835 if (forceUpdate) {
836 // The size changes caused by layout need to wait for rendering before taking a screenshot
837 auto piplineContext = GetContext();
838 CHECK_NULL_VOID(piplineContext);
839 auto taskExecutor = piplineContext->GetTaskExecutor();
840 CHECK_NULL_VOID(taskExecutor);
841 taskExecutor->PostDelayedTask(
842 [weakTarget = WeakClaim(RawPtr(targetNode)), callback]() {
843 auto target = weakTarget.Upgrade();
844 CHECK_NULL_VOID(target);
845 ComponentSnapshot::GetNormalCapture(target, std::move(callback));
846 },
847 TaskExecutor::TaskType::UI, FIRST_CAPTURE_DELAY_TIME, "ArkUISwiperGetNormalCapture");
848 } else {
849 ComponentSnapshot::GetNormalCapture(targetNode, std::move(callback));
850 }
851 }
852
UpdateCaptureSource(std::shared_ptr<Media::PixelMap> pixelMap,int32_t captureId,int32_t targetIndex)853 void SwiperPattern::UpdateCaptureSource(
854 std::shared_ptr<Media::PixelMap> pixelMap, int32_t captureId, int32_t targetIndex)
855 {
856 // Async tasks require verifying if the pixel map is the correct target
857 if (!(captureId == GetLeftCaptureId() && leftCaptureIndex_.has_value() &&
858 targetIndex == leftCaptureIndex_.value()) &&
859 !(captureId == GetRightCaptureId() && rightCaptureIndex_.has_value() &&
860 targetIndex == rightCaptureIndex_.value())) {
861 return;
862 }
863 auto host = GetHost();
864 CHECK_NULL_VOID(host);
865 auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
866 CHECK_NULL_VOID(targetNode);
867 auto targetLayoutProperty = targetNode->GetLayoutProperty<LayoutProperty>();
868 CHECK_NULL_VOID(targetLayoutProperty);
869 auto targetMargin = targetLayoutProperty->CreateMargin();
870 MarginProperty margin;
871 margin.left = CalcLength(targetMargin.left.has_value() ? targetMargin.left.value() : 0.0f);
872 margin.right = CalcLength(targetMargin.right.has_value() ? targetMargin.right.value() : 0.0f);
873 margin.top = CalcLength(targetMargin.top.has_value() ? targetMargin.top.value() : 0.0f);
874 margin.bottom = CalcLength(targetMargin.bottom.has_value() ? targetMargin.bottom.value() : 0.0f);
875
876 auto captureNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(captureId)));
877 CHECK_NULL_VOID(captureNode);
878 auto imageLayoutProperty = captureNode->GetLayoutProperty<ImageLayoutProperty>();
879 CHECK_NULL_VOID(imageLayoutProperty);
880 imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(PixelMap::CreatePixelMap(&pixelMap)));
881 imageLayoutProperty->UpdateMargin(margin);
882 captureNode->MarkModifyDone();
883 captureNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
884 }
885
InitSurfaceChangedCallback()886 void SwiperPattern::InitSurfaceChangedCallback()
887 {
888 auto pipeline = GetContext();
889 CHECK_NULL_VOID(pipeline);
890 if (!HasSurfaceChangedCallback()) {
891 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
892 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
893 WindowSizeChangeReason type) {
894 if (type == WindowSizeChangeReason::UNDEFINED && newWidth == prevWidth && newHeight == prevHeight) {
895 return;
896 }
897 auto swiper = weak.Upgrade();
898 if (!swiper) {
899 return;
900 }
901
902 if (type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::UNDEFINED) {
903 swiper->windowSizeChangeReason_ = type;
904 swiper->StopAutoPlay();
905 }
906 auto currentIndex =
907 swiper->targetIndex_.has_value() ? swiper->targetIndex_.value() : swiper->currentIndex_;
908
909 swiper->needFireCustomAnimationEvent_ = swiper->translateAnimationIsRunning_;
910 if (swiper->SupportSwiperCustomAnimation() && swiper->needFireCustomAnimationEvent_) {
911 swiper->indexsInAnimation_.insert(swiper->GetLoopIndex(currentIndex));
912 }
913
914 swiper->StopPropertyTranslateAnimation(swiper->isFinishAnimation_);
915 swiper->StopTranslateAnimation();
916 swiper->StopSpringAnimationImmediately();
917 swiper->StopFadeAnimation();
918 swiper->StopIndicatorAnimation();
919 const auto& surfaceChangeCallback = swiper->swiperController_->GetSurfaceChangeCallback();
920 if (surfaceChangeCallback) {
921 surfaceChangeCallback();
922 }
923 swiper->currentOffset_ = 0.0f;
924 swiper->itemPosition_.clear();
925 swiper->placeItemWidth_.reset();
926 swiper->isVoluntarilyClear_ = true;
927 swiper->jumpIndex_ = currentIndex;
928 swiper->SetIndicatorJumpIndex(currentIndex);
929 swiper->MarkDirtyNodeSelf();
930 swiper->SetLazyForEachFlag();
931 });
932 UpdateSurfaceChangedCallbackId(callbackId);
933 }
934 }
935
IsFocusNodeInItemPosition(const RefPtr<FocusHub> & targetFocusHub)936 bool SwiperPattern::IsFocusNodeInItemPosition(const RefPtr<FocusHub>& targetFocusHub)
937 {
938 for (const auto& item : itemPosition_) {
939 auto itemNode = GetCurrentFrameNode(item.first);
940 if (!itemNode) {
941 continue;
942 }
943 if (itemNode->GetFirstFocusHubChild() == targetFocusHub) {
944 return true;
945 }
946 }
947 return false;
948 }
949
FlushFocus(const RefPtr<FrameNode> & curShowFrame)950 void SwiperPattern::FlushFocus(const RefPtr<FrameNode>& curShowFrame)
951 {
952 if (GetAndResetDisableFlushFocus()) {
953 return;
954 }
955 CHECK_NULL_VOID(curShowFrame);
956 auto swiperHost = GetHost();
957 CHECK_NULL_VOID(swiperHost);
958 auto swiperFocusHub = swiperHost->GetFocusHub();
959 CHECK_NULL_VOID(swiperFocusHub);
960 auto showChildFocusHub = curShowFrame->GetFirstFocusHubChild();
961 CHECK_NULL_VOID(showChildFocusHub);
962 int32_t skipCnt = 0;
963 if (IsShowIndicator()) {
964 ++skipCnt;
965 }
966 if (HasLeftButtonNode()) {
967 ++skipCnt;
968 }
969 if (HasRightButtonNode()) {
970 ++skipCnt;
971 }
972 std::list<RefPtr<FocusHub>> focusNodes;
973 swiperFocusHub->FlushChildrenFocusHub(focusNodes);
974 for (auto iter = focusNodes.rbegin(); iter != focusNodes.rend(); ++iter) {
975 const auto& node = *iter;
976 if (skipCnt > 0 || !node) {
977 --skipCnt;
978 continue;
979 }
980 if (IsUseCustomAnimation() && hasTabsAncestor_) {
981 node->SetParentFocusable(node == showChildFocusHub);
982 } else {
983 node->SetParentFocusable(IsFocusNodeInItemPosition(node));
984 }
985 }
986
987 RefPtr<FocusHub> needFocusNode = showChildFocusHub;
988 if (IsShowIndicator() && isLastIndicatorFocused_) {
989 needFocusNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
990 }
991 CHECK_NULL_VOID(needFocusNode);
992 lastWeakShowNode_ = AceType::WeakClaim(AceType::RawPtr(curShowFrame));
993 if (swiperFocusHub->IsCurrentFocus()) {
994 needFocusNode->RequestFocusImmediately();
995 } else {
996 if (swiperFocusHub->AcceptFocusOfPriorityChild()) {
997 return;
998 }
999 swiperFocusHub->SetLastWeakFocusNode(AceType::WeakClaim(AceType::RawPtr(needFocusNode)));
1000 }
1001 }
GetFocusHubChild(std::string childFrameName)1002 RefPtr<FocusHub> SwiperPattern::GetFocusHubChild(std::string childFrameName)
1003 {
1004 auto swiperHost = GetHost();
1005 CHECK_NULL_RETURN(swiperHost, nullptr);
1006 auto swiperFocusHub = swiperHost->GetFocusHub();
1007 CHECK_NULL_RETURN(swiperFocusHub, nullptr);
1008 RefPtr<FocusHub> target;
1009 swiperFocusHub->AnyChildFocusHub([&target, childFrameName](const RefPtr<FocusHub>& child) {
1010 CHECK_NULL_RETURN(child, true);
1011 if (child->GetFrameName() == childFrameName) {
1012 target = child;
1013 return true;
1014 }
1015 return false;
1016 });
1017 return target;
1018 }
1019
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)1020 WeakPtr<FocusHub> SwiperPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
1021 {
1022 auto curFocusNode = currentFocusNode.Upgrade();
1023 CHECK_NULL_RETURN(curFocusNode, nullptr);
1024 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::UP) ||
1025 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::SHIFT_TAB) ||
1026 (GetDirection() == Axis::VERTICAL && step == FocusStep::LEFT)) {
1027 return PreviousFocus(curFocusNode);
1028 }
1029 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
1030 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::TAB) ||
1031 (GetDirection() == Axis::VERTICAL && step == FocusStep::RIGHT)) {
1032 return NextFocus(curFocusNode);
1033 }
1034 return nullptr;
1035 }
1036
PreviousFocus(const RefPtr<FocusHub> & curFocusNode)1037 WeakPtr<FocusHub> SwiperPattern::PreviousFocus(const RefPtr<FocusHub>& curFocusNode)
1038 {
1039 CHECK_NULL_RETURN(curFocusNode, nullptr);
1040 RefPtr<FocusHub> indicatorNode;
1041 RefPtr<FocusHub> leftArrowNode;
1042 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
1043 CHECK_NULL_RETURN(props, nullptr);
1044 if (HasLeftButtonNode()) {
1045 leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
1046 CHECK_NULL_RETURN(leftArrowNode, nullptr);
1047 }
1048 if (HasIndicatorNode()) {
1049 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
1050 CHECK_NULL_RETURN(indicatorNode, nullptr);
1051 }
1052 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
1053 isLastIndicatorFocused_ = false;
1054 (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ? curFocusNode->SetParentFocusable(false)
1055 : curFocusNode->SetParentFocusable(true);
1056 return nullptr;
1057 }
1058 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
1059 if (!HasLeftButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ||
1060 props->GetHoverShowValue(false)) {
1061 isLastIndicatorFocused_ = true;
1062 curFocusNode->SetParentFocusable(true);
1063 return nullptr;
1064 }
1065 isLastIndicatorFocused_ = false;
1066 leftArrowNode->SetParentFocusable(true);
1067 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
1068 }
1069 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
1070 if (HasIndicatorNode()) {
1071 isLastIndicatorFocused_ = true;
1072 indicatorNode->SetParentFocusable(true);
1073 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
1074 }
1075 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
1076 curFocusNode->SetParentFocusable(true);
1077 return nullptr;
1078 }
1079 isLastIndicatorFocused_ = true;
1080 leftArrowNode->SetParentFocusable(true);
1081 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
1082 }
1083 curFocusNode->SetParentFocusable(true);
1084 return nullptr;
1085 }
1086
NextFocus(const RefPtr<FocusHub> & curFocusNode)1087 WeakPtr<FocusHub> SwiperPattern::NextFocus(const RefPtr<FocusHub>& curFocusNode)
1088 {
1089 CHECK_NULL_RETURN(curFocusNode, nullptr);
1090 RefPtr<FocusHub> indicatorNode;
1091 RefPtr<FocusHub> rightArrowNode;
1092 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
1093 CHECK_NULL_RETURN(props, nullptr);
1094 if (HasIndicatorNode()) {
1095 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
1096 CHECK_NULL_RETURN(indicatorNode, nullptr);
1097 }
1098 if (HasRightButtonNode()) {
1099 rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
1100 CHECK_NULL_RETURN(rightArrowNode, nullptr);
1101 }
1102 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
1103 if (HasIndicatorNode()) {
1104 isLastIndicatorFocused_ = true;
1105 indicatorNode->SetParentFocusable(true);
1106 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
1107 }
1108 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
1109 curFocusNode->SetParentFocusable(true);
1110 return nullptr;
1111 }
1112 isLastIndicatorFocused_ = true;
1113 rightArrowNode->SetParentFocusable(true);
1114 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
1115 }
1116 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
1117 if (!HasRightButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ||
1118 props->GetHoverShowValue(false)) {
1119 isLastIndicatorFocused_ = true;
1120 curFocusNode->SetParentFocusable(true);
1121 return nullptr;
1122 }
1123 isLastIndicatorFocused_ = false;
1124 rightArrowNode->SetParentFocusable(true);
1125 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
1126 }
1127 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
1128 isLastIndicatorFocused_ = false;
1129 (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ? curFocusNode->SetParentFocusable(false)
1130 : curFocusNode->SetParentFocusable(true);
1131 return nullptr;
1132 }
1133 curFocusNode->SetParentFocusable(true);
1134 return nullptr;
1135 }
1136
GetLoopIndex(int32_t originalIndex) const1137 int32_t SwiperPattern::GetLoopIndex(int32_t originalIndex) const
1138 {
1139 auto totalCount = TotalCount();
1140 if (totalCount <= 0) {
1141 return originalIndex;
1142 }
1143 auto loopIndex = originalIndex;
1144 while (loopIndex < 0) {
1145 loopIndex = loopIndex + totalCount;
1146 }
1147 loopIndex %= totalCount;
1148 return loopIndex;
1149 }
1150
AdjustCurrentFocusIndex()1151 void SwiperPattern::AdjustCurrentFocusIndex()
1152 {
1153 if (GetDisplayCount() <= 1) {
1154 currentFocusIndex_ = currentIndex_;
1155 return;
1156 }
1157
1158 if (currentFocusIndex_ >= currentIndex_ && currentFocusIndex_ < currentIndex_ + GetDisplayCount()) {
1159 return;
1160 }
1161
1162 currentFocusIndex_ = currentIndex_;
1163 }
1164
CheckAndFireCustomAnimation()1165 void SwiperPattern::CheckAndFireCustomAnimation()
1166 {
1167 if (!SupportSwiperCustomAnimation() || !needFireCustomAnimationEvent_) {
1168 return;
1169 }
1170
1171 itemPositionInAnimation_.clear();
1172 for (const auto& item : itemPosition_) {
1173 auto index = GetLoopIndex(item.first);
1174 itemPositionInAnimation_[index] = item.second;
1175 }
1176 FireSwiperCustomAnimationEvent();
1177 FireContentDidScrollEvent();
1178 itemPositionInAnimation_.clear();
1179 }
1180
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1181 bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1182 {
1183 if (!isDragging_ || isInit_) {
1184 SetLazyLoadFeature(true);
1185 }
1186 if (!isInit_) {
1187 OnIndexChange(true);
1188 oldIndex_ = currentIndex_;
1189 }
1190
1191 auto isInit = isInit_;
1192 isInit_ = false;
1193
1194 if (!IsAutoPlay() && config.skipMeasure && config.skipLayout) {
1195 return false;
1196 }
1197
1198 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
1199 CHECK_NULL_RETURN(props, false);
1200 auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm();
1201 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
1202 auto algo = DynamicCast<SwiperLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
1203 CHECK_NULL_RETURN(algo, false);
1204
1205 // set tabs invisible item freeze state.
1206 HandleTabsAncestor();
1207
1208 if (props->GetIsCustomAnimation().value_or(false)) {
1209 needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
1210 auto currentIndex = props->GetIndexValue(0);
1211 HandleTabsCachedMaxCount(currentIndex, customAnimationToIndex_.value_or(currentIndex));
1212 return false;
1213 }
1214 if (SupportSwiperCustomAnimation()) {
1215 needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
1216 itemPositionInAnimation_ = algo->GetItemsPositionInAnimation();
1217 FireContentDidScrollEvent();
1218 }
1219 itemPositionWillInvisible_.clear();
1220
1221 UpdateLayoutProperties(algo);
1222 PostIdleTask(GetHost());
1223 HandleTabsCachedMaxCount(startIndex_, endIndex_);
1224
1225 int32_t startIndex = startIndex_;
1226 int32_t endIndex = endIndex_;
1227 if (startIndex != prevStartIndex_ || endIndex != prevEndIndex_) {
1228 auto host = GetHost();
1229 CHECK_NULL_RETURN(host, false);
1230 host->OnAccessibilityEvent(AccessibilityEventType::SCROLLING_EVENT, startIndex, endIndex);
1231 }
1232 prevStartIndex_ = startIndex_;
1233 prevEndIndex_ = endIndex_;
1234
1235 if (!itemPosition_.empty()) {
1236 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
1237 auto firstItem = GetFirstItemInfoInVisibleArea();
1238 auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
1239 if (turnPageRateCallback && isDragging_ && !NearZero(translateLength)) {
1240 turnPageRateCallback(firstItem.first, -firstItem.second.startPos / translateLength);
1241 }
1242
1243 placeItemWidth_ = translateLength;
1244 }
1245 if (hasCachedCapture_) {
1246 isCaptureReverse_ = algo->GetIsCaptureReverse();
1247 UpdateTargetCapture(algo->GetIsNeedUpdateCapture());
1248 }
1249
1250 if (!targetIndex_) {
1251 if (isUserFinish_) {
1252 SetIndicatorJumpIndex(jumpIndex_);
1253 }
1254
1255 CheckMarkDirtyNodeForRenderIndicator();
1256 }
1257
1258 PlayScrollAnimation(currentDelta_, currentIndexOffset_);
1259 if (jumpIndex_) {
1260 ResetAnimationParam();
1261 auto pipeline = GetContext();
1262 if (pipeline) {
1263 pipeline->AddAfterRenderTask([weak = WeakClaim(this)]() {
1264 auto swiper = weak.Upgrade();
1265 CHECK_NULL_VOID(swiper);
1266 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_TAB_SWITCH, true);
1267 AceAsyncTraceEndCommercial(
1268 0, swiper->hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1269 });
1270 }
1271 UpdateCurrentIndex(algo->GetCurrentIndex());
1272 AdjustCurrentFocusIndex();
1273 auto curChild = dirty->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_));
1274 if (curChild && IsContentFocused()) {
1275 auto curChildFrame = curChild->GetHostNode();
1276 CHECK_NULL_RETURN(curChildFrame, false);
1277 FlushFocus(curChildFrame);
1278 }
1279 currentIndexOffset_ = 0.0f;
1280 springOffset_ = 0.0f;
1281 if (!isInit) {
1282 OnIndexChange(true);
1283 }
1284
1285 if (SupportSwiperCustomAnimation() && prevFrameAnimationRunning_) {
1286 for (const auto& item : itemPosition_) {
1287 auto index = GetLoopIndex(item.first);
1288 indexsInAnimation_.insert(index);
1289 }
1290 }
1291
1292 jumpIndex_.reset();
1293 pauseTargetIndex_.reset();
1294 auto delayTime = GetInterval() - GetDuration();
1295 delayTime = std::clamp(delayTime, 0, delayTime);
1296 if (NeedAutoPlay() && isUserFinish_) {
1297 PostTranslateTask(delayTime);
1298 }
1299
1300 CheckAndFireCustomAnimation();
1301 } else if (RunningTranslateAnimation() && !NearEqual(oldContentMainSize_, algo->GetContentMainSize())) {
1302 HandleRunningTranslateAnimation();
1303 } else if (targetIndex_) {
1304 HandleTargetIndex(dirty, algo);
1305 #ifdef SUPPORT_DIGITAL_CROWN
1306 if (IsCrownSpring()) {
1307 SetIsCrownSpring(false);
1308 }
1309 #endif
1310 velocity_.reset();
1311 pauseTargetIndex_ = targetIndex_;
1312 } else if (algo->GetJumpIndex().has_value()) {
1313 // jumpIndex_ is set inside layout algorithm to reset layout, need reset currentIndexOffset_
1314 currentIndexOffset_ = 0.0f;
1315 springOffset_ = 0.0f;
1316 }
1317 mainSizeIsMeasured_ = algo->GetMainSizeIsMeasured();
1318 contentCrossSize_ = algo->GetContentCrossSize();
1319 currentDelta_ = 0.0f;
1320 oldContentMainSize_ = contentMainSize_;
1321 crossMatchChild_ = algo->IsCrossMatchChild();
1322 ignoreBlankOffset_ = algo->GetIgnoreBlankOffset();
1323 oldIndex_ = currentIndex_;
1324 oldChildrenSize_ = TotalCount();
1325 oldRealTotalCount_ = RealTotalCount();
1326 needFireCustomAnimationEvent_ = true;
1327 prevFrameAnimationRunning_ = false;
1328 SetLayoutDisplayCount(GetHost());
1329 if (windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION) {
1330 StartAutoPlay();
1331 windowSizeChangeReason_ = WindowSizeChangeReason::UNDEFINED;
1332 }
1333
1334 if (onContentDidScroll_) {
1335 indexsInAnimation_.clear();
1336 }
1337
1338 const auto& paddingProperty = props->GetPaddingProperty();
1339 jumpOnChange_ = false;
1340 return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
1341 }
1342
HandleRunningTranslateAnimation()1343 void SwiperPattern::HandleRunningTranslateAnimation()
1344 {
1345 auto pipeline = GetContext();
1346 RefPtr<TaskExecutor> taskExecutor = pipeline ? pipeline->GetTaskExecutor() : nullptr;
1347 if (taskExecutor) {
1348 resetLayoutTask_.Cancel();
1349 resetLayoutTask_.Reset([weak = AceType::WeakClaim(this)] {
1350 auto swiper = weak.Upgrade();
1351 CHECK_NULL_VOID(swiper);
1352 if (swiper->RunningTranslateAnimation()) {
1353 swiper->isUserFinish_ = false;
1354 swiper->FinishAnimation();
1355 swiper->currentDelta_ = 0.0f;
1356 swiper->itemPosition_.clear();
1357 swiper->isVoluntarilyClear_ = true;
1358 swiper->jumpIndex_ = swiper->currentIndex_;
1359 swiper->MarkDirtyNodeSelf();
1360 }
1361 });
1362 taskExecutor->PostTask(resetLayoutTask_, TaskExecutor::TaskType::UI, "ArkUISwiperResetLayout");
1363 }
1364 }
1365
HandleTargetIndex(const RefPtr<LayoutWrapper> & dirty,const RefPtr<SwiperLayoutAlgorithm> & algo)1366 void SwiperPattern::HandleTargetIndex(const RefPtr<LayoutWrapper>& dirty, const RefPtr<SwiperLayoutAlgorithm>& algo)
1367 {
1368 auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
1369 auto iter = itemPosition_.find(targetIndexValue);
1370 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1371 CHECK_NULL_VOID(props);
1372
1373 if (iter == itemPosition_.end()) {
1374 HandleTargetItemNotFound(props, targetIndexValue, algo);
1375 return;
1376 }
1377
1378 float targetPos = iter->second.startPos;
1379 bool isNeedForwardTranslate = IsNeedForwardTranslate(props, targetIndexValue);
1380 bool isNeedBackwardTranslate = IsNeedBackwardTranslate(props, targetIndexValue);
1381 bool isNeedPlayTranslateAnimation = translateAnimationIsRunning_ || isNeedForwardTranslate ||
1382 isNeedBackwardTranslate || AutoLinearAnimationNeedReset(targetPos);
1383 // remove space at end when displayCount is auto and loop is false
1384 if (!SwiperUtils::IsStretch(props) && !IsLoop()) {
1385 auto item = itemPosition_.rbegin();
1386 if (item->first == TotalCount() - 1) {
1387 auto endSpace = CalculateVisibleSize() - (item->second.endPos - targetPos);
1388 targetPos -= Positive(endSpace) ? endSpace : 0.0f;
1389 }
1390 }
1391 auto context = GetContext();
1392 if (context && !isNeedPlayTranslateAnimation && !SupportSwiperCustomAnimation()) {
1393 std::optional<float> pixelRoundTargetPos;
1394 #ifdef SUPPORT_DIGITAL_CROWN
1395 // translate property will be pixel rounded in common scenarios.
1396 if (!IsHorizontalAndRightToLeft() && SwiperUtils::CheckIsSingleCase(props) &&
1397 iter->second.node && iter->second.node->GetRenderContext()) {
1398 auto paintRect = iter->second.node->GetRenderContext()->GetPaintRectWithoutTransform();
1399 pixelRoundTargetPos = -(GetDirection() == Axis::HORIZONTAL ? paintRect.GetX() : paintRect.GetY());
1400 }
1401 #endif
1402 if (propertyAnimationIsRunning_ && targetIndex_ == runningTargetIndex_) {
1403 // If property animation is running and the target index is the same as the running target index, the
1404 // animation is not played
1405 return;
1406 }
1407 context->AddAfterLayoutTask([weak = WeakClaim(this), targetPos, pixelRoundTargetPos,
1408 velocity = velocity_.value_or(0.0f), nextIndex = iter->first]() {
1409 auto swiper = weak.Upgrade();
1410 CHECK_NULL_VOID(swiper);
1411 swiper->PlayPropertyTranslateAnimation(-targetPos, nextIndex, velocity, false, pixelRoundTargetPos);
1412 swiper->PlayIndicatorTranslateAnimation(-targetPos, nextIndex);
1413 });
1414 runningTargetIndex_ = targetIndex_;
1415 } else {
1416 PlayTranslateAnimation(
1417 currentOffset_, currentOffset_ - targetPos, iter->first, false, velocity_.value_or(0.0f));
1418 }
1419 }
1420
HandleTargetItemNotFound(const RefPtr<SwiperLayoutProperty> & props,int32_t targetIndexValue,const RefPtr<SwiperLayoutAlgorithm> & algo)1421 void SwiperPattern::HandleTargetItemNotFound(
1422 const RefPtr<SwiperLayoutProperty>& props, int32_t targetIndexValue, const RefPtr<SwiperLayoutAlgorithm>& algo)
1423 {
1424 if (!itemPosition_.empty() && SwiperUtils::IsStretch(props)) {
1425 auto firstItem = GetFirstItemInfoInVisibleArea();
1426 auto targetPos = firstItem.second.startPos +
1427 (targetIndexValue - firstItem.first) * (placeItemWidth_.value_or(0.0f) + GetItemSpace());
1428 PlayTranslateAnimation(
1429 currentOffset_, currentOffset_ - targetPos, targetIndexValue, false, velocity_.value_or(0.0f));
1430 } else {
1431 PlayTranslateAnimation(currentOffset_, currentOffset_ - algo->GetTargetStartPos(), targetIndexValue, false,
1432 velocity_.value_or(0.0f));
1433 }
1434 }
1435
IsNeedForwardTranslate(const RefPtr<SwiperLayoutProperty> & props,int32_t targetIndexValue)1436 bool SwiperPattern::IsNeedForwardTranslate(const RefPtr<SwiperLayoutProperty>& props, int32_t targetIndexValue)
1437 {
1438 if (!IsLoop()) {
1439 return false;
1440 }
1441
1442 auto lastItemIndex = Positive(props->GetCalculatedNextMargin()) ? targetIndexValue + GetDisplayCount()
1443 : targetIndexValue + GetDisplayCount() - 1;
1444 return itemPosition_.find(lastItemIndex) == itemPosition_.end();
1445 }
1446
IsNeedBackwardTranslate(const RefPtr<SwiperLayoutProperty> & props,int32_t targetIndexValue)1447 bool SwiperPattern::IsNeedBackwardTranslate(const RefPtr<SwiperLayoutProperty>& props, int32_t targetIndexValue)
1448 {
1449 if (!IsLoop() || targetIndexValue >= currentIndex_) {
1450 return false;
1451 }
1452
1453 auto firstItemIndex = Positive(props->GetCalculatedPrevMargin()) ? targetIndexValue + TotalCount() - 1
1454 : targetIndexValue + TotalCount();
1455 return itemPosition_.find(firstItemIndex) != itemPosition_.end();
1456 }
1457
HandleTabsAncestor()1458 void SwiperPattern::HandleTabsAncestor()
1459 {
1460 if (hasTabsAncestor_) {
1461 for (int32_t index = 0; index < RealTotalCount(); index++) {
1462 auto childFrameNode = GetCurrentFrameNode(index);
1463 if (childFrameNode) {
1464 auto isActive = childFrameNode->IsActive();
1465 childFrameNode->SetFreeze(!isActive);
1466 }
1467 }
1468 }
1469 }
1470
UpdateLayoutProperties(const RefPtr<SwiperLayoutAlgorithm> & algo)1471 void SwiperPattern::UpdateLayoutProperties(const RefPtr<SwiperLayoutAlgorithm>& algo)
1472 {
1473 autoLinearReachBoundary_ = false;
1474 startMainPos_ = algo->GetStartPosition();
1475 endMainPos_ = algo->GetEndPosition();
1476 startIndex_ = algo->GetStartIndex();
1477 endIndex_ = algo->GetEndIndex();
1478 cachedItems_ = algo->GetCachedItems();
1479 layoutConstraint_ = algo->GetLayoutConstraint();
1480 itemPosition_ = std::move(algo->GetItemPosition());
1481 currentOffset_ -= algo->GetCurrentOffset();
1482 contentMainSize_ = algo->GetContentMainSize();
1483 }
1484
AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const1485 float SwiperPattern::AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const
1486 {
1487 if (!NeedEnableIgnoreBlankOffset()) {
1488 return 0.0f;
1489 }
1490 if (isStartOverScroll && NonNegative(ignoreBlankOffset_)) {
1491 return prevMarginIgnoreBlank_ ? GetPrevMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1492 }
1493 if (!isStartOverScroll && NonPositive(ignoreBlankOffset_)) {
1494 return nextMarginIgnoreBlank_ ? -GetNextMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1495 }
1496 return 0.0f;
1497 }
1498
UpdateIgnoreBlankOffsetWithIndex()1499 void SwiperPattern::UpdateIgnoreBlankOffsetWithIndex()
1500 {
1501 if (!NeedEnableIgnoreBlankOffset()) {
1502 auto lastIgnoreBlankOffset = ignoreBlankOffset_;
1503 ignoreBlankOffset_ = 0.0f;
1504 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1505 return;
1506 }
1507
1508 if (targetIndex_.has_value()) {
1509 float lastIgnoreBlankOffset = ignoreBlankOffset_;
1510 if (prevMarginIgnoreBlank_ && targetIndex_.value() == 0) {
1511 ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1512 } else if (nextMarginIgnoreBlank_ && targetIndex_.value() >= (TotalCount() - GetDisplayCount())) {
1513 ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1514 } else {
1515 ignoreBlankOffset_ = 0.0f;
1516 }
1517 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1518 }
1519 }
1520
UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)1521 void SwiperPattern::UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)
1522 {
1523 if (!NeedEnableIgnoreBlankOffset()) {
1524 return;
1525 }
1526 float lastIgnoreBlankOffset = ignoreBlankOffset_;
1527 if (prevMarginIgnoreBlank_ && overScrollDirection) {
1528 ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1529 } else if (nextMarginIgnoreBlank_ && !overScrollDirection) {
1530 ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1531 } else {
1532 ignoreBlankOffset_ = 0.0f;
1533 }
1534
1535 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1536 }
1537
UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)1538 void SwiperPattern::UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)
1539 {
1540 if (NearEqual(ignoreBlankOffset_, lastIgnoreBlankOffset)) {
1541 return;
1542 }
1543
1544 float adjustOffset = ignoreBlankOffset_ - lastIgnoreBlankOffset;
1545 for (auto& item : itemPosition_) {
1546 item.second.startPos -= adjustOffset;
1547 item.second.endPos -= adjustOffset;
1548 }
1549 }
1550
IsAutoLinear() const1551 bool SwiperPattern::IsAutoLinear() const
1552 {
1553 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1554 CHECK_NULL_RETURN(props, false);
1555 return !SwiperUtils::IsStretch(props);
1556 }
1557
AutoLinearAnimationNeedReset(float translate) const1558 bool SwiperPattern::AutoLinearAnimationNeedReset(float translate) const
1559 {
1560 if (!IsAutoLinear()) {
1561 return false;
1562 }
1563
1564 if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
1565 return false;
1566 }
1567
1568 if (NonPositive(translate)) {
1569 return false;
1570 }
1571
1572 auto iter = itemPosition_.rbegin();
1573 auto endPos = iter->second.endPos;
1574 if (endPos - CalculateVisibleSize() < translate) {
1575 return true;
1576 }
1577
1578 return false;
1579 }
1580
OnAnimationTranslateZero(int32_t nextIndex,bool stopAutoPlay)1581 void SwiperPattern::OnAnimationTranslateZero(int32_t nextIndex, bool stopAutoPlay)
1582 {
1583 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
1584
1585 if (!NeedAutoPlay() || !isUserFinish_) {
1586 return;
1587 }
1588
1589 if (stopAutoPlay) {
1590 MarkDirtyNodeSelf();
1591 } else {
1592 auto delayTime = GetInterval() - GetDuration();
1593 delayTime = std::clamp(delayTime, 0, delayTime);
1594 PostTranslateTask(delayTime);
1595 }
1596 }
1597
FireChangeEvent(int32_t preIndex,int32_t currentIndex,bool isInLayout) const1598 void SwiperPattern::FireChangeEvent(int32_t preIndex, int32_t currentIndex, bool isInLayout) const
1599 {
1600 if (jumpOnChange_) {
1601 return;
1602 }
1603 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1604 CHECK_NULL_VOID(swiperEventHub);
1605 swiperEventHub->FireChangeEvent(preIndex, currentIndex, isInLayout);
1606 swiperEventHub->FireIndicatorChangeEvent(currentIndex);
1607 swiperEventHub->FireIndicatorIndexChangeEvent(currentIndex);
1608 swiperEventHub->FireChangeDoneEvent(moveDirection_);
1609 if (swiperController_) {
1610 swiperController_->FireOnChangeEvent(currentIndex);
1611 }
1612
1613 if (jumpIndex_) {
1614 auto host = GetHost();
1615 CHECK_NULL_VOID(host);
1616 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1617 }
1618 }
1619
FireAnimationStartEvent(int32_t currentIndex,int32_t nextIndex,const AnimationCallbackInfo & info) const1620 void SwiperPattern::FireAnimationStartEvent(
1621 int32_t currentIndex, int32_t nextIndex, const AnimationCallbackInfo& info) const
1622 {
1623 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1624 CHECK_NULL_VOID(swiperEventHub);
1625 swiperEventHub->FireAnimationStartEvent(currentIndex, nextIndex, info);
1626 auto host = GetHost();
1627 CHECK_NULL_VOID(host);
1628 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
1629 }
1630
FireAnimationEndEvent(int32_t currentIndex,const AnimationCallbackInfo & info,bool isInterrupt) const1631 void SwiperPattern::FireAnimationEndEvent(
1632 int32_t currentIndex, const AnimationCallbackInfo& info, bool isInterrupt) const
1633 {
1634 if (currentIndex == -1) {
1635 return;
1636 }
1637 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1638 CHECK_NULL_VOID(swiperEventHub);
1639 isInterrupt ? swiperEventHub->FireAnimationEndOnForceEvent(currentIndex, info)
1640 : swiperEventHub->FireAnimationEndEvent(currentIndex, info);
1641 auto host = GetHost();
1642 CHECK_NULL_VOID(host);
1643 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1644 }
1645
FireGestureSwipeEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const1646 void SwiperPattern::FireGestureSwipeEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
1647 {
1648 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1649 CHECK_NULL_VOID(swiperEventHub);
1650 swiperEventHub->FireGestureSwipeEvent(currentIndex, info);
1651 }
1652
FireSelectedEvent(int32_t currentIndex,int32_t targetIndex)1653 void SwiperPattern::FireSelectedEvent(int32_t currentIndex, int32_t targetIndex)
1654 {
1655 if (jumpOnChange_) {
1656 return;
1657 }
1658 if (currentIndex == targetIndex && !fastAnimationRunning_) {
1659 return;
1660 }
1661
1662 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1663 CHECK_NULL_VOID(swiperEventHub);
1664 if (selectedIndex_ != GetLoopIndex(targetIndex)) {
1665 selectedIndex_ = GetLoopIndex(targetIndex);
1666 swiperEventHub->FireSelectedEvent(GetLoopIndex(targetIndex));
1667 }
1668 }
1669
FireUnselectedEvent(int32_t currentIndex,int32_t targetIndex)1670 void SwiperPattern::FireUnselectedEvent(int32_t currentIndex, int32_t targetIndex)
1671 {
1672 if (currentIndex == targetIndex || currentIndex != GetLoopIndex(currentIndex)) {
1673 return;
1674 }
1675 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1676 CHECK_NULL_VOID(swiperEventHub);
1677 if (unselectedIndex_ != GetLoopIndex(currentIndex)) {
1678 unselectedIndex_ = GetLoopIndex(currentIndex);
1679 swiperEventHub->FireUnselectedEvent(GetLoopIndex(currentIndex));
1680 }
1681 }
1682
FireScrollStateEvent(ScrollState scrollState)1683 void SwiperPattern::FireScrollStateEvent(ScrollState scrollState)
1684 {
1685 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
1686 CHECK_NULL_VOID(swiperEventHub);
1687 if (scrollState_ != scrollState) {
1688 scrollState_ = scrollState;
1689 swiperEventHub->FireScrollStateChangedEvent(scrollState);
1690 }
1691 }
1692
HandleSwiperCustomAnimation(float offset)1693 void SwiperPattern::HandleSwiperCustomAnimation(float offset)
1694 {
1695 if (!SupportSwiperCustomAnimation()) {
1696 return;
1697 }
1698 if (itemPosition_.empty()) {
1699 needUnmountIndexs_.clear();
1700 itemPositionInAnimation_.clear();
1701 return;
1702 }
1703 if (NearZero(offset)) {
1704 return;
1705 }
1706
1707 if (itemPositionInAnimation_.empty()) {
1708 CalculateAndUpdateItemInfo();
1709 }
1710 indexsInAnimation_.clear();
1711 CalculateAndUpdateItemInfo(offset);
1712
1713 std::set<int32_t> unmountIndexs;
1714 for (auto& item : itemPositionInAnimation_) {
1715 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end() &&
1716 needUnmountIndexs_.find(item.first) == needUnmountIndexs_.end()) {
1717 indexsInAnimation_.insert(item.first);
1718 needUnmountIndexs_.insert(item.first);
1719 item.second.startPos += offset;
1720 item.second.endPos += offset;
1721 unmountIndexs.insert(item.first);
1722 }
1723 }
1724 for (const auto& index : unmountIndexs) {
1725 auto iter = itemPositionInAnimation_.find(index);
1726 if (iter == itemPositionInAnimation_.end()) {
1727 continue;
1728 }
1729
1730 OnSwiperCustomAnimationFinish(iter->second.task, index, iter->second.isFinishAnimation);
1731 }
1732
1733 FireSwiperCustomAnimationEvent();
1734 }
1735
CalculateAndUpdateItemInfo(float offset)1736 void SwiperPattern::CalculateAndUpdateItemInfo(float offset)
1737 {
1738 auto prevMargin = GetPrevMargin();
1739 auto nextMargin = GetNextMargin();
1740 auto visibleSize = CalculateVisibleSize();
1741 auto itemSpace = GetItemSpace();
1742 auto isLoop = IsLoop();
1743 auto displayCount = GetDisplayCount();
1744 auto swipeByGroup = IsSwipeByGroup();
1745
1746 for (auto& item : itemPosition_) {
1747 auto index = item.first;
1748 auto startPos = item.second.startPos + offset;
1749 auto endPos = item.second.endPos + offset;
1750 auto itemPosDiff = endPos - startPos + itemSpace;
1751 auto pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index, displayCount) : index;
1752 auto pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index, displayCount) : index;
1753 auto pageStartPos = swipeByGroup ? startPos - itemPosDiff * (index - pageStartIndex) : startPos;
1754 auto pageEndPos = swipeByGroup ? endPos + itemPosDiff * (pageEndIndex - index) : endPos;
1755
1756 if (LessOrEqual(pageEndPos, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace) ||
1757 GreatOrEqual(pageStartPos, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace)) {
1758 continue;
1759 }
1760
1761 if (GreatNotEqual(startPos - itemSpace, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace) &&
1762 itemPosition_.find(index - 1) == itemPosition_.end() && (isLoop || index > 0)) {
1763 if (!targetIndex_.has_value() || index < targetIndex_.value() || index - 1 >= targetIndex_.value()) {
1764 pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index - 1, displayCount) : index - 1;
1765 }
1766 }
1767 if (LessNotEqual(
1768 endPos + itemSpace, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace) &&
1769 itemPosition_.find(index + 1) == itemPosition_.end() && (isLoop || index < RealTotalCount() - 1)) {
1770 if (!targetIndex_.has_value() || index > targetIndex_.value() || index + 1 <= targetIndex_.value()) {
1771 pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index + 1, displayCount) : index + 1;
1772 }
1773 }
1774 auto currentIndex = index - 1;
1775 while (currentIndex >= pageStartIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1776 UpdateItemInfoInCustomAnimation(currentIndex, startPos - itemPosDiff * (index - currentIndex),
1777 endPos - itemPosDiff * (index - currentIndex));
1778 currentIndex--;
1779 }
1780 currentIndex = index + 1;
1781 while (currentIndex <= pageEndIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1782 UpdateItemInfoInCustomAnimation(currentIndex, startPos + itemPosDiff * (currentIndex - index),
1783 endPos + itemPosDiff * (currentIndex - index));
1784 currentIndex++;
1785 }
1786 UpdateItemInfoInCustomAnimation(index, startPos, endPos);
1787 }
1788 }
1789
UpdateItemInfoInCustomAnimation(int32_t index,float startPos,float endPos)1790 void SwiperPattern::UpdateItemInfoInCustomAnimation(int32_t index, float startPos, float endPos)
1791 {
1792 index = GetLoopIndex(index);
1793 if (IsSwipeByGroup() && index >= RealTotalCount()) {
1794 return;
1795 }
1796 indexsInAnimation_.insert(index);
1797 needUnmountIndexs_.erase(index);
1798 auto itemInAnimation = itemPositionInAnimation_.find(index);
1799 if (itemInAnimation == itemPositionInAnimation_.end()) {
1800 itemPositionInAnimation_[index] = { startPos, endPos, nullptr };
1801 } else {
1802 itemInAnimation->second.startPos = startPos;
1803 itemInAnimation->second.endPos = endPos;
1804 if (itemInAnimation->second.task) {
1805 itemInAnimation->second.task.Cancel();
1806 }
1807 }
1808 }
1809
FireSwiperCustomAnimationEvent()1810 void SwiperPattern::FireSwiperCustomAnimationEvent()
1811 {
1812 CHECK_NULL_VOID(onSwiperCustomContentTransition_);
1813 auto transition = onSwiperCustomContentTransition_->transition;
1814 CHECK_NULL_VOID(transition);
1815
1816 auto selectedIndex = GetCurrentIndex();
1817 auto itemPosition = itemPositionInAnimation_;
1818 for (auto& item : itemPosition) {
1819 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1820 continue;
1821 }
1822 auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1823 if (IsHorizontalAndRightToLeft()) {
1824 offset = Dimension(-item.second.startPos, DimensionUnit::PX).ConvertToVp();
1825 }
1826 auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1827 if (NonPositive(mainAxisLength)) {
1828 continue;
1829 }
1830 auto position = offset / mainAxisLength;
1831 auto proxy = AceType::MakeRefPtr<SwiperContentTransitionProxy>();
1832 proxy->SetSelectedIndex(selectedIndex);
1833 proxy->SetIndex(item.first);
1834 proxy->SetPosition(position);
1835 proxy->SetMainAxisLength(mainAxisLength);
1836 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), index = item.first]() {
1837 auto swiper = weak.Upgrade();
1838 CHECK_NULL_VOID(swiper);
1839 auto item = swiper->itemPositionInAnimation_.find(index);
1840 if (item == swiper->itemPositionInAnimation_.end()) {
1841 return;
1842 }
1843 item->second.isFinishAnimation = true;
1844 swiper->OnSwiperCustomAnimationFinish(item->second.task, index, true);
1845 });
1846 transition(proxy);
1847 }
1848 }
1849
FireContentDidScrollEvent()1850 void SwiperPattern::FireContentDidScrollEvent()
1851 {
1852 if (indexsInAnimation_.empty() || itemPositionInAnimation_.empty()) {
1853 return;
1854 }
1855
1856 CHECK_NULL_VOID(onContentDidScroll_);
1857 auto event = *onContentDidScroll_;
1858 CHECK_NULL_VOID(event);
1859 auto selectedIndex = GetCurrentIndex();
1860
1861 SwiperLayoutAlgorithm::PositionMap mergeMap;
1862 mergeMap.insert(itemPositionInAnimation_.begin(), itemPositionInAnimation_.end());
1863 mergeMap.insert(itemPositionWillInvisible_.begin(), itemPositionWillInvisible_.end());
1864 for (auto& item : mergeMap) {
1865 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1866 continue;
1867 }
1868 auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1869 auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1870 if (NonPositive(mainAxisLength)) {
1871 continue;
1872 }
1873 auto position = offset / mainAxisLength;
1874 event(selectedIndex, item.first, position, mainAxisLength);
1875 }
1876 }
1877
OnSwiperCustomAnimationFinish(CancelableCallback<void ()> & task,int32_t index,bool isFinishAnimation)1878 void SwiperPattern::OnSwiperCustomAnimationFinish(
1879 CancelableCallback<void()>& task, int32_t index, bool isFinishAnimation)
1880 {
1881 if (needUnmountIndexs_.find(index) == needUnmountIndexs_.end()) {
1882 return;
1883 }
1884 auto pipeline = GetContext();
1885 CHECK_NULL_VOID(pipeline);
1886 auto taskExecutor = pipeline->GetTaskExecutor();
1887 CHECK_NULL_VOID(taskExecutor);
1888 if (task) {
1889 task.Cancel();
1890 }
1891
1892 int32_t timeout = 0;
1893 if (onSwiperCustomContentTransition_ && !isFinishAnimation) {
1894 timeout = onSwiperCustomContentTransition_->timeout;
1895 }
1896
1897 if (timeout == 0) {
1898 auto item = itemPositionInAnimation_.find(index);
1899 if (item != itemPositionInAnimation_.end()) {
1900 itemPositionWillInvisible_[index] = item->second;
1901 }
1902 needUnmountIndexs_.erase(index);
1903 itemPositionInAnimation_.erase(index);
1904 MarkDirtyNodeSelf();
1905 return;
1906 }
1907
1908 task.Reset([weak = AceType::WeakClaim(this), index] {
1909 auto swiper = weak.Upgrade();
1910 CHECK_NULL_VOID(swiper);
1911 swiper->needUnmountIndexs_.erase(index);
1912 swiper->itemPositionInAnimation_.erase(index);
1913 swiper->MarkDirtyNodeSelf();
1914 });
1915 taskExecutor->PostDelayedTask(task, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperDelayedCustomAnimation");
1916 }
1917
SwipeToWithoutAnimation(int32_t index,std::optional<int32_t> rawIndex)1918 void SwiperPattern::SwipeToWithoutAnimation(int32_t index, std::optional<int32_t> rawIndex)
1919 {
1920 if (currentIndex_ != index) {
1921 FireWillShowEvent(index);
1922 FireWillHideEvent(currentIndex_);
1923 }
1924 if (IsVisibleChildrenSizeLessThanSwiper()) {
1925 return;
1926 }
1927
1928 if (propertyAnimationIsRunning_) {
1929 StopPropertyTranslateAnimation(isFinishAnimation_);
1930 }
1931
1932 StopTranslateAnimation();
1933 StopFadeAnimation();
1934 StopSpringAnimationImmediately();
1935 StopIndicatorAnimation(true);
1936 jumpIndex_ = index;
1937 if (rawIndex.has_value()) {
1938 auto tempIndex = CheckIndexRange(rawIndex.value());
1939 tempIndex = IsSwipeByGroup() ? SwiperUtils::ComputePageIndex(tempIndex, GetDisplayCount()) : tempIndex;
1940 jumpIndexByUser_ = CheckTargetIndex(tempIndex);
1941 }
1942 AceAsyncTraceBeginCommercial(0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1943 uiCastJumpIndex_ = index;
1944 MarkDirtyNodeSelf();
1945 FireAndCleanScrollingListener();
1946 }
1947
StopSpringAnimationAndFlushImmediately()1948 void SwiperPattern::StopSpringAnimationAndFlushImmediately()
1949 {
1950 if (springAnimationIsRunning_) {
1951 StopSpringAnimationImmediately();
1952 currentDelta_ = 0.0f;
1953 itemPosition_.clear();
1954 isVoluntarilyClear_ = true;
1955 jumpIndex_ = currentIndex_;
1956 MarkDirtyNodeSelf();
1957 auto pipeline = GetContext();
1958 CHECK_NULL_VOID(pipeline);
1959 pipeline->FlushUITasks();
1960 }
1961 }
1962
IsUseCustomAnimation() const1963 bool SwiperPattern::IsUseCustomAnimation() const
1964 {
1965 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1966 CHECK_NULL_RETURN(props, false);
1967 return props->GetIsCustomAnimation().value_or(false);
1968 }
1969
NeedFastAnimation() const1970 bool SwiperPattern::NeedFastAnimation() const
1971 {
1972 return tabAnimationMode_ == TabAnimateMode::CONTENT_FIRST_WITH_JUMP ||
1973 tabAnimationMode_ == TabAnimateMode::ACTION_FIRST_WITH_JUMP;
1974 }
1975
SwipeTo(int32_t index)1976 void SwiperPattern::SwipeTo(int32_t index)
1977 {
1978 auto targetIndex = IsLoop() ? index : (index < 0 || index > (TotalCount() - 1)) ? 0 : index;
1979 targetIndex = IsLoop() ? targetIndex : std::clamp(targetIndex, 0, TotalCount() - GetDisplayCount());
1980 if (!ContentWillChange(targetIndex)) {
1981 return;
1982 }
1983
1984 if (IsUseCustomAnimation()) {
1985 OnCustomContentTransition(targetIndex);
1986 MarkDirtyNodeSelf();
1987 return;
1988 }
1989
1990 if (IsVisibleChildrenSizeLessThanSwiper()) {
1991 return;
1992 }
1993
1994 // If targetIndex_ has a value, means animation is still running, stop it before play new animation.
1995 if (currentIndex_ == targetIndex && !targetIndex_.has_value()) {
1996 return;
1997 }
1998 StopFadeAnimation();
1999 if (springAnimationIsRunning_) {
2000 StopSpringAnimationImmediately();
2001 jumpIndex_ = currentIndex_;
2002 MarkDirtyNodeSelf();
2003 auto pipeline = GetContext();
2004 CHECK_NULL_VOID(pipeline);
2005 pipeline->FlushUITasks();
2006 }
2007 StopAutoPlay();
2008 StopTranslateAnimation();
2009
2010 StopIndicatorAnimation();
2011 if (propertyAnimationIsRunning_) {
2012 StopPropertyTranslateAnimation(isFinishAnimation_);
2013 }
2014
2015 if (hasTabsAncestor_ && NeedFastAnimation()) {
2016 FastAnimation(targetIndex);
2017 }
2018 targetIndex_ = targetIndex;
2019 UpdateTabBarAnimationDuration(index);
2020 if (GetDuration() == 0 || !isVisible_) {
2021 SwipeToWithoutAnimation(index);
2022 return;
2023 }
2024
2025 if (currentIndex_ != targetIndex_.value_or(0)) {
2026 FireWillShowEvent(targetIndex_.value_or(0));
2027 FireWillHideEvent(currentIndex_);
2028 }
2029 MarkDirtyNodeSelf();
2030 }
2031
UpdateTabBarAnimationDuration(int32_t index)2032 void SwiperPattern::UpdateTabBarAnimationDuration(int32_t index)
2033 {
2034 auto host = GetHost();
2035 CHECK_NULL_VOID(host);
2036 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2037 CHECK_NULL_VOID(tabsNode);
2038 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
2039 CHECK_NULL_VOID(tabBarNode);
2040 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
2041 CHECK_NULL_VOID(tabBarPattern);
2042 tabBarPattern->UpdateAnimationDuration();
2043 }
2044
CheckTargetIndex(int32_t targetIndex,bool isForceBackward)2045 int32_t SwiperPattern::CheckTargetIndex(int32_t targetIndex, bool isForceBackward)
2046 {
2047 if (!IsAutoLinear()) {
2048 return targetIndex;
2049 }
2050 while (GetLoopIndex(targetIndex) != GetLoopIndex(currentIndex_)) {
2051 auto currentFrameNode = GetCurrentFrameNode(GetLoopIndex(targetIndex));
2052 CHECK_NULL_RETURN(currentFrameNode, targetIndex);
2053 auto props = currentFrameNode->GetLayoutProperty<LayoutProperty>();
2054 CHECK_NULL_RETURN(props, targetIndex);
2055 if (props->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
2056 return targetIndex;
2057 }
2058 if (isForceBackward || currentIndex_ < targetIndex) {
2059 ++targetIndex;
2060 } else {
2061 --targetIndex;
2062 }
2063 if (!IsLoop() && (targetIndex < 0 || targetIndex >= TotalCount())) {
2064 return currentIndex_;
2065 }
2066 }
2067 return targetIndex;
2068 }
2069
ShowNext(bool needCheckWillScroll)2070 void SwiperPattern::ShowNext(bool needCheckWillScroll)
2071 {
2072 if (IsVisibleChildrenSizeLessThanSwiper()) {
2073 return;
2074 }
2075 indicatorDoingAnimation_ = false;
2076 auto childrenSize = TotalCount();
2077 auto displayCount = GetDisplayCount();
2078 if (childrenSize <= 0 || displayCount == 0) {
2079 return;
2080 }
2081
2082 auto stepItems = IsSwipeByGroup() ? displayCount : 1;
2083 auto fromIndex = targetIndex_.value_or(currentIndex_);
2084 auto nextIndex = fromIndex + stepItems;
2085 if (fromIndex >= childrenSize - displayCount && !IsLoop()) {
2086 return;
2087 }
2088
2089 StopAutoPlay();
2090 StopSpringAnimationAndFlushImmediately();
2091 StopFadeAnimation();
2092 if (propertyAnimationIsRunning_ || translateAnimationIsRunning_) {
2093 isUserFinish_ = false;
2094 FinishAnimation();
2095 if (!ContentWillChange(currentIndex_ + 1)) {
2096 return;
2097 }
2098 }
2099
2100 if (needCheckWillScroll && HasOnContentWillScroll()) {
2101 auto offset = CalcWillScrollOffset(nextIndex);
2102 if (!ContentWillScroll(currentIndex_, nextIndex, -offset)) {
2103 return;
2104 }
2105 }
2106 StopIndicatorAnimation();
2107
2108 moveDirection_ = true;
2109
2110 if (isVisibleArea_) {
2111 targetIndex_ = CheckTargetIndex(nextIndex);
2112 MarkDirtyNodeSelf();
2113 auto pipeline = GetContext();
2114 CHECK_NULL_VOID(pipeline);
2115 pipeline->FlushUITasks();
2116 } else {
2117 SwipeToWithoutAnimation(nextIndex);
2118 }
2119 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
2120 CHECK_NULL_VOID(swiperEventHub);
2121 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
2122 }
2123
ShowPrevious(bool needCheckWillScroll)2124 void SwiperPattern::ShowPrevious(bool needCheckWillScroll)
2125 {
2126 if (IsVisibleChildrenSizeLessThanSwiper()) {
2127 return;
2128 }
2129
2130 if (IsAutoLinear() && static_cast<int32_t>(itemPosition_.size()) == TotalCount() && !autoLinearReachBoundary_) {
2131 return;
2132 }
2133
2134 indicatorDoingAnimation_ = false;
2135 auto childrenSize = TotalCount();
2136 auto displayCount = GetDisplayCount();
2137 if (childrenSize <= 0 || displayCount == 0) {
2138 return;
2139 }
2140
2141 auto stepItems = IsSwipeByGroup() ? displayCount : 1;
2142 auto fromIndex = targetIndex_.value_or(currentIndex_);
2143 auto prevIndex = fromIndex - stepItems;
2144 if (fromIndex <= 0 && !IsLoop()) {
2145 return;
2146 }
2147
2148 StopAutoPlay();
2149 StopSpringAnimationAndFlushImmediately();
2150 StopFadeAnimation();
2151 if (propertyAnimationIsRunning_ || translateAnimationIsRunning_) {
2152 isUserFinish_ = false;
2153 FinishAnimation();
2154 if (!ContentWillChange(currentIndex_ - 1)) {
2155 return;
2156 }
2157 }
2158
2159 if (needCheckWillScroll && HasOnContentWillScroll()) {
2160 auto offset = CalcWillScrollOffset(prevIndex);
2161 if (!ContentWillScroll(currentIndex_, prevIndex, offset)) {
2162 return;
2163 }
2164 }
2165 StopIndicatorAnimation();
2166
2167 moveDirection_ = false;
2168
2169 if (isVisibleArea_) {
2170 targetIndex_ = CheckTargetIndex(prevIndex);
2171 MarkDirtyNodeSelf();
2172 auto pipeline = GetContext();
2173 CHECK_NULL_VOID(pipeline);
2174 pipeline->FlushUITasks();
2175 } else {
2176 SwipeToWithoutAnimation(prevIndex);
2177 }
2178 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
2179 CHECK_NULL_VOID(swiperEventHub);
2180 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
2181 }
2182
FastAnimation(int32_t targetIndex)2183 void SwiperPattern::FastAnimation(int32_t targetIndex)
2184 {
2185 fastCurrentIndex_.reset();
2186 if (abs(currentIndex_ - targetIndex) > JUMP_NEAR_VALUE) {
2187 jumpOnChange_ = true;
2188 auto tempIndex = targetIndex - ((currentIndex_ < targetIndex) ? JUMP_NEAR_VALUE : -JUMP_NEAR_VALUE);
2189 fastCurrentIndex_ = currentIndex_;
2190 jumpIndex_ = tempIndex;
2191 auto host = GetHost();
2192 CHECK_NULL_VOID(host);
2193 MarkDirtyNodeSelf();
2194 auto pipeline = GetContext();
2195 CHECK_NULL_VOID(pipeline);
2196 pipeline->FlushUITaskWithSingleDirtyNode(host);
2197 pipeline->FlushSyncGeometryNodeTasks();
2198 SetIndicatorIsInFast(true);
2199 }
2200 }
2201
GetCurrentIndex(bool original)2202 int32_t SwiperPattern::GetCurrentIndex(bool original)
2203 {
2204 if (!original || !targetIndex_.has_value() || !fastCurrentIndex_.has_value()) {
2205 return GetLoopIndex(currentIndex_);
2206 }
2207 if (targetIndex_.value_or(0) != GetLoopIndex(currentIndex_)) {
2208 auto currentIndex = GetLoopIndex(fastCurrentIndex_.value_or(0));
2209 fastCurrentIndex_.reset();
2210 return currentIndex;
2211 }
2212 return GetLoopIndex(currentIndex_);
2213 }
2214
IsInFastAnimation() const2215 bool SwiperPattern::IsInFastAnimation() const
2216 {
2217 if (!NeedFastAnimation()) {
2218 return false;
2219 }
2220 if (targetIndex_) {
2221 return true;
2222 }
2223 return propertyAnimationIsRunning_;
2224 }
2225
ChangeIndex(int32_t index,SwiperAnimationMode mode)2226 void SwiperPattern::ChangeIndex(int32_t index, SwiperAnimationMode mode)
2227 {
2228 auto host = GetHost();
2229 FREE_NODE_CHECK(host, ChangeIndex, index, mode);
2230 int32_t targetIndex = 0;
2231 if (!ComputeTargetIndex(index, targetIndex)) {
2232 return;
2233 }
2234
2235 fastCurrentIndex_.reset();
2236 targetIndex = CheckTargetIndex(targetIndex);
2237 if (mode == SwiperAnimationMode::NO_ANIMATION) {
2238 needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
2239
2240 if (GetMaxDisplayCount() > 0) {
2241 SetIndicatorChangeIndexStatus(false);
2242 }
2243
2244 SwipeToWithoutAnimation(GetLoopIndex(targetIndex), index);
2245 } else if (mode == SwiperAnimationMode::DEFAULT_ANIMATION) {
2246 if (GetMaxDisplayCount() > 0) {
2247 SetIndicatorChangeIndexStatus(true);
2248 }
2249 SwipeTo(targetIndex);
2250 } else if (mode == SwiperAnimationMode::FAST_ANIMATION) {
2251 // skip to the tab near 3 to target
2252 FastAnimation(targetIndex);
2253 if (GetMaxDisplayCount() > 0) {
2254 SetIndicatorChangeIndexStatus(true);
2255 }
2256 SwipeTo(targetIndex);
2257 }
2258 }
2259
ComputeTargetIndex(int32_t index,int32_t & targetIndex) const2260 bool SwiperPattern::ComputeTargetIndex(int32_t index, int32_t& targetIndex) const
2261 {
2262 index = CheckIndexRange(index);
2263 auto itemCount = TotalCount();
2264 auto displayCount = GetDisplayCount();
2265 auto loopCount =
2266 itemCount == 0 ? 0 : (currentIndex_ >= 0 ? currentIndex_ / itemCount : (currentIndex_ + 1) / itemCount - 1);
2267 targetIndex = loopCount * itemCount + index;
2268 targetIndex = IsSwipeByGroup() ? SwiperUtils::ComputePageIndex(targetIndex, displayCount) : targetIndex;
2269 if (targetIndex_.has_value() && targetIndex_.value() == targetIndex) {
2270 return false;
2271 }
2272 return true;
2273 }
2274
SetCachedCount(int32_t cachedCount)2275 void SwiperPattern::SetCachedCount(int32_t cachedCount)
2276 {
2277 auto host = GetHost();
2278 FREE_NODE_CHECK(host, SetCachedCount, cachedCount);
2279 if (cachedCount_.has_value() && cachedCount_.value() != cachedCount) {
2280 SetLazyLoadFeature(true);
2281 }
2282 cachedCount_ = cachedCount;
2283 }
2284
ChangeIndex(int32_t index,bool useAnimation)2285 void SwiperPattern::ChangeIndex(int32_t index, bool useAnimation)
2286 {
2287 auto host = GetHost();
2288 FREE_NODE_CHECK(host, ChangeIndex, index, useAnimation);
2289 int32_t targetIndex = 0;
2290 if (!ComputeTargetIndex(index, targetIndex)) {
2291 return;
2292 }
2293
2294 fastCurrentIndex_.reset();
2295 targetIndex = CheckTargetIndex(targetIndex);
2296 if (useAnimation) {
2297 if (GetMaxDisplayCount() > 0) {
2298 SetIndicatorChangeIndexStatus(true);
2299 }
2300
2301 SwipeTo(targetIndex);
2302 } else {
2303 needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
2304
2305 if (GetMaxDisplayCount() > 0) {
2306 SetIndicatorChangeIndexStatus(false);
2307 }
2308
2309 SwipeToWithoutAnimation(GetLoopIndex(targetIndex), index);
2310 }
2311 }
2312
FinishAnimation()2313 void SwiperPattern::FinishAnimation()
2314 {
2315 if (translateAnimationIsRunning_) {
2316 isFinishAnimation_ = true;
2317 StopTranslateAnimation();
2318 }
2319 StopSpringAnimation();
2320 StopFadeAnimation();
2321 StopIndicatorAnimation(true);
2322 if (propertyAnimationIsRunning_) {
2323 isFinishAnimation_ = true;
2324 StopPropertyTranslateAnimation(isFinishAnimation_);
2325 }
2326 if (isUserFinish_) {
2327 if (swiperController_ && swiperController_->GetFinishCallback()) {
2328 auto finishCallback = swiperController_->GetFinishCallback();
2329 finishCallback();
2330 swiperController_->SetFinishCallback(nullptr);
2331 }
2332 } else {
2333 isUserFinish_ = true;
2334 }
2335 }
2336
PreloadItems(const std::set<int32_t> & indexSet)2337 void SwiperPattern::PreloadItems(const std::set<int32_t>& indexSet)
2338 {
2339 std::set<int32_t> validIndexSet;
2340 auto childrenSize = RealTotalCount();
2341 for (const auto& index : indexSet) {
2342 if (index < 0 || index >= childrenSize) {
2343 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
2344 "BusinessError 401: Parameter error. Each value in indices must be valid index value of child.");
2345 return;
2346 }
2347 validIndexSet.emplace(index);
2348 }
2349
2350 if (validIndexSet.empty()) {
2351 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
2352 "BusinessError 401: Parameter error. The parameter indices must be a non-empty array.");
2353 return;
2354 }
2355
2356 auto preloadTask = [weak = WeakClaim(this), id = GetHostInstanceId(), indexSet]() {
2357 ContainerScope scope(id);
2358 auto swiperPattern = weak.Upgrade();
2359 CHECK_NULL_VOID(swiperPattern);
2360 auto host = swiperPattern->GetHost();
2361 CHECK_NULL_VOID(host);
2362 auto parent = host->GetParent();
2363 if (AceType::InstanceOf<TabsNode>(parent)) {
2364 swiperPattern->DoTabsPreloadItems(indexSet);
2365 } else {
2366 swiperPattern->DoSwiperPreloadItems(indexSet);
2367 }
2368
2369 swiperPattern->FirePreloadFinishEvent(ERROR_CODE_NO_ERROR);
2370 };
2371
2372 auto pipeline = GetContext();
2373 CHECK_NULL_VOID(pipeline);
2374 auto taskExecutor = pipeline->GetTaskExecutor();
2375 CHECK_NULL_VOID(taskExecutor);
2376 taskExecutor->PostTask(preloadTask, TaskExecutor::TaskType::UI, "ArkUIFirePreloadFinish");
2377 }
2378
FirePreloadFinishEvent(int32_t errorCode,std::string message)2379 void SwiperPattern::FirePreloadFinishEvent(int32_t errorCode, std::string message)
2380 {
2381 if (swiperController_ && swiperController_->GetPreloadFinishCallback()) {
2382 auto preloadFinishCallback = swiperController_->GetPreloadFinishCallback();
2383 swiperController_->SetPreloadFinishCallback(nullptr);
2384 preloadFinishCallback(errorCode, message);
2385 }
2386 }
2387
DoTabsPreloadItems(const std::set<int32_t> & indexSet)2388 void SwiperPattern::DoTabsPreloadItems(const std::set<int32_t>& indexSet)
2389 {
2390 auto host = GetHost();
2391 CHECK_NULL_VOID(host);
2392 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
2393 CHECK_NULL_VOID(props);
2394 auto geometryNode = host->GetGeometryNode();
2395 CHECK_NULL_VOID(geometryNode);
2396 auto contentConstraint = props->GetContentLayoutConstraint();
2397 auto frameSize = OptionalSizeF(geometryNode->GetPaddingSize());
2398 auto childConstraint = SwiperUtils::CreateChildConstraint(props, frameSize, false);
2399 for (auto index : indexSet) {
2400 auto tabContent = GetCurrentFrameNode(index);
2401 if (!tabContent) {
2402 continue;
2403 }
2404 if (!tabContent->GetChildren().empty()) {
2405 continue;
2406 }
2407 auto tabContentPattern = tabContent->GetPattern<TabContentPattern>();
2408 if (!tabContentPattern) {
2409 continue;
2410 }
2411 tabContentPattern->BeforeCreateLayoutWrapper();
2412
2413 for (const auto& child : tabContent->GetChildren()) {
2414 child->Build(nullptr);
2415 }
2416 if (contentConstraint.has_value() && tabContent->GetGeometryNode()) {
2417 tabContent->GetGeometryNode()->SetParentLayoutConstraint(childConstraint);
2418 FrameNode::ProcessOffscreenNode(tabContent);
2419 }
2420 }
2421 }
2422
BuildForEachChild(const std::set<int32_t> & indexSet,const RefPtr<UINode> & child)2423 void SwiperPattern::BuildForEachChild(const std::set<int32_t>& indexSet, const RefPtr<UINode>& child)
2424 {
2425 auto childNode = FindForEachNode(child);
2426 if (!childNode) {
2427 return;
2428 }
2429
2430 auto forEachNode = AceType::DynamicCast<ForEachNode>(childNode.value());
2431 auto repeatNode = AceType::DynamicCast<RepeatVirtualScrollNode>(childNode.value());
2432 auto repeatNode2 = AceType::DynamicCast<RepeatVirtualScroll2Node>(childNode.value());
2433 for (auto index : indexSet) {
2434 if (forEachNode && forEachNode->GetChildAtIndex(index)) {
2435 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper preload item index: %{public}d, id:%{public}d", index, swiperId_);
2436 forEachNode->GetChildAtIndex(index)->Build(nullptr);
2437 continue;
2438 }
2439
2440 if (repeatNode) {
2441 repeatNode->GetFrameChildByIndex(index, true);
2442 }
2443
2444 if (repeatNode2) {
2445 repeatNode2->GetFrameChildByIndex(index, true);
2446 }
2447 }
2448 }
2449
DoSwiperPreloadItems(const std::set<int32_t> & indexSet)2450 void SwiperPattern::DoSwiperPreloadItems(const std::set<int32_t>& indexSet)
2451 {
2452 auto host = GetHost();
2453 CHECK_NULL_VOID(host);
2454 auto targetNode = FindLazyForEachNode(host);
2455 if (targetNode.has_value()) {
2456 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
2457 for (auto index : indexSet) {
2458 if (lazyForEachNode) {
2459 lazyForEachNode->GetFrameChildByIndex(index, true);
2460 }
2461 }
2462 }
2463 const auto& children = host->GetChildren();
2464 for (const auto& child : children) {
2465 BuildForEachChild(indexSet, child);
2466 }
2467 }
2468
OnTranslateAnimationFinish()2469 void SwiperPattern::OnTranslateAnimationFinish()
2470 {
2471 if (!translateAnimationIsRunning_) {
2472 return;
2473 }
2474 fastAnimationRunning_ = false;
2475 translateAnimationIsRunning_ = false;
2476 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
2477 }
2478
StopTranslateAnimation()2479 void SwiperPattern::StopTranslateAnimation()
2480 {
2481 if (translateAnimationIsRunning_) {
2482 auto host = GetHost();
2483 CHECK_NULL_VOID(host);
2484 fastAnimationRunning_ = false;
2485 translateAnimationIsRunning_ = false;
2486 prevFrameAnimationRunning_ = true;
2487
2488 if (NearZero(translateAnimationEndPos_ - currentOffset_)) {
2489 AnimationUtils::StopAnimation(translateAnimation_);
2490 fastCurrentIndex_.reset();
2491 targetIndex_.reset();
2492 } else {
2493 AnimationOption option;
2494 option.SetCurve(Curves::LINEAR);
2495 option.SetDuration(0);
2496 translateAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
2497 auto swiper = weak.Upgrade();
2498 CHECK_NULL_VOID(swiper);
2499 auto host = swiper->GetHost();
2500 CHECK_NULL_VOID(host);
2501 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, swiper->currentOffset_);
2502 }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, host->GetContextRefPtr());
2503 }
2504
2505 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_, true);
2506 }
2507 }
2508
StopSpringAnimationImmediately()2509 void SwiperPattern::StopSpringAnimationImmediately()
2510 {
2511 if (!springAnimationIsRunning_) {
2512 return;
2513 }
2514 auto host = GetHost();
2515 CHECK_NULL_VOID(host);
2516 AnimationOption option;
2517 option.SetCurve(Curves::LINEAR);
2518 option.SetDuration(0);
2519 springAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
2520 auto swiper = weak.Upgrade();
2521 CHECK_NULL_VOID(swiper);
2522 auto host = swiper->GetHost();
2523 CHECK_NULL_VOID(host);
2524 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, swiper->currentIndexOffset_);
2525 swiper->FireScrollStateEvent(ScrollState::IDLE);
2526 }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, host->GetContextRefPtr());
2527 OnSpringAnimationFinish();
2528 }
2529
StopSpringAnimation()2530 void SwiperPattern::StopSpringAnimation()
2531 {
2532 if (springAnimationIsRunning_) {
2533 AnimationUtils::StopAnimation(springAnimation_);
2534 }
2535 }
2536
StopFadeAnimation()2537 void SwiperPattern::StopFadeAnimation()
2538 {
2539 AnimationUtils::StopAnimation(fadeAnimation_);
2540 if (fadeAnimationIsRunning_) {
2541 fadeAnimationIsRunning_ = false;
2542 }
2543 }
2544
SaveIndicatorProperty(const RefPtr<FrameNode> & indicatorNode,SwiperIndicatorType swiperIndicatorType)2545 void SwiperPattern::SaveIndicatorProperty(
2546 const RefPtr<FrameNode>& indicatorNode, SwiperIndicatorType swiperIndicatorType)
2547 {
2548 if (swiperIndicatorType == SwiperIndicatorType::DOT) {
2549 SwiperHelper::SaveDotIndicatorProperty(indicatorNode, *this);
2550 } else if (swiperIndicatorType == SwiperIndicatorType::ARC_DOT) {
2551 SaveCircleDotIndicatorProperty(indicatorNode);
2552 } else {
2553 SwiperHelper::SaveDigitIndicatorProperty(indicatorNode, *this);
2554 }
2555 }
2556
InitIndicator()2557 void SwiperPattern::InitIndicator()
2558 {
2559 auto swiperNode = GetHost();
2560 CHECK_NULL_VOID(swiperNode);
2561 RefPtr<FrameNode> indicatorNode;
2562 auto indicatorType = GetIndicatorType();
2563 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
2564 CHECK_NULL_VOID(layoutProperty);
2565 hoverFlag_ = HasIndicatorNode() != IsShowIndicator() ? HOVER_NONE : hoverFlag_;
2566 if (!HasIndicatorNode()) {
2567 if (!IsShowIndicator()) {
2568 return;
2569 }
2570 if (layoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::ARC_DOT) {
2571 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, CreateIndicatorId(),
2572 []() { return AceType::MakeRefPtr<ArcSwiperIndicatorPattern>(); });
2573 } else {
2574 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, CreateIndicatorId(),
2575 [indicatorType]() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(indicatorType); });
2576 }
2577 swiperNode->UINode::AddChild(indicatorNode);
2578 } else {
2579 indicatorNode =
2580 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetIndicatorId())));
2581 CHECK_NULL_VOID(indicatorNode);
2582 if (!IsShowIndicator()) {
2583 RemoveIndicatorNode();
2584 return;
2585 }
2586 if ((indicatorType == SwiperIndicatorType::DIGIT && lastSwiperIndicatorType_ == SwiperIndicatorType::DOT) ||
2587 (indicatorType == SwiperIndicatorType::DOT && lastSwiperIndicatorType_ == SwiperIndicatorType::DIGIT)) {
2588 RemoveIndicatorNode();
2589 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, CreateIndicatorId(),
2590 [indicatorType]() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(indicatorType); });
2591 swiperNode->UINode::AddChild(indicatorNode);
2592 }
2593 }
2594 lastSwiperIndicatorType_ = indicatorType;
2595 CHECK_NULL_VOID(indicatorNode);
2596 SaveIndicatorProperty(indicatorNode, layoutProperty->GetIndicatorTypeValue(SwiperIndicatorType::DOT));
2597
2598 auto renderContext = indicatorNode->GetRenderContext();
2599 CHECK_NULL_VOID(renderContext);
2600 BorderRadiusProperty radius;
2601 radius.SetRadius(INDICATOR_BORDER_RADIUS);
2602 renderContext->UpdateBorderRadius(radius);
2603
2604 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
2605 indicatorPattern->SetIndicatorInteractive(isIndicatorInteractive_);
2606
2607 indicatorNode->MarkModifyDone();
2608 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2609 }
2610
InitArrow()2611 void SwiperPattern::InitArrow()
2612 {
2613 auto swiperNode = GetHost();
2614 CHECK_NULL_VOID(swiperNode);
2615 RefPtr<FrameNode> leftArrow;
2616 RefPtr<FrameNode> rightArrow;
2617 if (!HasLeftButtonNode() && !HasRightButtonNode()) {
2618 if (!IsShowArrow()) {
2619 return;
2620 }
2621 leftArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_LEFT_ARROW_ETS_TAG, GetLeftButtonId(),
2622 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2623 swiperNode->AddChild(leftArrow);
2624 rightArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_ARROW_ETS_TAG, GetRightButtonId(),
2625 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2626 swiperNode->AddChild(rightArrow);
2627 } else {
2628 leftArrow =
2629 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
2630 CHECK_NULL_VOID(leftArrow);
2631 rightArrow =
2632 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
2633 CHECK_NULL_VOID(rightArrow);
2634 if (!IsShowArrow()) {
2635 RemoveLeftButtonNode();
2636 RemoveRightButtonNode();
2637 return;
2638 }
2639 }
2640
2641 SaveArrowProperty(leftArrow);
2642 SaveArrowProperty(rightArrow);
2643
2644 leftArrow->MarkModifyDone();
2645 rightArrow->MarkModifyDone();
2646 }
2647
CheckAndReportEvent()2648 void SwiperPattern::CheckAndReportEvent()
2649 {
2650 if (gestureStatus_ == GestureStatus::INIT || gestureStatus_ == GestureStatus::END) {
2651 gestureStatus_ = GestureStatus::START;
2652 return;
2653 }
2654
2655 EventReport::ReportScrollableErrorEvent(
2656 "Swiper", ScrollableErrorType::GESTURE_MISMATCH, "Swiper previous pan event lost end.");
2657 }
2658
ActionStartTask()2659 SwiperPattern::PanEventFunction SwiperPattern::ActionStartTask()
2660 {
2661 return [weak = WeakClaim(this)](const GestureEvent& info) {
2662 auto pattern = weak.Upgrade();
2663 CHECK_NULL_VOID(pattern);
2664 pattern->CheckAndReportEvent();
2665 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag start. SourceTool: %{public}d, id:%{public}d",
2666 info.GetSourceTool(), pattern->swiperId_);
2667 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2668 pattern->isFirstAxisAction_ = true;
2669 return;
2670 }
2671 pattern->FireAndCleanScrollingListener();
2672 pattern->HandleDragStart(info);
2673 // notify scrollStart upwards
2674 pattern->NotifyParentScrollStart(weak, pattern->direction_ == Axis::HORIZONTAL
2675 ? info.GetGlobalLocation().GetX()
2676 : info.GetGlobalLocation().GetY());
2677 };
2678 }
2679
ActionUpdateTask()2680 SwiperPattern::PanEventFunction SwiperPattern::ActionUpdateTask()
2681 {
2682 return [weak = WeakClaim(this)](const GestureEvent& info) {
2683 auto pattern = weak.Upgrade();
2684 CHECK_NULL_VOID(pattern);
2685 auto infoChecked = info;
2686 // Reverse velocity and delta when receiving.
2687 if (pattern->IsHorizontalAndRightToLeft()) {
2688 infoChecked.SetMainVelocity(-info.GetMainVelocity());
2689 infoChecked.SetMainDelta(-info.GetMainDelta());
2690 }
2691 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2692 if (pattern->isFirstAxisAction_) {
2693 pattern->isFirstAxisAction_ = false;
2694 } else if (pattern->pageFlipMode_ == PageFlipMode::SINGLE &&
2695 (pattern->propertyAnimationIsRunning_ || pattern->translateAnimationIsRunning_)) {
2696 return;
2697 }
2698 if (!pattern->CheckSwiperPanEvent(infoChecked.GetMainDelta())) {
2699 return;
2700 }
2701 if (GreatNotEqual(infoChecked.GetMainDelta(), 0.0)) {
2702 pattern->ShowPrevious(true);
2703 } else if (LessNotEqual(infoChecked.GetMainDelta(), 0.0)) {
2704 pattern->ShowNext(true);
2705 }
2706 } else {
2707 pattern->HandleDragUpdate(infoChecked);
2708 }
2709 };
2710 }
2711
ActionEndTask()2712 SwiperPattern::PanEventFunction SwiperPattern::ActionEndTask()
2713 {
2714 return [weak = WeakClaim(this)](const GestureEvent& info) {
2715 auto pattern = weak.Upgrade();
2716 CHECK_NULL_VOID(pattern);
2717 pattern->SetGestureStatus(GestureStatus::END);
2718 TAG_LOGI(AceLogTag::ACE_SWIPER,
2719 "Swiper drag end. Velocity: %{public}f px/s, SourceTool: %{public}d id:%{public}d", info.GetMainVelocity(),
2720 info.GetSourceTool(), pattern->swiperId_);
2721 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2722 pattern->InitIndexCanChangeMap();
2723 return;
2724 }
2725 bool isUsingTouchPad =
2726 (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD);
2727 auto velocity =
2728 isUsingTouchPad ? info.GetMainVelocity() * pattern->GetVelocityCoefficient() : info.GetMainVelocity();
2729 // Reverse velocity when receiving.
2730 velocity = pattern->IsHorizontalAndRightToLeft() ? -velocity : velocity;
2731 auto mainDelta = pattern->IsHorizontalAndRightToLeft() ? -info.GetMainDelta() : info.GetMainDelta();
2732 pattern->HandleDragEnd(velocity, mainDelta);
2733 pattern->InitIndexCanChangeMap();
2734 if (LessOrEqual(std::abs(velocity), pattern->newMinTurnPageVelocity_) &&
2735 std::abs(velocity) > MIN_DUMP_VELOCITY_THRESHOLD) {
2736 auto host = pattern->GetHost();
2737 CHECK_NULL_VOID(host);
2738 auto eventHub = host->GetOrCreateEventHub<EventHub>();
2739 CHECK_NULL_VOID(eventHub);
2740 auto gestureEventHub = eventHub->GetOrCreateGestureEventHub();
2741 CHECK_NULL_VOID(gestureEventHub);
2742 gestureEventHub->DumpVelocityInfoFroPanEvent(info.GetPointerId());
2743 }
2744 };
2745 }
2746
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)2747 void SwiperPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
2748 {
2749 if (direction_ == GetDirection() && panEvent_) {
2750 return;
2751 }
2752 // fade offset need to be reset when is still dragging
2753 if (direction_ != GetDirection()) {
2754 fadeOffset_ = 0.f;
2755 }
2756 direction_ = GetDirection();
2757
2758 auto actionCancelTask = [weak = WeakClaim(this)]() {
2759 auto pattern = weak.Upgrade();
2760 if (pattern) {
2761 pattern->SetGestureStatus(GestureStatus::END);
2762 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag cancel id:%{public}d", pattern->swiperId_);
2763 pattern->HandleDragEnd(0.0);
2764 pattern->InitIndexCanChangeMap();
2765 }
2766 };
2767
2768 AddPanEvent(gestureHub, ActionStartTask(), ActionUpdateTask(), ActionEndTask(), std::move(actionCancelTask));
2769 }
2770
AddPanEvent(const RefPtr<GestureEventHub> & gestureHub,GestureEventFunc && actionStart,GestureEventFunc && actionUpdate,GestureEventFunc && actionEnd,GestureEventNoParameter && actionCancel)2771 void SwiperPattern::AddPanEvent(const RefPtr<GestureEventHub>& gestureHub, GestureEventFunc&& actionStart,
2772 GestureEventFunc&& actionUpdate, GestureEventFunc&& actionEnd, GestureEventNoParameter&& actionCancel)
2773 {
2774 if (GetDirection() == Axis::VERTICAL) {
2775 panDirection_.type = PanDirection::VERTICAL;
2776 } else {
2777 panDirection_.type = PanDirection::HORIZONTAL;
2778 }
2779 if (panEvent_) {
2780 gestureHub->RemovePanEvent(panEvent_);
2781 }
2782
2783 panEvent_ = MakeRefPtr<PanEvent>(
2784 std::move(actionStart), std::move(actionUpdate), std::move(actionEnd), std::move(actionCancel));
2785 PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
2786 { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
2787 gestureHub->AddPanEvent(panEvent_, panDirection_, 1, distanceMap);
2788 }
2789
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)2790 void SwiperPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
2791 {
2792 if (touchEvent_) {
2793 return;
2794 }
2795
2796 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2797 auto pattern = weak.Upgrade();
2798 if (pattern) {
2799 pattern->HandleTouchEvent(info);
2800 }
2801 };
2802
2803 if (touchEvent_) {
2804 gestureHub->RemoveTouchEvent(touchEvent_);
2805 }
2806 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2807 gestureHub->AddTouchEvent(touchEvent_);
2808 }
2809
InitOnFocusInternal(const RefPtr<FocusHub> & focusHub)2810 void SwiperPattern::InitOnFocusInternal(const RefPtr<FocusHub>& focusHub)
2811 {
2812 auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
2813 auto pattern = weak.Upgrade();
2814 if (pattern) {
2815 pattern->HandleFocusInternal();
2816 }
2817 };
2818 focusHub->SetOnFocusInternal(std::move(focusTask));
2819 }
2820
HandleFocusInternal()2821 void SwiperPattern::HandleFocusInternal()
2822 {
2823 currentFocusIndex_ = currentIndex_;
2824
2825 auto host = GetHost();
2826 CHECK_NULL_VOID(host);
2827 auto focusHub = host->GetFocusHub();
2828 CHECK_NULL_VOID(focusHub);
2829 auto lastFocusNode = focusHub->GetLastWeakFocusNode().Upgrade();
2830 CHECK_NULL_VOID(lastFocusNode);
2831 for (const auto& item : itemPosition_) {
2832 auto itemNode = GetCurrentFrameNode(item.first);
2833 if (!itemNode) {
2834 continue;
2835 }
2836 if (itemNode->GetFirstFocusHubChild() == lastFocusNode) {
2837 currentFocusIndex_ = item.first;
2838 return;
2839 }
2840 }
2841 }
2842
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)2843 void SwiperPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
2844 {
2845 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
2846 auto pattern = wp.Upgrade();
2847 if (pattern) {
2848 return pattern->OnKeyEvent(event);
2849 }
2850 return false;
2851 };
2852 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
2853 }
2854
IsContentFocused()2855 bool SwiperPattern::IsContentFocused()
2856 {
2857 auto swiperHost = GetHost();
2858 CHECK_NULL_RETURN(swiperHost, true);
2859 auto swiperFocusHub = swiperHost->GetFocusHub();
2860 CHECK_NULL_RETURN(swiperFocusHub, true);
2861 bool ret = true;
2862 swiperFocusHub->AnyChildFocusHub([&ret](const RefPtr<FocusHub>& child) {
2863 if (!child || !child->IsCurrentFocus()) {
2864 return false;
2865 }
2866 auto frameName = child->GetFrameName();
2867 if (frameName == V2::SWIPER_INDICATOR_ETS_TAG || frameName == V2::SWIPER_RIGHT_ARROW_ETS_TAG ||
2868 frameName == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
2869 ret = false;
2870 }
2871 return true;
2872 });
2873 return ret;
2874 }
2875
IsContentChildFocusable(int32_t childIndex) const2876 bool SwiperPattern::IsContentChildFocusable(int32_t childIndex) const
2877 {
2878 auto child = GetCurrentFrameNode(childIndex);
2879 CHECK_NULL_RETURN(child, false);
2880 auto focusHub = child->GetFocusHub();
2881 CHECK_NULL_RETURN(focusHub, false);
2882 return focusHub->IsFocusable();
2883 }
2884
FindFocusableContentIndex(MoveStep moveStep)2885 bool SwiperPattern::FindFocusableContentIndex(MoveStep moveStep)
2886 {
2887 if (itemPosition_.empty()) {
2888 return false;
2889 }
2890 if (!IsContentFocused() || GetDisplayCount() <= 1) {
2891 return false;
2892 }
2893 if (moveStep == MoveStep::PREV) {
2894 auto endIndex = itemPosition_.begin()->first;
2895 for (auto i = currentFocusIndex_ - 1; i >= endIndex; --i) {
2896 currentFocusIndex_ = i;
2897 if (IsContentChildFocusable(i)) {
2898 return true;
2899 }
2900 }
2901 } else if (moveStep == MoveStep::NEXT) {
2902 auto endIndex = itemPosition_.rbegin()->first;
2903 for (auto i = currentFocusIndex_ + 1; i <= endIndex; ++i) {
2904 currentFocusIndex_ = i;
2905 if (IsContentChildFocusable(i)) {
2906 return true;
2907 }
2908 }
2909 }
2910 return false;
2911 }
2912
OnKeyEvent(const KeyEvent & event)2913 bool SwiperPattern::OnKeyEvent(const KeyEvent& event)
2914 {
2915 if (event.action != KeyAction::DOWN) {
2916 return false;
2917 }
2918 auto step = GetKeyMoveStep(event, GetDirection(), IsHorizontalAndRightToLeft());
2919 if (step == MoveStep::NONE) {
2920 return false;
2921 }
2922 if (FindFocusableContentIndex(step)) {
2923 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2924 } else {
2925 if (step == MoveStep::PREV) {
2926 ShowPrevious(true);
2927 currentFocusIndex_ =
2928 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2929 } else {
2930 ShowNext(true);
2931 currentFocusIndex_ =
2932 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2933 }
2934 }
2935 return true;
2936 }
2937
StopAutoPlay()2938 void SwiperPattern::StopAutoPlay()
2939 {
2940 if (IsAutoPlay()) {
2941 isInAutoPlay_ = false;
2942 translateTask_.Cancel();
2943 }
2944 }
2945
StartAutoPlay()2946 void SwiperPattern::StartAutoPlay()
2947 {
2948 if (NeedAutoPlay() && !translateAnimationIsRunning_ && !propertyAnimationIsRunning_) {
2949 PostTranslateTask(GetInterval());
2950 }
2951 }
2952
OnVisibleChange(bool isVisible)2953 void SwiperPattern::OnVisibleChange(bool isVisible)
2954 {
2955 isVisible_ = isVisible;
2956 if (isInit_) {
2957 return;
2958 }
2959
2960 if (!isVisible_) {
2961 StopAutoPlay();
2962 return;
2963 }
2964
2965 if (NeedStartAutoPlay()) {
2966 StartAutoPlay();
2967 }
2968 }
2969
UpdateCurrentOffset(float offset)2970 void SwiperPattern::UpdateCurrentOffset(float offset)
2971 {
2972 if (itemPosition_.empty()) {
2973 MarkDirtyNodeSelf();
2974 return;
2975 }
2976 if (!IsLoop() && (isDragging_ || childScrolling_)) {
2977 // handle edge effects
2978 if (CheckOverScroll(offset)) {
2979 ResetCurrentFrameNodeAnimation();
2980 return;
2981 }
2982 }
2983 if (!IsLoop() && GetEdgeEffect() != EdgeEffect::SPRING && IsOutOfBoundary(offset)) {
2984 offset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2985 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2986 }
2987 currentDelta_ -= offset;
2988 currentIndexOffset_ += offset;
2989 if (isDragging_ || childScrolling_) {
2990 AnimationCallbackInfo callbackInfo;
2991 callbackInfo.currentOffset =
2992 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2993 if (IsHorizontalAndRightToLeft()) {
2994 callbackInfo.currentOffset =
2995 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2996 }
2997 bool skipGestureSwipe = TotalCount() == 1 && GetEdgeEffect() == EdgeEffect::NONE;
2998 if (!skipGestureSwipe) {
2999 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
3000 }
3001 }
3002 HandleSwiperCustomAnimation(-currentDelta_);
3003 MarkDirtyNodeSelf();
3004 }
3005
CheckOverScroll(float offset)3006 bool SwiperPattern::CheckOverScroll(float offset)
3007 {
3008 switch (GetEdgeEffect()) {
3009 case EdgeEffect::SPRING:
3010 if (SpringOverScroll(offset)) {
3011 return true;
3012 }
3013 break;
3014 case EdgeEffect::FADE:
3015 if (FadeOverScroll(offset)) {
3016 return true;
3017 }
3018 break;
3019 case EdgeEffect::NONE:
3020 if (IsOutOfBoundary(offset)) {
3021 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
3022 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
3023 currentDelta_ -= realOffset;
3024 HandleSwiperCustomAnimation(realOffset);
3025 MarkDirtyNodeSelf();
3026 return true;
3027 }
3028 break;
3029 }
3030 return false;
3031 }
3032
SpringOverScroll(float offset)3033 bool SwiperPattern::SpringOverScroll(float offset)
3034 {
3035 bool outOfBounds = IsOutOfBoundary(offset);
3036 if (!outOfBounds) {
3037 springOffset_ = 0.0f;
3038 return false;
3039 }
3040
3041 ResetParentNodeColor();
3042 auto visibleSize = CalculateVisibleSize();
3043 if (LessOrEqual(visibleSize, 0.0)) {
3044 return true;
3045 }
3046 auto currentRealOffset = springOffset_ * SwiperHelper::CalculateFriction(std::abs(springOffset_ / visibleSize));
3047 auto delta = 0.0f;
3048 if (IsOutOfBoundary()) {
3049 springOffset_ += offset;
3050 } else {
3051 if (offset > 0) {
3052 springOffset_ = itemPosition_.begin()->second.startPos + offset + AdjustIgnoreBlankOverScrollOffSet(true);
3053 } else {
3054 springOffset_ =
3055 itemPosition_.rbegin()->second.endPos + offset - visibleSize + AdjustIgnoreBlankOverScrollOffSet(false);
3056 }
3057 delta = offset - springOffset_;
3058 }
3059 if (std::abs(springOffset_) > visibleSize) {
3060 springOffset_ = springOffset_ > 0 ? visibleSize : -visibleSize;
3061 }
3062 auto realOffset = springOffset_ * SwiperHelper::CalculateFriction(std::abs(springOffset_ / visibleSize));
3063 delta += (realOffset - currentRealOffset);
3064 currentDelta_ -= delta;
3065 currentIndexOffset_ += delta;
3066 AnimationCallbackInfo callbackInfo;
3067 callbackInfo.currentOffset =
3068 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3069 if (IsHorizontalAndRightToLeft()) {
3070 callbackInfo.currentOffset =
3071 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3072 }
3073
3074 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
3075 HandleSwiperCustomAnimation(delta);
3076 MarkDirtyNodeSelf();
3077 return true;
3078 }
3079
FadeOverScroll(float offset)3080 bool SwiperPattern::FadeOverScroll(float offset)
3081 {
3082 if (IsOutOfBoundary(fadeOffset_ + offset)) {
3083 if (!IsVisibleChildrenSizeLessThanSwiper() && NearZero(fadeOffset_)) {
3084 UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart(offset));
3085 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
3086 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
3087 currentDelta_ -= realOffset;
3088 offset -= realOffset;
3089 HandleSwiperCustomAnimation(realOffset);
3090 }
3091 fadeOffset_ += offset;
3092 auto host = GetHost();
3093 CHECK_NULL_RETURN(host, false);
3094 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3095 MarkDirtyNodeSelf();
3096 return true;
3097 }
3098 fadeOffset_ = 0.0f;
3099 return false;
3100 }
3101
IsHorizontalAndRightToLeft() const3102 bool SwiperPattern::IsHorizontalAndRightToLeft() const
3103 {
3104 auto host = GetHost();
3105 if (hasTabsAncestor_ && host) {
3106 host = AceType::DynamicCast<FrameNode>(host->GetParent());
3107 }
3108 CHECK_NULL_RETURN(host, false);
3109 CHECK_NULL_RETURN(host->GetLayoutProperty(), false);
3110 return GetDirection() == Axis::HORIZONTAL &&
3111 host->GetLayoutProperty()->GetNonAutoLayoutDirection() == TextDirection::RTL;
3112 }
3113
GetNonAutoLayoutDirection() const3114 TextDirection SwiperPattern::GetNonAutoLayoutDirection() const
3115 {
3116 auto host = GetHost();
3117 CHECK_NULL_RETURN(host, TextDirection::LTR);
3118 CHECK_NULL_RETURN(host->GetLayoutProperty(), TextDirection::LTR);
3119 return host->GetLayoutProperty()->GetNonAutoLayoutDirection();
3120 }
3121
UpdateNextValidIndex()3122 void SwiperPattern::UpdateNextValidIndex()
3123 {
3124 // item may be invalid in auto linear scene, mark next valid item
3125 if (IsAutoLinear()) {
3126 currentFirstIndex_ = CheckTargetIndex(currentFirstIndex_, true);
3127 nextValidIndex_ = GetLoopIndex(CheckTargetIndex(currentFirstIndex_ + 1, true));
3128 } else {
3129 nextValidIndex_ = -1;
3130 }
3131 }
3132
CheckMarkDirtyNodeForRenderIndicator(float additionalOffset,std::optional<int32_t> nextIndex)3133 void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset, std::optional<int32_t> nextIndex)
3134 {
3135 additionalOffset = IsHorizontalAndRightToLeft() ? -additionalOffset : additionalOffset;
3136 if (!HasIndicatorNode()) {
3137 return;
3138 }
3139 auto child = GetCommonIndicatorNode();
3140 CHECK_NULL_VOID(child);
3141
3142 if (!IsIndicator(child->GetTag())) {
3143 return;
3144 }
3145
3146 int32_t preFirstIndex = currentFirstIndex_;
3147 auto currentPageStatus = (IsHorizontalAndRightToLeft() && GetMaxDisplayCount() > 0)
3148 ? CalcCurrentPageStatusOnRTL(additionalOffset)
3149 : CalcCurrentPageStatus(additionalOffset);
3150 float currentTurnPageRate = currentPageStatus.first;
3151 currentFirstIndex_ = currentPageStatus.second;
3152
3153 groupTurnPageRate_ =
3154 (!IsAutoLinear() && IsSwipeByGroup() ? CalculateGroupTurnPageRate(additionalOffset) : 0.0f);
3155 currentFirstIndex_ = nextIndex.value_or(currentFirstIndex_);
3156 UpdateNextValidIndex();
3157 currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
3158 auto isRtl = IsHorizontalAndRightToLeft() && GetMaxDisplayCount() <= 0;
3159 isRtl ? CalculateGestureStateOnRTL(additionalOffset, currentTurnPageRate, preFirstIndex)
3160 : CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
3161 turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
3162 turnPageRate_ = isRtl ? std::abs(turnPageRate_) - 1.0f : turnPageRate_;
3163 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
3164 CheckMarkForIndicatorBoundary();
3165 isRtl ? HandleTouchBottomLoopOnRTL() : HandleTouchBottomLoop();
3166
3167 if (IsVisibleChildrenSizeLessThanSwiper()) {
3168 turnPageRate_ = 0.0f;
3169 groupTurnPageRate_ = 0.0f;
3170 gestureState_ = GestureState::GESTURE_STATE_NONE;
3171 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
3172 }
3173
3174 if (!indicatorDoingAnimation_) {
3175 child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3176 }
3177 if (GetLoopIndex(currentIndex_) != currentFirstIndex_) {
3178 auto swiperEventHub = GetOrCreateEventHub<SwiperEventHub>();
3179 CHECK_NULL_VOID(swiperEventHub);
3180 swiperEventHub->FireIndicatorChangeEvent(currentFirstIndex_);
3181 }
3182 }
3183
CheckMarkForIndicatorBoundary()3184 void SwiperPattern::CheckMarkForIndicatorBoundary()
3185 {
3186 bool isRtl = IsHorizontalAndRightToLeft();
3187
3188 auto startIndex = isRtl ? TotalCount() - 1 : 0;
3189 auto endIndex = isRtl ? 0 : TotalCount() - 1;
3190 if (!IsLoop() && ((currentFirstIndex_ == startIndex && GreatNotEqualCustomPrecision(turnPageRate_, 0.0f)) ||
3191 (currentFirstIndex_ == endIndex && LessNotEqualCustomPrecision(turnPageRate_, 0.0f)))) {
3192 return;
3193 }
3194 }
3195
CalculateGroupTurnPageRate(float additionalOffset)3196 float SwiperPattern::CalculateGroupTurnPageRate(float additionalOffset)
3197 {
3198 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3199 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3200 auto firstItemIndex = firstItemInfoInVisibleArea.first;
3201 auto displayCount = GetDisplayCount();
3202 auto itemSpace = GetItemSpace();
3203 auto swiperWidth = CalculateVisibleSize();
3204 auto totalCount = TotalCount();
3205 float groupTurnPageRate = FLT_MAX;
3206 float currentStartPos = 0.0f;
3207
3208 if (swiperWidth == 0 || displayCount == 0 || totalCount == 0) {
3209 return 0.0f;
3210 }
3211 if (itemPosition_.empty() || itemPosition_.find(firstItemIndex) == itemPosition_.end()) {
3212 return 0.0f;
3213 }
3214 if (firstItemIndex >= currentIndex_) {
3215 currentStartPos = itemPosition_[firstItemIndex].startPos -
3216 (itemSpace + firstItemLength) * (firstItemIndex - currentIndex_);
3217
3218 if (currentStartPos > 0) {
3219 return 0.0f;
3220 }
3221 if (!IsLoop() && firstItemIndex % totalCount >= totalCount - displayCount) {
3222 return 0.0f;
3223 }
3224
3225 groupTurnPageRate = NearZero(swiperWidth) ? 0 : (currentStartPos + additionalOffset) / swiperWidth;
3226 } else if (firstItemIndex < currentIndex_) {
3227 currentStartPos = itemPosition_[firstItemIndex].startPos - (itemSpace + firstItemLength) *
3228 (displayCount - ((currentIndex_ - firstItemIndex) - 1) % displayCount - 1);
3229
3230 if (currentStartPos > 0) {
3231 return 0.0f;
3232 }
3233
3234 groupTurnPageRate = NearZero(swiperWidth) ? 0 :(currentStartPos + additionalOffset) / swiperWidth;
3235 } else {
3236 groupTurnPageRate = 0.0f;
3237 }
3238
3239 if (IsHorizontalAndRightToLeft()) {
3240 groupTurnPageRate = std::abs(groupTurnPageRate) <= 1.0f ? std::abs(groupTurnPageRate) - 1.0f : 0.0f;
3241 }
3242
3243 return (groupTurnPageRate == FLT_MAX ? groupTurnPageRate_ : groupTurnPageRate);
3244 }
3245
CalculateStepAndItemCount() const3246 std::pair<int32_t, int32_t> SwiperPattern::CalculateStepAndItemCount() const
3247 {
3248 if (IsAutoLinear()) {
3249 return { RealTotalCount(), 1 };
3250 }
3251 auto displaycount = GetDisplayCount();
3252
3253 int32_t itemCount = (IsSwipeByGroup() ? TotalCount() : DisplayIndicatorTotalCount());
3254 int32_t step = (IsSwipeByGroup() ? displaycount : 1);
3255
3256 return { itemCount, step };
3257 }
3258
UpdateAnimationProperty(float velocity)3259 void SwiperPattern::UpdateAnimationProperty(float velocity)
3260 {
3261 if (fastAnimationRunning_) {
3262 return;
3263 }
3264 if (isDragging_ || childScrolling_) {
3265 targetIndex_ = CheckTargetIndex(ComputeNextIndexByVelocity(velocity));
3266 velocity_ = velocity;
3267 } else {
3268 targetIndex_ = pauseTargetIndex_;
3269 velocity_ = velocity;
3270 }
3271
3272 MarkDirtyNodeSelf();
3273 moveDirection_ = velocity <= 0;
3274 }
3275
NestedScrollToParent(float velocity)3276 void SwiperPattern::NestedScrollToParent(float velocity)
3277 {
3278 auto parent = GetNestedScrollParent();
3279 if (NearZero(GetDistanceToEdge())) {
3280 ResetCurrentFrameNodeAnimation();
3281 }
3282 if (!IsLoop() && parent && NearZero(GetDistanceToEdge())) {
3283 parent->HandleScrollVelocity(velocity);
3284 StartAutoPlay();
3285 } else {
3286 NotifyParentScrollEnd();
3287 }
3288 }
3289
HandleTouchEvent(const TouchEventInfo & info)3290 void SwiperPattern::HandleTouchEvent(const TouchEventInfo& info)
3291 {
3292 if (info.GetTouches().empty()) {
3293 return;
3294 }
3295 auto locationInfo = info.GetTouches().front();
3296 auto touchType = locationInfo.GetTouchType();
3297 if (touchType == TouchType::DOWN) {
3298 HandleTouchDown(locationInfo);
3299 } else if (touchType == TouchType::UP) {
3300 HandleTouchUp();
3301 } else if (touchType == TouchType::CANCEL) {
3302 HandleTouchUp();
3303 }
3304 }
3305
InsideIndicatorRegion(const TouchLocationInfo & locationInfo)3306 bool SwiperPattern::InsideIndicatorRegion(const TouchLocationInfo& locationInfo)
3307 {
3308 auto host = GetHost();
3309 CHECK_NULL_RETURN(host, false);
3310 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
3311 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
3312 return false;
3313 }
3314 auto geometryNode = indicatorNode->GetGeometryNode();
3315 CHECK_NULL_RETURN(geometryNode, false);
3316 auto hotRegion = geometryNode->GetFrameRect();
3317 auto touchPoint = PointF(static_cast<float>(locationInfo.GetLocalLocation().GetX()),
3318 static_cast<float>(locationInfo.GetLocalLocation().GetY()));
3319 return hotRegion.IsInRegion(touchPoint);
3320 }
3321
UpdateOverlongForceStopPageRate(float forceStopPageRate)3322 void SwiperPattern::UpdateOverlongForceStopPageRate(float forceStopPageRate)
3323 {
3324 CHECK_NULL_VOID(updateOverlongForceStopPageRateFunc_);
3325 updateOverlongForceStopPageRateFunc_(forceStopPageRate);
3326 }
3327
HandleTouchDown(const TouchLocationInfo & locationInfo)3328 void SwiperPattern::HandleTouchDown(const TouchLocationInfo& locationInfo)
3329 {
3330 ACE_SCOPED_TRACE("Swiper HandleTouchDown");
3331 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchDown id: %{public}d", swiperId_);
3332 isTouchDown_ = true;
3333 isTouchDownOnOverlong_ = true;
3334 if (InsideIndicatorRegion(locationInfo)) {
3335 return;
3336 }
3337
3338 if (childScrolling_) {
3339 // Even if the child fails to notify scrollEnd, we reset childScrolling_ flag on TouchDown to ensure its
3340 // value is correct.
3341 childScrolling_ = false;
3342 }
3343
3344 if (!stopWhenTouched_) {
3345 return;
3346 }
3347 auto isOverlongIndicator = GetMaxDisplayCount() > 0;
3348 if (!isOverlongIndicator) {
3349 StopIndicatorAnimation(true);
3350 }
3351
3352 if (propertyAnimationIsRunning_) {
3353 StopPropertyTranslateAnimation(isFinishAnimation_);
3354 }
3355
3356 if (isOverlongIndicator) {
3357 UpdateOverlongForceStopPageRate(CalcCurrentTurnPageRate());
3358 StopIndicatorAnimation(true);
3359 }
3360
3361 indicatorDoingAnimation_ = false;
3362 // Stop translate animation when touch down.
3363 if (translateAnimationIsRunning_) {
3364 StopTranslateAnimation();
3365 }
3366
3367 if (springAnimationIsRunning_) {
3368 AnimationUtils::PauseAnimation(springAnimation_);
3369 isTouchDownSpringAnimation_ = true;
3370 }
3371
3372 AnimationUtils::PauseAnimation(fadeAnimation_);
3373 if (fadeAnimationIsRunning_) {
3374 isTouchDownFadeAnimation_ = true;
3375 }
3376
3377 // Stop auto play when touch down.
3378 StopAutoPlay();
3379 }
3380
HandleTouchUp()3381 void SwiperPattern::HandleTouchUp()
3382 {
3383 ACE_SCOPED_TRACE("Swiper HandleTouchUp");
3384 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchUp id: %{public}d", swiperId_);
3385 isTouchDown_ = false;
3386 isTouchDownOnOverlong_ = false;
3387 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3388 if (!isDragging_ && !childScrolling_ && !NearZero(firstItemInfoInVisibleArea.second.startPos) &&
3389 !springAnimationIsRunning_) {
3390 UpdateAnimationProperty(0.0);
3391 }
3392
3393 if (springAnimationIsRunning_ && isTouchDownSpringAnimation_) {
3394 isTouchDownSpringAnimation_ = false;
3395 AnimationUtils::ResumeAnimation(springAnimation_);
3396 }
3397
3398 if (fadeAnimationIsRunning_ && isTouchDownFadeAnimation_) {
3399 isTouchDownFadeAnimation_ = false;
3400 AnimationUtils::ResumeAnimation(fadeAnimation_);
3401 }
3402
3403 if (!isDragging_) {
3404 StartAutoPlay();
3405 }
3406
3407 if (GetMaxDisplayCount() > 0) {
3408 UpdateOverlongForceStopPageRate(FLT_MAX);
3409 }
3410 }
3411
HandleDragStart(const GestureEvent & info)3412 void SwiperPattern::HandleDragStart(const GestureEvent& info)
3413 {
3414 if (!hasTabsAncestor_) {
3415 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_SWIPER_SCROLL,
3416 PerfActionType::FIRST_MOVE, "");
3417 } else {
3418 AceAsyncTraceBeginCommercial(0, APP_TABS_SCROLL);
3419 }
3420 UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::START);
3421 StopAnimationOnScrollStart(
3422 info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD, true);
3423 StopAutoPlay();
3424
3425 const auto& tabBarFinishCallback = swiperController_->GetTabBarFinishCallback();
3426 if (tabBarFinishCallback) {
3427 tabBarFinishCallback();
3428 }
3429
3430 const auto& removeEventCallback = swiperController_->GetRemoveTabBarEventCallback();
3431 if (removeEventCallback) {
3432 removeEventCallback();
3433 }
3434
3435 gestureSwipeIndex_ = currentIndex_;
3436 isDragging_ = true;
3437 isTouchDown_ = true;
3438 isTouchDownOnOverlong_ = true;
3439 mainDeltaSum_ = 0.0f;
3440 ResetAnimationParam();
3441 // in drag process, close lazy feature.
3442 SetLazyLoadFeature(false);
3443 }
3444
StopAnimationOnScrollStart(bool flushImmediately,bool stopLongPointAnimation)3445 void SwiperPattern::StopAnimationOnScrollStart(bool flushImmediately, bool stopLongPointAnimation)
3446 {
3447 if (propertyAnimationIsRunning_) {
3448 StopPropertyTranslateAnimation(isFinishAnimation_);
3449 }
3450 StopIndicatorAnimation(stopLongPointAnimation);
3451 StopTranslateAnimation();
3452 StopFadeAnimation();
3453 if (flushImmediately) {
3454 StopSpringAnimationAndFlushImmediately();
3455 } else {
3456 StopSpringAnimationImmediately();
3457 }
3458 }
3459
HandleDragUpdate(const GestureEvent & info)3460 void SwiperPattern::HandleDragUpdate(const GestureEvent& info)
3461 {
3462 isTouchDownOnOverlong_ = true;
3463 auto velocity = info.GetMainVelocity();
3464 UpdateDragFRCSceneInfo(velocity, SceneStatus::RUNNING);
3465 UpdateNodeRate();
3466 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD) {
3467 isTouchPad_ = true;
3468 }
3469
3470 PointF dragPoint(
3471 static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
3472 NGGestureRecognizer::Transform(dragPoint, GetHost(), true, info.GetIsPostEventResult(), info.GetPostEventNodeId());
3473 if (IsOutOfHotRegion(dragPoint)) {
3474 isTouchPad_ = false;
3475 return;
3476 }
3477
3478 auto mainDelta = static_cast<float>(info.GetMainDelta());
3479 ProcessDelta(mainDelta, contentMainSize_, mainDeltaSum_);
3480 mainDeltaSum_ += mainDelta;
3481
3482 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(static_cast<float>(mainDelta))) {
3483 return;
3484 }
3485
3486 if (propertyAnimationIsRunning_) {
3487 return;
3488 }
3489
3490 ScrollResult result = HandleScroll(static_cast<float>(mainDelta),
3491 SCROLL_FROM_UPDATE, NestedState::GESTURE, velocity);
3492 if (!result.reachEdge || (result.reachEdge && GetEdgeEffect() == EdgeEffect::SPRING && !NearZero(mainDelta, 0.0)
3493 && CheckContentWillScroll(mainDelta, mainDelta))) {
3494 FireScrollStateEvent(ScrollState::SCROLL);
3495 }
3496 UpdateItemRenderGroup(true);
3497 isTouchPad_ = false;
3498 }
3499
TriggerAddTabBarEvent() const3500 void SwiperPattern::TriggerAddTabBarEvent() const
3501 {
3502 const auto& addEventCallback = swiperController_->GetAddTabBarEventCallback();
3503 if (addEventCallback) {
3504 addEventCallback();
3505 }
3506 }
3507
ReportTraceOnDragEnd() const3508 void SwiperPattern::ReportTraceOnDragEnd() const
3509 {
3510 if (!hasTabsAncestor_) {
3511 PerfMonitor::GetPerfMonitor()->EndCommercial(PerfConstants::APP_SWIPER_SCROLL, false);
3512 } else {
3513 AceAsyncTraceEndCommercial(0, APP_TABS_SCROLL);
3514 }
3515 }
3516
HandleDragEnd(double dragVelocity,float mainDelta)3517 void SwiperPattern::HandleDragEnd(double dragVelocity, float mainDelta)
3518 {
3519 ReportTraceOnDragEnd();
3520
3521 isTouchDown_ = false;
3522 isTouchDownOnOverlong_ = false;
3523 if (!CheckSwiperPanEvent(dragVelocity) || !CheckContentWillScroll(dragVelocity, mainDelta)) {
3524 dragVelocity = 0.0;
3525 }
3526 if (!childScrolling_) {
3527 UpdateDragFRCSceneInfo(dragVelocity, SceneStatus::END);
3528 }
3529
3530 TriggerAddTabBarEvent();
3531
3532 auto pipeline = GetContext();
3533 CHECK_NULL_VOID(pipeline);
3534 if (SupportSwiperCustomAnimation()) {
3535 pipeline->FlushDirtyNodeUpdate();
3536 }
3537
3538 pipeline->FlushUITasks();
3539 if (itemPosition_.empty()) {
3540 EventReport::ReportScrollableErrorEvent(
3541 "Swiper", ScrollableErrorType::INTERNAL_ERROR, "Swiper item position is empty.");
3542 return;
3543 }
3544
3545 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(0.0f)) {
3546 return;
3547 }
3548
3549 if (CheckDragOutOfBoundary(dragVelocity)) {
3550 return;
3551 }
3552
3553 UpdateAnimationProperty(static_cast<float>(dragVelocity));
3554 // nested and reached end (but not out of bounds), need to pass velocity to parent scrollable
3555 NestedScrollToParent(dragVelocity);
3556 if (pipeline) {
3557 pipeline->FlushUITasks();
3558 pipeline->FlushMessages();
3559 }
3560
3561 isDragging_ = false;
3562 if (!targetIndex_) {
3563 FireScrollStateEvent(ScrollState::IDLE);
3564 }
3565 if (currentIndex_ != pauseTargetIndex_.value_or(0)) {
3566 FireWillShowEvent(pauseTargetIndex_.value_or(0));
3567 FireWillHideEvent(currentIndex_);
3568 }
3569 }
3570
UpdateCurrentIndex(int32_t index)3571 void SwiperPattern::UpdateCurrentIndex(int32_t index)
3572 {
3573 currentIndex_ = index;
3574 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
3575 CHECK_NULL_VOID(props);
3576 props->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
3577 }
3578
ComputeSwipePageNextIndex(float velocity,bool onlyDistance) const3579 int32_t SwiperPattern::ComputeSwipePageNextIndex(float velocity, bool onlyDistance) const
3580 {
3581 auto swiperWidth = CalculateVisibleSize();
3582 if (LessOrEqual(swiperWidth, 0)) {
3583 return currentIndex_;
3584 }
3585
3586 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3587 auto firstIndex = firstItemInfoInVisibleArea.first;
3588 auto displayCount = GetDisplayCount();
3589 auto endIndex = SwiperUtils::ComputePageEndIndex(firstIndex, displayCount);
3590 auto iter = itemPosition_.find(endIndex);
3591 if (iter == itemPosition_.end()) {
3592 return currentIndex_;
3593 }
3594
3595 auto currentEndIndex = SwiperUtils::ComputePageEndIndex(currentIndex_, displayCount);
3596 auto dragDistance = iter->second.endPos;
3597 auto dragForward = currentIndex_ > firstIndex;
3598 auto dragThresholdFlag = dragForward ? dragDistance > swiperWidth / swiperProportion_ :
3599 (dragDistance < swiperWidth / swiperProportion_) | (currentEndIndex < firstIndex);
3600 auto nextIndex = currentIndex_;
3601 if (dragThresholdFlag) {
3602 nextIndex = dragForward ? currentIndex_ - displayCount : currentIndex_ + displayCount;
3603 }
3604
3605 if (!onlyDistance && std::abs(velocity) > newMinTurnPageVelocity_ && velocity != 0.0f) {
3606 auto direction = GreatNotEqual(velocity, 0.0f);
3607 if (dragForward != direction || !dragThresholdFlag) {
3608 nextIndex = velocity > 0.0f ? nextIndex - displayCount : nextIndex + displayCount;
3609 }
3610 }
3611
3612 if (!IsAutoLinear() && nextIndex > currentIndex_ + displayCount) {
3613 nextIndex = currentIndex_ + displayCount;
3614 }
3615
3616 if (!IsLoop()) {
3617 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - displayCount));
3618 }
3619
3620 return nextIndex;
3621 }
3622
GetVelocityCoefficient()3623 float SwiperPattern::GetVelocityCoefficient()
3624 {
3625 auto pipelineContext = GetContext();
3626 CHECK_NULL_RETURN(pipelineContext, 1);
3627 auto swiperTheme = pipelineContext->GetTheme<SwiperTheme>();
3628 CHECK_NULL_RETURN(swiperTheme, 1);
3629 auto velocityCoefficient = swiperTheme->GetTouchPadVelocityCoefficient();
3630 return velocityCoefficient;
3631 }
3632
ComputeNextIndexInSinglePage(float velocity,bool onlyDistance) const3633 int32_t SwiperPattern::ComputeNextIndexInSinglePage(float velocity, bool onlyDistance) const
3634 {
3635 auto firstItemInfo = GetFirstItemInfoInVisibleArea();
3636 auto swiperWidthHalf = (firstItemInfo.second.endPos - firstItemInfo.second.startPos) / swiperProportion_;
3637 if (LessOrEqual(swiperWidthHalf, 0)) {
3638 return currentIndex_;
3639 }
3640 // if direction is true, expected index to decrease by 1
3641 bool direction = Positive(velocity);
3642
3643 bool overTurnPageVelocity =
3644 !onlyDistance && (std::abs(velocity) > (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
3645 ? newMinTurnPageVelocity_
3646 : MIN_TURN_PAGE_VELOCITY));
3647
3648 auto firstIndex = firstItemInfo.first;
3649 auto baseIndex = -firstItemInfo.second.startPos < swiperWidthHalf ? firstIndex : firstIndex + 1;
3650 if (overTurnPageVelocity) {
3651 return direction ? baseIndex - 1 : baseIndex + 1;
3652 }
3653 return baseIndex;
3654 }
3655
ComputeNextIndexByVelocity(float velocity,bool onlyDistance) const3656 int32_t SwiperPattern::ComputeNextIndexByVelocity(float velocity, bool onlyDistance) const
3657 {
3658 #ifdef SUPPORT_DIGITAL_CROWN
3659 if (IsCrownSpring() && velocity == 0.0f) {
3660 return currentIndex_;
3661 }
3662 #endif
3663 if (IsSwipeByGroup()) {
3664 return ComputeSwipePageNextIndex(velocity, onlyDistance);
3665 }
3666
3667 auto nextIndex = currentIndex_;
3668 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3669 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3670 if (LessOrEqual(firstItemLength, 0)) {
3671 return nextIndex;
3672 }
3673
3674 auto firstIndex = firstItemInfoInVisibleArea.first;
3675 auto dragDistance = firstItemInfoInVisibleArea.second.endPos;
3676 if (firstIndex == currentIndex_ && firstItemInfoInVisibleArea.second.startPos > 0) {
3677 firstIndex--;
3678 dragDistance = firstItemInfoInVisibleArea.second.startPos;
3679 }
3680 auto direction = GreatNotEqual(velocity, 0.0);
3681 auto dragThresholdFlag =
3682 direction ? dragDistance > firstItemLength / swiperProportion_ :
3683 firstItemInfoInVisibleArea.second.endPos < firstItemLength / swiperProportion_;
3684 auto turnVelocity = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? newMinTurnPageVelocity_
3685 : MIN_TURN_PAGE_VELOCITY;
3686 if ((!onlyDistance && std::abs(velocity) > turnVelocity) || dragThresholdFlag) {
3687 nextIndex = direction ? firstIndex : firstItemInfoInVisibleArea.first + 1;
3688 } else {
3689 nextIndex = direction ? firstIndex + 1 : firstItemInfoInVisibleArea.first;
3690 }
3691
3692 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3693 // don't run this in nested scroll. Parallel nested scroll can deviate > 1 page from currentIndex_
3694 if (!childScrolling_ && SwiperUtils::IsStretch(props) && GetDisplayCount() == 1) {
3695 nextIndex =
3696 std::clamp(ComputeNextIndexInSinglePage(velocity, onlyDistance), currentIndex_ - 1, currentIndex_ + 1);
3697 }
3698
3699 if (!IsAutoLinear() && nextIndex > currentIndex_ + GetDisplayCount()) {
3700 nextIndex = currentIndex_ + GetDisplayCount();
3701 }
3702
3703 if (!IsLoop()) {
3704 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - GetDisplayCount()));
3705 }
3706 return nextIndex;
3707 }
3708
NeedStartNewAnimation(const OffsetF & offset) const3709 bool SwiperPattern::NeedStartNewAnimation(const OffsetF& offset) const
3710 {
3711 if (itemPositionInAnimation_.empty()) {
3712 return true;
3713 }
3714
3715 for (const auto& animationItem : itemPositionInAnimation_) {
3716 auto iter = itemPosition_.find(animationItem.first);
3717 if (iter == itemPosition_.end()) {
3718 return true;
3719 }
3720 if ((animationItem.second.node && animationItem.second.finalOffset != offset) ||
3721 !NearEqual(animationItem.second.startPos, iter->second.startPos) ||
3722 !NearEqual(animationItem.second.endPos, iter->second.endPos)) {
3723 return true;
3724 }
3725 }
3726
3727 return false;
3728 }
3729
UpdateCurrentFocus()3730 void SwiperPattern::UpdateCurrentFocus()
3731 {
3732 do {
3733 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
3734 if (!curChildFrame) {
3735 break;
3736 }
3737 FlushFocus(curChildFrame);
3738 currentFocusIndex_ = currentIndex_;
3739 } while (0);
3740 }
3741
CheckDragOutOfBoundary(double dragVelocity)3742 bool SwiperPattern::CheckDragOutOfBoundary(double dragVelocity)
3743 {
3744 if (IsLoop()) {
3745 return false;
3746 }
3747
3748 auto edgeEffect = GetEdgeEffect();
3749 // edge effect is NONE and reached boundary
3750 const bool noneOutOfBoundary =
3751 (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) &&
3752 NearZero(GetDistanceToEdge()) && edgeEffect == EdgeEffect::NONE;
3753 if (IsOutOfBoundary() || !NearZero(fadeOffset_) || noneOutOfBoundary) {
3754 isDragging_ = false;
3755
3756 if (edgeEffect == EdgeEffect::SPRING) {
3757 PlaySpringAnimation(dragVelocity);
3758 return true;
3759 }
3760
3761 if (edgeEffect == EdgeEffect::FADE) {
3762 PlayFadeAnimation();
3763 return true;
3764 }
3765
3766 auto nextIndex = ComputeNextIndexByVelocity(static_cast<float>(dragVelocity), true);
3767 if (currentIndex_ != nextIndex) {
3768 FireWillShowEvent(nextIndex_);
3769 FireWillHideEvent(currentIndex_);
3770
3771 UpdateCurrentIndex(nextIndex);
3772 UpdateCurrentFocus();
3773 OnIndexChange();
3774 oldIndex_ = currentIndex_;
3775 }
3776
3777 if (edgeEffect == EdgeEffect::NONE) {
3778 auto parent = GetNestedScrollParent();
3779 const bool isForward = NonPositive(dragVelocity);
3780 if (parent && GetNestedScroll().NeedParent(isForward)) {
3781 parent->HandleScrollVelocity(dragVelocity);
3782 }
3783 StartAutoPlay();
3784 UpdateItemRenderGroup(false);
3785 return true;
3786 }
3787 }
3788
3789 return false;
3790 }
3791
UpdateTranslateForCaptureNode(const OffsetF & offset,bool cancel)3792 void SwiperPattern::UpdateTranslateForCaptureNode(const OffsetF& offset, bool cancel)
3793 {
3794 CHECK_NULL_VOID(hasCachedCapture_);
3795 auto leftCaptureNode = GetLeftCaptureNode();
3796 CHECK_NULL_VOID(leftCaptureNode);
3797 auto rightCaptureNode = GetRightCaptureNode();
3798 CHECK_NULL_VOID(rightCaptureNode);
3799 auto leftRenderContext = leftCaptureNode->GetRenderContext();
3800 CHECK_NULL_VOID(leftRenderContext);
3801 auto rightRenderContext = rightCaptureNode->GetRenderContext();
3802 CHECK_NULL_VOID(rightRenderContext);
3803 if (cancel) {
3804 leftRenderContext->CancelTranslateXYAnimation();
3805 rightRenderContext->CancelTranslateXYAnimation();
3806 } else {
3807 leftRenderContext->UpdateTranslateInXY(offset);
3808 rightRenderContext->UpdateTranslateInXY(offset);
3809 captureFinalOffset_ = offset;
3810 }
3811 }
3812
UpdateFinalTranslateForSwiperItem(const SwiperLayoutAlgorithm::PositionMap & itemPosition)3813 void SwiperPattern::UpdateFinalTranslateForSwiperItem(const SwiperLayoutAlgorithm::PositionMap& itemPosition)
3814 {
3815 for (const auto& item : itemPosition) {
3816 auto frameNode = item.second.node;
3817 if (!frameNode) {
3818 continue;
3819 }
3820 auto renderContext = frameNode->GetRenderContext();
3821 if (!renderContext) {
3822 continue;
3823 }
3824 renderContext->UpdateTranslateInXY(item.second.finalOffset);
3825 }
3826 }
3827
UpdateTranslateForSwiperItem(SwiperLayoutAlgorithm::PositionMap & itemPosition,const OffsetF & offset,bool cancel)3828 void SwiperPattern::UpdateTranslateForSwiperItem(SwiperLayoutAlgorithm::PositionMap& itemPosition,
3829 const OffsetF& offset, bool cancel)
3830 {
3831 for (auto& item : itemPosition) {
3832 auto frameNode = item.second.node;
3833 if (!frameNode) {
3834 continue;
3835 }
3836 auto renderContext = frameNode->GetRenderContext();
3837 if (!renderContext) {
3838 continue;
3839 }
3840 if (cancel) {
3841 renderContext->CancelTranslateXYAnimation();
3842 } else {
3843 renderContext->UpdateTranslateInXY(offset);
3844 item.second.finalOffset = offset;
3845 }
3846 }
3847 }
3848
PlayPropertyTranslateAnimation(float translate,int32_t nextIndex,float velocity,bool stopAutoPlay,std::optional<float> pixelRoundTargetPos)3849 void SwiperPattern::PlayPropertyTranslateAnimation(
3850 float translate, int32_t nextIndex, float velocity, bool stopAutoPlay, std::optional<float> pixelRoundTargetPos)
3851 {
3852 if (NearZero(translate)) {
3853 SetIndicatorChangeIndexStatus(false, GetLoopIndex(currentIndex_));
3854 OnAnimationTranslateZero(nextIndex, stopAutoPlay);
3855 return;
3856 }
3857
3858 AnimationOption option;
3859 option.SetDuration(GetDuration());
3860 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
3861 if (iter != frameRateRange_.end()) {
3862 TAG_LOGI(AceLogTag::ACE_SWIPER,
3863 "Property translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}, "
3864 "id: %{public}d",
3865 iter->second->min_, iter->second->max_, iter->second->preferred_, swiperId_);
3866 iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
3867 option.SetFrameRateRange(iter->second);
3868 } else {
3869 option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
3870 }
3871 motionVelocity_ = velocity / translate;
3872 auto curve = GetCurveIncludeMotion();
3873 auto minimumAmplitudeRatio = DEFAULT_MINIMUM_AMPLITUDE_PX / translate;
3874 if (InstanceOf<InterpolatingSpring>(curve) &&
3875 LessNotEqualCustomPrecision(
3876 minimumAmplitudeRatio, InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO)) {
3877 auto interpolatingSpring = AceType::DynamicCast<InterpolatingSpring>(curve);
3878 interpolatingSpring->UpdateMinimumAmplitudeRatio(minimumAmplitudeRatio);
3879 }
3880 option.SetCurve(curve);
3881 option.SetFinishCallbackType(GetFinishCallbackType());
3882 OffsetF offset;
3883 if (GetDirection() == Axis::HORIZONTAL) {
3884 offset.AddX(translate);
3885 } else {
3886 offset.AddY(translate);
3887 }
3888 if (propertyAnimationIsRunning_) {
3889 if (!NeedStartNewAnimation(offset)) {
3890 stopIndicatorAnimation_ = false;
3891 return;
3892 }
3893 std::optional<int32_t> targetIndex;
3894 if (targetIndex_) {
3895 targetIndex = targetIndex_;
3896 }
3897 StopPropertyTranslateAnimation(isFinishAnimation_);
3898 StopIndicatorAnimation();
3899
3900 if (targetIndex) {
3901 targetIndex_ = targetIndex;
3902 MarkDirtyNodeSelf();
3903 return;
3904 }
3905 }
3906 auto finishCallback = [weak = WeakClaim(this), offset]() {
3907 auto swiper = weak.Upgrade();
3908 CHECK_NULL_VOID(swiper);
3909 #ifdef OHOS_PLATFORM
3910 if (swiper->isInAutoPlay_) {
3911 ResSchedReport::GetInstance().ResSchedDataReport("auto_play_off");
3912 }
3913 #endif
3914 if (!swiper->hasTabsAncestor_) {
3915 PerfMonitor::GetPerfMonitor()->EndCommercial(PerfConstants::APP_SWIPER_FLING, true);
3916 } else {
3917 AceAsyncTraceEndCommercial(0, APP_TABS_FLING);
3918 }
3919 swiper->OnPropertyTranslateAnimationFinish(offset);
3920 swiper->FireScrollStateEvent(ScrollState::IDLE);
3921 };
3922 // initial translate info use final offset
3923 UpdateFinalTranslateForSwiperItem(itemPosition_);
3924 UpdateTranslateForCaptureNode(captureFinalOffset_);
3925 auto adOffset = offset;
3926 if (IsHorizontalAndRightToLeft()) {
3927 if (GetDirection() == Axis::HORIZONTAL) {
3928 adOffset.SetX(-adOffset.GetX());
3929 } else {
3930 adOffset.SetY(-adOffset.GetY());
3931 }
3932 }
3933 #ifdef SUPPORT_DIGITAL_CROWN
3934 if (pixelRoundTargetPos.has_value()) {
3935 if (GetDirection() == Axis::HORIZONTAL) {
3936 adOffset.SetX(pixelRoundTargetPos.value());
3937 } else {
3938 adOffset.SetY(pixelRoundTargetPos.value());
3939 }
3940 }
3941 #endif
3942 // property callback will call immediately.
3943 auto propertyUpdateCallback = [swiper = WeakClaim(this), offset = adOffset]() {
3944 auto swiperPattern = swiper.Upgrade();
3945 CHECK_NULL_VOID(swiperPattern);
3946 #ifdef OHOS_PLATFORM
3947 if (swiperPattern->isInAutoPlay_) {
3948 ResSchedReport::GetInstance().ResSchedDataReport("auto_play_on");
3949 }
3950 #endif
3951 if (!swiperPattern->hasTabsAncestor_) {
3952 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_SWIPER_FLING,
3953 PerfActionType::LAST_UP, "");
3954 } else {
3955 AceAsyncTraceBeginCommercial(0, APP_TABS_FLING);
3956 }
3957 TAG_LOGI(AceLogTag::ACE_SWIPER,
3958 "Swiper start property animation with offsetX: %{public}f, offsetY: %{public}f, id: %{public}d",
3959 offset.GetX(), offset.GetY(), swiperPattern->swiperId_);
3960 ACE_SCOPED_TRACE_COMMERCIAL("%s start property animation, X: %f, Y: %f",
3961 swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, offset.GetX(), offset.GetY());
3962 swiperPattern->UpdateTranslateForSwiperItem(swiperPattern->itemPosition_, offset);
3963 swiperPattern->itemPositionInAnimation_ = swiperPattern->itemPosition_;
3964 swiperPattern->UpdateTranslateForCaptureNode(offset);
3965 swiperPattern->FireScrollStateEvent(ScrollState::FLING);
3966 };
3967 if (fastCurrentIndex_.has_value()) {
3968 fastAnimationRunning_ = true;
3969 unselectedIndex_ = GetLoopIndex(currentIndex_);
3970 }
3971 propertyAnimationIsRunning_ = true;
3972 propertyAnimationIndex_ = nextIndex;
3973 contentMainSizeBeforeAni_ = contentMainSize_;
3974 FireSelectedEvent(currentIndex_, nextIndex);
3975 FireUnselectedEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex));
3976 ElementRegister::GetInstance()->ReSyncGeometryTransition(GetHost(), option);
3977 auto host = GetHost();
3978 CHECK_NULL_VOID(host);
3979 AnimationUtils::Animate(
3980 option, propertyUpdateCallback, finishCallback, nullptr /* repeatCallback */, host->GetContextRefPtr());
3981 AnimationCallbackInfo info;
3982 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3983 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3984 info.targetOffset = GetCustomPropertyTargetOffset() - Dimension(translate, DimensionUnit::PX).ConvertToVp();
3985 if (IsHorizontalAndRightToLeft()) {
3986 info.currentOffset =
3987 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3988 info.targetOffset = GetCustomPropertyTargetOffset() - Dimension(-translate, DimensionUnit::PX).ConvertToVp();
3989 }
3990
3991 auto pipeline = GetContext();
3992 CHECK_NULL_VOID(pipeline);
3993 if (GetDuration() == 0) {
3994 // if the duration is 0, the animation will be end immediately, so the start event should be triggered
3995 // after Layout Task to ensure the timing of events.
3996 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3997 auto swiper = weak.Upgrade();
3998 CHECK_NULL_VOID(swiper);
3999 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
4000 swiper->FireAndCleanScrollingListener();
4001 });
4002 } else {
4003 pipeline->AddAfterRenderTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
4004 auto swiper = weak.Upgrade();
4005 CHECK_NULL_VOID(swiper);
4006 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
4007 swiper->FireAndCleanScrollingListener();
4008 });
4009 }
4010
4011 // enable lazy load feature.
4012 SetLazyLoadFeature(true);
4013 UpdateItemRenderGroup(true);
4014 }
4015
UpdateOffsetAfterPropertyAnimation(float offset)4016 void SwiperPattern::UpdateOffsetAfterPropertyAnimation(float offset)
4017 {
4018 UpdateCurrentOffset(offset);
4019 auto host = GetHost();
4020 CHECK_NULL_VOID(host);
4021 host->SetLayoutDirtyMarked(true);
4022 auto context = host->GetContext();
4023 if (context) {
4024 context->FlushUITaskWithSingleDirtyNode(host);
4025 context->FlushSyncGeometryNodeTasks();
4026 }
4027 }
4028
OnPropertyTranslateAnimationFinish(const OffsetF & offset)4029 void SwiperPattern::OnPropertyTranslateAnimationFinish(const OffsetF& offset)
4030 {
4031 if (!propertyAnimationIsRunning_) {
4032 // force stop.
4033 return;
4034 }
4035 OffsetF finalOffset =
4036 itemPositionInAnimation_.empty() ? OffsetF()
4037 : itemPositionInAnimation_.begin()->second.node
4038 ? itemPositionInAnimation_.begin()->second.node->GetRenderContext()->GetTranslateXYProperty()
4039 : OffsetF();
4040 TAG_LOGI(AceLogTag::ACE_SWIPER,
4041 "Swiper finish property animation with offsetX: %{public}f, offsetY: %{public}f isVerifiedSuc %{public}d, id: "
4042 "%{public}d",
4043 finalOffset.GetX(), finalOffset.GetY(), !IsItemOverlay(), swiperId_);
4044 ACE_SCOPED_TRACE_COMMERCIAL("%s finish property animation, X: %f, Y: %f isVerifiedSuc %d",
4045 hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, finalOffset.GetX(), finalOffset.GetY(),
4046 !IsItemOverlay());
4047 fastAnimationRunning_ = false;
4048 propertyAnimationIsRunning_ = false;
4049 syncCancelAniIsFailed_ = false;
4050 fastCurrentIndex_.reset();
4051 auto correctOffset = offset.GetMainOffset(GetDirection());
4052 // before targetIndex be reset.
4053 CheckTargetPositon(correctOffset);
4054 targetIndex_.reset();
4055 // reset translate.
4056 UpdateTranslateForSwiperItem(itemPositionInAnimation_, OffsetF());
4057 itemPositionInAnimation_.clear();
4058 UpdateTranslateForCaptureNode(OffsetF());
4059 // update postion info.
4060 UpdateOffsetAfterPropertyAnimation(correctOffset);
4061 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
4062 }
4063
CheckTargetPositon(float & correctOffset)4064 void SwiperPattern::CheckTargetPositon(float& correctOffset)
4065 {
4066 if (contentMainSizeBeforeAni_ != contentMainSize_ && targetIndex_.has_value() && !itemPosition_.empty()) {
4067 auto iter = itemPosition_.find(targetIndex_.value());
4068 if (iter != itemPosition_.end()) {
4069 correctOffset = -iter->second.startPos;
4070 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper correctOffset: %{public}f", correctOffset);
4071 }
4072 }
4073 }
4074
PropertyCancelAnimationFinish(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper,bool isInterrupt)4075 void SwiperPattern::PropertyCancelAnimationFinish(
4076 bool isFinishAnimation, bool isBeforeCreateLayoutWrapper, bool isInterrupt)
4077 {
4078 fastCurrentIndex_.reset();
4079 targetIndex_.reset();
4080 OffsetF currentOffset;
4081 for (auto iter = itemPositionInAnimation_.rbegin(); iter != itemPositionInAnimation_.rend(); ++iter) {
4082 auto frameNode = iter->second.node;
4083 auto renderContext = frameNode ? frameNode->GetRenderContext() : nullptr;
4084 if (renderContext) {
4085 currentOffset = renderContext->GetTranslateXYProperty();
4086 break;
4087 }
4088 }
4089 if (IsHorizontalAndRightToLeft()) {
4090 if (GetDirection() == Axis::HORIZONTAL) {
4091 currentOffset.SetX(-currentOffset.GetX());
4092 } else {
4093 currentOffset.SetY(-currentOffset.GetY());
4094 }
4095 }
4096 ACE_SCOPED_TRACE("Swiper stop propertyAni offset %f", currentOffset.GetMainOffset(GetDirection()));
4097 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper stop propertyAni offset %{public}f, id: %{public}d",
4098 currentOffset.GetMainOffset(GetDirection()), swiperId_);
4099 UpdateTranslateForSwiperItem(itemPositionInAnimation_, OffsetF());
4100 itemPositionInAnimation_.clear();
4101 UpdateTranslateForCaptureNode(OffsetF());
4102 if (!isBeforeCreateLayoutWrapper) {
4103 UpdateOffsetAfterPropertyAnimation(currentOffset.GetMainOffset(GetDirection()));
4104 }
4105 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation, true, isInterrupt);
4106 }
4107
StopPropertyTranslateAnimation(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper,bool isInterrupt)4108 void SwiperPattern::StopPropertyTranslateAnimation(
4109 bool isFinishAnimation, bool isBeforeCreateLayoutWrapper, bool isInterrupt)
4110 {
4111 if (!propertyAnimationIsRunning_ || syncCancelAniIsFailed_) {
4112 return;
4113 }
4114 fastAnimationRunning_ = false;
4115 propertyAnimationIsRunning_ = false;
4116 AnimationOption option;
4117 option.SetDuration(0);
4118 option.SetCurve(Curves::LINEAR);
4119 auto propertyUpdateCallback = [weak = WeakClaim(this)]() {
4120 auto swiper = weak.Upgrade();
4121 CHECK_NULL_VOID(swiper);
4122 // cancel translate for swiper item and capture node
4123 swiper->UpdateTranslateForSwiperItem(swiper->itemPositionInAnimation_, OffsetF(), true);
4124 swiper->UpdateTranslateForCaptureNode(OffsetF(), true);
4125 };
4126 AnimationUtils::OpenImplicitAnimation(option, Curves::LINEAR, nullptr);
4127 propertyUpdateCallback();
4128 bool isSyncSuc = AnimationUtils::CloseImplicitCancelAnimation();
4129 if (!isSyncSuc) {
4130 EventReport::ReportScrollableErrorEvent(
4131 "Swiper", ScrollableErrorType::STOP_ANIMATION_TIMEOUT, "Swiper stop propertyAni sync failed");
4132 ACE_SCOPED_TRACE("Swiper stop propertyAni sync failed");
4133 TAG_LOGW(AceLogTag::ACE_SWIPER, "Swiper stop propertyAni sync failed");
4134 // sync cancel animation failed, need to wait for the animation to finish completely
4135 syncCancelAniIsFailed_ = true;
4136 propertyAnimationIsRunning_ = true;
4137 return;
4138 }
4139 PropertyCancelAnimationFinish(isFinishAnimation, isBeforeCreateLayoutWrapper, isInterrupt);
4140 }
4141
InitAnimationCurve()4142 void SwiperPattern::InitAnimationCurve()
4143 {
4144 auto pipelineContext = GetContext();
4145 CHECK_NULL_VOID(pipelineContext);
4146 auto swiperTheme = pipelineContext->GetTheme<SwiperTheme>();
4147 CHECK_NULL_VOID(swiperTheme);
4148 animationCurveStiffness_ = swiperTheme->GetAnimationCurveStiffness();
4149 animationCurveDamping_ = swiperTheme->GetAnimationCurveDamping();
4150 }
4151
GetCurveIncludeMotion()4152 RefPtr<Curve> SwiperPattern::GetCurveIncludeMotion()
4153 {
4154 auto curve = GetCurve();
4155 auto container = Container::Current();
4156 bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
4157 if (isLauncherFeature) {
4158 finishCallbackType_ = FinishCallbackType::LOGICALLY;
4159 }
4160
4161 if (curve) {
4162 if (InstanceOf<SpringCurve>(curve)) {
4163 auto springCurve = DynamicCast<SpringCurve>(curve);
4164 // check velocity to judge if this current velocity.
4165 if (springCurve->GetCurrentVelocity() < 0) {
4166 return AceType::MakeRefPtr<SpringCurve>(
4167 motionVelocity_, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
4168 }
4169 }
4170 if (InstanceOf<InterpolatingSpring>(curve)) {
4171 auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
4172 // check velocity to judge if this current velocity.
4173 if (interpolatingSpring->GetVelocity() < 0) {
4174 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, interpolatingSpring->GetMass(),
4175 interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
4176 }
4177 }
4178 return curve;
4179 }
4180 #ifdef SUPPORT_DIGITAL_CROWN
4181 if (IsCrownSpring()) {
4182 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, 1.0f, 228.0f, 30.0f);
4183 }
4184 #endif
4185 // use spring motion feature.
4186 // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
4187 InitAnimationCurve();
4188 return AceType::MakeRefPtr<InterpolatingSpring>(
4189 motionVelocity_, SWIPER_CURVE_MASS, animationCurveStiffness_, animationCurveDamping_);
4190 }
4191
GetIndicatorHeadCurve()4192 RefPtr<Curve> SwiperPattern::GetIndicatorHeadCurve()
4193 {
4194 auto curve = GetCurve();
4195 auto maxMotionVelocity = static_cast<float>(MAX_INDICATOR_VELOCITY / DEFAULT_INDICATOR_HEAD_DISTANCE.ConvertToPx());
4196 auto motionVelocity = std::min(motionVelocity_, maxMotionVelocity);
4197 if (!curve) {
4198 InitAnimationCurve();
4199 return AceType::MakeRefPtr<InterpolatingSpring>(
4200 motionVelocity, SWIPER_CURVE_MASS, animationCurveStiffness_, animationCurveDamping_);
4201 }
4202
4203 if (InstanceOf<SpringCurve>(curve)) {
4204 auto springCurve = DynamicCast<SpringCurve>(curve);
4205 if (springCurve->GetCurrentVelocity() < 0) {
4206 return AceType::MakeRefPtr<SpringCurve>(
4207 motionVelocity, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
4208 }
4209 }
4210
4211 if (InstanceOf<InterpolatingSpring>(curve)) {
4212 auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
4213 if (interpolatingSpring->GetVelocity() < 0) {
4214 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity, interpolatingSpring->GetMass(),
4215 interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
4216 }
4217 }
4218
4219 return curve;
4220 }
4221
PlayIndicatorTranslateAnimation(float translate,std::optional<int32_t> nextIndex)4222 void SwiperPattern::PlayIndicatorTranslateAnimation(float translate, std::optional<int32_t> nextIndex)
4223 {
4224 if (NearZero(translate)) {
4225 return;
4226 }
4227 if (!stopIndicatorAnimation_) {
4228 stopIndicatorAnimation_ = true;
4229 return;
4230 }
4231 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
4232 if (!HasIndicatorNode() && !turnPageRateCallback) {
4233 return;
4234 }
4235 CheckMarkDirtyNodeForRenderIndicator(translate, nextIndex);
4236 AnimationUtils::StopAnimation(indicatorAnimation_);
4237 indicatorAnimationIsRunning_ = false;
4238 if (itemPosition_.empty()) {
4239 return;
4240 }
4241
4242 auto host = GetHost();
4243 CHECK_NULL_VOID(host);
4244 auto weak = AceType::WeakClaim(this);
4245 host->CreateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0, [weak](float value) {
4246 auto swiper = weak.Upgrade();
4247 CHECK_NULL_VOID(swiper);
4248 const auto& turnPageRateCallback = swiper->swiperController_->GetTurnPageRateCallback();
4249 auto firstItem = swiper->GetFirstItemInfoInVisibleArea();
4250 auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
4251 if (turnPageRateCallback && !NearZero(translateLength) && swiper->propertyAnimationIsRunning_) {
4252 turnPageRateCallback(firstItem.first, (-firstItem.second.startPos - value) / translateLength);
4253 }
4254 });
4255
4256 AnimationOption option;
4257 option.SetDuration(GetDuration());
4258 option.SetCurve(Curves::LINEAR);
4259
4260 host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0);
4261 indicatorAnimationIsRunning_ = true;
4262 indicatorAnimation_ = AnimationUtils::StartAnimation(
4263 option,
4264 [weakHost = WeakClaim(RawPtr(host)), translate]() {
4265 auto host = weakHost.Upgrade();
4266 CHECK_NULL_VOID(host);
4267 host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, translate);
4268 },
4269 [weak]() {
4270 auto swiperPattern = weak.Upgrade();
4271 CHECK_NULL_VOID(swiperPattern);
4272 swiperPattern->indicatorAnimationIsRunning_ = false;
4273 }, nullptr /* repeatCallback */, host->GetContextRefPtr());
4274 }
4275
PlayTranslateAnimation(float startPos,float endPos,int32_t nextIndex,bool restartAutoPlay,float velocity)4276 void SwiperPattern::PlayTranslateAnimation(
4277 float startPos, float endPos, int32_t nextIndex, bool restartAutoPlay, float velocity)
4278 {
4279 if (translateAnimationIsRunning_) {
4280 return;
4281 }
4282 if (NearZero(endPos - startPos)) {
4283 OnAnimationTranslateZero(nextIndex, restartAutoPlay);
4284 return;
4285 }
4286
4287 if (HasIndicatorNode()) {
4288 CheckMarkDirtyNodeForRenderIndicator(endPos - startPos, nextIndex);
4289 }
4290
4291 auto host = GetHost();
4292 CHECK_NULL_VOID(host);
4293 auto weak = AceType::WeakClaim(this);
4294 host->CreateAnimatablePropertyFloat(
4295 TRANSLATE_PROPERTY_NAME, 0,
4296 [weak](float value) {
4297 auto swiper = weak.Upgrade();
4298 CHECK_NULL_VOID(swiper);
4299 // currentDelta_ needs to be adjusted when the previous frame has not been processed.
4300 value += swiper->currentDelta_;
4301 swiper->UpdateCurrentOffset(static_cast<float>(value - swiper->currentOffset_));
4302 },
4303 PropertyUnit::PIXEL_POSITION);
4304
4305 AnimationOption option;
4306 auto duration = GetDuration();
4307 bool finishAnimation = (duration == 0);
4308 motionVelocity_ = velocity / (endPos - startPos);
4309 option.SetCurve(GetCurveIncludeMotion());
4310 option.SetDuration(duration);
4311 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
4312 if (iter != frameRateRange_.end()) {
4313 TAG_LOGI(AceLogTag::ACE_SWIPER,
4314 "Translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}",
4315 iter->second->min_, iter->second->max_, iter->second->preferred_);
4316 iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
4317 option.SetFrameRateRange(iter->second);
4318 } else {
4319 option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
4320 }
4321 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, startPos);
4322 translateAnimationIsRunning_ = true;
4323 propertyAnimationIndex_ = nextIndex;
4324 translateAnimationEndPos_ = endPos;
4325 translateAnimation_ = AnimationUtils::StartAnimation(
4326 option,
4327 [weak, startPos, endPos, nextIndex, velocity]() {
4328 auto swiper = weak.Upgrade();
4329 CHECK_NULL_VOID(swiper);
4330 auto host = swiper->GetHost();
4331 CHECK_NULL_VOID(host);
4332 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, endPos);
4333 AceAsyncTraceBeginCommercial(
4334 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
4335 AnimationCallbackInfo info;
4336 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
4337 info.currentOffset = swiper->GetCustomPropertyOffset() +
4338 Dimension(swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4339 info.targetOffset =
4340 swiper->GetCustomPropertyTargetOffset() + Dimension(startPos - endPos, DimensionUnit::PX).ConvertToVp();
4341 if (swiper->IsHorizontalAndRightToLeft()) {
4342 info.currentOffset = swiper->GetCustomPropertyOffset() +
4343 Dimension(-swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4344 }
4345 swiper->FireSelectedEvent(
4346 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex));
4347 swiper->FireUnselectedEvent(
4348 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex));
4349 swiper->FireAnimationStartEvent(
4350 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex), info);
4351 swiper->FireAndCleanScrollingListener();
4352 swiper->FireScrollStateEvent(ScrollState::FLING);
4353 },
4354 [weak, finishAnimation]() {
4355 auto swiper = weak.Upgrade();
4356 CHECK_NULL_VOID(swiper);
4357 AceAsyncTraceEndCommercial(
4358 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
4359 if (finishAnimation && swiper->translateAnimationIsRunning_) {
4360 swiper->isFinishAnimation_ = true;
4361 }
4362 swiper->fastCurrentIndex_.reset();
4363 swiper->targetIndex_.reset();
4364 swiper->OnTranslateAnimationFinish();
4365 swiper->FireScrollStateEvent(ScrollState::IDLE);
4366 }, nullptr /* repeatCallback */, host->GetContextRefPtr());
4367 if (fastCurrentIndex_.has_value()) {
4368 fastAnimationRunning_ = true;
4369 unselectedIndex_ = GetLoopIndex(currentIndex_);
4370 }
4371 SetLazyLoadFeature(true);
4372 UpdateItemRenderGroup(true);
4373 }
4374
CustomizeSafeAreaPadding(PaddingPropertyF safeAreaPadding,bool needRotate)4375 PaddingPropertyF SwiperPattern::CustomizeSafeAreaPadding(PaddingPropertyF safeAreaPadding, bool needRotate)
4376 {
4377 bool isVertical = GetDirection() == Axis::VERTICAL;
4378 if (needRotate) {
4379 isVertical = !isVertical;
4380 }
4381 if (isVertical) {
4382 safeAreaPadding.top = std::nullopt;
4383 safeAreaPadding.bottom = std::nullopt;
4384 } else {
4385 safeAreaPadding.left = std::nullopt;
4386 safeAreaPadding.right = std::nullopt;
4387 }
4388 return safeAreaPadding;
4389 }
4390
AccumulatingTerminateHelper(RectF & adjustingRect,ExpandEdges & totalExpand,bool fromSelf,LayoutSafeAreaType ignoreType)4391 bool SwiperPattern::AccumulatingTerminateHelper(
4392 RectF& adjustingRect, ExpandEdges& totalExpand, bool fromSelf, LayoutSafeAreaType ignoreType)
4393 {
4394 auto host = GetHost();
4395 CHECK_NULL_RETURN(host, false);
4396 if (host->IsScrollableAxisInsensitive()) {
4397 return false;
4398 }
4399 auto expandFromSwiper = host->GetAccumulatedSafeAreaExpand(
4400 false, { .edges = GetDirection() == Axis::VERTICAL ? LAYOUT_SAFE_AREA_EDGE_HORIZONTAL
4401 : LAYOUT_SAFE_AREA_EDGE_VERTICAL });
4402 auto geometryNode = host->GetGeometryNode();
4403 CHECK_NULL_RETURN(geometryNode, false);
4404 auto frameRect = geometryNode->GetFrameRect();
4405 totalExpand = totalExpand.Plus(AdjacentExpandToRect(adjustingRect, expandFromSwiper, frameRect));
4406 return true;
4407 }
4408
OnSpringAnimationStart(float velocity)4409 void SwiperPattern::OnSpringAnimationStart(float velocity)
4410 {
4411 AnimationCallbackInfo info;
4412 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
4413 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4414 if (IsHorizontalAndRightToLeft()) {
4415 info.currentOffset =
4416 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4417 }
4418
4419 nextIndex_ = ComputeNextIndexByVelocity(velocity, true);
4420 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
4421 info.targetOffset = info.currentOffset;
4422 } else {
4423 FireWillShowEvent(nextIndex_);
4424 FireWillHideEvent(currentIndex_);
4425 auto iter = itemPosition_.find(nextIndex_);
4426 auto nextOffset = iter != itemPosition_.end() ? iter->second.startPos : 0.0f;
4427 info.targetOffset = GetCustomPropertyTargetOffset() + Dimension(nextOffset, DimensionUnit::PX).ConvertToVp();
4428 }
4429
4430 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
4431 }
4432
OnSpringAnimationFinish()4433 void SwiperPattern::OnSpringAnimationFinish()
4434 {
4435 if (!springAnimationIsRunning_) {
4436 return;
4437 }
4438 PerfMonitor::GetPerfMonitor()->EndCommercial(PerfConstants::APP_LIST_FLING, false);
4439 AceAsyncTraceEndCommercial(0, TRAILING_ANIMATION);
4440 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper finish spring animation offset %{public}f, id: %{public}d",
4441 currentIndexOffset_, swiperId_);
4442 ACE_SCOPED_TRACE_COMMERCIAL("%s finish spring animation, offset: %f",
4443 hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, currentIndexOffset_);
4444 springAnimationIsRunning_ = false;
4445 isTouchDownSpringAnimation_ = false;
4446 OnSpringAndFadeAnimationFinish();
4447 }
4448
EstimateSpringOffset(float realOffset)4449 float SwiperPattern::EstimateSpringOffset(float realOffset)
4450 {
4451 float springOffset = 0.0f;
4452 if (GetEdgeEffect() != EdgeEffect::SPRING || !IsOutOfBoundary() || NearEqual(realOffset, 0.0f)) {
4453 return springOffset;
4454 }
4455 auto visibleSize = CalculateVisibleSize();
4456 if (LessOrEqual(visibleSize, 0.0f)) {
4457 return springOffset;
4458 }
4459 constexpr float MIN_FRICTION = 0.419f;
4460 auto absRealOffset = std::abs(realOffset);
4461 auto start = absRealOffset;
4462 auto end = std::min(visibleSize, absRealOffset / MIN_FRICTION);
4463 while (LessNotEqual(start, end)) {
4464 constexpr float factor = 0.5f;
4465 springOffset = (start + end) * factor;
4466 auto estimate = springOffset * SwiperHelper::CalculateFriction(springOffset / visibleSize);
4467 if (NearEqual(estimate, absRealOffset)) {
4468 break;
4469 }
4470 if (estimate < absRealOffset) {
4471 start = springOffset;
4472 } else {
4473 end = springOffset;
4474 }
4475 }
4476 if (springOffset > 0 && realOffset < 0) {
4477 springOffset = -springOffset;
4478 }
4479 if (NearZero(springOffset)) {
4480 springOffset = 0.0f;
4481 }
4482 return springOffset;
4483 }
4484
OnSpringAndFadeAnimationFinish()4485 void SwiperPattern::OnSpringAndFadeAnimationFinish()
4486 {
4487 auto itemInfoInVisibleArea = std::make_pair(0, SwiperItemInfo {});
4488 if (!itemPosition_.empty()) {
4489 auto item = itemPosition_.find(nextIndex_);
4490 itemInfoInVisibleArea =
4491 std::make_pair(item->first, SwiperItemInfo { item->second.startPos, item->second.endPos });
4492 }
4493 if (GetLoopIndex(currentIndex_) != GetLoopIndex(nextIndex_)) {
4494 UpdateCurrentIndex(nextIndex_);
4495 UpdateCurrentFocus();
4496 OnIndexChange();
4497 oldIndex_ = currentIndex_;
4498 }
4499 AnimationCallbackInfo info;
4500 auto indexStartPos = itemInfoInVisibleArea.second.startPos;
4501 info.currentOffset = GetCustomPropertyOffset() + Dimension(indexStartPos, DimensionUnit::PX).ConvertToVp();
4502 if (IsHorizontalAndRightToLeft()) {
4503 info.currentOffset = GetCustomPropertyOffset() + Dimension(-indexStartPos, DimensionUnit::PX).ConvertToVp();
4504 }
4505 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
4506 currentIndexOffset_ = indexStartPos;
4507 springOffset_ = EstimateSpringOffset(currentIndexOffset_);
4508 UpdateItemRenderGroup(false);
4509 NotifyParentScrollEnd();
4510
4511 if (!isTouchDown_) {
4512 StartAutoPlay();
4513 }
4514
4515 fadeAnimationIsRunning_ = false;
4516 isTouchDownFadeAnimation_ = false;
4517 }
4518
OnFadeAnimationStart()4519 void SwiperPattern::OnFadeAnimationStart()
4520 {
4521 AnimationCallbackInfo info;
4522 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4523 if (IsHorizontalAndRightToLeft()) {
4524 info.currentOffset =
4525 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4526 }
4527 nextIndex_ = ComputeNextIndexByVelocity(0.0);
4528 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
4529 info.targetOffset = info.currentOffset;
4530 } else {
4531 FireWillShowEvent(nextIndex_);
4532 FireWillHideEvent(currentIndex_);
4533 info.targetOffset = GetCustomPropertyTargetOffset();
4534 }
4535
4536 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
4537 fadeAnimationIsRunning_ = true;
4538 }
4539
PlayFadeAnimation()4540 void SwiperPattern::PlayFadeAnimation()
4541 {
4542 if (NearZero(fadeOffset_)) {
4543 fadeAnimationIsRunning_ = false;
4544 return;
4545 }
4546
4547 auto host = GetHost();
4548 CHECK_NULL_VOID(host);
4549 auto weak = AceType::WeakClaim(this);
4550 host->CreateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0, Animation<double>::ValueCallback([weak](float value) {
4551 auto swiper = weak.Upgrade();
4552 if (swiper && swiper->GetHost() && !swiper->isTouchDown_) {
4553 swiper->fadeOffset_ = value;
4554 swiper->GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4555 }
4556 }));
4557
4558 AnimationOption option;
4559 option.SetDuration(FADE_DURATION);
4560 option.SetCurve(Curves::LINEAR);
4561
4562 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, fadeOffset_);
4563 nextIndex_ = currentIndex_;
4564 fadeAnimation_ = AnimationUtils::StartAnimation(
4565 option,
4566 [weak]() {
4567 auto swiperPattern = weak.Upgrade();
4568 CHECK_NULL_VOID(swiperPattern);
4569 swiperPattern->OnFadeAnimationStart();
4570 auto host = swiperPattern->GetHost();
4571 CHECK_NULL_VOID(host);
4572 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0.f);
4573 },
4574 [weak]() {
4575 auto swiperPattern = weak.Upgrade();
4576 CHECK_NULL_VOID(swiperPattern);
4577 swiperPattern->OnSpringAndFadeAnimationFinish();
4578 }, nullptr /* repeatCallback */, host->GetContextRefPtr());
4579 }
4580
CreateSpringProperty()4581 void SwiperPattern::CreateSpringProperty()
4582 {
4583 auto host = GetHost();
4584 CHECK_NULL_VOID(host);
4585 host->CreateAnimatablePropertyFloat(
4586 SPRING_PROPERTY_NAME, 0,
4587 [weak = AceType::WeakClaim(this)](float position) {
4588 auto swiper = weak.Upgrade();
4589 CHECK_NULL_VOID(swiper);
4590 auto positionDelta = static_cast<float>(position) - swiper->currentIndexOffset_;
4591 swiper->UpdateCurrentOffset(positionDelta);
4592 if (LessNotEqual(std::abs(positionDelta), 1) && !NearZero(positionDelta)) {
4593 AceAsyncTraceBeginCommercial(0, TRAILING_ANIMATION);
4594 }
4595 },
4596 PropertyUnit::PIXEL_POSITION);
4597 }
4598
PlaySpringAnimation(double dragVelocity)4599 void SwiperPattern::PlaySpringAnimation(double dragVelocity)
4600 {
4601 UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart());
4602 if (RunningTranslateAnimation()) {
4603 return;
4604 }
4605 auto host = GetHost();
4606 CHECK_NULL_VOID(host);
4607 auto mainSize = CalculateVisibleSize();
4608 if (LessOrEqual(mainSize, 0) || itemPosition_.empty()) {
4609 return;
4610 }
4611 childScrolling_ = false;
4612 auto leading = currentIndexOffset_ + mainSize - itemPosition_.rbegin()->second.endPos;
4613 auto trailing = currentIndexOffset_ - itemPosition_.begin()->second.startPos;
4614 ExtentPair extentPair = ExtentPair(leading, trailing);
4615 CreateSpringProperty();
4616 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, currentIndexOffset_);
4617 auto delta = currentIndexOffset_ < 0.0f ? extentPair.Leading() : extentPair.Trailing();
4618 if (IsVisibleChildrenSizeLessThanSwiper()) {
4619 delta = extentPair.Trailing();
4620 }
4621 // spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
4622 auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
4623 AnimationOption option;
4624 option.SetCurve(springCurve);
4625 option.SetDuration(SPRING_DURATION);
4626 nextIndex_ = currentIndex_;
4627 springAnimation_ = AnimationUtils::StartAnimation(
4628 option,
4629 [weak = AceType::WeakClaim(this), delta]() {
4630 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_LIST_FLING,
4631 PerfActionType::FIRST_MOVE, "");
4632 auto swiperPattern = weak.Upgrade();
4633 CHECK_NULL_VOID(swiperPattern);
4634 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper start spring animation with offset:%{public}f, id:%{public}d",
4635 delta, swiperPattern->swiperId_);
4636 ACE_SCOPED_TRACE_COMMERCIAL(
4637 "%s start spring animation", swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG);
4638 swiperPattern->FireScrollStateEvent(ScrollState::FLING);
4639 auto host = swiperPattern->GetHost();
4640 CHECK_NULL_VOID(host);
4641 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, delta);
4642 },
4643 [weak = AceType::WeakClaim(this)]() {
4644 auto swiperPattern = weak.Upgrade();
4645 CHECK_NULL_VOID(swiperPattern);
4646 swiperPattern->OnSpringAnimationFinish();
4647 swiperPattern->FireScrollStateEvent(ScrollState::IDLE);
4648 }, nullptr /* repeatCallback */, host->GetContextRefPtr());
4649 OnSpringAnimationStart(static_cast<float>(dragVelocity));
4650 springAnimationIsRunning_ = true;
4651 }
4652
IsOutOfBoundary(float mainOffset) const4653 bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
4654 {
4655 if (IsLoop() || itemPosition_.empty()) {
4656 return false;
4657 }
4658
4659 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
4660 startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
4661 auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
4662 auto visibleWindowSize = CalculateVisibleSize();
4663 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
4664 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
4665 auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
4666 return isOutOfStart || isOutOfEnd;
4667 }
4668
IsOutOfStart(float mainOffset) const4669 bool SwiperPattern::IsOutOfStart(float mainOffset) const
4670 {
4671 if (IsLoop() || itemPosition_.empty()) {
4672 return false;
4673 }
4674
4675 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
4676 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
4677 return itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.f);
4678 }
4679
IsOutOfEnd(float mainOffset) const4680 bool SwiperPattern::IsOutOfEnd(float mainOffset) const
4681 {
4682 if (IsLoop() || itemPosition_.empty()) {
4683 return false;
4684 }
4685
4686 auto visibleWindowSize = CalculateVisibleSize();
4687 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
4688 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
4689 return itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
4690 }
4691
IsAtStart() const4692 bool SwiperPattern::IsAtStart() const
4693 {
4694 if (IsLoop() || itemPosition_.empty()) {
4695 return false;
4696 }
4697
4698 auto startPos = itemPosition_.begin()->second.startPos;
4699 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
4700 return itemPosition_.begin()->first == 0 && GreatOrEqual(startPos, 0.f);
4701 }
4702
IsAtEnd() const4703 bool SwiperPattern::IsAtEnd() const
4704 {
4705 if (IsLoop() || itemPosition_.empty()) {
4706 return false;
4707 }
4708
4709 auto visibleWindowSize = CalculateVisibleSize();
4710 auto endPos = itemPosition_.rbegin()->second.endPos;
4711 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
4712 return itemPosition_.rbegin()->first == TotalCount() - 1 && LessOrEqual(endPos, visibleWindowSize);
4713 }
4714
AutoLinearIsOutOfBoundary(float mainOffset) const4715 bool SwiperPattern::AutoLinearIsOutOfBoundary(float mainOffset) const
4716 {
4717 // Check the scenario where all child nodes are within the window but isloop is true
4718 if (!IsLoop() || itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
4719 return false;
4720 }
4721
4722 auto startPos = itemPosition_.begin()->second.startPos;
4723 auto isOutOfStart = GreatNotEqual(startPos + mainOffset, 0.0);
4724
4725 auto visibleWindowSize = CalculateVisibleSize();
4726 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
4727 auto isOutOfEnd = LessNotEqual(endPos, visibleWindowSize);
4728
4729 return isOutOfStart || isOutOfEnd;
4730 }
4731
GetDistanceToEdge() const4732 float SwiperPattern::GetDistanceToEdge() const
4733 {
4734 if (IsLoop() || itemPosition_.empty()) {
4735 return 0.0f;
4736 }
4737 if (itemPosition_.begin()->first == 0) {
4738 return -itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
4739 }
4740 auto visibleWindowSize = CalculateVisibleSize();
4741 return itemPosition_.rbegin()->second.endPos - visibleWindowSize + AdjustIgnoreBlankOverScrollOffSet(false);
4742 }
4743
MainSize() const4744 float SwiperPattern::MainSize() const
4745 {
4746 auto host = GetHost();
4747 CHECK_NULL_RETURN(host, 0.0);
4748 auto geometryNode = host->GetGeometryNode();
4749 CHECK_NULL_RETURN(geometryNode, 0.0);
4750 return geometryNode->GetFrameSize().MainSize(GetDirection());
4751 }
4752
GetMainContentSize() const4753 float SwiperPattern::GetMainContentSize() const
4754 {
4755 auto host = GetHost();
4756 CHECK_NULL_RETURN(host, 0.0);
4757 auto geometryNode = host->GetGeometryNode();
4758 CHECK_NULL_RETURN(geometryNode, 0.0);
4759 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4760 CHECK_NULL_RETURN(props, 0.0);
4761 auto size = props->GetDirection().value_or(Axis::HORIZONTAL) == Axis::VERTICAL ?
4762 geometryNode->GetPaddingSize().Height() : geometryNode->GetPaddingSize().Width();
4763 return size;
4764 }
4765
GetItemSpace() const4766 float SwiperPattern::GetItemSpace() const
4767 {
4768 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4769 CHECK_NULL_RETURN(props, 0.0f);
4770 if (props->IgnoreItemSpace()) {
4771 return 0.0f;
4772 }
4773 auto itemSpace = props->GetItemSpace().value_or(0.0_vp).ConvertToPx();
4774 auto host = GetHost();
4775 CHECK_NULL_RETURN(host, 0.0f);
4776 auto geometryNode = host->GetGeometryNode();
4777 CHECK_NULL_RETURN(geometryNode, 0.0f);
4778 auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
4779 if (itemSpace > mainSize) {
4780 itemSpace = 0.0f;
4781 }
4782 return itemSpace;
4783 }
4784
IsCachedShow() const4785 bool SwiperPattern::IsCachedShow() const
4786 {
4787 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4788 CHECK_NULL_RETURN(props, false);
4789 return props->GetCachedIsShown().value_or(false);
4790 }
4791
GetPrevMargin() const4792 float SwiperPattern::GetPrevMargin() const
4793 {
4794 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4795 CHECK_NULL_RETURN(props, 0.0f);
4796 return props->GetCalculatedPrevMargin();
4797 }
4798
GetNextMargin() const4799 float SwiperPattern::GetNextMargin() const
4800 {
4801 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4802 CHECK_NULL_RETURN(props, 0.0f);
4803 return props->GetCalculatedNextMargin();
4804 }
4805
GetDirection() const4806 Axis SwiperPattern::GetDirection() const
4807 {
4808 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4809 CHECK_NULL_RETURN(props, Axis::HORIZONTAL);
4810 return props->GetDirection().value_or(Axis::HORIZONTAL);
4811 }
4812
CurrentIndex() const4813 int32_t SwiperPattern::CurrentIndex() const
4814 {
4815 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4816 CHECK_NULL_RETURN(props, 0);
4817 return props->GetIndex().value_or(0);
4818 }
4819
GetDisplayCount() const4820 int32_t SwiperPattern::GetDisplayCount() const
4821 {
4822 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4823 CHECK_NULL_RETURN(props, 1);
4824 auto displayCount = CalculateDisplayCount();
4825 return displayCount;
4826 }
4827
CalculateDisplayCount() const4828 int32_t SwiperPattern::CalculateDisplayCount() const
4829 {
4830 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4831 CHECK_NULL_RETURN(props, 1);
4832 bool isAutoFill = IsAutoFill();
4833 if (isAutoFill) {
4834 auto minSize = props->GetMinSize()->ConvertToPx();
4835 float contentWidth = GetMainContentSize();
4836 auto displayCount =
4837 CalculateCount(contentWidth, minSize, SWIPER_MARGIN.ConvertToPx(), SWIPER_GUTTER.ConvertToPx());
4838 if (LessOrEqual(minSize, 0)) {
4839 displayCount = 1;
4840 }
4841
4842 displayCount = displayCount > 0 ? displayCount : 1;
4843 auto totalCount = TotalCount();
4844 displayCount = displayCount > totalCount ? totalCount : displayCount;
4845 auto displayCountProperty = props->GetDisplayCount().value_or(1);
4846 if (displayCountProperty != displayCount) {
4847 props->UpdateDisplayCount(displayCount);
4848 auto host = GetHost();
4849 CHECK_NULL_RETURN(host, 1);
4850 host->MarkDirtyNode(
4851 (crossMatchChild_ ? PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD : PROPERTY_UPDATE_MEASURE_SELF) |
4852 PROPERTY_UPDATE_RENDER);
4853 }
4854 return displayCount;
4855 } else {
4856 return props->GetDisplayCount().value_or(1);
4857 }
4858 }
4859
CalculateCount(float contentWidth,float minSize,float margin,float gutter,float swiperPadding) const4860 int32_t SwiperPattern::CalculateCount(
4861 float contentWidth, float minSize, float margin, float gutter, float swiperPadding) const
4862 {
4863 return static_cast<int32_t>(floor((contentWidth - 2 * margin + gutter - 2 * swiperPadding) / (minSize + gutter)));
4864 }
4865
IsAutoFill() const4866 bool SwiperPattern::IsAutoFill() const
4867 {
4868 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4869 CHECK_NULL_RETURN(props, false);
4870 return props->GetMinSize().has_value();
4871 }
4872
IsAutoPlay() const4873 bool SwiperPattern::IsAutoPlay() const
4874 {
4875 auto props = GetPaintProperty<SwiperPaintProperty>();
4876 CHECK_NULL_RETURN(props, false);
4877 return props->GetAutoPlay().value_or(false);
4878 }
4879
GetDuration() const4880 int32_t SwiperPattern::GetDuration() const
4881 {
4882 const int32_t DEFAULT_DURATION = 400;
4883 auto props = GetPaintProperty<SwiperPaintProperty>();
4884 CHECK_NULL_RETURN(props, DEFAULT_DURATION);
4885 return props->GetDuration().value_or(DEFAULT_DURATION);
4886 }
4887
GetInterval() const4888 int32_t SwiperPattern::GetInterval() const
4889 {
4890 const int32_t DEFAULT_INTERVAL = 3000;
4891 auto props = GetPaintProperty<SwiperPaintProperty>();
4892 CHECK_NULL_RETURN(props, DEFAULT_INTERVAL);
4893 return props->GetAutoPlayInterval().value_or(DEFAULT_INTERVAL);
4894 }
4895
GetCurve() const4896 RefPtr<Curve> SwiperPattern::GetCurve() const
4897 {
4898 auto props = GetPaintProperty<SwiperPaintProperty>();
4899 CHECK_NULL_RETURN(props, nullptr);
4900 return props->GetCurve().value_or(nullptr);
4901 }
4902
IsLoop() const4903 bool SwiperPattern::IsLoop() const
4904 {
4905 auto host = GetHost();
4906 CHECK_NULL_RETURN(host, false);
4907 if (HasRepeatTotalCountDifference(host)) {
4908 return false;
4909 }
4910 if (hasCachedCapture_) {
4911 return true;
4912 }
4913 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4914 CHECK_NULL_RETURN(props, true);
4915 if (TotalDisPlayCount() > TotalCount() ||
4916 (TotalDisPlayCount() == TotalCount() && SwiperUtils::IsStretch(props) &&
4917 (NonPositive(props->GetCalculatedPrevMargin()) || NonPositive(props->GetCalculatedNextMargin())))) {
4918 return false;
4919 }
4920 return props->GetLoop().value_or(true);
4921 }
4922
IsEnabled() const4923 bool SwiperPattern::IsEnabled() const
4924 {
4925 auto props = GetPaintProperty<SwiperPaintProperty>();
4926 CHECK_NULL_RETURN(props, true);
4927 return props->GetEnabled().value_or(true);
4928 }
4929
GetEdgeEffect() const4930 EdgeEffect SwiperPattern::GetEdgeEffect() const
4931 {
4932 auto props = GetPaintProperty<SwiperPaintProperty>();
4933 CHECK_NULL_RETURN(props, EdgeEffect::SPRING);
4934 return props->GetEdgeEffect().value_or(EdgeEffect::SPRING);
4935 }
4936
IsDisableSwipe() const4937 bool SwiperPattern::IsDisableSwipe() const
4938 {
4939 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4940 CHECK_NULL_RETURN(props, false);
4941 return props->GetDisableSwipe().value_or(false);
4942 }
4943
IsShowIndicator() const4944 bool SwiperPattern::IsShowIndicator() const
4945 {
4946 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4947 CHECK_NULL_RETURN(props, true);
4948 return props->GetShowIndicatorValue(true);
4949 }
4950
IsShowArrow() const4951 bool SwiperPattern::IsShowArrow() const
4952 {
4953 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4954 CHECK_NULL_RETURN(props, true);
4955 return props->GetDisplayArrowValue(false);
4956 }
4957
GetIndicatorType() const4958 SwiperIndicatorType SwiperPattern::GetIndicatorType() const
4959 {
4960 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4961 CHECK_NULL_RETURN(props, SwiperIndicatorType::DOT);
4962 return props->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
4963 }
4964
GetSwiperParameters() const4965 std::shared_ptr<SwiperParameters> SwiperPattern::GetSwiperParameters() const
4966 {
4967 if (swiperParameters_ == nullptr) {
4968 swiperParameters_ = std::make_shared<SwiperParameters>();
4969 auto pipelineContext = PipelineBase::GetCurrentContext();
4970 CHECK_NULL_RETURN(pipelineContext, swiperParameters_);
4971 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4972 CHECK_NULL_RETURN(swiperIndicatorTheme, swiperParameters_);
4973 swiperParameters_->itemWidth = swiperIndicatorTheme->GetSize();
4974 swiperParameters_->itemHeight = swiperIndicatorTheme->GetSize();
4975 swiperParameters_->selectedItemWidth = swiperIndicatorTheme->GetSize();
4976 swiperParameters_->selectedItemHeight = swiperIndicatorTheme->GetSize();
4977 swiperParameters_->maskValue = false;
4978 swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
4979 swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
4980 swiperParameters_->maxDisplayCountVal = 0;
4981 swiperParameters_->dimSpace = swiperIndicatorTheme->GetIndicatorDotItemSpace();
4982 swiperParameters_->ignoreSizeValue = false;
4983 swiperParameters_->setIgnoreSizeValue = false;
4984 }
4985 return swiperParameters_;
4986 }
4987
GetSwiperArrowParameters() const4988 std::shared_ptr<SwiperArrowParameters> SwiperPattern::GetSwiperArrowParameters() const
4989 {
4990 if (swiperArrowParameters_ == nullptr) {
4991 swiperArrowParameters_ = std::make_shared<SwiperArrowParameters>();
4992 auto pipelineContext = PipelineBase::GetCurrentContext();
4993 CHECK_NULL_RETURN(pipelineContext, swiperArrowParameters_);
4994 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4995 CHECK_NULL_RETURN(swiperIndicatorTheme, swiperArrowParameters_);
4996 swiperArrowParameters_->isShowBackground = false;
4997 swiperArrowParameters_->isSidebarMiddle = false;
4998 swiperArrowParameters_->backgroundSize = swiperIndicatorTheme->GetSmallArrowSize();
4999 swiperArrowParameters_->backgroundColor = swiperIndicatorTheme->GetSmallArrowBackgroundColor();
5000 swiperArrowParameters_->arrowSize = swiperIndicatorTheme->GetSmallArrowSize();
5001 swiperArrowParameters_->arrowColor = swiperIndicatorTheme->GetSmallArrowColor();
5002 }
5003 return swiperArrowParameters_;
5004 }
5005
GetSwiperDigitalParameters() const5006 std::shared_ptr<SwiperDigitalParameters> SwiperPattern::GetSwiperDigitalParameters() const
5007 {
5008 if (swiperDigitalParameters_ == nullptr) {
5009 swiperDigitalParameters_ = std::make_shared<SwiperDigitalParameters>();
5010 auto pipelineContext = PipelineBase::GetCurrentContext();
5011 CHECK_NULL_RETURN(pipelineContext, swiperDigitalParameters_);
5012 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
5013 swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
5014 swiperDigitalParameters_->selectedFontColor =
5015 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
5016 swiperDigitalParameters_->fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
5017 swiperDigitalParameters_->selectedFontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
5018 swiperDigitalParameters_->fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
5019 swiperDigitalParameters_->selectedFontWeight =
5020 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
5021 swiperDigitalParameters_->ignoreSizeValue = false;
5022 swiperDigitalParameters_->setIgnoreSizeValue = false;
5023 }
5024 return swiperDigitalParameters_;
5025 }
5026
TotalCount() const5027 int32_t SwiperPattern::TotalCount() const
5028 {
5029 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5030 CHECK_NULL_RETURN(props, 1);
5031 auto displayCount = props->GetDisplayCount().value_or(1);
5032 auto totalCount = RealTotalCount();
5033 if (IsSwipeByGroup() && displayCount != 0) {
5034 totalCount =
5035 static_cast<int32_t>(std::ceil(static_cast<float>(totalCount) / static_cast<float>(displayCount))) *
5036 displayCount;
5037 }
5038
5039 return totalCount;
5040 }
5041
RealTotalCount() const5042 int32_t SwiperPattern::RealTotalCount() const
5043 {
5044 auto host = GetHost();
5045 CHECK_NULL_RETURN(host, 0);
5046 // last child is swiper indicator
5047 int num = 0;
5048 if (!isBindIndicator_ && IsShowIndicator() && HasIndicatorNode()) {
5049 num += 1;
5050 }
5051 if (HasLeftButtonNode()) {
5052 num += 1;
5053 }
5054 if (HasRightButtonNode()) {
5055 num += 1;
5056 }
5057 if (hasCachedCapture_ && leftCaptureId_.has_value() && rightCaptureId_.has_value()) {
5058 num += CAPTURE_COUNT;
5059 }
5060 return host->TotalChildCount() - num;
5061 }
5062
DisplayIndicatorTotalCount() const5063 int32_t SwiperPattern::DisplayIndicatorTotalCount() const
5064 {
5065 if (IsAutoLinear()) {
5066 return RealTotalCount();
5067 }
5068 auto displayCount = GetDisplayCount();
5069 auto realTotalCount = RealTotalCount();
5070 if (realTotalCount <= 0) {
5071 return 0;
5072 }
5073 if (realTotalCount <= displayCount) {
5074 return 1;
5075 }
5076 if (IsSwipeByGroup() && displayCount != 0) {
5077 int32_t totalPages = 0;
5078 totalPages = realTotalCount / displayCount;
5079
5080 if (realTotalCount % displayCount) {
5081 totalPages++;
5082 }
5083
5084 return totalPages;
5085 } else {
5086 if (IsLoop()) {
5087 return realTotalCount;
5088 } else {
5089 return realTotalCount - displayCount + 1;
5090 }
5091 }
5092 }
5093
GetFirstItemInfoInVisibleArea() const5094 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetFirstItemInfoInVisibleArea() const
5095 {
5096 if (itemPosition_.empty()) {
5097 return std::make_pair(0, SwiperItemInfo {});
5098 }
5099 for (const auto& item : itemPosition_) {
5100 if (LessNotEqualCustomPrecision(item.second.startPos, 0, -0.01f) &&
5101 LessNotEqualCustomPrecision(item.second.endPos, 0, -0.01f)) {
5102 continue;
5103 }
5104 if (LessOrEqualCustomPrecision(item.second.startPos, 0, 0.01f) &&
5105 GreatNotEqualCustomPrecision(item.second.endPos, 0, 0.01f)) {
5106 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
5107 }
5108 if (GreatNotEqualCustomPrecision(item.second.startPos, 0, 0.01f) &&
5109 GreatNotEqualCustomPrecision(item.second.endPos, 0, 0.01f)) {
5110 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
5111 }
5112 }
5113 return std::make_pair(itemPosition_.begin()->first,
5114 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
5115 }
5116
GetFirstIndexInVisibleArea() const5117 int32_t SwiperPattern::GetFirstIndexInVisibleArea() const
5118 {
5119 if (itemPosition_.empty()) {
5120 return 0;
5121 }
5122 for (const auto& item : itemPosition_) {
5123 if (Negative(item.second.startPos) && Negative(item.second.endPos)) {
5124 continue;
5125 }
5126 if (Positive(item.second.endPos)) {
5127 return item.first;
5128 }
5129 }
5130 return itemPosition_.begin()->first;
5131 }
5132
GetLastItemInfoInVisibleArea() const5133 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetLastItemInfoInVisibleArea() const
5134 {
5135 if (itemPosition_.empty()) {
5136 return std::make_pair(0, SwiperItemInfo {});
5137 }
5138 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5139 auto lastItemIndex = firstItemInfoInVisibleArea.first + GetDisplayCount() - 1;
5140 auto iter = itemPosition_.find(lastItemIndex);
5141 if (iter != itemPosition_.end()) {
5142 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
5143 }
5144 return std::make_pair(itemPosition_.rbegin()->first,
5145 SwiperItemInfo { itemPosition_.rbegin()->second.startPos, itemPosition_.rbegin()->second.endPos });
5146 }
5147
GetSecondItemInfoInVisibleArea() const5148 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetSecondItemInfoInVisibleArea() const
5149 {
5150 if (itemPosition_.empty()) {
5151 return std::make_pair(0, SwiperItemInfo {});
5152 }
5153 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5154 auto secondItemIndex = firstItemInfoInVisibleArea.first + 1;
5155 auto iter = itemPosition_.find(secondItemIndex);
5156 if (iter != itemPosition_.end()) {
5157 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
5158 }
5159 return std::make_pair(itemPosition_.begin()->first,
5160 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
5161 }
5162
IsOutOfHotRegion(const PointF & dragPoint) const5163 bool SwiperPattern::IsOutOfHotRegion(const PointF& dragPoint) const
5164 {
5165 auto host = GetHost();
5166 CHECK_NULL_RETURN(host, true);
5167 auto context = host->GetRenderContext();
5168 CHECK_NULL_RETURN(context, true);
5169
5170 auto hotRegion = context->GetPaintRectWithoutTransform();
5171 return !hotRegion.IsInRegion(dragPoint + OffsetF(hotRegion.GetX(), hotRegion.GetY()));
5172 }
5173
UpdatePaintProperty(const RefPtr<FrameNode> & indicatorNode)5174 void SwiperPattern::UpdatePaintProperty(const RefPtr<FrameNode>& indicatorNode)
5175 {
5176 CHECK_NULL_VOID(indicatorNode);
5177 auto paintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
5178 CHECK_NULL_VOID(paintProperty);
5179 auto pipelineContext = PipelineBase::GetCurrentContext();
5180 CHECK_NULL_VOID(pipelineContext);
5181 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
5182 CHECK_NULL_VOID(swiperIndicatorTheme);
5183 auto swiperParameters = GetSwiperParameters();
5184 CHECK_NULL_VOID(swiperParameters);
5185 paintProperty->UpdateItemWidth(swiperParameters->itemWidth.value_or(swiperIndicatorTheme->GetSize()));
5186 paintProperty->UpdateItemHeight(swiperParameters->itemHeight.value_or(swiperIndicatorTheme->GetSize()));
5187 paintProperty->UpdateSelectedItemWidth(
5188 swiperParameters->selectedItemWidth.value_or(swiperIndicatorTheme->GetSize()));
5189 paintProperty->UpdateSelectedItemHeight(
5190 swiperParameters->selectedItemHeight.value_or(swiperIndicatorTheme->GetSize()));
5191 paintProperty->UpdateIndicatorMask(swiperParameters->maskValue.value_or(false));
5192 paintProperty->UpdateColor(swiperParameters->colorVal.value_or(swiperIndicatorTheme->GetColor()));
5193 paintProperty->UpdateSelectedColor(
5194 swiperParameters->selectedColorVal.value_or(swiperIndicatorTheme->GetSelectedColor()));
5195 paintProperty->UpdateIsCustomSize(isCustomSize_);
5196 paintProperty->UpdateSpace(swiperParameters->dimSpace.value_or(swiperIndicatorTheme->GetIndicatorDotItemSpace()));
5197 paintProperty->UpdateIgnoreSize(swiperParameters->ignoreSizeValue.value_or(false));
5198 MarkDirtyNodeSelf();
5199 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5200 }
5201
SetDigitStartAndEndProperty(const RefPtr<FrameNode> & indicatorNode)5202 void SwiperPattern::SetDigitStartAndEndProperty(const RefPtr<FrameNode>& indicatorNode)
5203 {
5204 CHECK_NULL_VOID(indicatorNode);
5205 auto indicatorProps = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
5206 CHECK_NULL_VOID(indicatorProps);
5207 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5208 CHECK_NULL_VOID(props);
5209 const auto digitalParams = GetSwiperDigitalParameters();
5210 CHECK_NULL_VOID(digitalParams);
5211 bool isRtl = GetNonAutoLayoutDirection() == TextDirection::RTL;
5212 if (digitalParams->dimStart.has_value()) {
5213 auto dimValue = digitalParams->dimStart.value().Value() >= 0.0 ? digitalParams->dimStart.value()
5214 : Dimension(0.0, DimensionUnit::VP);
5215 isRtl ? indicatorProps->UpdateRight(dimValue) : indicatorProps->UpdateLeft(dimValue);
5216 isRtl ? props->UpdateRight(dimValue) : props->UpdateLeft(digitalParams->dimLeft.value_or(0.0_vp));
5217 ;
5218 } else if (digitalParams->dimEnd.has_value()) {
5219 auto dimValue = digitalParams->dimEnd.value().Value() >= 0.0 ? digitalParams->dimEnd.value()
5220 : Dimension(0.0, DimensionUnit::VP);
5221 isRtl ? indicatorProps->UpdateLeft(dimValue) : indicatorProps->UpdateRight(dimValue);
5222 isRtl ? props->UpdateLeft(dimValue) : props->UpdateRight(digitalParams->dimRight.value_or(0.0_vp));
5223 }
5224 }
5225
PostTranslateTask(uint32_t delayTime)5226 void SwiperPattern::PostTranslateTask(uint32_t delayTime)
5227 {
5228 auto pipeline = GetContext();
5229 CHECK_NULL_VOID(pipeline);
5230 auto taskExecutor = pipeline->GetTaskExecutor();
5231 CHECK_NULL_VOID(taskExecutor);
5232
5233 if (translateTask_) {
5234 translateTask_.Cancel();
5235 }
5236
5237 auto weak = AceType::WeakClaim(this);
5238 translateTask_.Reset([weak, delayTime] {
5239 auto swiper = weak.Upgrade();
5240 if (swiper) {
5241 swiper->isInAutoPlay_ = true;
5242 auto childrenSize = swiper->TotalCount();
5243 auto displayCount = swiper->GetDisplayCount();
5244 if (childrenSize <= 0 || displayCount <= 0 || swiper->itemPosition_.empty()) {
5245 return;
5246 }
5247 if (!swiper->IsLoop() && swiper->GetLoopIndex(swiper->currentIndex_) + 1 > (childrenSize - displayCount)) {
5248 return;
5249 }
5250 auto stepItems = swiper->IsSwipeByGroup() ? displayCount : 1;
5251 swiper->targetIndex_ = swiper->CheckTargetIndex(swiper->currentIndex_ + stepItems);
5252 ACE_SCOPED_TRACE("Swiper autoPlay delayTime %d targetIndex %d isVisibleArea_ %d isWindowShow_ %d",
5253 delayTime, swiper->targetIndex_.value(), swiper->isVisibleArea_, swiper->isWindowShow_);
5254 swiper->MarkDirtyNodeSelf();
5255 }
5256 });
5257
5258 taskExecutor->PostDelayedTask(translateTask_, TaskExecutor::TaskType::UI, delayTime, "ArkUISwiperTranslate");
5259 }
5260
HandleVisibleChange(bool visible)5261 void SwiperPattern::HandleVisibleChange(bool visible)
5262 {
5263 isVisibleArea_ = visible;
5264 if (!visible) {
5265 translateTask_.Cancel();
5266 isInAutoPlay_ = false;
5267 return;
5268 }
5269
5270 if (NeedStartAutoPlay()) {
5271 StartAutoPlay();
5272 }
5273 }
5274
RegisterVisibleAreaChange()5275 void SwiperPattern::RegisterVisibleAreaChange()
5276 {
5277 auto host = GetHost();
5278 CHECK_NULL_VOID(host);
5279 auto pipeline = GetContext();
5280 CHECK_NULL_VOID(pipeline);
5281 pipeline->AddWindowStateChangedCallback(host->GetId());
5282
5283 if (hasVisibleChangeRegistered_) {
5284 return;
5285 }
5286
5287 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
5288 auto swiperPattern = weak.Upgrade();
5289 CHECK_NULL_VOID(swiperPattern);
5290 swiperPattern->HandleVisibleChange(visible);
5291 };
5292 pipeline->RemoveVisibleAreaChangeNode(host->GetId());
5293 std::vector<double> ratioList = { 0.0 };
5294 pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, true);
5295 hasVisibleChangeRegistered_ = true;
5296
5297 auto isFormRender = pipeline->IsFormRender();
5298 auto formMgr = pipeline->GetFormVisibleManager();
5299 if (!isFormRender || !formMgr) {
5300 return;
5301 }
5302 formMgr->RemoveFormVisibleChangeNode(host->GetId());
5303 auto formCallback = [weak = WeakClaim(this)](bool visible) {
5304 auto swiperPattern = weak.Upgrade();
5305 CHECK_NULL_VOID(swiperPattern);
5306 swiperPattern->HandleVisibleChange(visible);
5307 };
5308 formMgr->AddFormVisibleChangeNode(host, formCallback);
5309 }
5310
NeedAutoPlay() const5311 bool SwiperPattern::NeedAutoPlay() const
5312 {
5313 bool reachEnd = GetLoopIndex(CurrentIndex()) >= TotalCount() - 1 && !IsLoop();
5314 return IsAutoPlay() && !reachEnd && NeedStartAutoPlay() && !isIndicatorLongPress_;
5315 }
5316
TriggerAnimationEndOnSwipeToLeft()5317 void SwiperPattern::TriggerAnimationEndOnSwipeToLeft()
5318 {
5319 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5320 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
5321 auto firstIndexStartPos = firstItemInfoInVisibleArea.second.startPos;
5322 if (std::abs(firstIndexStartPos) < (firstItemLength / swiperProportion_)) {
5323 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
5324 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
5325 } else {
5326 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
5327 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
5328 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
5329 }
5330 }
5331
TriggerAnimationEndOnSwipeToRight()5332 void SwiperPattern::TriggerAnimationEndOnSwipeToRight()
5333 {
5334 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5335 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
5336 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
5337 auto secondIndexStartPos = secondItemInfoInVisibleArea.second.startPos;
5338 if (std::abs(secondIndexStartPos) < (firstItemLength / swiperProportion_)) {
5339 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
5340 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
5341 } else {
5342 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
5343 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
5344 }
5345 }
5346
UpdateIndexOnAnimationStop()5347 void SwiperPattern::UpdateIndexOnAnimationStop()
5348 {
5349 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
5350 if (currentIndex_ == firstItemInfoInVisibleArea.first) {
5351 // swipe to left
5352 TriggerAnimationEndOnSwipeToLeft();
5353 } else {
5354 // swipe to right
5355 TriggerAnimationEndOnSwipeToRight();
5356 }
5357 }
5358
UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)5359 void SwiperPattern::UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)
5360 {
5361 auto iter = itemPosition_.find(currentIndex_);
5362 if (iter == itemPosition_.end()) {
5363 UpdateCurrentIndex(pauseTargetIndex);
5364 if (itemPosition_.find(pauseTargetIndex) != itemPosition_.end()) {
5365 currentIndexOffset_ = itemPosition_.find(pauseTargetIndex)->second.startPos;
5366 }
5367 return;
5368 }
5369
5370 auto swiperWidth = MainSize();
5371 auto currentOffset = iter->second.startPos;
5372 if (std::abs(currentOffset) < (swiperWidth / swiperProportion_)) {
5373 return;
5374 }
5375
5376 if (currentOffset < 0.0f) {
5377 auto nextPageIndex = currentIndex_ + GetDisplayCount();
5378 auto nextIter = itemPosition_.find(nextPageIndex);
5379 if (nextIter == itemPosition_.end()) {
5380 return;
5381 }
5382
5383 auto nextPageOffset = nextIter->second.startPos;
5384 currentIndexOffset_ = nextPageOffset;
5385 UpdateCurrentIndex(nextPageIndex);
5386 } else {
5387 auto prevPageIndex = currentIndex_ - GetDisplayCount();
5388 auto prevIter = itemPosition_.find(prevPageIndex);
5389 if (prevIter == itemPosition_.end()) {
5390 return;
5391 }
5392
5393 auto prevPageOffset = prevIter->second.startPos;
5394 currentIndexOffset_ = prevPageOffset;
5395 UpdateCurrentIndex(prevPageIndex);
5396 }
5397 }
5398
TriggerAnimationEndOnForceStop(bool isInterrupt)5399 void SwiperPattern::TriggerAnimationEndOnForceStop(bool isInterrupt)
5400 {
5401 auto pauseTargetIndex = pauseTargetIndex_.has_value() ? pauseTargetIndex_.value() : currentIndex_;
5402 if (currentIndex_ != pauseTargetIndex) {
5403 if (IsSwipeByGroup()) {
5404 UpdateIndexOnSwipePageStop(pauseTargetIndex);
5405 } else {
5406 UpdateIndexOnAnimationStop();
5407 }
5408
5409 UpdateCurrentFocus();
5410 OnIndexChange();
5411 oldIndex_ = currentIndex_;
5412 }
5413 AnimationCallbackInfo info;
5414 info.isForceStop = true;
5415 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
5416 if (IsHorizontalAndRightToLeft()) {
5417 info.currentOffset =
5418 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
5419 }
5420 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info, isInterrupt);
5421 UpdateItemRenderGroup(false);
5422 }
5423
TriggerEventOnFinish(int32_t nextIndex)5424 void SwiperPattern::TriggerEventOnFinish(int32_t nextIndex)
5425 {
5426 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
5427
5428 AnimationCallbackInfo info;
5429 info.isForceStop = false;
5430 info.currentOffset = GetCustomPropertyOffset();
5431 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
5432 }
5433
GetCachedCount() const5434 int32_t SwiperPattern::GetCachedCount() const
5435 {
5436 auto host = GetHost();
5437 CHECK_NULL_RETURN(host, 1);
5438 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
5439 CHECK_NULL_RETURN(props, 1);
5440 auto cachedCount = props->GetCachedCount().value_or(1);
5441
5442 if (IsSwipeByGroup()) {
5443 cachedCount *= GetDisplayCount();
5444 }
5445
5446 return cachedCount;
5447 }
5448
SetLazyLoadFeature(bool useLazyLoad)5449 void SwiperPattern::SetLazyLoadFeature(bool useLazyLoad)
5450 {
5451 requestLongPredict_ = useLazyLoad;
5452 SetLazyForEachLongPredict(useLazyLoad);
5453
5454 if (!useLazyLoad) {
5455 return;
5456 }
5457 auto cacheCount = std::min(GetCachedCount(), RealTotalCount());
5458 std::set<int32_t> forEachIndexSet;
5459 for (auto count = 1; count <= cacheCount; count++) {
5460 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ + count));
5461 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ - count));
5462 }
5463 if (forEachIndexSet.empty()) {
5464 return;
5465 }
5466
5467 auto host = GetHost();
5468 CHECK_NULL_VOID(host);
5469 const auto& children = host->GetChildren();
5470 for (const auto& child : children) {
5471 if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
5472 continue;
5473 }
5474 auto pipeline = GetContext();
5475 CHECK_NULL_VOID(pipeline);
5476 auto taskExecutor = pipeline->GetTaskExecutor();
5477 CHECK_NULL_VOID(taskExecutor);
5478 taskExecutor->PostTask(
5479 [weak = WeakClaim(RawPtr(child)), id = host->GetInstanceId(), forEachIndexSet]() {
5480 ContainerScope scope(id);
5481 auto node = weak.Upgrade();
5482 CHECK_NULL_VOID(node);
5483 auto forEachNode = AceType::DynamicCast<ForEachNode>(node);
5484 CHECK_NULL_VOID(forEachNode);
5485 for (auto index : forEachIndexSet) {
5486 auto childNode = forEachNode->GetChildAtIndex(index);
5487 CHECK_NULL_VOID(childNode);
5488 childNode->Build(nullptr);
5489 }
5490 },
5491 TaskExecutor::TaskType::UI, "ArkUISwiperSetLazyLoadFeature");
5492 }
5493 }
5494
SetLazyForEachLongPredict(bool useLazyLoad) const5495 void SwiperPattern::SetLazyForEachLongPredict(bool useLazyLoad) const
5496 {
5497 // lazyBuild feature.
5498 auto host = GetHost();
5499 CHECK_NULL_VOID(host);
5500 auto targetNode = FindLazyForEachNode(host);
5501 if (targetNode.has_value()) {
5502 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
5503 CHECK_NULL_VOID(lazyForEachNode);
5504 lazyForEachNode->SetRequestLongPredict(useLazyLoad);
5505 }
5506 }
5507
SetLazyLoadIsLoop() const5508 void SwiperPattern::SetLazyLoadIsLoop() const
5509 {
5510 auto host = GetHost();
5511 CHECK_NULL_VOID(host);
5512 auto targetNode = FindLazyForEachNode(host);
5513 if (targetNode.has_value()) {
5514 auto isLoop = IsLoop();
5515 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
5516 if (lazyForEachNode) {
5517 lazyForEachNode->SetIsLoop(isLoop);
5518 }
5519 auto repeatVirtualNode = AceType::DynamicCast<RepeatVirtualScrollNode>(targetNode.value());
5520 if (repeatVirtualNode) {
5521 repeatVirtualNode->SetIsLoop(isLoop);
5522 }
5523
5524 auto repeatVirtualNode2 = AceType::DynamicCast<RepeatVirtualScroll2Node>(targetNode.value());
5525 if (repeatVirtualNode2) {
5526 repeatVirtualNode2->SetIsLoop(isLoop);
5527 }
5528 }
5529 }
5530
PostIdleTask(const RefPtr<FrameNode> & frameNode)5531 void SwiperPattern::PostIdleTask(const RefPtr<FrameNode>& frameNode)
5532 {
5533 if (cachedItems_.empty()) {
5534 return;
5535 }
5536 auto pipelineContext = GetContext();
5537 CHECK_NULL_VOID(pipelineContext);
5538 pipelineContext->AddPredictTask(
5539 [weak = WeakClaim(RawPtr(frameNode))](int64_t deadline, bool canUseLongPredictTask) {
5540 auto frameNode = weak.Upgrade();
5541 CHECK_NULL_VOID(frameNode);
5542 auto pattern = frameNode->GetPattern<SwiperPattern>();
5543 CHECK_NULL_VOID(pattern);
5544 if (!canUseLongPredictTask || !pattern->GetRequestLongPredict()) {
5545 pattern->PostIdleTask(frameNode);
5546 return;
5547 }
5548 auto cachedItems = pattern->GetCachedItems();
5549 for (auto it = cachedItems.begin(); it != cachedItems.end();) {
5550 if (GetSysTimestamp() > deadline) {
5551 break;
5552 }
5553 ACE_SCOPED_TRACE("Swiper cached self index: %d", *it);
5554 auto wrapper = frameNode->GetOrCreateChildByIndex(*it, false, true);
5555 if (!wrapper) {
5556 it = cachedItems.erase(it);
5557 continue;
5558 }
5559 auto childNode = wrapper->GetHostNode();
5560 if (childNode && childNode->GetGeometryNode()) {
5561 childNode->GetGeometryNode()->SetParentLayoutConstraint(pattern->GetLayoutConstraint());
5562 FrameNode::ProcessOffscreenNode(childNode);
5563 }
5564 it = cachedItems.erase(it);
5565 }
5566 pattern->SetCachedItems(cachedItems);
5567 if (!cachedItems.empty()) {
5568 pattern->PostIdleTask(frameNode);
5569 }
5570 });
5571 }
5572
SetLayoutDisplayCount(const RefPtr<FrameNode> & swiperNode)5573 void SwiperPattern::SetLayoutDisplayCount(const RefPtr<FrameNode>& swiperNode)
5574 {
5575 CHECK_NULL_VOID(swiperNode);
5576 if (!IsAutoFill()) {
5577 return;
5578 }
5579 if (HasLeftButtonNode()) {
5580 auto leftArrowNode =
5581 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(leftButtonId_.value())));
5582 CHECK_NULL_VOID(leftArrowNode);
5583 auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
5584 CHECK_NULL_VOID(leftArrowPattern);
5585 leftArrowPattern->SetLayoutDisplayCount(GetDisplayCount());
5586 }
5587 if (HasRightButtonNode()) {
5588 auto rightArrowNode =
5589 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(rightButtonId_.value())));
5590 CHECK_NULL_VOID(rightArrowNode);
5591 auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
5592 CHECK_NULL_VOID(rightArrowPattern);
5593 rightArrowPattern->SetLayoutDisplayCount(GetDisplayCount());
5594 }
5595 }
5596
IsVisibleChildrenSizeLessThanSwiper() const5597 bool SwiperPattern::IsVisibleChildrenSizeLessThanSwiper() const
5598 {
5599 if (itemPosition_.empty() || GetDisplayCount() > TotalCount()) {
5600 return true;
5601 }
5602 const auto firstItem = GetFirstItemInfoInVisibleArea();
5603 const auto lastItem = GetLastItemInfoInVisibleArea();
5604 const int32_t visibleItemCnt = lastItem.first - firstItem.first + 1;
5605 if (TotalCount() != visibleItemCnt) {
5606 return false;
5607 }
5608 const float childrenLength = lastItem.second.endPos - firstItem.second.startPos;
5609 if (NonPositive(childrenLength)) {
5610 return true;
5611 }
5612 return LessOrEqual(childrenLength, CalculateVisibleSize());
5613 }
5614
UpdateItemRenderGroup(bool itemRenderGroup)5615 void SwiperPattern::UpdateItemRenderGroup(bool itemRenderGroup)
5616 {
5617 for (auto& item : itemPosition_) {
5618 if (auto frameNode = item.second.node) {
5619 groupedItems_.insert(frameNode);
5620 }
5621 }
5622 auto host = GetHost();
5623 CHECK_NULL_VOID(host);
5624 for (auto child : host->GetChildren()) {
5625 auto frameNode = DynamicCast<FrameNode>(child);
5626 if (!frameNode || child->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
5627 continue;
5628 }
5629 groupedItems_.insert(frameNode);
5630 }
5631 for (auto iter = groupedItems_.begin(); iter != groupedItems_.end();) {
5632 if (auto node = iter->Upgrade()) {
5633 auto context = node->GetRenderContext();
5634 CHECK_NULL_VOID(context);
5635 context->UpdateSuggestedRenderGroup(itemRenderGroup);
5636 ++iter;
5637 } else {
5638 iter = groupedItems_.erase(iter);
5639 }
5640 }
5641 }
5642
OnTranslateFinish(int32_t nextIndex,bool restartAutoPlay,bool isFinishAnimation,bool forceStop,bool isInterrupt)5643 void SwiperPattern::OnTranslateFinish(
5644 int32_t nextIndex, bool restartAutoPlay, bool isFinishAnimation, bool forceStop, bool isInterrupt)
5645 {
5646 runningTargetIndex_.reset();
5647 if (forceStop && !isFinishAnimation) {
5648 TriggerAnimationEndOnForceStop(isInterrupt);
5649 } else {
5650 TriggerEventOnFinish(nextIndex);
5651 }
5652
5653 auto host = GetHost();
5654 CHECK_NULL_VOID(host);
5655 if (HasIndicatorNode()) {
5656 auto indicatorNode = GetCommonIndicatorNode();
5657 CHECK_NULL_VOID(indicatorNode);
5658 if (IsIndicator(indicatorNode->GetTag())) {
5659 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5660 MarkDirtyNodeSelf();
5661 }
5662 }
5663
5664 auto delayTime = GetInterval() - GetDuration();
5665 delayTime = std::clamp(delayTime, 0, delayTime);
5666 if (NeedAutoPlay() && isUserFinish_ && !forceStop) {
5667 PostTranslateTask(delayTime);
5668 }
5669 UpdateItemRenderGroup(false);
5670 }
5671
OnWindowShow()5672 void SwiperPattern::OnWindowShow()
5673 {
5674 if (!isParentHiddenChange_) {
5675 FireWillShowEvent(currentIndex_);
5676 }
5677 isWindowShow_ = true;
5678 if (NeedStartAutoPlay()) {
5679 StartAutoPlay();
5680 }
5681 }
5682
OnWindowHide()5683 void SwiperPattern::OnWindowHide()
5684 {
5685 if (!isParentHiddenChange_) {
5686 FireWillHideEvent(currentIndex_);
5687 }
5688 isWindowShow_ = false;
5689 StopAutoPlay();
5690
5691 if (isDragging_) {
5692 HandleDragEnd(0.0);
5693 }
5694
5695 StopSpringAnimationAndFlushImmediately();
5696 }
5697
ArrowHover(bool isHover,SwiperHoverFlag flag)5698 void SwiperPattern::ArrowHover(bool isHover, SwiperHoverFlag flag)
5699 {
5700 if (isHover) {
5701 hoverFlag_ |= flag;
5702 } else {
5703 hoverFlag_ &= (~flag);
5704 }
5705 if (HasLeftButtonNode() && HasRightButtonNode()) {
5706 auto swiperNode = GetHost();
5707 CHECK_NULL_VOID(swiperNode);
5708 auto leftArrowNode =
5709 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
5710 CHECK_NULL_VOID(leftArrowNode);
5711 auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
5712 CHECK_NULL_VOID(leftArrowPattern);
5713 leftArrowPattern->SetButtonVisible(hoverFlag_ != HOVER_NONE);
5714 auto rightArrowNode =
5715 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
5716 CHECK_NULL_VOID(rightArrowNode);
5717 auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
5718 CHECK_NULL_VOID(rightArrowPattern);
5719 rightArrowPattern->SetButtonVisible(hoverFlag_ != HOVER_NONE);
5720 }
5721 }
5722
SaveArrowProperty(const RefPtr<FrameNode> & arrowNode)5723 void SwiperPattern::SaveArrowProperty(const RefPtr<FrameNode>& arrowNode)
5724 {
5725 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5726 CHECK_NULL_VOID(props);
5727 const auto paintProps = GetPaintProperty<SwiperPaintProperty>();
5728 CHECK_NULL_VOID(props);
5729 const auto arrowProps = arrowNode->GetLayoutProperty<SwiperArrowLayoutProperty>();
5730 CHECK_NULL_VOID(arrowProps);
5731 arrowProps->UpdateDirection(props->GetDirection().value_or(Axis::HORIZONTAL));
5732 arrowProps->UpdateIndex(props->GetIndex().value_or(0));
5733 arrowProps->UpdateLoop(props->GetLoop().value_or(true));
5734 arrowProps->UpdateEnabled(paintProps->GetEnabled().value_or(true));
5735 arrowProps->UpdateDisplayArrow(props->GetDisplayArrowValue());
5736 arrowProps->UpdateHoverShow(props->GetHoverShowValue());
5737 arrowProps->UpdateIsShowBackground(props->GetIsShowBackgroundValue());
5738 arrowProps->UpdateBackgroundSize(props->GetBackgroundSizeValue());
5739 arrowProps->UpdateBackgroundColor(props->GetBackgroundColorValue());
5740 arrowProps->UpdateArrowSize(props->GetArrowSizeValue());
5741 arrowProps->UpdateArrowColor(props->GetArrowColorValue());
5742 arrowProps->UpdateIsSidebarMiddle(props->GetIsSidebarMiddleValue());
5743 }
5744
SetAccessibilityAction()5745 void SwiperPattern::SetAccessibilityAction()
5746 {
5747 auto host = GetHost();
5748 CHECK_NULL_VOID(host);
5749 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
5750 CHECK_NULL_VOID(accessibilityProperty);
5751 accessibilityProperty->SetActionScrollForward(
5752 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
5753 const auto& pattern = weakPtr.Upgrade();
5754 CHECK_NULL_VOID(pattern);
5755 const auto& accessibilityProperty = accessibility.Upgrade();
5756 CHECK_NULL_VOID(accessibilityProperty);
5757 if (!accessibilityProperty->IsScrollable()) {
5758 return;
5759 }
5760 pattern->ShowNext(true);
5761 });
5762
5763 accessibilityProperty->SetActionScrollBackward(
5764 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
5765 const auto& pattern = weakPtr.Upgrade();
5766 CHECK_NULL_VOID(pattern);
5767 const auto& accessibilityProperty = accessibility.Upgrade();
5768 CHECK_NULL_VOID(accessibilityProperty);
5769 if (!accessibilityProperty->IsScrollable()) {
5770 return;
5771 }
5772 pattern->ShowPrevious(true);
5773 });
5774 }
5775
NeedStartAutoPlay() const5776 bool SwiperPattern::NeedStartAutoPlay() const
5777 {
5778 return isWindowShow_ && isVisibleArea_;
5779 }
5780
ProvideRestoreInfo()5781 std::string SwiperPattern::ProvideRestoreInfo()
5782 {
5783 auto jsonObj = JsonUtil::Create(true);
5784 CHECK_NULL_RETURN(jsonObj, "");
5785 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5786 CHECK_NULL_RETURN(props, "");
5787 jsonObj->Put("Index", props->GetIndex().value_or(0));
5788 return jsonObj->ToString();
5789 }
5790
OnRestoreInfo(const std::string & restoreInfo)5791 void SwiperPattern::OnRestoreInfo(const std::string& restoreInfo)
5792 {
5793 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5794 CHECK_NULL_VOID(props);
5795 auto info = JsonUtil::ParseJsonString(restoreInfo);
5796 if (!info || !info->IsValid() || !info->IsObject()) {
5797 return;
5798 }
5799 auto jsonIsOn = info->GetValue("Index");
5800 props->UpdateIndex(jsonIsOn->GetInt());
5801 OnModifyDone();
5802 }
5803
InitHoverMouseEvent()5804 void SwiperPattern::InitHoverMouseEvent()
5805 {
5806 auto host = GetHost();
5807 CHECK_NULL_VOID(host);
5808 auto eventHub = host->GetOrCreateEventHub<EventHub>();
5809 CHECK_NULL_VOID(eventHub);
5810 auto inputHub = eventHub->GetOrCreateInputEventHub();
5811 CHECK_NULL_VOID(inputHub);
5812
5813 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
5814 auto pattern = weak.Upgrade();
5815 CHECK_NULL_VOID(pattern);
5816 if (!pattern->IsShowIndicator()) {
5817 pattern->ArrowHover(isHover, HOVER_SWIPER);
5818 }
5819 };
5820
5821 if (!hoverEvent_) {
5822 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
5823 inputHub->AddOnHoverEvent(hoverEvent_);
5824 }
5825
5826 auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
5827 auto pattern = weak.Upgrade();
5828 if (pattern) {
5829 pattern->HandleMouseEvent(info);
5830 }
5831 };
5832 if (mouseEvent_) {
5833 inputHub->RemoveOnMouseEvent(mouseEvent_);
5834 }
5835 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
5836 inputHub->AddOnMouseEvent(mouseEvent_);
5837 }
5838
HandleMouseEvent(const MouseInfo & info)5839 void SwiperPattern::HandleMouseEvent(const MouseInfo& info)
5840 {
5841 auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
5842 auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
5843 auto mousePoint = PointF(mouseOffsetX, mouseOffsetY);
5844 if (IsShowIndicator()) {
5845 CheckAndSetArrowHoverState(mousePoint);
5846 }
5847 }
5848
CheckAndSetArrowHoverState(const PointF & mousePoint)5849 void SwiperPattern::CheckAndSetArrowHoverState(const PointF& mousePoint)
5850 {
5851 if (!HasLeftButtonNode() || !HasRightButtonNode() || !HasIndicatorNode()) {
5852 return;
5853 }
5854
5855 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5856 CHECK_NULL_VOID(props);
5857 if (props->GetIsSidebarMiddleValue(false)) {
5858 return;
5859 }
5860
5861 RectF leftNodeRect;
5862 RectF rightNodeRect;
5863
5864 leftNodeRect = GetArrowFrameRect(GetLeftButtonId());
5865 rightNodeRect = GetArrowFrameRect(GetRightButtonId());
5866
5867 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
5868 leftNodeRect = GetArrowFrameRect(GetIndicatorId());
5869 }
5870
5871 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
5872 rightNodeRect = GetArrowFrameRect(GetIndicatorId());
5873 }
5874 RectF newNodeRect;
5875 if (GetDirection() == Axis::HORIZONTAL) {
5876 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(), rightNodeRect.Right() - leftNodeRect.Left(),
5877 std::min(rightNodeRect.Height(), leftNodeRect.Height()));
5878 } else {
5879 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(),
5880 std::min(rightNodeRect.Width(), leftNodeRect.Width()), rightNodeRect.Bottom() - leftNodeRect.Top());
5881 }
5882
5883 isAtHotRegion_ = newNodeRect.IsInRegion(mousePoint);
5884 ArrowHover(isAtHotRegion_, HOVER_SWIPER);
5885 }
5886
GetArrowFrameRect(const int32_t index) const5887 RectF SwiperPattern::GetArrowFrameRect(const int32_t index) const
5888 {
5889 auto swiperNode = GetHost();
5890 CHECK_NULL_RETURN(swiperNode, RectF(0, 0, 0, 0));
5891 auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(index)));
5892 CHECK_NULL_RETURN(arrowNode, RectF(0, 0, 0, 0));
5893 auto arrowGeometryNode = arrowNode->GetGeometryNode();
5894 CHECK_NULL_RETURN(arrowGeometryNode, RectF(0, 0, 0, 0));
5895 return arrowGeometryNode->GetFrameRect();
5896 }
5897
GetCustomPropertyOffset() const5898 float SwiperPattern::GetCustomPropertyOffset() const
5899 {
5900 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5901 CHECK_NULL_RETURN(props, 0.0);
5902 auto paddingAndBorder = props->CreatePaddingAndBorder();
5903 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
5904 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
5905 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
5906 return Dimension(paddingAndBorderValue + GetPrevMarginWithItemSpace(), DimensionUnit::PX).ConvertToVp();
5907 }
5908
GetCustomPropertyTargetOffset() const5909 float SwiperPattern::GetCustomPropertyTargetOffset() const
5910 {
5911 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5912 CHECK_NULL_RETURN(props, 0.0);
5913 auto paddingAndBorder = props->CreatePaddingAndBorder();
5914 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
5915 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
5916 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
5917
5918 auto preMarginPX = GetPrevMarginWithItemSpace();
5919 if (IsHorizontalAndRightToLeft()) {
5920 return Dimension(paddingAndBorderValue - preMarginPX, DimensionUnit::PX).ConvertToVp();
5921 }
5922 return Dimension(paddingAndBorderValue + preMarginPX, DimensionUnit::PX).ConvertToVp();
5923 }
5924
TotalDisPlayCount() const5925 int32_t SwiperPattern::TotalDisPlayCount() const
5926 {
5927 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5928 CHECK_NULL_RETURN(props, 1);
5929 auto displayCount = GetDisplayCount();
5930 if (SwiperUtils::IsStretch(props)) {
5931 if (Positive(props->GetCalculatedPrevMargin())) {
5932 displayCount++;
5933 }
5934 if (Positive(props->GetCalculatedNextMargin())) {
5935 displayCount++;
5936 }
5937 }
5938 return displayCount;
5939 }
5940
MarkDirtyNodeSelf()5941 void SwiperPattern::MarkDirtyNodeSelf()
5942 {
5943 auto host = GetHost();
5944 CHECK_NULL_VOID(host);
5945 if (!crossMatchChild_) {
5946 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5947 } else {
5948 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5949 }
5950 }
5951
ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)5952 void SwiperPattern::ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)
5953 {
5954 auto pipeline = GetContext();
5955 CHECK_NULL_VOID(pipeline);
5956
5957 fastCurrentIndex_.reset();
5958 targetIndex_.reset();
5959
5960 if (isFinishAnimation_) {
5961 currentDelta_ = 0.0f;
5962 itemPosition_.clear();
5963 isVoluntarilyClear_ = true;
5964 jumpIndex_ = nextIndex;
5965 MarkDirtyNodeSelf();
5966 pipeline->FlushUITasks();
5967 isFinishAnimation_ = false;
5968 } else if (currentIndex_ != nextIndex) {
5969 UpdateCurrentIndex(nextIndex);
5970 if (currentFocusIndex_ < currentIndex_ || currentFocusIndex_ >= currentIndex_ + GetDisplayCount()) {
5971 currentFocusIndex_ = currentIndex_;
5972 }
5973 auto host = GetHost();
5974 CHECK_NULL_VOID(host);
5975 do {
5976 auto curChildFrame =
5977 DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_)));
5978 if (!curChildFrame || !IsContentFocused()) {
5979 break;
5980 }
5981 FlushFocus(curChildFrame);
5982 } while (0);
5983 auto tempOldIndex = oldIndex_;
5984 oldIndex_ = nextIndex;
5985 currentFirstIndex_ = GetLoopIndex(nextIndex);
5986 turnPageRate_ = 0.0f;
5987 currentIndexOffset_ = 0.0f;
5988 if (pipeline->IsLayouting()) {
5989 pipeline->FlushUITaskWithSingleDirtyNode(host);
5990 pipeline->FlushSyncGeometryNodeTasks();
5991 } else {
5992 pipeline->FlushUITasks();
5993 pipeline->FlushMessages();
5994 }
5995 FireSelectedEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5996 FireUnselectedEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5997 FireChangeEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5998 // lazyBuild feature.
5999 SetLazyLoadFeature(true);
6000 }
6001 }
6002
OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child,float position,float)6003 void SwiperPattern::OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child, float position, float /* velocity */)
6004 {
6005 SetIsNestedInterrupt(false);
6006 if (IsDisableSwipe()) {
6007 return;
6008 }
6009 childScrolling_ = true;
6010 gestureSwipeIndex_ = currentIndex_;
6011 StopAnimationOnScrollStart(false);
6012 NotifyParentScrollStart(child, position);
6013 }
6014
NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child,float position)6015 void SwiperPattern::NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child, float position)
6016 {
6017 if (!GetIsFixedNestedScrollMode()) {
6018 SetParentScrollable();
6019 }
6020 auto parent = GetNestedScrollParent();
6021 CHECK_NULL_VOID(parent);
6022 const auto& nestedScroll = GetNestedScroll();
6023 if (parent && nestedScroll.NeedParent()) {
6024 parent->OnScrollStartRecursive(child, position);
6025 }
6026 }
6027
OnScrollEndRecursive(const std::optional<float> & velocity)6028 void SwiperPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
6029 {
6030 if (IsDisableSwipe()) {
6031 return;
6032 }
6033 // in case child didn't call swiper's HandleScrollVelocity
6034 if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
6035 HandleDragEnd(velocity.value_or(0.0f));
6036 }
6037 SetIsNestedInterrupt(false);
6038 childScrolling_ = false;
6039 InitIndexCanChangeMap();
6040 }
6041
OnScrollDragEndRecursive()6042 void SwiperPattern::OnScrollDragEndRecursive()
6043 {
6044 NestableScrollContainer::OnScrollDragEndRecursive();
6045 if (IsDisableSwipe()) {
6046 return;
6047 }
6048 // Swiper and child handle drag end event together.
6049 if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
6050 HandleDragEnd(0.0f);
6051 }
6052 }
6053
NotifyParentScrollEnd()6054 void SwiperPattern::NotifyParentScrollEnd()
6055 {
6056 auto parent = GetNestedScrollParent();
6057 const auto& nestedScroll = GetNestedScroll();
6058 if (parent && (nestedScroll.NeedParent() || GetIsNestedInterrupt())) {
6059 parent->OnScrollEndRecursive(std::nullopt);
6060 }
6061 }
6062
DuringTranslateAnimation() const6063 inline bool SwiperPattern::DuringTranslateAnimation() const
6064 {
6065 return (springAnimation_ && springAnimationIsRunning_ && !isTouchDownSpringAnimation_) || targetIndex_ ||
6066 propertyAnimationIsRunning_ || translateAnimationIsRunning_;
6067 }
6068
RunningTranslateAnimation() const6069 inline bool SwiperPattern::RunningTranslateAnimation() const
6070 {
6071 return springAnimationIsRunning_ || propertyAnimationIsRunning_ || translateAnimationIsRunning_;
6072 }
6073
DuringFadeAnimation() const6074 inline bool SwiperPattern::DuringFadeAnimation() const
6075 {
6076 return fadeAnimation_ && fadeAnimationIsRunning_ && !isTouchDownFadeAnimation_;
6077 }
6078
HandleScrollVelocity(float velocity,const RefPtr<NestableScrollContainer> & child)6079 bool SwiperPattern::HandleScrollVelocity(float velocity, const RefPtr<NestableScrollContainer>& child)
6080 {
6081 if (IsDisableSwipe()) {
6082 return false;
6083 }
6084 DestructSetter<bool> scope(childScrolling_, false);
6085 // haven't reached edge
6086 if (GetDistanceToEdge() > 0.0f || IsLoop()) {
6087 HandleDragEnd(velocity);
6088 return true;
6089 }
6090
6091 auto parent = GetNestedScrollParent();
6092 const auto nestedScroll = GetNestedScroll();
6093 if (parent && nestedScroll.NeedParent(NonPositive(velocity))) {
6094 // after reach end, parent handle velocity first
6095 if (parent->HandleScrollVelocity(velocity)) {
6096 return true;
6097 }
6098 }
6099 HandleDragEnd(velocity);
6100 // after reached end, NONE doesn't consume velocity, other edge effects do
6101 return GetEdgeEffect() != EdgeEffect::NONE;
6102 }
6103
HandleOutBoundarySelf(float offset,float & selfOffset,float & remainOffset)6104 void SwiperPattern::HandleOutBoundarySelf(float offset, float& selfOffset, float& remainOffset)
6105 {
6106 if (IsLoop()) {
6107 return;
6108 }
6109 if (GetEdgeEffect() == EdgeEffect::FADE && !NearZero(fadeOffset_)) {
6110 if ((Negative(offset) && Positive(fadeOffset_)) || (Positive(offset) && Negative(fadeOffset_))) {
6111 if (GreatNotEqual(std::abs(fadeOffset_), std::abs(offset))) {
6112 remainOffset = 0.0f;
6113 selfOffset = offset;
6114 } else {
6115 remainOffset += fadeOffset_;
6116 selfOffset = -fadeOffset_;
6117 }
6118 }
6119 }
6120 if (GetEdgeEffect() == EdgeEffect::SPRING && !itemPosition_.empty()) {
6121 if (Negative(offset) && itemPosition_.begin()->first == 0) {
6122 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
6123 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
6124 if (Positive(startPos)) {
6125 selfOffset = -std::min(startPos, -offset);
6126 remainOffset -= selfOffset;
6127 }
6128 } else if (Positive(offset) && itemPosition_.rbegin()->first == TotalCount() - 1) {
6129 auto visibleWindowSize = CalculateVisibleSize();
6130 auto endPos = itemPosition_.rbegin()->second.endPos + AdjustIgnoreBlankOverScrollOffSet(false);
6131 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
6132 if (LessNotEqual(endPos, visibleWindowSize)) {
6133 selfOffset = std::min(visibleWindowSize - endPos, offset);
6134 remainOffset -= selfOffset;
6135 }
6136 }
6137 }
6138 }
6139
HandleOutBoundary(float offset,int32_t source,float velocity)6140 ScrollResult SwiperPattern::HandleOutBoundary(float offset, int32_t source, float velocity)
6141 {
6142 float selfOffset = 0.0f;
6143 float remainOffset = offset;
6144 HandleOutBoundarySelf(offset, selfOffset, remainOffset);
6145 auto parent = GetNestedScrollParent();
6146 if (!NearZero(remainOffset) && parent) {
6147 auto res = parent->HandleScroll(remainOffset, source, NestedState::CHILD_CHECK_OVER_SCROLL, velocity);
6148 remainOffset = res.remain;
6149 }
6150 if (!NearZero(selfOffset)) {
6151 UpdateCurrentOffset(selfOffset);
6152 }
6153 return { remainOffset, true };
6154 }
6155
HandleScroll(float offset,int32_t source,NestedState state,float velocity)6156 ScrollResult SwiperPattern::HandleScroll(float offset, int32_t source, NestedState state, float velocity)
6157 {
6158 if (state == NestedState::CHILD_CHECK_OVER_SCROLL) {
6159 return HandleOutBoundary(offset, source, velocity);
6160 }
6161 if (source == SCROLL_FROM_ANIMATION && DuringTranslateAnimation()) {
6162 return { 0.0f, true };
6163 }
6164 if (IsDisableSwipe() || !CheckSwiperPanEvent(offset) || !CheckContentWillScroll(offset, offset)) {
6165 // deny conflicting animation from child
6166 return { offset, true };
6167 }
6168 if (state != NestedState::GESTURE) {
6169 // handle situations when multiple children are notifying scrollStart / scrollEnd
6170 // reset flag and animations to correct states when scroll happens
6171 childScrolling_ = true;
6172 if (DuringTranslateAnimation()) {
6173 StopAnimationOnScrollStart(false);
6174 }
6175 }
6176 // mouse scroll triggers showNext / showPrev instead of updating offset
6177 if (source == SCROLL_FROM_AXIS) {
6178 auto targetBfr = targetIndex_;
6179 (offset > 0) ? ShowPrevious() : ShowNext();
6180 if (targetBfr == targetIndex_) {
6181 // unchanged targetIndex_ implies Swiper has reached the edge and the mouse scroll isn't consumed.
6182 return { offset, true };
6183 }
6184 return { 0.0f, false };
6185 }
6186 auto parent = GetNestedScrollParent();
6187 auto nestedScroll = GetNestedScroll();
6188 if (!parent || !nestedScroll.NeedParent()) {
6189 if (IsOutOfBoundary(offset) && ChildFirst(state)) {
6190 CloseTheGap(offset);
6191 return { offset, true };
6192 }
6193 UpdateCurrentOffset(offset);
6194 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
6195 }
6196 ScrollResult result = { 0.f, !IsLoop() && GetDistanceToEdge() <= 0.f };
6197 if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::PARENT_FIRST) ||
6198 (Positive(offset) && nestedScroll.backward == NestedScrollMode::PARENT_FIRST))) {
6199 result = HandleScrollParentFirst(offset, source, state, velocity);
6200 } else if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::SELF_FIRST) ||
6201 (Positive(offset) && nestedScroll.backward == NestedScrollMode::SELF_FIRST))) {
6202 result = HandleScrollSelfFirst(offset, source, state, velocity);
6203 }
6204 return result;
6205 }
6206
HandleScrollParentFirst(float offset,int32_t source,NestedState state,float velocity)6207 ScrollResult SwiperPattern::HandleScrollParentFirst(float offset, int32_t source, NestedState state, float velocity)
6208 {
6209 // priority: parent scroll > self scroll > self overScroll > parent overScroll
6210 auto parent = GetNestedScrollParent();
6211 if (!parent) {
6212 return { 0.0f, true };
6213 }
6214 // skip CHECK_NULL, already checked in HandleScroll
6215 auto result = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
6216 offset = result.remain;
6217 if (IsOutOfBoundary(offset)) {
6218 if (NearZero(offset)) {
6219 return { 0.f, true };
6220 }
6221 CloseTheGap(offset);
6222 if (ChildFirst(state)) {
6223 if (result.reachEdge) {
6224 result = parent->HandleScroll(offset, source, NestedState::CHILD_OVER_SCROLL, velocity);
6225 }
6226 return { result.remain, true };
6227 }
6228 }
6229 // self Scroll && self overScroll
6230 UpdateCurrentOffset(offset);
6231 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
6232 }
6233
HandleScrollSelfFirst(float offset,int32_t source,NestedState state,float velocity)6234 ScrollResult SwiperPattern::HandleScrollSelfFirst(float offset, int32_t source, NestedState state, float velocity)
6235 {
6236 // priority: self scroll > parent scroll > parent overScroll > self overScroll
6237 if ((IsOutOfStart(offset) && Positive(offset)) || (IsOutOfEnd(offset) && Negative(offset))) {
6238 CloseTheGap(offset);
6239 // skip CHECK_NULL, already checked in HandleScroll
6240 auto parent = GetNestedScrollParent();
6241 if (!parent) {
6242 return { 0.0f, true };
6243 }
6244
6245 // reached edge, pass offset to parent
6246 auto res = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
6247 if (res.remain == 0.0f) {
6248 return { 0.0f, true };
6249 }
6250 // parent handle overScroll first
6251 if (res.reachEdge) {
6252 res = parent->HandleScroll(res.remain, source, NestedState::CHILD_OVER_SCROLL, velocity);
6253 }
6254 if (ChildFirst(state)) {
6255 return { res.remain, true };
6256 }
6257 if (res.remain != 0.0f) {
6258 // self overScroll
6259 UpdateCurrentOffset(res.remain);
6260 }
6261 } else {
6262 // regular scroll
6263 UpdateCurrentOffset(offset);
6264 }
6265 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
6266 }
6267
CloseTheGap(float & offset)6268 void SwiperPattern::CloseTheGap(float& offset)
6269 {
6270 float distanceToEdge = GetDistanceToEdge();
6271 if (Positive(distanceToEdge)) {
6272 if (GreatOrEqual(std::abs(offset), distanceToEdge)) {
6273 UpdateCurrentOffset(Positive(offset) ? distanceToEdge : -distanceToEdge);
6274 offset = Positive(offset) ? offset - distanceToEdge : offset + distanceToEdge;
6275 }
6276 }
6277 }
6278
ChildFirst(NestedState state)6279 inline bool SwiperPattern::ChildFirst(NestedState state)
6280 {
6281 // SELF/CHILD priority: self scroll > child scroll > self overScroll > child overScroll
6282 return state == NestedState::CHILD_SCROLL // child hasn't reach edge
6283 || GetEdgeEffect() == EdgeEffect::NONE;
6284 }
6285
UpdateDragFRCSceneInfo(float speed,SceneStatus sceneStatus)6286 void SwiperPattern::UpdateDragFRCSceneInfo(float speed, SceneStatus sceneStatus)
6287 {
6288 auto host = GetHost();
6289 CHECK_NULL_VOID(host);
6290 host->AddFRCSceneInfo(SWIPER_DRAG_SCENE, speed, sceneStatus);
6291 }
6292
GetLoopIndex(int32_t index,int32_t childrenSize) const6293 int32_t SwiperPattern::GetLoopIndex(int32_t index, int32_t childrenSize) const
6294 {
6295 if (childrenSize <= 0) {
6296 return index;
6297 }
6298 auto loopIndex = index;
6299 while (loopIndex < 0) {
6300 loopIndex = loopIndex + childrenSize;
6301 }
6302 loopIndex %= childrenSize;
6303 return loopIndex;
6304 }
6305
DumpAdvanceInfo()6306 void SwiperPattern::DumpAdvanceInfo()
6307 {
6308 SwiperHelper::DumpAdvanceInfo(*this);
6309 }
6310
RegisterScrollingListener(const RefPtr<ScrollingListener> listener)6311 void SwiperPattern::RegisterScrollingListener(const RefPtr<ScrollingListener> listener)
6312 {
6313 CHECK_NULL_VOID(listener);
6314 scrollingListener_.emplace_back(listener);
6315 }
6316
FireAndCleanScrollingListener()6317 void SwiperPattern::FireAndCleanScrollingListener()
6318 {
6319 for (auto listener : scrollingListener_) {
6320 CHECK_NULL_VOID(listener);
6321 listener->NotifyScrollingEvent();
6322 }
6323 scrollingListener_.clear();
6324 }
6325
CleanScrollingListener()6326 void SwiperPattern::CleanScrollingListener()
6327 {
6328 scrollingListener_.clear();
6329 }
6330
IsSwipeByGroup() const6331 bool SwiperPattern::IsSwipeByGroup() const
6332 {
6333 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
6334 CHECK_NULL_RETURN(props, false);
6335 return props->GetSwipeByGroup().value_or(false);
6336 }
6337
GetCurrentFrameNode(int32_t currentIndex) const6338 RefPtr<FrameNode> SwiperPattern::GetCurrentFrameNode(int32_t currentIndex) const
6339 {
6340 auto host = GetHost();
6341 CHECK_NULL_RETURN(host, nullptr);
6342 auto currentLayoutWrapper = host->GetChildByIndex(GetLoopIndex(currentIndex), true);
6343 CHECK_NULL_RETURN(currentLayoutWrapper, nullptr);
6344 return currentLayoutWrapper->GetHostNode();
6345 }
6346
OnCustomContentTransition(int32_t toIndex)6347 void SwiperPattern::OnCustomContentTransition(int32_t toIndex)
6348 {
6349 if (!currentProxyInAnimation_ && toIndex == CurrentIndex()) {
6350 return;
6351 }
6352
6353 customAnimationToIndex_ = toIndex;
6354 indexsInAnimation_.insert(toIndex);
6355 auto fromIndex = CurrentIndex();
6356 if (currentProxyInAnimation_) {
6357 fromIndex = currentProxyInAnimation_->GetToIndex();
6358
6359 FireChangeEvent(CurrentIndex(), fromIndex);
6360
6361 UpdateCurrentIndex(fromIndex);
6362 oldIndex_ = fromIndex;
6363
6364 AnimationCallbackInfo info;
6365 info.currentOffset = GetCustomPropertyOffset();
6366 FireAnimationEndEvent(fromIndex, info);
6367
6368 currentProxyInAnimation_->SetHasOnChanged(true);
6369 }
6370 if (fromIndex != toIndex) {
6371 FireWillShowEvent(toIndex);
6372 FireWillHideEvent(fromIndex);
6373 }
6374 auto pipelineContext = GetContext();
6375 CHECK_NULL_VOID(pipelineContext);
6376 pipelineContext->AddAfterLayoutTask([weak = WeakClaim(this), fromIndex, toIndex]() {
6377 auto swiperPattern = weak.Upgrade();
6378 CHECK_NULL_VOID(swiperPattern);
6379 swiperPattern->TriggerCustomContentTransitionEvent(fromIndex, toIndex);
6380 });
6381
6382 MarkDirtyNodeSelf();
6383 }
6384
TriggerCustomContentTransitionEvent(int32_t fromIndex,int32_t toIndex)6385 void SwiperPattern::TriggerCustomContentTransitionEvent(int32_t fromIndex, int32_t toIndex)
6386 {
6387 if (customAnimationToIndex_.value_or(toIndex) != toIndex) {
6388 TAG_LOGW(AceLogTag::ACE_SWIPER,
6389 "Swiper TriggerCustomContentTransitionEvent, fromIndex:%{public}d, toIndex:%{public}d", fromIndex, toIndex);
6390 needUnmountIndexs_.insert(toIndex);
6391 indexsInAnimation_.erase(toIndex);
6392 MarkDirtyNodeSelf();
6393 return;
6394 }
6395 CHECK_NULL_VOID(onTabsCustomContentTransition_);
6396
6397 auto tabContentAnimatedTransition = (*onTabsCustomContentTransition_)(fromIndex, toIndex);
6398 auto transition = tabContentAnimatedTransition.transition;
6399
6400 if (!transition) {
6401 OnCustomAnimationFinish(fromIndex, toIndex, false);
6402 return;
6403 }
6404
6405 auto proxy = AceType::MakeRefPtr<TabContentTransitionProxy>();
6406 proxy->SetFromIndex(fromIndex);
6407 proxy->SetToIndex(toIndex);
6408 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), fromIndex, toIndex](bool hasOnChanged) {
6409 auto swiperPattern = weak.Upgrade();
6410 CHECK_NULL_VOID(swiperPattern);
6411 swiperPattern->OnCustomAnimationFinish(fromIndex, toIndex, hasOnChanged);
6412 });
6413
6414 transition(proxy);
6415 currentProxyInAnimation_ = proxy;
6416
6417 AnimationCallbackInfo info;
6418 info.currentOffset = GetCustomPropertyOffset();
6419 info.targetOffset = GetCustomPropertyTargetOffset();
6420 FireSelectedEvent(fromIndex, toIndex);
6421 FireUnselectedEvent(fromIndex, toIndex);
6422 FireAnimationStartEvent(fromIndex, toIndex, info);
6423
6424 auto pipeline = GetContext();
6425 CHECK_NULL_VOID(pipeline);
6426 auto taskExecutor = pipeline->GetTaskExecutor();
6427 CHECK_NULL_VOID(taskExecutor);
6428
6429 auto timeout = tabContentAnimatedTransition.timeout;
6430 auto timeoutTask = [weak = AceType::WeakClaim(AceType::RawPtr(proxy))] {
6431 auto transitionProxy = weak.Upgrade();
6432 CHECK_NULL_VOID(transitionProxy);
6433 transitionProxy->FinishTransition();
6434 };
6435
6436 taskExecutor->PostDelayedTask(timeoutTask, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperFinishTransition");
6437 }
6438
OnCustomAnimationFinish(int32_t fromIndex,int32_t toIndex,bool hasOnChanged)6439 void SwiperPattern::OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged)
6440 {
6441 customAnimationToIndex_.reset();
6442 needUnmountIndexs_.insert(fromIndex);
6443 indexsInAnimation_.erase(toIndex);
6444
6445 if (!hasOnChanged) {
6446 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
6447 CHECK_NULL_VOID(props);
6448 props->UpdateIndexWithoutMeasure(GetLoopIndex(toIndex));
6449 oldIndex_ = fromIndex;
6450
6451 AnimationCallbackInfo info;
6452 info.currentOffset = GetCustomPropertyOffset();
6453 FireAnimationEndEvent(toIndex, info);
6454 }
6455
6456 if (indexsInAnimation_.empty()) {
6457 currentProxyInAnimation_ = nullptr;
6458 }
6459 auto curChildFrame = GetCurrentFrameNode(toIndex);
6460 if (curChildFrame) {
6461 FlushFocus(curChildFrame);
6462 }
6463 auto host = GetHost();
6464 CHECK_NULL_VOID(host);
6465 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
6466 auto pipeline = GetContext();
6467 CHECK_NULL_VOID(pipeline);
6468 pipeline->FlushUITasks();
6469 pipeline->FlushMessages();
6470 }
6471
SetSwiperEventCallback(bool disableSwipe)6472 void SwiperPattern::SetSwiperEventCallback(bool disableSwipe)
6473 {
6474 CHECK_NULL_VOID(swiperController_);
6475 auto removeSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
6476 auto swiperPattern = weak.Upgrade();
6477 CHECK_NULL_VOID(swiperPattern);
6478 auto host = swiperPattern->GetHost();
6479 CHECK_NULL_VOID(host);
6480 auto hub = host->GetOrCreateEventHub<EventHub>();
6481 CHECK_NULL_VOID(hub);
6482 auto gestureHub = hub->GetOrCreateGestureEventHub();
6483 CHECK_NULL_VOID(gestureHub);
6484 gestureHub->RemoveTouchEvent(swiperPattern->touchEvent_);
6485 if (!disableSwipe) {
6486 gestureHub->RemovePanEvent(swiperPattern->panEvent_);
6487 }
6488 };
6489 swiperController_->SetRemoveSwiperEventCallback(std::move(removeSwiperEventCallback));
6490
6491 auto addSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
6492 auto swiperPattern = weak.Upgrade();
6493 CHECK_NULL_VOID(swiperPattern);
6494 auto host = swiperPattern->GetHost();
6495 CHECK_NULL_VOID(host);
6496 auto hub = host->GetOrCreateEventHub<EventHub>();
6497 CHECK_NULL_VOID(hub);
6498 auto gestureHub = hub->GetOrCreateGestureEventHub();
6499 CHECK_NULL_VOID(gestureHub);
6500 gestureHub->AddTouchEvent(swiperPattern->touchEvent_);
6501 if (!disableSwipe) {
6502 PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
6503 { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
6504 gestureHub->AddPanEvent(swiperPattern->panEvent_, swiperPattern->panDirection_, 1, distanceMap);
6505 }
6506 };
6507 swiperController_->SetAddSwiperEventCallback(std::move(addSwiperEventCallback));
6508 }
6509
UpdateSwiperPanEvent(bool disableSwipe)6510 void SwiperPattern::UpdateSwiperPanEvent(bool disableSwipe)
6511 {
6512 auto host = GetHost();
6513 CHECK_NULL_VOID(host);
6514 auto hub = host->GetOrCreateEventHub<EventHub>();
6515 CHECK_NULL_VOID(hub);
6516 auto gestureHub = hub->GetOrCreateGestureEventHub();
6517 CHECK_NULL_VOID(gestureHub);
6518
6519 if (!disableSwipe) {
6520 InitPanEvent(gestureHub);
6521 } else if (panEvent_) {
6522 TAG_LOGI(AceLogTag::ACE_SWIPER, "Remove pan event when disable swipe. id:%{public}d", swiperId_);
6523 gestureHub->RemovePanEvent(panEvent_);
6524 panEvent_.Reset();
6525 if (isDragging_) {
6526 HandleDragEnd(0.0);
6527 }
6528 }
6529 }
6530
ProcessDelta(float & delta,float mainSize,float deltaSum)6531 void SwiperPattern::ProcessDelta(float& delta, float mainSize, float deltaSum)
6532 {
6533 if (std::abs(delta) > mainSize) {
6534 delta = delta > 0 ? mainSize : -mainSize;
6535 }
6536
6537 if ((std::abs(deltaSum + delta)) > mainSize) {
6538 delta = GreatNotEqual((deltaSum + delta), 0) ? (mainSize - deltaSum) : (-deltaSum - mainSize);
6539 }
6540 }
6541
ContentWillChange(int32_t comingIndex)6542 bool SwiperPattern::ContentWillChange(int32_t comingIndex)
6543 {
6544 return ContentWillChange(GetCurrentIndex(), comingIndex);
6545 }
6546
ContentWillChange(int32_t currentIndex,int32_t comingIndex)6547 bool SwiperPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
6548 {
6549 auto host = GetHost();
6550 CHECK_NULL_RETURN(host, true);
6551 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
6552 CHECK_NULL_RETURN(tabsNode, true);
6553 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
6554 CHECK_NULL_RETURN(tabsPattern, true);
6555 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
6556 CHECK_NULL_RETURN(tabBarNode, true);
6557 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
6558 CHECK_NULL_RETURN(tabBarPattern, true);
6559 if (!tabBarPattern->GetTabContentWillChangeFlag() && tabsPattern->GetInterceptStatus() &&
6560 currentIndex != comingIndex) {
6561 tabBarPattern->ResetTabContentWillChangeFlag();
6562 auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
6563 return ret.has_value() ? ret.value() : true;
6564 }
6565 tabBarPattern->ResetTabContentWillChangeFlag();
6566 return true;
6567 }
6568
CheckSwiperPanEvent(float mainDeltaOrVelocity)6569 bool SwiperPattern::CheckSwiperPanEvent(float mainDeltaOrVelocity)
6570 {
6571 int32_t currentIndex = GetCurrentIndex();
6572 int32_t comingIndex = currentIndex;
6573 if (GreatNotEqual(mainDeltaOrVelocity, 0.0)) {
6574 comingIndex = comingIndex < 1 ? 0 : comingIndex - 1;
6575 } else if (LessNotEqual(mainDeltaOrVelocity, 0.0)) {
6576 comingIndex = comingIndex > TotalCount() - INDEX_DIFF_TWO ? TotalCount() - 1 : comingIndex + 1;
6577 }
6578
6579 auto iter = indexCanChangeMap_.find(comingIndex);
6580 if (iter != indexCanChangeMap_.end()) {
6581 return iter->second;
6582 }
6583 bool ret = ContentWillChange(currentIndex, comingIndex);
6584 indexCanChangeMap_.emplace(comingIndex, ret);
6585 return ret;
6586 }
6587
CalcFirstItemWithoutItemSpace() const6588 std::pair<int32_t, SwiperItemInfo> SwiperPattern::CalcFirstItemWithoutItemSpace() const
6589 {
6590 if (itemPosition_.empty()) {
6591 return std::make_pair(0, SwiperItemInfo {});
6592 }
6593 for (const auto& item : itemPosition_) {
6594 auto startPos = item.second.startPos;
6595 auto endPos = item.second.endPos;
6596 auto itemSpace = GetItemSpace();
6597 startPos -= itemSpace;
6598 if (startPos < 0 && endPos < 0) {
6599 continue;
6600 }
6601 if (startPos <= 0 && endPos > 0) {
6602 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, endPos });
6603 }
6604 if (startPos > 0 && endPos > 0) {
6605 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, endPos });
6606 }
6607 }
6608 return std::make_pair(itemPosition_.begin()->first,
6609 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
6610 }
6611
CalcComingIndex(float mainDelta) const6612 int32_t SwiperPattern::CalcComingIndex(float mainDelta) const
6613 {
6614 auto firstItemInfoInVisibleArea = CalcFirstItemWithoutItemSpace();
6615 auto firstStartPos = firstItemInfoInVisibleArea.second.startPos;
6616 auto firstEndPos = firstItemInfoInVisibleArea.second.endPos;
6617 auto firstItemLength = firstEndPos - firstStartPos;
6618 if (LessOrEqual(firstItemLength, 0)) {
6619 return GetLoopIndex(currentIndex_);
6620 }
6621
6622 auto firstIndex = firstItemInfoInVisibleArea.first;
6623 auto step = 0;
6624 auto displayCount = GetDisplayCount();
6625 if (GreatNotEqual(mainDelta, 0.0)) {
6626 if (IsSwipeByGroup()) {
6627 step = -displayCount;
6628 } else if (firstIndex >= currentIndex_) {
6629 step = -1;
6630 } else {
6631 step = firstEndPos > firstItemLength ? firstIndex - currentIndex_ - 1 : firstIndex - currentIndex_;
6632 }
6633 } else if (LessNotEqual(mainDelta, 0.0)) {
6634 if (IsSwipeByGroup()) {
6635 step = displayCount;
6636 } else if (firstIndex <= currentIndex_) {
6637 step = 1;
6638 } else {
6639 step = firstIndex - currentIndex_;
6640 step += static_cast<int32_t>(std::ceil(std::abs(firstStartPos) / firstItemLength));
6641 }
6642 }
6643
6644 auto comingIndex = IsLoop() ? GetLoopIndex(currentIndex_ + step)
6645 : std::clamp(GetLoopIndex(currentIndex_) + step, 0, RealTotalCount() - 1);
6646 return comingIndex;
6647 }
6648
CalcWillScrollOffset(int32_t comingIndex)6649 float SwiperPattern::CalcWillScrollOffset(int32_t comingIndex)
6650 {
6651 if (itemPosition_.empty()) {
6652 return 0.0f;
6653 }
6654
6655 auto itemMainSize = CalculateVisibleSize();
6656 if (GetDisplayCount() > 1 && !IsSwipeByGroup()) {
6657 itemMainSize /= GetDisplayCount();
6658 }
6659
6660 if (NeedEnableIgnoreBlankOffset()) {
6661 auto currentIndex = GetLoopIndex(currentIndex_);
6662 comingIndex = GetLoopIndex(comingIndex);
6663 auto realLastIndex = RealTotalCount() - 1;
6664 auto secondIndex = 1;
6665 auto lastIndex = realLastIndex;
6666 auto penultimateIndex = realLastIndex - 1;
6667 if (IsSwipeByGroup()) {
6668 auto displayCount = GetDisplayCount();
6669 secondIndex = displayCount;
6670 lastIndex = SwiperUtils::ComputePageIndex(realLastIndex, displayCount);
6671 penultimateIndex = GetLoopIndex(lastIndex - displayCount);
6672 }
6673
6674 if (((currentIndex == 0 && comingIndex == secondIndex) || (currentIndex == secondIndex && comingIndex == 0)) &&
6675 prevMarginIgnoreBlank_) {
6676 auto offset = itemMainSize - GetPrevMargin();
6677 return offset;
6678 }
6679
6680 if (((currentIndex == penultimateIndex && comingIndex == lastIndex) ||
6681 (currentIndex == lastIndex && comingIndex == penultimateIndex)) &&
6682 nextMarginIgnoreBlank_) {
6683 auto offset = itemMainSize - GetNextMargin();
6684 return offset;
6685 }
6686 }
6687
6688 auto offset = itemMainSize + GetItemSpace();
6689 return offset;
6690 }
6691
CheckContentWillScroll(float checkValue,float mainDelta)6692 bool SwiperPattern::CheckContentWillScroll(float checkValue, float mainDelta)
6693 {
6694 if (itemPosition_.empty()) {
6695 return true;
6696 }
6697
6698 if (!HasOnContentWillScroll()) {
6699 return true;
6700 }
6701
6702 auto comingIndex = CalcComingIndex(checkValue);
6703 bool willScroll = ContentWillScroll(GetLoopIndex(currentIndex_), comingIndex, mainDelta);
6704 return willScroll;
6705 }
6706
ContentWillScroll(int32_t currentIndex,int32_t comingIndex,float offset)6707 bool SwiperPattern::ContentWillScroll(int32_t currentIndex, int32_t comingIndex, float offset)
6708 {
6709 currentIndex = GetLoopIndex(currentIndex);
6710 comingIndex = GetLoopIndex(comingIndex);
6711 auto result = OnContentWillScroll(currentIndex, comingIndex, offset);
6712 if (result && !result.value()) {
6713 return false;
6714 }
6715
6716 return true;
6717 }
6718
OnContentWillScroll(int32_t currentIndex,int32_t comingIndex,float offset) const6719 std::optional<bool> SwiperPattern::OnContentWillScroll(int32_t currentIndex, int32_t comingIndex, float offset) const
6720 {
6721 std::optional<bool> ret;
6722 if (!HasOnContentWillScroll()) {
6723 return ret;
6724 }
6725
6726 if (currentIndex != comingIndex) {
6727 auto event = *onContentWillScroll_;
6728 SwiperContentWillScrollResult result;
6729 result.currentIndex = currentIndex;
6730 result.comingIndex = comingIndex;
6731 result.offset = offset;
6732 ret = event(result);
6733 }
6734 return ret;
6735 }
6736
UpdateBottomTypeOnMultipleRTL(int32_t currentFirstIndex)6737 void SwiperPattern::UpdateBottomTypeOnMultipleRTL(int32_t currentFirstIndex)
6738 {
6739 CHECK_NULL_VOID(targetIndex_);
6740 auto targetIndex = targetIndex_.value();
6741 if (targetIndex < currentIndex_ && GetLoopIndex(targetIndex) == 0) {
6742 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
6743 return;
6744 }
6745
6746 if (targetIndex > currentIndex_ && GetLoopIndex(targetIndex) == TotalCount() - 1) {
6747 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
6748 return;
6749 }
6750
6751 if (targetIndex != currentIndex_ && currentFirstIndex == TotalCount() - 1 &&
6752 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
6753 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6754 return;
6755 }
6756
6757 if (targetIndex != currentIndex_ && currentFirstIndex == 0 &&
6758 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT) {
6759 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6760 return;
6761 }
6762 }
6763
HandleTouchBottomLoopOnRTL()6764 void SwiperPattern::HandleTouchBottomLoopOnRTL()
6765 {
6766 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6767 auto currentIndex = GetLoopIndex(currentIndex_);
6768 auto totalCount = TotalCount();
6769 auto displayCount = GetDisplayCount();
6770 bool commTouchBottom = (currentFirstIndex == totalCount - 1);
6771 bool releaseLeftTouchBottomStart = (currentIndex == totalCount - 1);
6772 bool releaseLeftTouchBottomEnd = (currentFirstIndex == 0);
6773 bool releaseRightTouchBottom = (currentFirstIndex == totalCount - 1);
6774 if (!IsAutoLinear() && IsSwipeByGroup()) {
6775 commTouchBottom = (currentFirstIndex >= totalCount - displayCount);
6776 releaseLeftTouchBottomStart = (currentIndex == totalCount - displayCount);
6777 releaseRightTouchBottom = (currentFirstIndex >= totalCount - displayCount);
6778 releaseLeftTouchBottomEnd = (currentFirstIndex < displayCount);
6779 }
6780 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
6781 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
6782 if (followTouchBottom) {
6783 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
6784 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6785 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
6786 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6787 }
6788 return;
6789 }
6790
6791 if (releaseLeftTouchBottomEnd && releaseLeftTouchBottomStart &&
6792 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT) {
6793 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6794 return;
6795 }
6796
6797 if (releaseRightTouchBottom && currentIndex == 0 &&
6798 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
6799 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6800 return;
6801 }
6802
6803 if (GetDisplayCount() > 1 || IsAutoLinear()) {
6804 UpdateBottomTypeOnMultipleRTL(currentFirstIndex);
6805 }
6806 }
6807
UpdateBottomTypeOnMultiple(int32_t currentFirstIndex)6808 void SwiperPattern::UpdateBottomTypeOnMultiple(int32_t currentFirstIndex)
6809 {
6810 CHECK_NULL_VOID(targetIndex_);
6811 auto targetIndex = targetIndex_.value();
6812 if (targetIndex < currentIndex_ && GetLoopIndex(targetIndex) == 0) {
6813 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
6814 return;
6815 }
6816
6817 if (targetIndex > currentIndex_ && GetLoopIndex(targetIndex) == TotalCount() - 1) {
6818 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
6819 return;
6820 }
6821
6822 if (targetIndex != currentIndex_ && currentFirstIndex == TotalCount() - 1 &&
6823 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT) {
6824 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6825 return;
6826 }
6827
6828 if (targetIndex != currentIndex_ && currentFirstIndex == 0 &&
6829 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
6830 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6831 return;
6832 }
6833 }
6834
HandleTouchBottomLoop()6835 void SwiperPattern::HandleTouchBottomLoop()
6836 {
6837 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6838 auto currentIndex = GetLoopIndex(currentIndex_);
6839 if (IsHorizontalAndRightToLeft()) {
6840 currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
6841 currentIndex = TotalCount() - 1 - currentIndex;
6842 }
6843
6844 bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
6845 bool releaseTouchBottom = (currentIndex == TotalCount() - 1);
6846 if (!IsAutoLinear() && IsSwipeByGroup()) {
6847 commTouchBottom = currentFirstIndex >= TotalCount() - GetDisplayCount();
6848 releaseTouchBottom = currentIndex >= TotalCount() - GetDisplayCount();
6849 }
6850 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
6851 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
6852 if (followTouchBottom) {
6853 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
6854 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6855 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
6856 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6857 }
6858 return;
6859 }
6860
6861 bool leftReleaseTouchBottom =
6862 (commTouchBottom && (currentIndex == 0 && gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT));
6863 bool rightReleaseTouchBottom = ((currentFirstIndex == 0) && (releaseTouchBottom) &&
6864 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT);
6865 if (leftReleaseTouchBottom || rightReleaseTouchBottom) {
6866 if (currentIndex == 0) {
6867 // left bottom
6868 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
6869 return;
6870 } else if (releaseTouchBottom) {
6871 // right bottom
6872 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
6873 return;
6874 }
6875 }
6876
6877 if (GetDisplayCount() > 1 || IsAutoLinear()) {
6878 UpdateBottomTypeOnMultiple(currentFirstIndex);
6879 }
6880 }
6881
CalculateGestureStateOnRTL(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)6882 void SwiperPattern::CalculateGestureStateOnRTL(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
6883 {
6884 if (GreatNotEqual(additionalOffset, 0.0f)) {
6885 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
6886 needTurn_ = false;
6887 return;
6888 }
6889
6890 if (LessNotEqual(additionalOffset, 0.0f)) {
6891 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
6892 needTurn_ = false;
6893 return;
6894 }
6895
6896 auto currentIndex = GetLoopIndex(currentIndex_);
6897 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6898 if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
6899 needTurn_ = true;
6900 if (isTouchDown_ && GreatOrEqual(mainDeltaSum_, 0.0f)) {
6901 needTurn_ = false;
6902 }
6903 } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
6904 needTurn_ = true;
6905 if (isTouchDown_ && (LessOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
6906 needTurn_ = false;
6907 }
6908 }
6909
6910 if (!IsLoop()) {
6911 needTurn_ = false;
6912 }
6913
6914 if (currentFirstIndex >= currentIndex) {
6915 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
6916 return;
6917 }
6918
6919 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
6920 }
6921
CalculateGestureState(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)6922 void SwiperPattern::CalculateGestureState(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
6923 {
6924 auto currentIndex = GetLoopIndex(currentIndex_);
6925 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
6926 if (IsHorizontalAndRightToLeft()) {
6927 preFirstIndex = TotalCount() - 1 - preFirstIndex;
6928 currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
6929 currentIndex = TotalCount() - 1 - currentIndex;
6930 }
6931
6932 // Keep follow hand
6933 if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
6934 needTurn_ = true;
6935 if (isTouchDown_ && LessOrEqual(mainDeltaSum_, 0.0f) && !childScrolling_) {
6936 needTurn_ = false;
6937 }
6938 } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
6939 needTurn_ = true;
6940 if (isTouchDown_ && (GreatOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
6941 needTurn_ = false;
6942 }
6943 }
6944
6945 if (GreatNotEqual(additionalOffset, 0.0f)) {
6946 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
6947 needTurn_ = false;
6948 } else if (LessNotEqual(additionalOffset, 0.0f)) {
6949 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
6950 needTurn_ = false;
6951 } else if (currentFirstIndex >= currentIndex) {
6952 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
6953
6954 if (!IsLoop() && currentFirstIndex == 0 && GreatOrEqual(mainDeltaSum_, 0.0f)) {
6955 gestureState_ = GestureState::GESTURE_STATE_FOLLOW_LEFT;
6956 needTurn_ = false;
6957 }
6958
6959 if (!IsLoop() && currentFirstIndex == TotalCount() - 1 && LessOrEqual(mainDeltaSum_, 0.0f)) {
6960 gestureState_ = GestureState::GESTURE_STATE_FOLLOW_RIGHT;
6961 needTurn_ = false;
6962 }
6963 } else if (currentFirstIndex < currentIndex) {
6964 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
6965 }
6966 return;
6967 }
6968
CalcCurrentPageStatusOnRTL(float additionalOffset,bool isTouchBottom) const6969 std::pair<float, float> SwiperPattern::CalcCurrentPageStatusOnRTL(float additionalOffset, bool isTouchBottom) const
6970 {
6971 float currentTurnPageRate = FLT_MAX;
6972 auto firstIndex = currentFirstIndex_;
6973 auto itemMainSize = CalculateVisibleSize();
6974 auto itemSpace = GetItemSpace();
6975 for (auto iter = itemPosition_.rbegin(); iter != itemPosition_.rend(); iter++) {
6976 auto startPos = itemMainSize - iter->second.endPos;
6977 auto endPos = itemMainSize - iter->second.startPos;
6978 if (isTouchBottom && Positive(itemSpace)) {
6979 startPos += itemSpace;
6980 endPos += itemSpace;
6981 }
6982
6983 if (LessNotEqualCustomPrecision((startPos + additionalOffset), 0, -0.01f) &&
6984 LessNotEqualCustomPrecision((endPos + additionalOffset), 0, -0.01f)) {
6985 continue;
6986 }
6987 if (GreatOrEqualCustomPrecision((startPos + additionalOffset), 0, -0.01f) &&
6988 GreatNotEqualCustomPrecision((endPos + additionalOffset), 0, 0.01f)) {
6989 firstIndex = iter->first;
6990 currentTurnPageRate = 0.0f;
6991 break;
6992 }
6993 if (GreatNotEqualCustomPrecision((endPos + additionalOffset), 0, 0.01f)) {
6994 firstIndex = iter->first;
6995 currentTurnPageRate =
6996 (NearEqual(endPos, startPos) ? 0 : ((startPos + additionalOffset) / (endPos - startPos)));
6997 break;
6998 }
6999 }
7000
7001 return std::make_pair(currentTurnPageRate, firstIndex);
7002 }
7003
CalcCurrentTurnPageRate(bool isTouchBottom) const7004 float SwiperPattern::CalcCurrentTurnPageRate(bool isTouchBottom) const
7005 {
7006 if (IsHorizontalAndRightToLeft()) {
7007 return CalcCurrentPageStatusOnRTL(0.0f, isTouchBottom).first;
7008 }
7009
7010 return CalcCurrentPageStatus(0.0f).first;
7011 }
7012
CalcCurrentPageStatus(float additionalOffset) const7013 std::pair<float, float> SwiperPattern::CalcCurrentPageStatus(float additionalOffset) const
7014 {
7015 float currentTurnPageRate = FLT_MAX;
7016 auto firstIndex = currentFirstIndex_;
7017 for (const auto& iter : itemPosition_) {
7018 if (LessNotEqualCustomPrecision((iter.second.startPos + additionalOffset), 0, -0.01f) &&
7019 LessNotEqualCustomPrecision((iter.second.endPos + additionalOffset), 0, -0.01f)) {
7020 continue;
7021 }
7022 if (GreatOrEqualCustomPrecision((iter.second.startPos + additionalOffset), 0, -0.01f) &&
7023 GreatNotEqualCustomPrecision((iter.second.endPos + additionalOffset), 0, 0.01f)) {
7024 firstIndex = iter.first;
7025 currentTurnPageRate = 0.0f;
7026 break;
7027 }
7028 if (GreatNotEqualCustomPrecision((iter.second.endPos + additionalOffset), 0, 0.01f)) {
7029 firstIndex = iter.first;
7030 currentTurnPageRate =
7031 (NearEqual(iter.second.endPos, iter.second.startPos)
7032 ? 0
7033 : ((iter.second.startPos + additionalOffset) / (iter.second.endPos - iter.second.startPos)));
7034 break;
7035 }
7036 }
7037
7038 return std::make_pair(currentTurnPageRate, firstIndex);
7039 }
7040
StopIndicatorAnimation(bool ifImmediately)7041 void SwiperPattern::StopIndicatorAnimation(bool ifImmediately)
7042 {
7043 AnimationUtils::StopAnimation(indicatorAnimation_);
7044
7045 if (stopIndicatorAnimationFunc_) {
7046 stopIndicatorAnimationFunc_(ifImmediately);
7047 }
7048 }
7049
FireWillHideEvent(int32_t willHideIndex) const7050 void SwiperPattern::FireWillHideEvent(int32_t willHideIndex) const
7051 {
7052 if (!hasTabsAncestor_) {
7053 return;
7054 }
7055 auto host = GetHost();
7056 CHECK_NULL_VOID(host);
7057 auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willHideIndex));
7058 CHECK_NULL_VOID(tabContentNode);
7059 auto tabContentEventHub = tabContentNode->GetOrCreateEventHub<TabContentEventHub>();
7060 CHECK_NULL_VOID(tabContentEventHub);
7061 tabContentEventHub->FireWillHideEvent();
7062 }
7063
FireWillShowEvent(int32_t willShowIndex) const7064 void SwiperPattern::FireWillShowEvent(int32_t willShowIndex) const
7065 {
7066 if (!hasTabsAncestor_) {
7067 return;
7068 }
7069 auto host = GetHost();
7070 CHECK_NULL_VOID(host);
7071 auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willShowIndex));
7072 CHECK_NULL_VOID(tabContentNode);
7073 auto tabContentEventHub = tabContentNode->GetOrCreateEventHub<TabContentEventHub>();
7074 CHECK_NULL_VOID(tabContentEventHub);
7075 tabContentEventHub->FireWillShowEvent();
7076 }
7077
SetOnHiddenChangeForParent()7078 void SwiperPattern::SetOnHiddenChangeForParent()
7079 {
7080 auto host = GetHost();
7081 CHECK_NULL_VOID(host);
7082 auto parent = host->GetAncestorNodeOfFrame(false);
7083 CHECK_NULL_VOID(parent);
7084 while (parent) {
7085 if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
7086 break;
7087 }
7088 parent = parent->GetAncestorNodeOfFrame(false);
7089 }
7090 auto onHiddenChange = [weak = WeakClaim(this)](bool isShow) {
7091 auto swiperPattern = weak.Upgrade();
7092 CHECK_NULL_VOID(swiperPattern);
7093 auto index = swiperPattern->GetCurrentIndex();
7094
7095 if (isShow) {
7096 swiperPattern->FireWillShowEvent(index);
7097 } else {
7098 swiperPattern->FireWillHideEvent(index);
7099 }
7100 swiperPattern->isParentHiddenChange_ = true;
7101 };
7102 CHECK_NULL_VOID(parent);
7103 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
7104 auto pagePattern = parent->GetPattern<PagePattern>();
7105 CHECK_NULL_VOID(pagePattern);
7106 pagePattern->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
7107 }
7108
7109 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
7110 auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
7111 CHECK_NULL_VOID(navDestinationePattern);
7112 auto navDestinationEventHub = navDestinationePattern->GetOrCreateEventHub<NavDestinationEventHub>();
7113 CHECK_NULL_VOID(navDestinationEventHub);
7114 navDestinationEventHub->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
7115 }
7116 }
7117
RemoveOnHiddenChange()7118 void SwiperPattern::RemoveOnHiddenChange()
7119 {
7120 auto host = GetHost();
7121 CHECK_NULL_VOID(host);
7122 auto parent = host->GetAncestorNodeOfFrame(false);
7123 CHECK_NULL_VOID(parent);
7124 while (parent) {
7125 if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
7126 break;
7127 }
7128 parent = parent->GetAncestorNodeOfFrame(false);
7129 }
7130 CHECK_NULL_VOID(parent);
7131 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
7132 auto pagePattern = parent->GetPattern<PagePattern>();
7133 CHECK_NULL_VOID(pagePattern);
7134 pagePattern->RemoveOnHiddenChange(host->GetId());
7135 }
7136 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
7137 auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
7138 CHECK_NULL_VOID(navDestinationePattern);
7139 auto navDestinationEventHub = navDestinationePattern->GetOrCreateEventHub<NavDestinationEventHub>();
7140 CHECK_NULL_VOID(navDestinationEventHub);
7141 navDestinationEventHub->RemoveOnHiddenChange(host->GetId());
7142 }
7143 }
7144
FindLazyForEachNode(RefPtr<UINode> baseNode,bool isSelfNode) const7145 std::optional<RefPtr<UINode>> SwiperPattern::FindLazyForEachNode(RefPtr<UINode> baseNode, bool isSelfNode) const
7146 {
7147 if (AceType::DynamicCast<LazyForEachNode>(baseNode)) {
7148 return baseNode;
7149 }
7150 if (AceType::DynamicCast<RepeatVirtualScrollNode>(baseNode)) {
7151 return baseNode;
7152 }
7153 if (AceType::DynamicCast<RepeatVirtualScroll2Node>(baseNode)) {
7154 return baseNode;
7155 }
7156 if (!isSelfNode && AceType::DynamicCast<FrameNode>(baseNode)) {
7157 return std::nullopt;
7158 }
7159 for (const auto& child : baseNode->GetChildren()) {
7160 auto targetNode = FindLazyForEachNode(child, false);
7161 if (targetNode.has_value()) {
7162 return targetNode;
7163 }
7164 }
7165 return std::nullopt;
7166 }
7167
FindForEachNode(const RefPtr<UINode> & baseNode,bool isSelfNode) const7168 std::optional<RefPtr<UINode>> SwiperPattern::FindForEachNode(const RefPtr<UINode>& baseNode, bool isSelfNode) const
7169 {
7170 if (AceType::DynamicCast<ForEachNode>(baseNode)) {
7171 return baseNode;
7172 }
7173
7174 if (AceType::DynamicCast<RepeatVirtualScrollNode>(baseNode)) {
7175 return baseNode;
7176 }
7177
7178 if (AceType::DynamicCast<RepeatVirtualScroll2Node>(baseNode)) {
7179 return baseNode;
7180 }
7181
7182 if (!isSelfNode && AceType::DynamicCast<FrameNode>(baseNode)) {
7183 return std::nullopt;
7184 }
7185
7186 for (const auto& child : baseNode->GetChildren()) {
7187 auto targetNode = FindForEachNode(child, false);
7188 if (targetNode.has_value()) {
7189 return targetNode;
7190 }
7191 }
7192
7193 return std::nullopt;
7194 }
7195
CreateNodePaintMethod()7196 RefPtr<NodePaintMethod> SwiperPattern::CreateNodePaintMethod()
7197 {
7198 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
7199 CHECK_NULL_RETURN(props, nullptr);
7200 const auto& paddingProperty = props->GetPaddingProperty();
7201 bool needClipPadding = paddingProperty != nullptr;
7202 bool needPaintFade = !IsLoop() && GetEdgeEffect() == EdgeEffect::FADE && !NearZero(fadeOffset_);
7203 auto paintMethod =
7204 MakeRefPtr<SwiperPaintMethod>(GetDirection(), IsHorizontalAndRightToLeft() ? -fadeOffset_ : fadeOffset_);
7205 paintMethod->SetNeedPaintFade(needPaintFade);
7206 paintMethod->SetNeedClipPadding(needClipPadding);
7207 return paintMethod;
7208 }
7209
UpdateNodeRate()7210 void SwiperPattern::UpdateNodeRate()
7211 {
7212 auto host = GetHost();
7213 CHECK_NULL_VOID(host);
7214 auto pipelineContext = GetContext();
7215 CHECK_NULL_VOID(pipelineContext);
7216 auto frameRateManager = pipelineContext->GetFrameRateManager();
7217 CHECK_NULL_VOID(frameRateManager);
7218 auto nodeId = host->GetId();
7219 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::GESTURE);
7220 if (iter != frameRateRange_.end() && iter->second->IsValid()) {
7221 auto expectedRate = iter->second->preferred_;
7222 TAG_LOGI(AceLogTag::ACE_SWIPER, "Expected gesture frame rate is: %{public}d", expectedRate);
7223 frameRateManager->UpdateNodeRate(nodeId, expectedRate);
7224 }
7225 }
7226
GetBindIndicatorParameters() const7227 std::shared_ptr<SwiperParameters> SwiperPattern::GetBindIndicatorParameters() const
7228 {
7229 auto bindIndicatorNode = GetIndicatorNode();
7230 CHECK_NULL_RETURN(bindIndicatorNode, nullptr);
7231 auto indicatorPattern = bindIndicatorNode->GetPattern<IndicatorPattern>();
7232 CHECK_NULL_RETURN(indicatorPattern, nullptr);
7233 return indicatorPattern->GetIndicatorParameters();
7234 }
7235
GetMaxDisplayCount() const7236 int32_t SwiperPattern::GetMaxDisplayCount() const
7237 {
7238 auto indicatorParameters = isBindIndicator_ ? GetBindIndicatorParameters() : swiperParameters_;
7239 if (!indicatorParameters || !indicatorParameters->maxDisplayCountVal.has_value()) {
7240 return 0;
7241 }
7242
7243 auto maxDisplayCount = indicatorParameters->maxDisplayCountVal.value();
7244 if (maxDisplayCount < MAX_DISPLAY_COUNT_MIN || maxDisplayCount > MAX_DISPLAY_COUNT_MAX) {
7245 return 0;
7246 }
7247
7248 auto childrenSize = RealTotalCount();
7249 if (childrenSize <= maxDisplayCount) {
7250 return 0;
7251 }
7252
7253 return maxDisplayCount;
7254 }
7255
SetIndicatorChangeIndexStatus(bool withAnimation,std::optional<int32_t> startIndex)7256 void SwiperPattern::SetIndicatorChangeIndexStatus(bool withAnimation, std::optional<int32_t> startIndex)
7257 {
7258 auto indicatorNode = GetCommonIndicatorNode();
7259 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
7260 return;
7261 }
7262
7263 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
7264 CHECK_NULL_VOID(indicatorPattern);
7265
7266 indicatorPattern->SetChangeIndexWithAnimation(withAnimation);
7267 indicatorPattern->SetStartIndex(startIndex);
7268 }
7269
SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)7270 void SwiperPattern::SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)
7271 {
7272 if (GetMaxDisplayCount() <= 0) {
7273 return;
7274 }
7275 auto indicatorNode = GetCommonIndicatorNode();
7276 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
7277 return;
7278 }
7279
7280 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
7281 CHECK_NULL_VOID(indicatorPattern);
7282
7283 indicatorPattern->SetJumpIndex(jumpIndex);
7284 }
7285
SetIndicatorIsInFast(std::optional<bool> isInFast)7286 void SwiperPattern::SetIndicatorIsInFast(std::optional<bool> isInFast)
7287 {
7288 if (GetMaxDisplayCount() <= 0) {
7289 return;
7290 }
7291 auto indicatorNode = GetCommonIndicatorNode();
7292 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
7293 return;
7294 }
7295
7296 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
7297 CHECK_NULL_VOID(indicatorPattern);
7298
7299 indicatorPattern->SetIsInFast(isInFast);
7300 }
7301
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const7302 void SwiperPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7303 {
7304 CHECK_NULL_VOID(json);
7305 Pattern::ToJsonValue(json, filter);
7306 /* no fixed attr below, just return */
7307 if (filter.IsFastFilter()) {
7308 return;
7309 }
7310
7311 auto nestedScroll = GetNestedScroll().forward;
7312 json->PutExtAttr("nestedScroll",
7313 nestedScroll == NestedScrollMode::SELF_ONLY ? "SwiperNestedScrollMode.SELF_ONLY"
7314 : "SwiperNestedScrollMode.SELF_FIRST",
7315 filter);
7316 json->PutExtAttr("stopWhenTouched", IsStopWhenTouched() ? "true" : "false", filter);
7317 json->PutExtAttr("currentIndex", currentIndex_, filter);
7318 json->PutExtAttr("currentOffset", currentOffset_, filter);
7319 json->PutExtAttr("uiCastJumpIndex", uiCastJumpIndex_.value_or(-1), filter);
7320
7321 if (indicatorIsBoolean_) {
7322 return;
7323 }
7324
7325 auto indicatorType = GetIndicatorType();
7326 const char* indicator = "indicator";
7327 if (indicatorType == SwiperIndicatorType::DOT) {
7328 json->PutExtAttr(indicator, SwiperHelper::GetDotIndicatorStyle(GetSwiperParameters()).c_str(), filter);
7329 } else if (indicatorType == SwiperIndicatorType::ARC_DOT) {
7330 json->PutExtAttr(indicator, GetArcDotIndicatorStyle().c_str(), filter);
7331 } else {
7332 json->PutExtAttr(
7333 indicator, SwiperHelper::GetDigitIndicatorStyle(GetSwiperDigitalParameters()).c_str(), filter);
7334 }
7335 }
7336
FromJson(const std::unique_ptr<JsonValue> & json)7337 void SwiperPattern::FromJson(const std::unique_ptr<JsonValue>& json)
7338 {
7339 CHECK_NULL_VOID(json);
7340 currentIndex_ = json->GetInt("currentIndex");
7341 auto currentOffset = json->GetDouble("currentOffset");
7342 auto jumpIndex = json->GetInt("uiCastJumpIndex");
7343 if (currentOffset != currentOffset_) {
7344 auto delta = currentOffset - currentOffset_;
7345 UpdateCurrentOffset(delta);
7346 } else if (jumpIndex >= 0) {
7347 jumpIndex_ = jumpIndex;
7348 MarkDirtyNodeSelf();
7349 }
7350 Pattern::FromJson(json);
7351 }
7352
GetGestureState()7353 GestureState SwiperPattern::GetGestureState()
7354 {
7355 auto gestureState = gestureState_;
7356 if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
7357 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
7358 gestureState_ = GestureState::GESTURE_STATE_NONE;
7359 }
7360
7361 return gestureState;
7362 }
7363
SetSwiperController(const RefPtr<SwiperController> & controller)7364 void SwiperPattern::SetSwiperController(const RefPtr<SwiperController>& controller)
7365 {
7366 CHECK_NULL_VOID(controller);
7367 swiperController_ = controller;
7368 SwiperHelper::InitSwiperController(controller, WeakClaim(this));
7369 }
7370
SetPropertyAnimationIsRunning(bool propertyAnimationIsRunning)7371 void SwiperPattern::SetPropertyAnimationIsRunning(bool propertyAnimationIsRunning)
7372 {
7373 propertyAnimationIsRunning_ = propertyAnimationIsRunning;
7374 }
7375
GetPropertyAnimationIsRunning()7376 bool SwiperPattern::GetPropertyAnimationIsRunning()
7377 {
7378 return propertyAnimationIsRunning_;
7379 }
7380
IsItemOverlay() const7381 bool SwiperPattern::IsItemOverlay() const
7382 {
7383 if (itemPosition_.empty()) {
7384 return false;
7385 }
7386 float lastItemEndPos = 0.0f;
7387 for (auto& item : itemPosition_) {
7388 auto frameNode = item.second.node;
7389 if (!frameNode) {
7390 continue;
7391 }
7392 auto renderContext = frameNode->GetRenderContext();
7393 if (!renderContext) {
7394 continue;
7395 }
7396 RectF rect = renderContext->GetPaintRectWithoutTransform();
7397 if (item.first == itemPosition_.begin()->first) {
7398 lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
7399 continue;
7400 }
7401 float currentItemStartPos = direction_ == Axis::HORIZONTAL ? rect.Left() : rect.Top();
7402 if (GreatNotEqual(lastItemEndPos, currentItemStartPos)) {
7403 return true;
7404 }
7405 lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
7406 }
7407 return false;
7408 }
7409
CheckSpecialItemCount() const7410 void SwiperPattern::CheckSpecialItemCount() const
7411 {
7412 auto swiperNode = AceType::DynamicCast<SwiperNode>(GetHost());
7413 CHECK_NULL_VOID(swiperNode);
7414 swiperNode->SetSpecialItemCount(indicatorId_.has_value() + leftButtonId_.has_value() + rightButtonId_.has_value() +
7415 leftCaptureId_.has_value() + rightCaptureId_.has_value());
7416 }
7417
CheckIndexRange(int32_t index) const7418 int32_t SwiperPattern::CheckIndexRange(int32_t index) const
7419 {
7420 auto itemCount = TotalCount();
7421 auto displayCount = GetDisplayCount();
7422 if (index < 0 || index >= itemCount || displayCount >= itemCount) {
7423 index = 0;
7424 } else if (!IsLoop() && index > itemCount - displayCount) {
7425 index = itemCount - displayCount;
7426 }
7427 return index;
7428 }
7429
DumpAdvanceInfo(std::unique_ptr<JsonValue> & json)7430 void SwiperPattern::DumpAdvanceInfo(std::unique_ptr<JsonValue>& json)
7431 {
7432 json->Put("isLastIndicatorFocused", isLastIndicatorFocused_);
7433 json->Put("moveDirection", moveDirection_);
7434 json->Put("indicatorDoingAnimation", indicatorDoingAnimation_);
7435 json->Put("hasVisibleChangeRegistered", hasVisibleChangeRegistered_);
7436 json->Put("isVisible", isVisible_);
7437 json->Put("isVisibleArea", isVisibleArea_);
7438 json->Put("isWindowShow", isWindowShow_);
7439 json->Put("IsCustomSize", isCustomSize_);
7440 json->Put("indicatorIsBoolean", indicatorIsBoolean_);
7441 json->Put("isAtHotRegion", isAtHotRegion_);
7442 json->Put("isDragging", isDragging_);
7443 json->Put("isTouchDown", isTouchDown_);
7444 json->Put("preLoop", preLoop_.has_value() ? std::to_string(preLoop_.value()).c_str() : "null");
7445 json->Put("indicatorId", indicatorId_.has_value() ? std::to_string(indicatorId_.value()).c_str() : "null");
7446 json->Put("leftButtonId", leftButtonId_.has_value() ? std::to_string(leftButtonId_.value()).c_str() : "null");
7447 json->Put("rightButtonId", rightButtonId_.has_value() ? std::to_string(rightButtonId_.value()).c_str() : "null");
7448 json->Put("crossMatchChild", crossMatchChild_);
7449 json->Put(
7450 "uiCastJumpIndex", uiCastJumpIndex_.has_value() ? std::to_string(uiCastJumpIndex_.value()).c_str() : "null");
7451 json->Put("jumpIndex", jumpIndex_.has_value() ? std::to_string(jumpIndex_.value()).c_str() : "null");
7452 json->Put("targetIndex", targetIndex_.has_value() ? std::to_string(targetIndex_.value()).c_str() : "null");
7453 json->Put(
7454 "pauseTargetIndex", pauseTargetIndex_.has_value() ? std::to_string(pauseTargetIndex_.value()).c_str() : "null");
7455 json->Put("velocity", velocity_.has_value() ? std::to_string(velocity_.value()).c_str() : "null");
7456 json->Put("curve", GetCurveIncludeMotion() ? GetCurveIncludeMotion()->ToString().c_str() : "null");
7457 json->Put("isFinishAnimation", isFinishAnimation_);
7458 json->Put("mainSizeIsMeasured", mainSizeIsMeasured_);
7459 json->Put("usePropertyAnimation", propertyAnimationIsRunning_);
7460 json->Put("isUserFinish", isUserFinish_);
7461 json->Put("isVoluntarilyClear", isVoluntarilyClear_);
7462 json->Put("isIndicatorLongPress", isIndicatorLongPress_);
7463 json->Put("stopIndicatorAnimation", stopIndicatorAnimation_);
7464 json->Put("isTouchPad", isTouchPad_);
7465 json->Put("surfaceChangedCallbackId",
7466 surfaceChangedCallbackId_.has_value() ? std::to_string(surfaceChangedCallbackId_.value()).c_str() : "null");
7467 json->Put("currentIndex", currentIndex_);
7468 json->Put("oldIndex", oldIndex_);
7469 BuildOffsetInfo(json);
7470 BuildIndicatorTypeInfo(json);
7471 BuildItemPositionInfo(json);
7472 BuildPanDirectionInfo(json);
7473 BuildAxisInfo(json);
7474 }
7475
BuildOffsetInfo(std::unique_ptr<JsonValue> & json)7476 void SwiperPattern::BuildOffsetInfo(std::unique_ptr<JsonValue>& json)
7477 {
7478 json->Put("currentOffset", std::to_string(currentOffset_).c_str());
7479 json->Put("fadeOffset", std::to_string(fadeOffset_).c_str());
7480 json->Put("touchBottomRate", std::to_string(touchBottomRate_).c_str());
7481 json->Put("currentIndexOffset", std::to_string(currentIndexOffset_).c_str());
7482 json->Put("gestureSwipeIndex", gestureSwipeIndex_);
7483 json->Put("currentFirstIndex", currentFirstIndex_);
7484 json->Put("startMainPos", startMainPos_);
7485 json->Put("endMainPos", endMainPos_);
7486 json->Put("contentMainSize", contentMainSize_);
7487 json->Put("contentCrossSize", contentCrossSize_);
7488 json->Put("propertyAnimationIndex", propertyAnimationIndex_);
7489 json->Put("mainDeltaSum", mainDeltaSum_);
7490 }
7491
BuildAxisInfo(std::unique_ptr<JsonValue> & json)7492 void SwiperPattern::BuildAxisInfo(std::unique_ptr<JsonValue>& json)
7493 {
7494 switch (direction_) {
7495 case Axis::NONE: {
7496 json->Put("Axis", "NONE");
7497 break;
7498 }
7499 case Axis::HORIZONTAL: {
7500 json->Put("Axis", "HORIZONTAL");
7501 break;
7502 }
7503 case Axis::FREE: {
7504 json->Put("Axis", "FREE");
7505 break;
7506 }
7507 case Axis::VERTICAL: {
7508 json->Put("Axis", "VERTICAL");
7509 break;
7510 }
7511 default: {
7512 break;
7513 }
7514 }
7515 }
7516
BuildItemPositionInfo(std::unique_ptr<JsonValue> & json)7517 void SwiperPattern::BuildItemPositionInfo(std::unique_ptr<JsonValue>& json)
7518 {
7519 if (!itemPosition_.empty()) {
7520 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
7521 for (auto item : itemPosition_) {
7522 std::unique_ptr<JsonValue> child = JsonUtil::CreateArray(true);
7523 child->Put("id", item.first);
7524 child->Put("startPos", std::to_string(item.second.startPos).c_str());
7525 child->Put("endPos", std::to_string(item.second.endPos).c_str());
7526 children->Put(child);
7527 }
7528 json->Put("itemPosition", children);
7529 }
7530 if (!itemPositionInAnimation_.empty()) {
7531 std::unique_ptr<JsonValue> children = JsonUtil::CreateArray(true);
7532 for (auto item : itemPositionInAnimation_) {
7533 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
7534 child->Put("id", item.first);
7535 child->Put("startPos", std::to_string(item.second.startPos).c_str());
7536 child->Put("endPos", std::to_string(item.second.endPos).c_str());
7537 children->Put(child);
7538 }
7539 json->Put("itemPositionInAnimation", children);
7540 }
7541 }
7542
BuildIndicatorTypeInfo(std::unique_ptr<JsonValue> & json)7543 void SwiperPattern::BuildIndicatorTypeInfo(std::unique_ptr<JsonValue>& json)
7544 {
7545 if (lastSwiperIndicatorType_.has_value()) {
7546 switch (lastSwiperIndicatorType_.value()) {
7547 case SwiperIndicatorType::DOT: {
7548 json->Put("SwiperIndicatorType", "DOT");
7549 break;
7550 }
7551 case SwiperIndicatorType::DIGIT: {
7552 json->Put("SwiperIndicatorType", "DIGIT");
7553 break;
7554 }
7555 default: {
7556 break;
7557 }
7558 }
7559 } else {
7560 json->Put("lastSwiperIndicatorType", "null");
7561 }
7562 }
7563
BuildPanDirectionInfo(std::unique_ptr<JsonValue> & json)7564 void SwiperPattern::BuildPanDirectionInfo(std::unique_ptr<JsonValue>& json)
7565 {
7566 switch (panDirection_.type) {
7567 case PanDirection::NONE: {
7568 json->Put("PanDirection", "NONE");
7569 break;
7570 }
7571 case PanDirection::LEFT: {
7572 json->Put("PanDirection", "LEFT");
7573 break;
7574 }
7575 case PanDirection::RIGHT: {
7576 json->Put("PanDirection", "RIGHT");
7577 break;
7578 }
7579 case PanDirection::HORIZONTAL: {
7580 json->Put("PanDirection", "HORIZONTAL");
7581 break;
7582 }
7583 case PanDirection::UP: {
7584 json->Put("PanDirection", "UP");
7585 break;
7586 }
7587 case PanDirection::DOWN: {
7588 json->Put("PanDirection", "DOWN");
7589 break;
7590 }
7591 case PanDirection::VERTICAL: {
7592 json->Put("PanDirection", "VERTICAL");
7593 break;
7594 }
7595 case PanDirection::ALL: {
7596 json->Put("PanDirection", "ALL");
7597 break;
7598 }
7599 default: {
7600 break;
7601 }
7602 }
7603 }
7604
HasRepeatTotalCountDifference(RefPtr<UINode> node) const7605 bool SwiperPattern::HasRepeatTotalCountDifference(RefPtr<UINode> node) const
7606 {
7607 CHECK_NULL_RETURN(node, false);
7608 auto& children = node->GetChildren();
7609 for (const auto& child : children) {
7610 auto repeat2 = AceType::DynamicCast<RepeatVirtualScroll2Node>(child);
7611 if (repeat2) {
7612 auto repeatRealCount = repeat2->FrameCount();
7613 auto repeatVirtualCount =
7614 (repeat2->GetTotalCount() <= INT_MAX) ? static_cast<int32_t>(repeat2->GetTotalCount()) : INT_MAX;
7615 if (repeatVirtualCount > repeatRealCount) {
7616 return true;
7617 }
7618 } else if (AceType::InstanceOf<FrameNode>(child) || AceType::InstanceOf<LazyForEachNode>(child) ||
7619 AceType::InstanceOf<RepeatVirtualScrollNode>(child) || AceType::InstanceOf<ForEachNode>(child) ||
7620 AceType::InstanceOf<CustomNode>(child)) {
7621 continue;
7622 } else {
7623 if (HasRepeatTotalCountDifference(child)) {
7624 return true;
7625 }
7626 }
7627 }
7628 return false;
7629 }
7630
SetPageFlipMode(int32_t pageFlipMode)7631 void SwiperPattern::SetPageFlipMode(int32_t pageFlipMode)
7632 {
7633 if (pageFlipMode < 0 || pageFlipMode > PAGE_FLIP_MODE_SIZE - 1) {
7634 pageFlipMode_ = PageFlipMode::CONTINUOUS;
7635 return;
7636 }
7637 pageFlipMode_ = static_cast<PageFlipMode>(pageFlipMode);
7638 }
7639
GetCommonIndicatorNode()7640 RefPtr<FrameNode> SwiperPattern::GetCommonIndicatorNode()
7641 {
7642 if (isBindIndicator_) {
7643 return GetIndicatorNode();
7644 } else {
7645 CHECK_NULL_RETURN(indicatorId_.has_value(), nullptr);
7646 auto host = GetHost();
7647 CHECK_NULL_RETURN(host, nullptr);
7648 return DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
7649 }
7650 }
7651
SetIndicatorNode(const RefPtr<FrameNode> & indicatorNode)7652 void SwiperPattern::SetIndicatorNode(const RefPtr<FrameNode>& indicatorNode)
7653 {
7654 if (isBindIndicator_) {
7655 indicatorNode_ = indicatorNode;
7656 auto host = GetHost();
7657 CHECK_NULL_VOID(host);
7658 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7659
7660 auto frameIndicatorNode = GetIndicatorNode();
7661 CHECK_NULL_VOID(frameIndicatorNode);
7662 frameIndicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7663 }
7664 }
7665
ResetIndicatorNode()7666 void SwiperPattern::ResetIndicatorNode()
7667 {
7668 auto frameNode = indicatorNode_.Upgrade();
7669 CHECK_NULL_VOID(frameNode);
7670 auto indicatorPattern = frameNode->GetPattern<IndicatorPattern>();
7671 CHECK_NULL_VOID(indicatorPattern);
7672 indicatorPattern->ResetSwiperNode();
7673 indicatorNode_ = nullptr;
7674 }
7675
NotifyDataChange(int32_t index,int32_t count)7676 void SwiperPattern::NotifyDataChange(int32_t index, int32_t count)
7677 {
7678 ACE_SCOPED_TRACE("Swiper NotifyDataChange index %d count %d", index, count);
7679 if (!oldChildrenSize_.has_value() || count == 0 || !GetMaintainVisibleContentPosition()) {
7680 return;
7681 }
7682 auto curretIndex = GetLoopIndex(currentIndex_, oldChildrenSize_.value());
7683 if (index < curretIndex || (index == curretIndex && count > 0)) {
7684 jumpIndex_ = jumpIndex_.value_or(CheckIndexRange(curretIndex + count));
7685 }
7686 }
7687
UpdateDefaultColor()7688 void SwiperPattern::UpdateDefaultColor()
7689 {
7690 auto host = GetHost();
7691 CHECK_NULL_VOID(host);
7692 auto pipeline = host->GetContext();
7693 CHECK_NULL_VOID(pipeline);
7694 auto swiperIndicatorTheme = pipeline->GetTheme<SwiperIndicatorTheme>();
7695 CHECK_NULL_VOID(swiperIndicatorTheme);
7696 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
7697 CHECK_NULL_VOID(props);
7698 if (swiperDigitalParameters_ && !swiperDigitalParameters_->parametersByUser.count("fontColor")) {
7699 swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
7700 }
7701 if (swiperDigitalParameters_ && !swiperDigitalParameters_->parametersByUser.count("selectedFontColor")) {
7702 swiperDigitalParameters_->selectedFontColor =
7703 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
7704 }
7705 if (swiperParameters_ && !swiperParameters_->parametersByUser.count("colorVal")) {
7706 swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
7707 }
7708 if (swiperParameters_ && !swiperParameters_->parametersByUser.count("selectedColorVal")) {
7709 swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
7710 }
7711 if (swiperArrowParameters_ && !swiperArrowParameters_->parametersByUser.count("backgroundColor")) {
7712 if (props->GetIsSidebarMiddleValue()) {
7713 props->UpdateBackgroundColor(swiperIndicatorTheme->GetBigArrowBackgroundColor());
7714 } else {
7715 props->UpdateBackgroundColor(swiperIndicatorTheme->GetSmallArrowBackgroundColor());
7716 }
7717 }
7718 if (swiperArrowParameters_ && !swiperArrowParameters_->parametersByUser.count("arrowColor")) {
7719 if (props->GetIsSidebarMiddleValue()) {
7720 props->UpdateArrowColor(swiperIndicatorTheme->GetBigArrowColor());
7721 } else {
7722 props->UpdateArrowColor(swiperIndicatorTheme->GetSmallArrowColor());
7723 }
7724 }
7725 }
7726
OnColorModeChange(uint32_t colorMode)7727 void SwiperPattern::OnColorModeChange(uint32_t colorMode)
7728 {
7729 UpdateDefaultColor();
7730 Pattern::OnColorModeChange(colorMode);
7731 if (!isBindIndicator_) {
7732 InitIndicator();
7733 } else if (NeedForceMeasure()) {
7734 MarkDirtyBindIndicatorNode();
7735 }
7736 InitArrow();
7737 }
7738
OnFontScaleConfigurationUpdate()7739 void SwiperPattern::OnFontScaleConfigurationUpdate()
7740 {
7741 auto pipeline = GetContext();
7742 CHECK_NULL_VOID(pipeline);
7743 pipeline->AddAfterReloadAnimationTask([weak = WeakClaim(this)]() {
7744 auto pattern = weak.Upgrade();
7745 CHECK_NULL_VOID(pattern);
7746 pattern->SetMainSizeIsMeasured(false);
7747 pattern->MarkDirtyNodeSelf();
7748 });
7749 }
7750 } // namespace OHOS::Ace::NG
7751