1 /*
2 * Copyright (c) 2022-2024 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/geometry/axis.h"
24 #include "base/geometry/dimension.h"
25 #include "base/geometry/ng/offset_t.h"
26 #include "base/log/ace_trace.h"
27 #include "base/log/log_wrapper.h"
28 #include "base/perfmonitor/perf_constants.h"
29 #include "base/perfmonitor/perf_monitor.h"
30 #include "base/ressched/ressched_report.h"
31 #include "base/utils/utils.h"
32 #include "core/animation/curve.h"
33 #include "core/animation/curves.h"
34 #include "core/animation/spring_curve.h"
35 #include "core/common/container_scope.h"
36 #include "core/common/recorder/node_data_cache.h"
37 #include "core/components/common/layout/constants.h"
38 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
39 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
40 #include "core/components_ng/pattern/stage/page_pattern.h"
41 #include "core/components_ng/pattern/swiper/swiper_helper.h"
42 #include "core/components_ng/pattern/swiper/swiper_layout_algorithm.h"
43 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
44 #include "core/components_ng/pattern/swiper/swiper_model.h"
45 #include "core/components_ng/pattern/swiper/swiper_node.h"
46 #include "core/components_ng/pattern/swiper/swiper_paint_method.h"
47 #include "core/components_ng/pattern/swiper/swiper_paint_property.h"
48 #include "core/components_ng/pattern/swiper/swiper_utils.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/pattern/tabs/tabs_pattern.h"
55 #include "core/components_ng/property/measure_utils.h"
56 #include "core/components_ng/property/property.h"
57 #include "core/components_ng/render/adapter/component_snapshot.h"
58 #include "core/components_ng/syntax/for_each_node.h"
59 #include "core/components_ng/syntax/lazy_for_each_node.h"
60 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
61 #include "core/components_v2/inspector/inspector_constants.h"
62 #include "core/event/ace_events.h"
63 #include "core/event/touch_event.h"
64 #include "core/pipeline_ng/pipeline_context.h"
65
66 namespace OHOS::Ace::NG {
67 namespace {
68
69 // TODO use theme.
70 constexpr int32_t MAX_DISPLAY_COUNT_MIN = 6;
71 constexpr int32_t MAX_DISPLAY_COUNT_MAX = 9;
72 constexpr int32_t MIN_TURN_PAGE_VELOCITY = 1200;
73 constexpr int32_t NEW_MIN_TURN_PAGE_VELOCITY = 780;
74 constexpr int32_t ERROR_CODE_NO_ERROR = 0;
75 constexpr int32_t ERROR_CODE_PARAM_INVALID = 401;
76 constexpr Dimension INDICATOR_BORDER_RADIUS = 16.0_vp;
77
78 constexpr float PX_EPSILON = 0.01f;
79 constexpr float FADE_DURATION = 500.0f;
80 constexpr float SPRING_DURATION = 600.0f;
81 constexpr float DEFAULT_MINIMUM_AMPLITUDE_PX = 1.0f;
82 constexpr int32_t INDEX_DIFF_TWO = 2;
83 constexpr int32_t FIRST_CAPTURE_DELAY_TIME = 30;
84 const std::string SWIPER_DRAG_SCENE = "swiper_drag_scene";
85 const std::string FADE_PROPERTY_NAME = "fade";
86 const std::string SPRING_PROPERTY_NAME = "spring";
87 const std::string INDICATOR_PROPERTY_NAME = "indicator";
88 const std::string TRANSLATE_PROPERTY_NAME = "translate";
89 constexpr uint16_t CAPTURE_PIXEL_ROUND_VALUE = static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_START) |
90 static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
91 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_END) |
92 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM);
93 constexpr int32_t SWIPER_HALF = 2;
94 constexpr int32_t CAPTURE_COUNT = 2;
95 constexpr char APP_SWIPER_NO_ANIMATION_SWITCH[] = "APP_SWIPER_NO_ANIMATION_SWITCH";
96 constexpr char APP_SWIPER_FRAME_ANIMATION[] = "APP_SWIPER_FRAME_ANIMATION";
97 constexpr char APP_TABS_FLING[] = "APP_TABS_FLING";
98 constexpr char APP_TABS_SCROLL[] = "APP_TABS_SCROLL";
99 constexpr char APP_TABS_NO_ANIMATION_SWITCH[] = "APP_TABS_NO_ANIMATION_SWITCH";
100 constexpr char APP_TABS_FRAME_ANIMATION[] = "APP_TABS_FRAME_ANIMATION";
101
102 // TODO define as common method
CalculateFriction(float gamma)103 float CalculateFriction(float gamma)
104 {
105 constexpr float SCROLL_RATIO = 0.72f;
106 if (GreatOrEqual(gamma, 1.0)) {
107 gamma = 1.0;
108 }
109 return SCROLL_RATIO * static_cast<float>(std::pow(1.0 - gamma, SQUARE));
110 }
111
112 constexpr int32_t COMPONENT_SWIPER_FLING = 1;
113 constexpr int32_t PAGE_FLIP_MODE_SIZE = 2;
114 const RefPtr<FrameRateRange> SWIPER_DEFAULT_FRAME_RATE =
115 AceType::MakeRefPtr<FrameRateRange>(0, 0, 0, COMPONENT_SWIPER_FLING);
116 constexpr int32_t MIN_DUMP_VELOCITY_THRESHOLD = 500;
117
118 constexpr int32_t JUMP_NEAR_VALUE = 3;
119 constexpr float MASS = 1.0f;
120 constexpr float STIFFNESS = 328.0f;
121 constexpr float DAMPING = 34.0f;
122 } // namespace
123
SwiperPattern()124 SwiperPattern::SwiperPattern()
125 {
126 swiperController_ = MakeRefPtr<SwiperController>();
127 SwiperHelper::InitSwiperController(swiperController_, WeakClaim(this));
128 }
129
OnAttachToFrameNode()130 void SwiperPattern::OnAttachToFrameNode()
131 {
132 auto host = GetHost();
133 CHECK_NULL_VOID(host);
134 host->GetRenderContext()->SetClipToFrame(true);
135 host->GetRenderContext()->SetClipToBounds(true);
136 host->GetRenderContext()->UpdateClipEdge(true);
137 InitSurfaceChangedCallback();
138 }
139
OnDetachFromFrameNode(FrameNode * node)140 void SwiperPattern::OnDetachFromFrameNode(FrameNode* node)
141 {
142 auto pipeline = PipelineContext::GetCurrentContextSafely();
143 CHECK_NULL_VOID(pipeline);
144 if (HasSurfaceChangedCallback()) {
145 pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
146 }
147 pipeline->RemoveWindowStateChangedCallback(node->GetId());
148 }
149
OnAttachToMainTree()150 void SwiperPattern::OnAttachToMainTree()
151 {
152 if (!isInit_) {
153 SetOnHiddenChangeForParent();
154 }
155 }
156
OnDetachFromMainTree()157 void SwiperPattern::OnDetachFromMainTree()
158 {
159 RemoveOnHiddenChange();
160 }
161
CreateLayoutAlgorithm()162 RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
163 {
164 auto host = GetHost();
165 CHECK_NULL_RETURN(host, nullptr);
166 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
167 CHECK_NULL_RETURN(props, nullptr);
168
169 auto algo = MakeRefPtr<SwiperLayoutAlgorithm>();
170 if (props->GetIsCustomAnimation().value_or(false)) {
171 algo->SetUseCustomAnimation(true);
172 algo->SetCustomAnimationToIndex(customAnimationToIndex_);
173 algo->SetIndexsInAnimation(indexsInAnimation_);
174 algo->SetNeedUnmountIndexs(needUnmountIndexs_);
175 return algo;
176 }
177 if (SupportSwiperCustomAnimation()) {
178 algo->SetNeedUnmountIndexs(needUnmountIndexs_);
179 algo->SetItemsPositionInAnimation(itemPositionInAnimation_);
180 }
181
182 if (jumpIndex_) {
183 algo->SetJumpIndex(jumpIndex_.value());
184 } else if (targetIndex_) {
185 algo->SetTargetIndex(targetIndex_.value());
186 }
187 algo->SetCachedShow(IsCachedShow());
188 algo->SetCurrentIndex(currentIndex_);
189 algo->SetContentCrossSize(contentCrossSize_);
190 algo->SetMainSizeIsMeasured(mainSizeIsMeasured_);
191 oldContentMainSize_ = contentMainSize_;
192 algo->SetContentMainSize(contentMainSize_);
193 algo->SetCurrentDelta(currentDelta_);
194 algo->SetDuringInteraction(isDragging_ || RunningTranslateAnimation());
195 algo->SetItemsPosition(itemPosition_);
196 if (IsOutOfBoundary() && !IsLoop()) {
197 algo->SetOverScrollFeature();
198 }
199 algo->SetTotalItemCount(TotalCount());
200 algo->SetIsLoop(IsLoop());
201 algo->SetSwipeByGroup(IsSwipeByGroup());
202 algo->SetRealTotalCount(RealTotalCount());
203 algo->SetPlaceItemWidth(placeItemWidth_);
204 algo->SetIsFrameAnimation(translateAnimationIsRunning_);
205
206 auto swiperPaintProperty = host->GetPaintProperty<SwiperPaintProperty>();
207 const auto effect = swiperPaintProperty->GetEdgeEffect().value_or(EdgeEffect::SPRING);
208 algo->SetCanOverScroll(effect == EdgeEffect::SPRING);
209 algo->SetHasCachedCapture(hasCachedCapture_);
210 algo->SetIsCaptureReverse(isCaptureReverse_);
211 algo->SetCachedCount(GetCachedCount());
212 algo->SetIgnoreBlankOffset(ignoreBlankOffset_);
213 return algo;
214 }
215
OnIndexChange()216 void SwiperPattern::OnIndexChange()
217 {
218 auto totalCount = TotalCount();
219 if (NonPositive(totalCount)) {
220 return;
221 }
222
223 auto oldIndex = GetLoopIndex(oldIndex_);
224 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != totalCount) {
225 oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
226 oldChildrenSize_ = totalCount;
227 }
228
229 auto targetIndex = GetLoopIndex(CurrentIndex());
230 if (oldIndex != targetIndex) {
231 FireChangeEvent(oldIndex, targetIndex);
232 // lazyBuild feature.
233 SetLazyLoadFeature(true);
234 }
235 }
236
StopAndResetSpringAnimation()237 void SwiperPattern::StopAndResetSpringAnimation()
238 {
239 if (springAnimationIsRunning_ && !isTouchDownSpringAnimation_) {
240 StopSpringAnimation();
241 currentDelta_ = 0.0f;
242 itemPosition_.clear();
243 isVoluntarilyClear_ = true;
244 jumpIndex_ = currentIndex_;
245 TAG_LOGI(AceLogTag::ACE_SWIPER, "jump index has been changed to %{public}d by spring animation reset",
246 jumpIndex_.value_or(-1));
247 }
248 UpdateItemRenderGroup(false);
249 }
250
OnLoopChange()251 void SwiperPattern::OnLoopChange()
252 {
253 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
254 CHECK_NULL_VOID(props);
255
256 if (!preLoop_.has_value()) {
257 preLoop_ = props->GetLoop().value_or(true);
258 return;
259 }
260
261 if (preLoop_.value() && !props->GetLoop().value_or(true)) {
262 needResetCurrentIndex_ = true;
263 }
264
265 if (preLoop_.value() != props->GetLoop().value_or(true) &&
266 (props->GetPrevMargin().has_value() || props->GetNextMargin().has_value())) {
267 jumpIndex_ = GetLoopIndex(currentIndex_);
268 }
269 preLoop_ = props->GetLoop().value_or(true);
270 }
271
AdjustCurrentIndexOnSwipePage(int32_t index)272 void SwiperPattern::AdjustCurrentIndexOnSwipePage(int32_t index)
273 {
274 auto adjustIndex = SwiperUtils::ComputePageIndex(index, GetDisplayCount());
275 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
276 CHECK_NULL_VOID(props);
277 props->UpdateIndexWithoutMeasure(GetLoopIndex(adjustIndex));
278 currentIndex_ = GetLoopIndex(adjustIndex);
279 }
280
InitCapture()281 void SwiperPattern::InitCapture()
282 {
283 auto host = GetHost();
284 CHECK_NULL_VOID(host);
285 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
286 CHECK_NULL_VOID(props);
287 bool hasCachedCapture = SwiperUtils::IsStretch(props) && props->GetLoop().value_or(true) && !IsSwipeByGroup() &&
288 GetDisplayCount() == TotalCount() - 1 &&
289 (Positive(props->GetPrevMarginValue(0.0_px).ConvertToPx()) ||
290 Positive(props->GetNextMarginValue(0.0_px).ConvertToPx()));
291 if (hasCachedCapture) {
292 leftCaptureIndex_ = std::nullopt;
293 rightCaptureIndex_ = std::nullopt;
294 }
295
296 if (!hasCachedCapture_ && hasCachedCapture) {
297 // Screenshot nodes need to be added at the forefront of all special nodes to display at the bottom
298 uint32_t number = static_cast<uint32_t>(indicatorId_.has_value()) + static_cast<uint32_t>(HasLeftButtonNode()) +
299 static_cast<uint32_t>(HasRightButtonNode()) + 1;
300 auto leftCaptureNode = FrameNode::GetOrCreateFrameNode(
301 V2::SWIPER_LEFT_CAPTURE_ETS_TAG, GetLeftCaptureId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
302 auto imageLayoutProperty = leftCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
303 CHECK_NULL_VOID(imageLayoutProperty);
304 imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
305 leftCaptureNode->MarkModifyDone();
306 host->AddChild(leftCaptureNode, -number);
307
308 auto rightCaptureNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_CAPTURE_ETS_TAG, GetRightCaptureId(),
309 []() { return AceType::MakeRefPtr<ImagePattern>(); });
310 imageLayoutProperty = rightCaptureNode->GetLayoutProperty<ImageLayoutProperty>();
311 CHECK_NULL_VOID(imageLayoutProperty);
312 imageLayoutProperty->UpdatePixelRound(CAPTURE_PIXEL_ROUND_VALUE);
313 rightCaptureNode->MarkModifyDone();
314 host->AddChild(rightCaptureNode, -number);
315 }
316 if (hasCachedCapture_ && !hasCachedCapture) {
317 RemoveAllCaptureNode();
318 }
319 if (SupportSwiperCustomAnimation() && hasCachedCapture) {
320 needUnmountIndexs_.clear();
321 itemPositionInAnimation_.clear();
322 }
323 hasCachedCapture_ = hasCachedCapture;
324 }
325
ResetOnForceMeasure()326 void SwiperPattern::ResetOnForceMeasure()
327 {
328 resetLayoutTask_.Cancel();
329 StopPropertyTranslateAnimation(isFinishAnimation_, false, true);
330 StopTranslateAnimation();
331 StopSpringAnimationImmediately();
332 StopFadeAnimation();
333 StopIndicatorAnimation(true);
334 currentOffset_ = 0.0f;
335 mainSizeIsMeasured_ = false;
336 currentDelta_ = 0.0f;
337 itemPosition_.clear();
338 isVoluntarilyClear_ = true;
339 jumpIndex_ = currentIndex_;
340 TAG_LOGI(
341 AceLogTag::ACE_SWIPER, "jump index has been changed to %{public}d by force measure", jumpIndex_.value_or(-1));
342 auto host = GetHost();
343 CHECK_NULL_VOID(host);
344 auto targetNode = FindLazyForEachNode(host);
345 if (targetNode.has_value()) {
346 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
347 CHECK_NULL_VOID(lazyForEachNode);
348 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
349 }
350 }
351
UpdateTabBarIndicatorCurve()352 void SwiperPattern::UpdateTabBarIndicatorCurve()
353 {
354 auto updateCubicCurveCallback = [weak = WeakClaim(this)]() {
355 auto swiperPattern = weak.Upgrade();
356 CHECK_NULL_VOID(swiperPattern);
357 auto host = swiperPattern->GetHost();
358 CHECK_NULL_VOID(host);
359 auto props = host->GetPaintProperty<SwiperPaintProperty>();
360 CHECK_NULL_VOID(props);
361 auto curve = MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
362 props->UpdateCurve(curve);
363 };
364 swiperController_->SetUpdateCubicCurveCallback(std::move(updateCubicCurveCallback));
365 }
366
NeedForceMeasure() const367 bool SwiperPattern::NeedForceMeasure() const
368 {
369 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
370 CHECK_NULL_RETURN(props, false);
371
372 return ((props->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
373 (isSwipeByGroup_.has_value() && isSwipeByGroup_.value() != IsSwipeByGroup());
374 }
375
MarkDirtyBindIndicatorNode() const376 void SwiperPattern::MarkDirtyBindIndicatorNode() const
377 {
378 auto indicatorNode = GetIndicatorNode();
379 CHECK_NULL_VOID(indicatorNode);
380 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
381 }
382
OnModifyDone()383 void SwiperPattern::OnModifyDone()
384 {
385 Pattern::OnModifyDone();
386 auto host = GetHost();
387 CHECK_NULL_VOID(host);
388 auto hub = host->GetEventHub<EventHub>();
389 CHECK_NULL_VOID(hub);
390 auto gestureHub = hub->GetOrCreateGestureEventHub();
391 CHECK_NULL_VOID(gestureHub);
392
393 auto index = CurrentIndex();
394 if (currentIndex_ != index && index >= 0) {
395 AceAsyncTraceBeginCommercial(
396 0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
397 }
398
399 if (!isBindIndicator_) {
400 InitIndicator();
401 } else if (NeedForceMeasure()) {
402 MarkDirtyBindIndicatorNode();
403 }
404 hoverFlag_ = HOVER_NONE;
405 InitArrow();
406 InitCapture();
407 CheckSpecialItemCount();
408 SetLazyLoadIsLoop();
409 RegisterVisibleAreaChange();
410 InitTouchEvent(gestureHub);
411 InitHoverMouseEvent();
412 StopAndResetSpringAnimation();
413 OnLoopChange();
414
415 if (NeedForceMeasure()) {
416 ResetOnForceMeasure();
417 }
418
419 isSwipeByGroup_ = IsSwipeByGroup();
420
421 bool disableSwipe = IsDisableSwipe();
422 UpdateSwiperPanEvent(disableSwipe);
423
424 auto focusHub = host->GetFocusHub();
425 if (focusHub) {
426 InitOnKeyEvent(focusHub);
427 InitOnFocusInternal(focusHub);
428 }
429
430 SetSwiperEventCallback(disableSwipe);
431 UpdateTabBarIndicatorCurve();
432
433 if (IsAutoPlay()) {
434 StartAutoPlay();
435 } else {
436 translateTask_.Cancel();
437 isInAutoPlay_ = false;
438 }
439
440 SetAccessibilityAction();
441 placeItemWidth_.reset();
442
443 if (IsSwipeByGroup()) {
444 needAdjustIndex_ = true;
445 }
446
447 if (isBindIndicator_) {
448 auto refUINode = indicatorNode_.Upgrade();
449 CHECK_NULL_VOID(refUINode);
450 auto frameNode = DynamicCast<NG::FrameNode>(refUINode);
451 CHECK_NULL_VOID(frameNode);
452 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
453 CHECK_NULL_VOID(indicatorPattern);
454 indicatorPattern->InitIndicatorEvent();
455 }
456 }
457
OnAfterModifyDone()458 void SwiperPattern::OnAfterModifyDone()
459 {
460 auto host = GetHost();
461 CHECK_NULL_VOID(host);
462 auto inspectorId = host->GetInspectorId().value_or("");
463 if (!inspectorId.empty()) {
464 Recorder::NodeDataCache::Get().PutInt(host, inspectorId, CurrentIndex());
465 }
466 }
467
CheckUserSetIndex(int32_t index)468 int32_t SwiperPattern::CheckUserSetIndex(int32_t index)
469 {
470 if (!IsAutoLinear()) {
471 return index;
472 }
473
474 if (index < 0 || index >= RealTotalCount()) {
475 index = 0;
476 }
477
478 auto childNode = GetCurrentFrameNode(GetLoopIndex(index));
479 CHECK_NULL_RETURN(childNode, index);
480 auto childLayoutProperty = childNode->GetLayoutProperty<LayoutProperty>();
481 CHECK_NULL_RETURN(childLayoutProperty, index);
482 if (childLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
483 return index;
484 }
485
486 return CheckTargetIndex(index + 1);
487 }
488
UpdateIndicatorOnChildChange()489 void SwiperPattern::UpdateIndicatorOnChildChange()
490 {
491 if (HasIndicatorNode()) {
492 StopIndicatorAnimation();
493 auto host = GetHost();
494 CHECK_NULL_VOID(host);
495 auto indicatorNode = GetCommonIndicatorNode();
496 if (indicatorNode && IsIndicator(indicatorNode->GetTag())) {
497 indicatorNode->MarkModifyDone();
498 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
499 }
500 }
501 }
502
BeforeCreateLayoutWrapper()503 void SwiperPattern::BeforeCreateLayoutWrapper()
504 {
505 auto host = GetHost();
506 CHECK_NULL_VOID(host);
507 if (host->GetChildrenUpdated() != -1) {
508 InitCapture();
509 if (NeedAutoPlay() && !translateTask_) {
510 StartAutoPlay();
511 }
512 UpdateCurrentFocus();
513 host->ChildrenUpdatedFrom(-1);
514 }
515
516 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
517 CHECK_NULL_VOID(props);
518 oldIndex_ = currentIndex_;
519 auto userSetCurrentIndex = CurrentIndex();
520 userSetCurrentIndex = CheckUserSetIndex(userSetCurrentIndex);
521 auto oldIndex = GetLoopIndex(oldIndex_);
522 if (oldChildrenSize_.has_value() && oldChildrenSize_.value() != TotalCount()) {
523 oldIndex = GetLoopIndex(oldIndex_, oldChildrenSize_.value());
524 UpdateIndicatorOnChildChange();
525 StartAutoPlay();
526 InitArrow();
527 if (IsLoop() && oldIndex != GetLoopIndex(currentIndex_)) {
528 currentIndex_ = oldIndex >= TotalCount() ? 0 : oldIndex;
529 }
530 }
531 int32_t maxValidIndex = IsLoop() ? RealTotalCount() : TotalCount() - GetDisplayCount() + 1;
532 if (userSetCurrentIndex < 0 || userSetCurrentIndex >= maxValidIndex || GetDisplayCount() >= RealTotalCount()) {
533 currentIndex_ = 0;
534 props->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
535 } else {
536 if (oldIndex != userSetCurrentIndex) {
537 currentIndex_ = userSetCurrentIndex;
538 propertyAnimationIndex_ = GetLoopIndex(propertyAnimationIndex_);
539 }
540 }
541
542 if (IsSwipeByGroup() && needAdjustIndex_) {
543 AdjustCurrentIndexOnSwipePage(CurrentIndex());
544 needAdjustIndex_ = false;
545 }
546
547 if (oldIndex_ != currentIndex_ || (itemPosition_.empty() && !isVoluntarilyClear_)) {
548 jumpIndex_ = GetLoopIndex(currentIndex_);
549 currentFirstIndex_ = jumpIndex_.value_or(0);
550 turnPageRate_ = 0.0f;
551 SetIndicatorJumpIndex(jumpIndex_);
552 }
553 isVoluntarilyClear_ = false;
554 if (jumpIndex_) {
555 if ((jumpIndex_.value() < 0 || jumpIndex_.value() >= TotalCount()) && !IsLoop()) {
556 jumpIndex_ = 0;
557 }
558 targetIndex_.reset();
559 nextIndex_ = jumpIndex_.value();
560 StopAutoPlay();
561 StopTranslateAnimation();
562 StopFadeAnimation();
563 StopSpringAnimation();
564 if (usePropertyAnimation_) {
565 StopPropertyTranslateAnimation(false, true);
566 StopIndicatorAnimation();
567 }
568 currentDelta_ = 0.0f;
569 }
570 if (oldIndex_ != currentIndex_ && !isInit_ && !IsUseCustomAnimation()) {
571 FireWillShowEvent(currentIndex_);
572 FireWillHideEvent(oldIndex_);
573 }
574
575 if (needResetCurrentIndex_) {
576 needResetCurrentIndex_ = false;
577 currentIndex_ = GetLoopIndex(currentIndex_);
578 props->UpdateIndexWithoutMeasure(currentIndex_);
579 }
580 UpdateIgnoreBlankOffsetWithIndex();
581 }
582
UpdateTargetCapture(bool forceUpdate)583 void SwiperPattern::UpdateTargetCapture(bool forceUpdate)
584 {
585 if (itemPosition_.empty()) {
586 return;
587 }
588 auto leftTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
589 auto rightTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
590 if (isCaptureReverse_) {
591 leftTargetIndex = GetLoopIndex(itemPosition_.begin()->first);
592 rightTargetIndex = GetLoopIndex(itemPosition_.rbegin()->first);
593 }
594 if (forceUpdate || !leftCaptureIndex_.has_value() || leftCaptureIndex_.value() != leftTargetIndex) {
595 CreateCaptureCallback(leftTargetIndex, GetLeftCaptureId(), forceUpdate);
596 leftCaptureIndex_ = leftTargetIndex;
597 }
598 if (forceUpdate || !rightCaptureIndex_.has_value() || rightCaptureIndex_.value() != rightTargetIndex) {
599 CreateCaptureCallback(rightTargetIndex, GetRightCaptureId(), forceUpdate);
600 rightCaptureIndex_ = rightTargetIndex;
601 }
602 }
603
CreateCaptureCallback(int32_t targetIndex,int32_t captureId,bool forceUpdate)604 void SwiperPattern::CreateCaptureCallback(int32_t targetIndex, int32_t captureId, bool forceUpdate)
605 {
606 auto host = GetHost();
607 CHECK_NULL_VOID(host);
608 auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
609 CHECK_NULL_VOID(targetNode);
610 auto callback = [weak = WeakClaim(this), captureId, targetIndex, hostInstanceId = GetHostInstanceId()](
611 std::shared_ptr<Media::PixelMap> pixelMap) {
612 ContainerScope scope(hostInstanceId);
613 auto piplineContext = PipelineContext::GetCurrentContext();
614 CHECK_NULL_VOID(piplineContext);
615 auto taskExecutor = piplineContext->GetTaskExecutor();
616 CHECK_NULL_VOID(taskExecutor);
617 taskExecutor->PostTask(
618 [weak, pixelMap, captureId, targetIndex]() mutable {
619 auto swiper = weak.Upgrade();
620 CHECK_NULL_VOID(swiper);
621 swiper->UpdateCaptureSource(pixelMap, captureId, targetIndex);
622 },
623 TaskExecutor::TaskType::UI, "ArkUISwiperUpdateCaptureSource");
624 };
625 if (forceUpdate) {
626 // The size changes caused by layout need to wait for rendering before taking a screenshot
627 auto piplineContext = PipelineContext::GetCurrentContext();
628 CHECK_NULL_VOID(piplineContext);
629 auto taskExecutor = piplineContext->GetTaskExecutor();
630 CHECK_NULL_VOID(taskExecutor);
631 taskExecutor->PostDelayedTask(
632 [targetNode, callback]() { ComponentSnapshot::GetNormalCapture(targetNode, std::move(callback)); },
633 TaskExecutor::TaskType::UI, FIRST_CAPTURE_DELAY_TIME, "ArkUISwiperGetNormalCapture");
634 } else {
635 ComponentSnapshot::GetNormalCapture(targetNode, std::move(callback));
636 }
637 }
638
UpdateCaptureSource(std::shared_ptr<Media::PixelMap> pixelMap,int32_t captureId,int32_t targetIndex)639 void SwiperPattern::UpdateCaptureSource(
640 std::shared_ptr<Media::PixelMap> pixelMap, int32_t captureId, int32_t targetIndex)
641 {
642 // Async tasks require verifying if the pixel map is the correct target
643 if (!(captureId == GetLeftCaptureId() && leftCaptureIndex_.has_value() &&
644 targetIndex == leftCaptureIndex_.value()) &&
645 !(captureId == GetRightCaptureId() && rightCaptureIndex_.has_value() &&
646 targetIndex == rightCaptureIndex_.value())) {
647 return;
648 }
649 auto host = GetHost();
650 CHECK_NULL_VOID(host);
651 auto targetNode = AceType::DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(targetIndex));
652 CHECK_NULL_VOID(targetNode);
653 auto targetLayoutProperty = targetNode->GetLayoutProperty<LayoutProperty>();
654 CHECK_NULL_VOID(targetLayoutProperty);
655 auto targetMargin = targetLayoutProperty->CreateMargin();
656 MarginProperty margin;
657 margin.left = CalcLength(targetMargin.left.has_value() ? targetMargin.left.value() : 0.0f);
658 margin.right = CalcLength(targetMargin.right.has_value() ? targetMargin.right.value() : 0.0f);
659 margin.top = CalcLength(targetMargin.top.has_value() ? targetMargin.top.value() : 0.0f);
660 margin.bottom = CalcLength(targetMargin.bottom.has_value() ? targetMargin.bottom.value() : 0.0f);
661
662 auto captureNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(captureId)));
663 CHECK_NULL_VOID(captureNode);
664 auto imageLayoutProperty = captureNode->GetLayoutProperty<ImageLayoutProperty>();
665 CHECK_NULL_VOID(imageLayoutProperty);
666 imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(PixelMap::CreatePixelMap(&pixelMap)));
667 imageLayoutProperty->UpdateMargin(margin);
668 captureNode->MarkModifyDone();
669 captureNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
670 }
671
InitSurfaceChangedCallback()672 void SwiperPattern::InitSurfaceChangedCallback()
673 {
674 auto host = GetHost();
675 CHECK_NULL_VOID(host);
676 auto pipeline = host->GetContextRefPtr();
677 CHECK_NULL_VOID(pipeline);
678 if (!HasSurfaceChangedCallback()) {
679 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
680 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
681 WindowSizeChangeReason type) {
682 if (type == WindowSizeChangeReason::UNDEFINED && newWidth == prevWidth && newHeight == prevHeight) {
683 return;
684 }
685 auto swiper = weak.Upgrade();
686 if (!swiper) {
687 return;
688 }
689
690 if (type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::UNDEFINED) {
691 swiper->windowSizeChangeReason_ = type;
692 swiper->StopAutoPlay();
693 }
694 auto currentIndex =
695 swiper->targetIndex_.has_value() ? swiper->targetIndex_.value() : swiper->currentIndex_;
696
697 swiper->needFireCustomAnimationEvent_ = swiper->translateAnimationIsRunning_;
698 swiper->StopPropertyTranslateAnimation(swiper->isFinishAnimation_);
699 swiper->StopTranslateAnimation();
700 swiper->StopSpringAnimationImmediately();
701 swiper->StopFadeAnimation();
702 swiper->StopIndicatorAnimation();
703 const auto& surfaceChangeCallback = swiper->swiperController_->GetSurfaceChangeCallback();
704 if (surfaceChangeCallback) {
705 surfaceChangeCallback();
706 }
707 swiper->currentOffset_ = 0.0f;
708 swiper->itemPosition_.clear();
709 swiper->placeItemWidth_.reset();
710 swiper->isVoluntarilyClear_ = true;
711 swiper->jumpIndex_ = currentIndex;
712 swiper->SetIndicatorJumpIndex(currentIndex);
713 swiper->MarkDirtyNodeSelf();
714 auto swiperNode = swiper->GetHost();
715 CHECK_NULL_VOID(swiperNode);
716 auto targetNode = swiper->FindLazyForEachNode(swiperNode);
717 if (targetNode.has_value()) {
718 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
719 CHECK_NULL_VOID(lazyForEachNode);
720 lazyForEachNode->SetFlagForGeneratedItem(PROPERTY_UPDATE_MEASURE);
721 }
722 });
723 UpdateSurfaceChangedCallbackId(callbackId);
724 }
725 }
726
IsFocusNodeInItemPosition(const RefPtr<FocusHub> & targetFocusHub)727 bool SwiperPattern::IsFocusNodeInItemPosition(const RefPtr<FocusHub>& targetFocusHub)
728 {
729 for (const auto& item : itemPosition_) {
730 auto itemNode = GetCurrentFrameNode(item.first);
731 if (!itemNode) {
732 continue;
733 }
734 if (itemNode->GetFirstFocusHubChild() == targetFocusHub) {
735 return true;
736 }
737 }
738 return false;
739 }
740
FlushFocus(const RefPtr<FrameNode> & curShowFrame)741 void SwiperPattern::FlushFocus(const RefPtr<FrameNode>& curShowFrame)
742 {
743 CHECK_NULL_VOID(curShowFrame);
744 auto swiperHost = GetHost();
745 CHECK_NULL_VOID(swiperHost);
746 auto swiperFocusHub = swiperHost->GetFocusHub();
747 CHECK_NULL_VOID(swiperFocusHub);
748 auto showChildFocusHub = curShowFrame->GetFirstFocusHubChild();
749 CHECK_NULL_VOID(showChildFocusHub);
750 int32_t skipCnt = 0;
751 if (IsShowIndicator()) {
752 ++skipCnt;
753 }
754 if (HasLeftButtonNode()) {
755 ++skipCnt;
756 }
757 if (HasRightButtonNode()) {
758 ++skipCnt;
759 }
760 std::list<RefPtr<FocusHub>> focusNodes;
761 swiperFocusHub->FlushChildrenFocusHub(focusNodes);
762 for (auto iter = focusNodes.rbegin(); iter != focusNodes.rend(); ++iter) {
763 const auto& node = *iter;
764 if (skipCnt > 0 || !node) {
765 --skipCnt;
766 continue;
767 }
768 if (IsUseCustomAnimation() && hasTabsAncestor_) {
769 node->SetParentFocusable(node == showChildFocusHub);
770 } else {
771 node->SetParentFocusable(IsFocusNodeInItemPosition(node));
772 }
773 }
774
775 RefPtr<FocusHub> needFocusNode = showChildFocusHub;
776 if (IsShowIndicator() && isLastIndicatorFocused_) {
777 needFocusNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
778 }
779 CHECK_NULL_VOID(needFocusNode);
780 lastWeakShowNode_ = AceType::WeakClaim(AceType::RawPtr(curShowFrame));
781 if (swiperFocusHub->IsCurrentFocus()) {
782 needFocusNode->RequestFocusImmediately();
783 } else {
784 if (swiperFocusHub->AcceptFocusOfPriorityChild()) {
785 return;
786 }
787 swiperFocusHub->SetLastWeakFocusNode(AceType::WeakClaim(AceType::RawPtr(needFocusNode)));
788 }
789 }
GetFocusHubChild(std::string childFrameName)790 RefPtr<FocusHub> SwiperPattern::GetFocusHubChild(std::string childFrameName)
791 {
792 auto swiperHost = GetHost();
793 CHECK_NULL_RETURN(swiperHost, nullptr);
794 auto swiperFocusHub = swiperHost->GetFocusHub();
795 CHECK_NULL_RETURN(swiperFocusHub, nullptr);
796 RefPtr<FocusHub> target;
797 swiperFocusHub->AnyChildFocusHub([&target, childFrameName](const RefPtr<FocusHub>& child) {
798 CHECK_NULL_RETURN(child, true);
799 if (child->GetFrameName() == childFrameName) {
800 target = child;
801 return true;
802 }
803 return false;
804 });
805 return target;
806 }
807
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)808 WeakPtr<FocusHub> SwiperPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
809 {
810 auto curFocusNode = currentFocusNode.Upgrade();
811 CHECK_NULL_RETURN(curFocusNode, nullptr);
812 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::UP) ||
813 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::SHIFT_TAB) ||
814 (GetDirection() == Axis::VERTICAL && step == FocusStep::LEFT)) {
815 return PreviousFocus(curFocusNode);
816 }
817 if ((GetDirection() == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
818 (GetDirection() == Axis::HORIZONTAL && step == FocusStep::TAB) ||
819 (GetDirection() == Axis::VERTICAL && step == FocusStep::RIGHT)) {
820 return NextFocus(curFocusNode);
821 }
822 return nullptr;
823 }
824
PreviousFocus(const RefPtr<FocusHub> & curFocusNode)825 WeakPtr<FocusHub> SwiperPattern::PreviousFocus(const RefPtr<FocusHub>& curFocusNode)
826 {
827 CHECK_NULL_RETURN(curFocusNode, nullptr);
828 RefPtr<FocusHub> indicatorNode;
829 RefPtr<FocusHub> leftArrowNode;
830 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
831 CHECK_NULL_RETURN(props, nullptr);
832 if (HasLeftButtonNode()) {
833 leftArrowNode = GetFocusHubChild(V2::SWIPER_LEFT_ARROW_ETS_TAG);
834 CHECK_NULL_RETURN(leftArrowNode, nullptr);
835 }
836 if (HasIndicatorNode()) {
837 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
838 CHECK_NULL_RETURN(indicatorNode, nullptr);
839 }
840 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
841 isLastIndicatorFocused_ = false;
842 (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ? curFocusNode->SetParentFocusable(false)
843 : curFocusNode->SetParentFocusable(true);
844 return nullptr;
845 }
846 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
847 if (!HasLeftButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == 0) ||
848 props->GetHoverShowValue(false)) {
849 isLastIndicatorFocused_ = true;
850 curFocusNode->SetParentFocusable(true);
851 return nullptr;
852 }
853 isLastIndicatorFocused_ = false;
854 leftArrowNode->SetParentFocusable(true);
855 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
856 }
857 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
858 if (HasIndicatorNode()) {
859 isLastIndicatorFocused_ = true;
860 indicatorNode->SetParentFocusable(true);
861 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
862 }
863 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
864 curFocusNode->SetParentFocusable(true);
865 return nullptr;
866 }
867 isLastIndicatorFocused_ = true;
868 leftArrowNode->SetParentFocusable(true);
869 return AceType::WeakClaim(AceType::RawPtr(leftArrowNode));
870 }
871 curFocusNode->SetParentFocusable(true);
872 return nullptr;
873 }
874
NextFocus(const RefPtr<FocusHub> & curFocusNode)875 WeakPtr<FocusHub> SwiperPattern::NextFocus(const RefPtr<FocusHub>& curFocusNode)
876 {
877 CHECK_NULL_RETURN(curFocusNode, nullptr);
878 RefPtr<FocusHub> indicatorNode;
879 RefPtr<FocusHub> rightArrowNode;
880 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
881 CHECK_NULL_RETURN(props, nullptr);
882 if (HasIndicatorNode()) {
883 indicatorNode = GetFocusHubChild(V2::SWIPER_INDICATOR_ETS_TAG);
884 CHECK_NULL_RETURN(indicatorNode, nullptr);
885 }
886 if (HasRightButtonNode()) {
887 rightArrowNode = GetFocusHubChild(V2::SWIPER_RIGHT_ARROW_ETS_TAG);
888 CHECK_NULL_RETURN(rightArrowNode, nullptr);
889 }
890 if (curFocusNode->GetFrameName() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
891 if (HasIndicatorNode()) {
892 isLastIndicatorFocused_ = true;
893 indicatorNode->SetParentFocusable(true);
894 return AceType::WeakClaim(AceType::RawPtr(indicatorNode));
895 }
896 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
897 curFocusNode->SetParentFocusable(true);
898 return nullptr;
899 }
900 isLastIndicatorFocused_ = true;
901 rightArrowNode->SetParentFocusable(true);
902 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
903 }
904 if (curFocusNode->GetFrameName() == V2::SWIPER_INDICATOR_ETS_TAG) {
905 if (!HasRightButtonNode() || (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ||
906 props->GetHoverShowValue(false)) {
907 isLastIndicatorFocused_ = true;
908 curFocusNode->SetParentFocusable(true);
909 return nullptr;
910 }
911 isLastIndicatorFocused_ = false;
912 rightArrowNode->SetParentFocusable(true);
913 return AceType::WeakClaim(AceType::RawPtr(rightArrowNode));
914 }
915 if (curFocusNode->GetFrameName() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
916 isLastIndicatorFocused_ = false;
917 (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) ? curFocusNode->SetParentFocusable(false)
918 : curFocusNode->SetParentFocusable(true);
919 return nullptr;
920 }
921 curFocusNode->SetParentFocusable(true);
922 return nullptr;
923 }
924
GetLoopIndex(int32_t originalIndex) const925 int32_t SwiperPattern::GetLoopIndex(int32_t originalIndex) const
926 {
927 if (TotalCount() <= 0) {
928 return originalIndex;
929 }
930 auto loopIndex = originalIndex;
931 while (loopIndex < 0) {
932 loopIndex = loopIndex + TotalCount();
933 }
934 loopIndex %= TotalCount();
935 return loopIndex;
936 }
937
AdjustCurrentFocusIndex()938 void SwiperPattern::AdjustCurrentFocusIndex()
939 {
940 if (GetDisplayCount() <= 1) {
941 currentFocusIndex_ = currentIndex_;
942 return;
943 }
944
945 if (currentFocusIndex_ >= currentIndex_ && currentFocusIndex_ < currentIndex_ + GetDisplayCount()) {
946 return;
947 }
948
949 currentFocusIndex_ = currentIndex_;
950 }
951
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)952 bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
953 {
954 if (!isDragging_ || isInit_) {
955 SetLazyLoadFeature(true);
956 }
957 if (!isInit_) {
958 OnIndexChange();
959 oldIndex_ = currentIndex_;
960 }
961
962 auto isInit = isInit_;
963 isInit_ = false;
964
965 if (!IsAutoPlay() && config.skipMeasure && config.skipLayout) {
966 return false;
967 }
968
969 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
970 CHECK_NULL_RETURN(props, false);
971 auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm();
972 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
973 auto algo = DynamicCast<SwiperLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
974 CHECK_NULL_RETURN(algo, false);
975
976 // set tabs invisible item freeze state.
977 if (hasTabsAncestor_) {
978 auto realTotalCount = RealTotalCount();
979 for (int32_t index = 0; index < realTotalCount; index++) {
980 auto childFrameNode = GetCurrentFrameNode(index);
981 if (childFrameNode) {
982 auto isActive = childFrameNode->IsActive();
983 childFrameNode->SetFreeze(!isActive);
984 }
985 }
986 }
987
988 if (props->GetIsCustomAnimation().value_or(false)) {
989 needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
990 return false;
991 }
992 if (SupportSwiperCustomAnimation()) {
993 needUnmountIndexs_ = algo->GetNeedUnmountIndexs();
994 itemPositionInAnimation_ = algo->GetItemsPositionInAnimation();
995 FireContentDidScrollEvent();
996 }
997 itemPositionWillInvisible_.clear();
998
999 autoLinearReachBoundary = false;
1000 bool isJump = false;
1001 startMainPos_ = algo->GetStartPosition();
1002 endMainPos_ = algo->GetEndPosition();
1003 startIndex_ = algo->GetStartIndex();
1004 endIndex_ = algo->GetEndIndex();
1005 cachedItems_ = algo->GetCachedItems();
1006 layoutConstraint_ = algo->GetLayoutConstraint();
1007 itemPosition_ = std::move(algo->GetItemPosition());
1008 PostIdleTask(GetHost());
1009 currentOffset_ -= algo->GetCurrentOffset();
1010 if (!itemPosition_.empty()) {
1011 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
1012 auto firstItem = GetFirstItemInfoInVisibleArea();
1013 auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
1014 if (turnPageRateCallback && isDragging_ && !NearZero(translateLength)) {
1015 turnPageRateCallback(firstItem.first, -firstItem.second.startPos / translateLength);
1016 }
1017
1018 placeItemWidth_ = translateLength;
1019 }
1020 if (hasCachedCapture_) {
1021 isCaptureReverse_ = algo->GetIsCaptureReverse();
1022 UpdateTargetCapture(algo->GetIsNeedUpdateCapture());
1023 }
1024
1025 if (!targetIndex_) {
1026 if (isUserFinish_) {
1027 SetIndicatorJumpIndex(jumpIndex_);
1028 }
1029
1030 CheckMarkDirtyNodeForRenderIndicator();
1031 }
1032
1033 if (jumpIndex_) {
1034 auto pipeline = GetContext();
1035 if (pipeline) {
1036 pipeline->AddAfterRenderTask([weak = WeakClaim(this)]() {
1037 auto swiper = weak.Upgrade();
1038 CHECK_NULL_VOID(swiper);
1039 AceAsyncTraceEndCommercial(
1040 0, swiper->hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1041 });
1042 }
1043 isJump = true;
1044 UpdateCurrentIndex(algo->GetCurrentIndex());
1045 AdjustCurrentFocusIndex();
1046 auto curChild = dirty->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_));
1047 if (curChild && IsContentFocused()) {
1048 auto curChildFrame = curChild->GetHostNode();
1049 CHECK_NULL_RETURN(curChildFrame, false);
1050 FlushFocus(curChildFrame);
1051 }
1052 currentIndexOffset_ = 0.0f;
1053 if (!isInit) {
1054 OnIndexChange();
1055 }
1056 jumpIndex_.reset();
1057 pauseTargetIndex_.reset();
1058 auto delayTime = GetInterval() - GetDuration();
1059 delayTime = std::clamp(delayTime, 0, delayTime);
1060 if (NeedAutoPlay() && isUserFinish_) {
1061 PostTranslateTask(delayTime);
1062 }
1063
1064 if (SupportSwiperCustomAnimation() && needFireCustomAnimationEvent_) {
1065 itemPositionInAnimation_ = itemPosition_;
1066 FireSwiperCustomAnimationEvent();
1067 itemPositionInAnimation_.clear();
1068 }
1069 } else if (RunningTranslateAnimation() && !NearEqual(oldContentMainSize_, algo->GetContentMainSize())) {
1070 auto pipeline = GetContext();
1071 RefPtr<TaskExecutor> taskExecutor = pipeline ? pipeline->GetTaskExecutor() : nullptr;
1072 if (taskExecutor) {
1073 resetLayoutTask_.Cancel();
1074 resetLayoutTask_.Reset([weak = AceType::WeakClaim(this)] {
1075 auto swiper = weak.Upgrade();
1076 CHECK_NULL_VOID(swiper);
1077 if (swiper->RunningTranslateAnimation()) {
1078 swiper->isUserFinish_ = false;
1079 swiper->FinishAnimation();
1080 swiper->currentDelta_ = 0.0f;
1081 swiper->itemPosition_.clear();
1082 swiper->isVoluntarilyClear_ = true;
1083 swiper->jumpIndex_ = swiper->currentIndex_;
1084 swiper->MarkDirtyNodeSelf();
1085 }
1086 });
1087 taskExecutor->PostTask(resetLayoutTask_, TaskExecutor::TaskType::UI, "ArkUISwiperResetLayout");
1088 }
1089 } else if (targetIndex_) {
1090 auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
1091 auto iter = itemPosition_.find(targetIndexValue);
1092 if (iter != itemPosition_.end()) {
1093 float targetPos = iter->second.startPos;
1094 auto context = GetContext();
1095 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1096 bool isNeedForwardTranslate = false;
1097 if (IsLoop()) {
1098 auto lastItemIndex = Positive(props->GetCalculatedNextMargin())
1099 ? targetIndexValue + GetDisplayCount()
1100 : targetIndexValue + GetDisplayCount() - 1;
1101 isNeedForwardTranslate = itemPosition_.find(lastItemIndex) == itemPosition_.end();
1102 }
1103 bool isNeedBackwardTranslate = false;
1104 if (IsLoop() && targetIndexValue < currentIndex_) {
1105 auto firstItemIndex = Positive(props->GetCalculatedPrevMargin()) ? targetIndexValue + TotalCount() - 1
1106 : targetIndexValue + TotalCount();
1107 isNeedBackwardTranslate = itemPosition_.find(firstItemIndex) != itemPosition_.end();
1108 }
1109 bool isNeedPlayTranslateAnimation = translateAnimationIsRunning_ || isNeedForwardTranslate ||
1110 isNeedBackwardTranslate || AutoLinearAnimationNeedReset(targetPos);
1111 if (context && !isNeedPlayTranslateAnimation && !SupportSwiperCustomAnimation()) {
1112 // displayCount is auto, loop is false, if the content width less than windows size
1113 // need offset to keep right aligned
1114 bool isNeedOffset = (GetLoopIndex(iter->first) == TotalCount() - 1) &&
1115 !props->GetDisplayCount().has_value() && !IsLoop() &&
1116 LessNotEqual(iter->second.endPos - iter->second.startPos, CalculateVisibleSize());
1117 float offset =
1118 isNeedOffset ? CalculateVisibleSize() - iter->second.endPos + iter->second.startPos : 0.0;
1119 targetPos -= offset;
1120
1121 context->AddAfterLayoutTask([weak = WeakClaim(this), targetPos, velocity = velocity_.value_or(0.0f),
1122 nextIndex = iter->first]() {
1123 auto swiper = weak.Upgrade();
1124 CHECK_NULL_VOID(swiper);
1125 swiper->PlayPropertyTranslateAnimation(-targetPos, nextIndex, velocity, false);
1126 swiper->PlayIndicatorTranslateAnimation(-targetPos, nextIndex);
1127 });
1128 } else {
1129 PlayTranslateAnimation(
1130 currentOffset_, currentOffset_ - targetPos, iter->first, false, velocity_.value_or(0.0f));
1131 }
1132 } else if (!itemPosition_.empty() && SwiperUtils::IsStretch(props)) {
1133 auto firstItem = GetFirstItemInfoInVisibleArea();
1134 auto targetPos = firstItem.second.startPos +
1135 (targetIndexValue - firstItem.first) * (placeItemWidth_.value() + GetItemSpace());
1136 PlayTranslateAnimation(
1137 currentOffset_, currentOffset_ - targetPos, targetIndexValue, false, velocity_.value_or(0.0f));
1138 } else {
1139 // AutoLinear Mode
1140 PlayTranslateAnimation(currentOffset_, currentOffset_ - algo->GetTargetStartPos(), targetIndexValue, false,
1141 velocity_.value_or(0.0f));
1142 }
1143 velocity_.reset();
1144 pauseTargetIndex_ = targetIndex_;
1145 }
1146 mainSizeIsMeasured_ = algo->GetMainSizeIsMeasured();
1147 contentCrossSize_ = algo->GetContentCrossSize();
1148 currentDelta_ = 0.0f;
1149 contentMainSize_ = algo->GetContentMainSize();
1150 oldContentMainSize_ = contentMainSize_;
1151 crossMatchChild_ = algo->IsCrossMatchChild();
1152 ignoreBlankOffset_ = algo->GetIgnoreBlankOffset();
1153 oldIndex_ = currentIndex_;
1154 oldChildrenSize_ = TotalCount();
1155 needFireCustomAnimationEvent_ = true;
1156
1157 if (windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION) {
1158 StartAutoPlay();
1159 windowSizeChangeReason_ = WindowSizeChangeReason::UNDEFINED;
1160 }
1161
1162 const auto& paddingProperty = props->GetPaddingProperty();
1163 jumpOnChange_ = false;
1164 return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
1165 }
1166
AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const1167 float SwiperPattern::AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const
1168 {
1169 if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
1170 return 0.0f;
1171 }
1172 if (isStartOverScroll && NonNegative(ignoreBlankOffset_)) {
1173 return prevMarginIgnoreBlank_ ? GetPrevMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1174 }
1175 if (!isStartOverScroll && NonPositive(ignoreBlankOffset_)) {
1176 return nextMarginIgnoreBlank_ ? -GetNextMarginWithItemSpace() + ignoreBlankOffset_ : ignoreBlankOffset_;
1177 }
1178 return 0.0f;
1179 }
1180
UpdateIgnoreBlankOffsetWithIndex()1181 void SwiperPattern::UpdateIgnoreBlankOffsetWithIndex()
1182 {
1183 if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
1184 auto lastIgnoreBlankOffset = ignoreBlankOffset_;
1185 ignoreBlankOffset_ = 0.0f;
1186 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1187 return;
1188 }
1189 if (targetIndex_.has_value()) {
1190 float lastIgnoreBlankOffset = ignoreBlankOffset_;
1191 if (prevMarginIgnoreBlank_ && targetIndex_.value() == 0) {
1192 ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1193 } else if (nextMarginIgnoreBlank_ && targetIndex_.value() >= (TotalCount() - GetDisplayCount())) {
1194 ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1195 } else {
1196 ignoreBlankOffset_ = 0.0f;
1197 }
1198 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1199 }
1200 }
1201
UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)1202 void SwiperPattern::UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)
1203 {
1204 if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
1205 return;
1206 }
1207 float lastIgnoreBlankOffset = ignoreBlankOffset_;
1208 if (prevMarginIgnoreBlank_ && overScrollDirection) {
1209 ignoreBlankOffset_ = -GetPrevMarginWithItemSpace();
1210 } else if (nextMarginIgnoreBlank_ && !overScrollDirection) {
1211 ignoreBlankOffset_ = GetNextMarginWithItemSpace();
1212 }
1213
1214 UpdateIgnoreBlankOffsetInMap(lastIgnoreBlankOffset);
1215 }
1216
UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)1217 void SwiperPattern::UpdateIgnoreBlankOffsetInMap(float lastIgnoreBlankOffset)
1218 {
1219 if (NearEqual(ignoreBlankOffset_, lastIgnoreBlankOffset)) {
1220 return;
1221 }
1222
1223 float adjustOffset = ignoreBlankOffset_ - lastIgnoreBlankOffset;
1224 for (auto& item : itemPosition_) {
1225 item.second.startPos -= adjustOffset;
1226 item.second.endPos -= adjustOffset;
1227 }
1228 }
1229
IsAutoLinear() const1230 bool SwiperPattern::IsAutoLinear() const
1231 {
1232 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1233 CHECK_NULL_RETURN(props, false);
1234 return !SwiperUtils::IsStretch(props);
1235 }
1236
AutoLinearAnimationNeedReset(float translate) const1237 bool SwiperPattern::AutoLinearAnimationNeedReset(float translate) const
1238 {
1239 if (!IsAutoLinear()) {
1240 return false;
1241 }
1242
1243 if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
1244 return false;
1245 }
1246
1247 if (NonPositive(translate)) {
1248 return false;
1249 }
1250
1251 auto iter = itemPosition_.rbegin();
1252 auto endPos = iter->second.endPos;
1253 if (endPos - CalculateVisibleSize() < translate) {
1254 return true;
1255 }
1256
1257 return false;
1258 }
1259
OnAnimationTranslateZero(int32_t nextIndex,bool stopAutoPlay)1260 void SwiperPattern::OnAnimationTranslateZero(int32_t nextIndex, bool stopAutoPlay)
1261 {
1262 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
1263
1264 if (!NeedAutoPlay() || !isUserFinish_) {
1265 return;
1266 }
1267
1268 if (stopAutoPlay) {
1269 MarkDirtyNodeSelf();
1270 } else {
1271 auto delayTime = GetInterval() - GetDuration();
1272 delayTime = std::clamp(delayTime, 0, delayTime);
1273 PostTranslateTask(delayTime);
1274 }
1275 }
1276
FireChangeEvent(int32_t preIndex,int32_t currentIndex) const1277 void SwiperPattern::FireChangeEvent(int32_t preIndex, int32_t currentIndex) const
1278 {
1279 if (jumpOnChange_) {
1280 return;
1281 }
1282 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1283 CHECK_NULL_VOID(swiperEventHub);
1284 swiperEventHub->FireChangeEvent(preIndex, currentIndex);
1285 swiperEventHub->FireIndicatorChangeEvent(currentIndex);
1286 swiperEventHub->FireIndicatorIndexChangeEvent(currentIndex);
1287 swiperEventHub->FireChangeDoneEvent(moveDirection_);
1288
1289 if (jumpIndex_) {
1290 auto host = GetHost();
1291 CHECK_NULL_VOID(host);
1292 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1293 }
1294 }
1295
FireAnimationStartEvent(int32_t currentIndex,int32_t nextIndex,const AnimationCallbackInfo & info) const1296 void SwiperPattern::FireAnimationStartEvent(
1297 int32_t currentIndex, int32_t nextIndex, const AnimationCallbackInfo& info) const
1298 {
1299 TAG_LOGI(AceLogTag::ACE_SWIPER, "FireAnimationStartEvent, currentIndex: %{public}d, nextIndex: %{public}d",
1300 currentIndex, nextIndex);
1301 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1302 CHECK_NULL_VOID(swiperEventHub);
1303 swiperEventHub->FireAnimationStartEvent(currentIndex, nextIndex, info);
1304 auto host = GetHost();
1305 CHECK_NULL_VOID(host);
1306 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
1307 }
1308
FireAnimationEndEvent(int32_t currentIndex,const AnimationCallbackInfo & info,bool isInterrupt) const1309 void SwiperPattern::FireAnimationEndEvent(
1310 int32_t currentIndex, const AnimationCallbackInfo& info, bool isInterrupt) const
1311 {
1312 TAG_LOGI(AceLogTag::ACE_SWIPER,
1313 "FireAnimationEndEvent currentIndex: %{public}d, currentOffset: has_value %{public}d, value %{public}fvp, "
1314 "isForce: %{public}d",
1315 currentIndex, info.currentOffset.has_value(), info.currentOffset.value_or(0.0), info.isForceStop);
1316 if (currentIndex == -1) {
1317 return;
1318 }
1319 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1320 CHECK_NULL_VOID(swiperEventHub);
1321 isInterrupt ? swiperEventHub->FireAnimationEndOnForceEvent(currentIndex, info)
1322 : swiperEventHub->FireAnimationEndEvent(currentIndex, info);
1323 auto host = GetHost();
1324 CHECK_NULL_VOID(host);
1325 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
1326 }
1327
FireGestureSwipeEvent(int32_t currentIndex,const AnimationCallbackInfo & info) const1328 void SwiperPattern::FireGestureSwipeEvent(int32_t currentIndex, const AnimationCallbackInfo& info) const
1329 {
1330 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1331 CHECK_NULL_VOID(swiperEventHub);
1332 swiperEventHub->FireGestureSwipeEvent(currentIndex, info);
1333 }
1334
HandleSwiperCustomAnimation(float offset)1335 void SwiperPattern::HandleSwiperCustomAnimation(float offset)
1336 {
1337 if (!SupportSwiperCustomAnimation()) {
1338 return;
1339 }
1340 if (itemPosition_.empty()) {
1341 needUnmountIndexs_.clear();
1342 itemPositionInAnimation_.clear();
1343 return;
1344 }
1345 if (NearZero(offset)) {
1346 return;
1347 }
1348
1349 if (itemPositionInAnimation_.empty()) {
1350 for (auto& item : itemPosition_) {
1351 UpdateItemInfoInCustomAnimation(item.first, item.second.startPos, item.second.endPos);
1352 }
1353 }
1354 indexsInAnimation_.clear();
1355 CalculateAndUpdateItemInfo(offset);
1356
1357 auto visibleIndex = CalcVisibleIndex();
1358 auto visibleIndexWithOffset = CalcVisibleIndex(offset);
1359 std::set<int32_t> unmountIndexs;
1360 for (auto& item : itemPositionInAnimation_) {
1361 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end() &&
1362 needUnmountIndexs_.find(item.first) == needUnmountIndexs_.end() &&
1363 visibleIndex.find(item.first) != visibleIndex.end() &&
1364 visibleIndexWithOffset.find(item.first) == visibleIndexWithOffset.end()) {
1365 indexsInAnimation_.insert(item.first);
1366 needUnmountIndexs_.insert(item.first);
1367 item.second.startPos += offset;
1368 item.second.endPos += offset;
1369 unmountIndexs.insert(item.first);
1370 }
1371 }
1372 for (const auto& index : unmountIndexs) {
1373 auto iter = itemPositionInAnimation_.find(index);
1374 if (iter == itemPositionInAnimation_.end()) {
1375 continue;
1376 }
1377
1378 OnSwiperCustomAnimationFinish(iter->second.task, index, iter->second.isFinishAnimation);
1379 }
1380
1381 FireSwiperCustomAnimationEvent();
1382 }
1383
CalcVisibleIndex(float offset) const1384 std::set<int32_t> SwiperPattern::CalcVisibleIndex(float offset) const
1385 {
1386 auto visibleSize = CalculateVisibleSize();
1387 auto itemSpace = GetItemSpace();
1388 auto isLoop = IsLoop();
1389 auto displayCount = GetDisplayCount();
1390 auto swipeByGroup = IsSwipeByGroup();
1391 std::set<int32_t> visibleIndex;
1392
1393 for (auto& item : itemPosition_) {
1394 auto index = item.first;
1395 auto startPos = item.second.startPos + offset;
1396 auto endPos = item.second.endPos + offset;
1397 auto itemPosDiff = endPos - startPos + itemSpace;
1398 auto pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index, displayCount) : index;
1399 auto pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index, displayCount) : index;
1400 auto pageStartPos = swipeByGroup ? startPos - itemPosDiff * (index - pageStartIndex) : startPos;
1401 auto pageEndPos = swipeByGroup ? endPos + itemPosDiff * (pageEndIndex - index) : endPos;
1402
1403 if (LessOrEqual(pageEndPos, -GetPrevMarginWithItemSpace())) {
1404 continue;
1405 }
1406 if (GreatOrEqual(pageStartPos, visibleSize + GetNextMarginWithItemSpace())) {
1407 continue;
1408 }
1409
1410 if (GreatNotEqual(startPos - itemSpace, -GetPrevMarginWithItemSpace()) &&
1411 itemPosition_.find(index - 1) == itemPosition_.end() && (isLoop || index > 0)) {
1412 pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index - 1, displayCount) : index - 1;
1413 }
1414 if (LessNotEqual(endPos + itemSpace, visibleSize + GetNextMarginWithItemSpace()) &&
1415 itemPosition_.find(index + 1) == itemPosition_.end() && (isLoop || index < RealTotalCount() - 1)) {
1416 pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index + 1, displayCount) : index + 1;
1417 }
1418 auto currentIndex = index - 1;
1419 while (currentIndex >= pageStartIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1420 visibleIndex.insert(GetLoopIndex(currentIndex));
1421 currentIndex--;
1422 }
1423 currentIndex = index + 1;
1424 while (currentIndex <= pageEndIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1425 visibleIndex.insert(GetLoopIndex(currentIndex));
1426 currentIndex++;
1427 }
1428 visibleIndex.insert(GetLoopIndex(index));
1429 }
1430
1431 return visibleIndex;
1432 }
1433
CalculateAndUpdateItemInfo(float offset)1434 void SwiperPattern::CalculateAndUpdateItemInfo(float offset)
1435 {
1436 auto prevMargin = GetPrevMargin();
1437 auto nextMargin = GetNextMargin();
1438 auto visibleSize = CalculateVisibleSize();
1439 auto itemSpace = GetItemSpace();
1440 auto isLoop = IsLoop();
1441 auto displayCount = GetDisplayCount();
1442 auto swipeByGroup = IsSwipeByGroup();
1443
1444 for (auto& item : itemPosition_) {
1445 auto index = item.first;
1446 auto startPos = item.second.startPos + offset;
1447 auto endPos = item.second.endPos + offset;
1448 auto itemPosDiff = endPos - startPos + itemSpace;
1449 auto pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index, displayCount) : index;
1450 auto pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index, displayCount) : index;
1451 auto pageStartPos = swipeByGroup ? startPos - itemPosDiff * (index - pageStartIndex) : startPos;
1452 auto pageEndPos = swipeByGroup ? endPos + itemPosDiff * (pageEndIndex - index) : endPos;
1453
1454 if (LessOrEqual(pageEndPos, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace)) {
1455 continue;
1456 }
1457 if (GreatOrEqual(pageStartPos, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace)) {
1458 continue;
1459 }
1460
1461 if (GreatNotEqual(startPos - itemSpace, NearZero(prevMargin) ? 0.0f : -prevMargin - itemSpace) &&
1462 itemPosition_.find(index - 1) == itemPosition_.end() && (isLoop || index > 0)) {
1463 pageStartIndex = swipeByGroup ? SwiperUtils::ComputePageIndex(index - 1, displayCount) : index - 1;
1464 }
1465 if (LessNotEqual(
1466 endPos + itemSpace, NearZero(nextMargin) ? visibleSize : visibleSize + nextMargin + itemSpace) &&
1467 itemPosition_.find(index + 1) == itemPosition_.end() && (isLoop || index < RealTotalCount() - 1)) {
1468 pageEndIndex = swipeByGroup ? SwiperUtils::ComputePageEndIndex(index + 1, displayCount) : index + 1;
1469 }
1470 auto currentIndex = index - 1;
1471 while (currentIndex >= pageStartIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1472 UpdateItemInfoInCustomAnimation(currentIndex, startPos - itemPosDiff * (index - currentIndex),
1473 endPos - itemPosDiff * (index - currentIndex));
1474 currentIndex--;
1475 }
1476 currentIndex = index + 1;
1477 while (currentIndex <= pageEndIndex && itemPosition_.find(currentIndex) == itemPosition_.end()) {
1478 UpdateItemInfoInCustomAnimation(currentIndex, startPos + itemPosDiff * (currentIndex - index),
1479 endPos + itemPosDiff * (currentIndex - index));
1480 currentIndex++;
1481 }
1482 UpdateItemInfoInCustomAnimation(index, startPos, endPos);
1483 }
1484 }
1485
UpdateItemInfoInCustomAnimation(int32_t index,float startPos,float endPos)1486 void SwiperPattern::UpdateItemInfoInCustomAnimation(int32_t index, float startPos, float endPos)
1487 {
1488 index = GetLoopIndex(index);
1489 if (IsSwipeByGroup() && index >= RealTotalCount()) {
1490 return;
1491 }
1492 indexsInAnimation_.insert(index);
1493 needUnmountIndexs_.erase(index);
1494 auto itemInAnimation = itemPositionInAnimation_.find(index);
1495 if (itemInAnimation == itemPositionInAnimation_.end()) {
1496 itemPositionInAnimation_[index] = { startPos, endPos, nullptr };
1497 } else {
1498 itemInAnimation->second.startPos = startPos;
1499 itemInAnimation->second.endPos = endPos;
1500 if (itemInAnimation->second.task) {
1501 itemInAnimation->second.task.Cancel();
1502 }
1503 }
1504 }
1505
FireSwiperCustomAnimationEvent()1506 void SwiperPattern::FireSwiperCustomAnimationEvent()
1507 {
1508 CHECK_NULL_VOID(onSwiperCustomContentTransition_);
1509 auto transition = onSwiperCustomContentTransition_->transition;
1510 CHECK_NULL_VOID(transition);
1511
1512 auto selectedIndex = GetCurrentIndex();
1513 for (auto& item : itemPositionInAnimation_) {
1514 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1515 continue;
1516 }
1517 auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1518 if (IsHorizontalAndRightToLeft()) {
1519 offset = Dimension(-item.second.startPos, DimensionUnit::PX).ConvertToVp();
1520 }
1521 auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1522 if (NonPositive(mainAxisLength)) {
1523 continue;
1524 }
1525 auto position = offset / mainAxisLength;
1526 auto proxy = AceType::MakeRefPtr<SwiperContentTransitionProxy>();
1527 proxy->SetSelectedIndex(selectedIndex);
1528 proxy->SetIndex(item.first);
1529 proxy->SetPosition(position);
1530 proxy->SetMainAxisLength(mainAxisLength);
1531 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), index = item.first]() {
1532 auto swiper = weak.Upgrade();
1533 CHECK_NULL_VOID(swiper);
1534 auto item = swiper->itemPositionInAnimation_.find(index);
1535 if (item == swiper->itemPositionInAnimation_.end()) {
1536 return;
1537 }
1538 item->second.isFinishAnimation = true;
1539 swiper->OnSwiperCustomAnimationFinish(item->second.task, index, true);
1540 });
1541 transition(proxy);
1542 }
1543 }
1544
FireContentDidScrollEvent()1545 void SwiperPattern::FireContentDidScrollEvent()
1546 {
1547 if (indexsInAnimation_.empty() || itemPositionInAnimation_.empty()) {
1548 return;
1549 }
1550
1551 CHECK_NULL_VOID(onContentDidScroll_);
1552 auto event = *onContentDidScroll_;
1553 auto selectedIndex = GetCurrentIndex();
1554
1555 SwiperLayoutAlgorithm::PositionMap mergeMap;
1556 mergeMap.insert(itemPositionInAnimation_.begin(), itemPositionInAnimation_.end());
1557 mergeMap.insert(itemPositionWillInvisible_.begin(), itemPositionWillInvisible_.end());
1558 for (auto& item : mergeMap) {
1559 if (indexsInAnimation_.find(item.first) == indexsInAnimation_.end()) {
1560 continue;
1561 }
1562 auto offset = Dimension(item.second.startPos, DimensionUnit::PX).ConvertToVp();
1563 auto mainAxisLength = Dimension(item.second.endPos - item.second.startPos, DimensionUnit::PX).ConvertToVp();
1564 if (NonPositive(mainAxisLength)) {
1565 continue;
1566 }
1567 auto position = offset / mainAxisLength;
1568 event(selectedIndex, item.first, position, mainAxisLength);
1569 }
1570 indexsInAnimation_.clear();
1571 }
1572
OnSwiperCustomAnimationFinish(CancelableCallback<void ()> & task,int32_t index,bool isFinishAnimation)1573 void SwiperPattern::OnSwiperCustomAnimationFinish(
1574 CancelableCallback<void()>& task, int32_t index, bool isFinishAnimation)
1575 {
1576 if (needUnmountIndexs_.find(index) == needUnmountIndexs_.end()) {
1577 return;
1578 }
1579 auto pipeline = PipelineContext::GetCurrentContext();
1580 CHECK_NULL_VOID(pipeline);
1581 auto taskExecutor = pipeline->GetTaskExecutor();
1582 CHECK_NULL_VOID(taskExecutor);
1583 if (task) {
1584 task.Cancel();
1585 }
1586
1587 int32_t timeout = 0;
1588 if (onSwiperCustomContentTransition_ && !isFinishAnimation) {
1589 timeout = onSwiperCustomContentTransition_->timeout;
1590 }
1591
1592 if (timeout == 0) {
1593 auto item = itemPositionInAnimation_.find(index);
1594 if (item != itemPositionInAnimation_.end()) {
1595 itemPositionWillInvisible_[index] = item->second;
1596 }
1597 needUnmountIndexs_.erase(index);
1598 itemPositionInAnimation_.erase(index);
1599 MarkDirtyNodeSelf();
1600 return;
1601 }
1602
1603 task.Reset([weak = AceType::WeakClaim(this), index] {
1604 auto swiper = weak.Upgrade();
1605 CHECK_NULL_VOID(swiper);
1606 swiper->needUnmountIndexs_.erase(index);
1607 swiper->itemPositionInAnimation_.erase(index);
1608 swiper->MarkDirtyNodeSelf();
1609 });
1610 taskExecutor->PostDelayedTask(task, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperDelayedCustomAnimation");
1611 }
1612
SwipeToWithoutAnimation(int32_t index)1613 void SwiperPattern::SwipeToWithoutAnimation(int32_t index)
1614 {
1615 if (currentIndex_ != index) {
1616 FireWillShowEvent(index);
1617 FireWillHideEvent(currentIndex_);
1618 }
1619 if (IsVisibleChildrenSizeLessThanSwiper()) {
1620 return;
1621 }
1622
1623 if (usePropertyAnimation_) {
1624 StopPropertyTranslateAnimation(isFinishAnimation_);
1625 }
1626
1627 StopTranslateAnimation();
1628 StopFadeAnimation();
1629 StopSpringAnimationImmediately();
1630 StopIndicatorAnimation(true);
1631 jumpIndex_ = index;
1632 AceAsyncTraceBeginCommercial(0, hasTabsAncestor_ ? APP_TABS_NO_ANIMATION_SWITCH : APP_SWIPER_NO_ANIMATION_SWITCH);
1633 uiCastJumpIndex_ = index;
1634 MarkDirtyNodeSelf();
1635 FireAndCleanScrollingListener();
1636 }
1637
StopSpringAnimationAndFlushImmediately()1638 void SwiperPattern::StopSpringAnimationAndFlushImmediately()
1639 {
1640 if (springAnimationIsRunning_) {
1641 StopSpringAnimationImmediately();
1642 currentDelta_ = 0.0f;
1643 itemPosition_.clear();
1644 isVoluntarilyClear_ = true;
1645 jumpIndex_ = currentIndex_;
1646 MarkDirtyNodeSelf();
1647 auto pipeline = PipelineContext::GetCurrentContext();
1648 if (pipeline) {
1649 pipeline->FlushUITasks();
1650 }
1651 }
1652 }
1653
IsUseCustomAnimation() const1654 bool SwiperPattern::IsUseCustomAnimation() const
1655 {
1656 auto props = GetLayoutProperty<SwiperLayoutProperty>();
1657 CHECK_NULL_RETURN(props, false);
1658 return props->GetIsCustomAnimation().value_or(false);
1659 }
1660
NeedFastAnimation() const1661 bool SwiperPattern::NeedFastAnimation() const
1662 {
1663 return tabAnimationMode_ == TabAnimateMode::CONTENT_FIRST_WITH_JUMP ||
1664 tabAnimationMode_ == TabAnimateMode::ACTION_FIRST_WITH_JUMP;
1665 }
1666
SwipeTo(int32_t index)1667 void SwiperPattern::SwipeTo(int32_t index)
1668 {
1669 auto targetIndex = IsLoop() ? index : (index < 0 || index > (TotalCount() - 1)) ? 0 : index;
1670 targetIndex = IsLoop() ? targetIndex : std::clamp(targetIndex, 0, TotalCount() - GetDisplayCount());
1671 if (!ContentWillChange(targetIndex)) {
1672 return;
1673 }
1674
1675 if (IsUseCustomAnimation()) {
1676 OnCustomContentTransition(targetIndex);
1677 MarkDirtyNodeSelf();
1678 return;
1679 }
1680
1681 if (IsVisibleChildrenSizeLessThanSwiper()) {
1682 return;
1683 }
1684
1685 // If targetIndex_ has a value, means animation is still running, stop it before play new animation.
1686 if (currentIndex_ == targetIndex && !targetIndex_.has_value()) {
1687 return;
1688 }
1689 StopFadeAnimation();
1690 if (springAnimationIsRunning_) {
1691 StopSpringAnimationImmediately();
1692 jumpIndex_ = currentIndex_;
1693 MarkDirtyNodeSelf();
1694 auto pipeline = PipelineContext::GetCurrentContext();
1695 if (pipeline) {
1696 pipeline->FlushUITasks();
1697 }
1698 }
1699 StopAutoPlay();
1700 StopTranslateAnimation();
1701
1702 StopIndicatorAnimation();
1703 if (usePropertyAnimation_) {
1704 StopPropertyTranslateAnimation(isFinishAnimation_);
1705 }
1706
1707 if (hasTabsAncestor_ && NeedFastAnimation()) {
1708 FastAnimation(targetIndex);
1709 }
1710
1711 targetIndex_ = targetIndex;
1712
1713 UpdateTabBarAnimationDuration(index);
1714 if (GetDuration() == 0 || !isVisible_) {
1715 SwipeToWithoutAnimation(index);
1716 return;
1717 }
1718
1719 if (currentIndex_ != targetIndex_.value_or(0)) {
1720 FireWillShowEvent(targetIndex_.value_or(0));
1721 FireWillHideEvent(currentIndex_);
1722 }
1723 MarkDirtyNodeSelf();
1724 }
1725
UpdateTabBarAnimationDuration(int32_t index)1726 void SwiperPattern::UpdateTabBarAnimationDuration(int32_t index)
1727 {
1728 auto host = GetHost();
1729 CHECK_NULL_VOID(host);
1730 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1731 CHECK_NULL_VOID(tabsNode);
1732 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
1733 CHECK_NULL_VOID(tabBarNode);
1734 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
1735 CHECK_NULL_VOID(tabBarPattern);
1736 tabBarPattern->UpdateAnimationDuration();
1737 }
1738
CheckTargetIndex(int32_t targetIndex,bool isForceBackward)1739 int32_t SwiperPattern::CheckTargetIndex(int32_t targetIndex, bool isForceBackward)
1740 {
1741 if (!IsAutoLinear()) {
1742 return targetIndex;
1743 }
1744 while (GetLoopIndex(targetIndex) != GetLoopIndex(currentIndex_)) {
1745 auto currentFrameNode = GetCurrentFrameNode(GetLoopIndex(targetIndex));
1746 CHECK_NULL_RETURN(currentFrameNode, targetIndex);
1747 auto props = currentFrameNode->GetLayoutProperty<LayoutProperty>();
1748 CHECK_NULL_RETURN(props, targetIndex);
1749 if (props->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::GONE) {
1750 return targetIndex;
1751 }
1752 if (isForceBackward || currentIndex_ < targetIndex) {
1753 if (IsHorizontalAndRightToLeft()) {
1754 --targetIndex;
1755 } else {
1756 ++targetIndex;
1757 }
1758 } else {
1759 if (IsHorizontalAndRightToLeft()) {
1760 ++targetIndex;
1761 } else {
1762 --targetIndex;
1763 }
1764 }
1765 if (!IsLoop() && (targetIndex < 0 || targetIndex >= TotalCount())) {
1766 return currentIndex_;
1767 }
1768 }
1769 return targetIndex;
1770 }
1771
ShowNext(bool needCheckWillScroll)1772 void SwiperPattern::ShowNext(bool needCheckWillScroll)
1773 {
1774 if (IsVisibleChildrenSizeLessThanSwiper()) {
1775 return;
1776 }
1777 indicatorDoingAnimation_ = false;
1778 auto childrenSize = TotalCount();
1779 std::optional<int32_t> preIndex;
1780 auto loopIndex = usePropertyAnimation_ ? GetLoopIndex(propertyAnimationIndex_) : GetLoopIndex(currentIndex_);
1781 if (preTargetIndex_.has_value()) {
1782 loopIndex = GetLoopIndex(preTargetIndex_.value());
1783 preIndex = preTargetIndex_.value();
1784 }
1785 if (loopIndex >= childrenSize - GetDisplayCount() && !IsLoop()) {
1786 return;
1787 }
1788 if (childrenSize <= 0 || GetDisplayCount() == 0) {
1789 return;
1790 }
1791 StopAutoPlay();
1792
1793 StopSpringAnimationAndFlushImmediately();
1794 StopFadeAnimation();
1795 StopIndicatorAnimation();
1796 if (preIndex || usePropertyAnimation_ || translateAnimationIsRunning_) {
1797 isUserFinish_ = false;
1798 FinishAnimation();
1799 if (!ContentWillChange(currentIndex_ + 1)) {
1800 return;
1801 }
1802 }
1803
1804 if (needCheckWillScroll && HasOnContentWillScroll()) {
1805 auto nextIndex = currentIndex_ + (IsSwipeByGroup() ? GetDisplayCount() : 1);
1806 auto offset = CalcWillScrollOffset(nextIndex);
1807 if (!ContentWillScroll(currentIndex_, nextIndex, -offset)) {
1808 return;
1809 }
1810 }
1811
1812 moveDirection_ = true;
1813
1814 auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1815 if (isVisibleArea_) {
1816 targetIndex_ = CheckTargetIndex(currentIndex_ + stepItems);
1817 preTargetIndex_ = targetIndex_;
1818 MarkDirtyNodeSelf();
1819 auto pipeline = PipelineContext::GetCurrentContext();
1820 if (pipeline) {
1821 pipeline->FlushUITasks();
1822 }
1823 } else {
1824 SwipeToWithoutAnimation(currentIndex_ + stepItems);
1825 }
1826 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1827 CHECK_NULL_VOID(swiperEventHub);
1828 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1829 }
1830
ShowPrevious(bool needCheckWillScroll)1831 void SwiperPattern::ShowPrevious(bool needCheckWillScroll)
1832 {
1833 if (IsVisibleChildrenSizeLessThanSwiper()) {
1834 return;
1835 }
1836
1837 if (IsAutoLinear() && static_cast<int32_t>(itemPosition_.size()) == TotalCount() && !autoLinearReachBoundary) {
1838 return;
1839 }
1840
1841 indicatorDoingAnimation_ = false;
1842 auto childrenSize = TotalCount();
1843 std::optional<int32_t> preIndex;
1844 auto loopIndex = usePropertyAnimation_ ? GetLoopIndex(propertyAnimationIndex_) : GetLoopIndex(currentIndex_);
1845 if (preTargetIndex_.has_value()) {
1846 loopIndex = GetLoopIndex(preTargetIndex_.value());
1847 preIndex = preTargetIndex_.value();
1848 }
1849 if (loopIndex <= 0 && !IsLoop()) {
1850 return;
1851 }
1852 if (childrenSize <= 0 || GetDisplayCount() == 0) {
1853 return;
1854 }
1855 StopAutoPlay();
1856 StopSpringAnimationAndFlushImmediately();
1857 StopFadeAnimation();
1858 StopIndicatorAnimation();
1859
1860 if (preIndex || usePropertyAnimation_ || translateAnimationIsRunning_) {
1861 isUserFinish_ = false;
1862 FinishAnimation();
1863 if (!ContentWillChange(currentIndex_ - 1)) {
1864 return;
1865 }
1866 }
1867
1868 if (needCheckWillScroll && HasOnContentWillScroll()) {
1869 auto prevIndex = currentIndex_ - (IsSwipeByGroup() ? GetDisplayCount() : 1);
1870 auto offset = CalcWillScrollOffset(prevIndex);
1871 if (!ContentWillScroll(currentIndex_, prevIndex, offset)) {
1872 return;
1873 }
1874 }
1875
1876 moveDirection_ = false;
1877
1878 auto stepItems = IsSwipeByGroup() ? GetDisplayCount() : 1;
1879 if (isVisibleArea_) {
1880 targetIndex_ = CheckTargetIndex(currentIndex_ - stepItems);
1881 preTargetIndex_ = targetIndex_;
1882 MarkDirtyNodeSelf();
1883 auto pipeline = PipelineContext::GetCurrentContext();
1884 if (pipeline) {
1885 pipeline->FlushUITasks();
1886 }
1887 } else {
1888 SwipeToWithoutAnimation(currentIndex_ - stepItems);
1889 }
1890 auto swiperEventHub = GetEventHub<SwiperEventHub>();
1891 CHECK_NULL_VOID(swiperEventHub);
1892 swiperEventHub->FireIndicatorChangeEvent(GetLoopIndex(currentIndex_));
1893 }
1894
FastAnimation(int32_t targetIndex)1895 void SwiperPattern::FastAnimation(int32_t targetIndex)
1896 {
1897 if (abs(currentIndex_ - targetIndex) > JUMP_NEAR_VALUE) {
1898 jumpOnChange_ = true;
1899 auto tempIndex = targetIndex - ((currentIndex_ < targetIndex) ? JUMP_NEAR_VALUE : -JUMP_NEAR_VALUE);
1900 jumpIndex_ = tempIndex;
1901 auto host = GetHost();
1902 CHECK_NULL_VOID(host);
1903 MarkDirtyNodeSelf();
1904 auto pipeline = GetContext();
1905 CHECK_NULL_VOID(pipeline);
1906 pipeline->FlushUITaskWithSingleDirtyNode(host);
1907 pipeline->FlushSyncGeometryNodeTasks();
1908 }
1909 }
1910
IsInFastAnimation() const1911 bool SwiperPattern::IsInFastAnimation() const
1912 {
1913 if (!NeedFastAnimation()) {
1914 return false;
1915 }
1916 if (targetIndex_) {
1917 return true;
1918 }
1919 return usePropertyAnimation_;
1920 }
1921
ChangeIndex(int32_t index,SwiperAnimationMode mode)1922 void SwiperPattern::ChangeIndex(int32_t index, SwiperAnimationMode mode)
1923 {
1924 int32_t targetIndex = 0;
1925 if (!ComputeTargetIndex(index, targetIndex)) {
1926 return;
1927 }
1928
1929 targetIndex = CheckTargetIndex(targetIndex);
1930 if (mode == SwiperAnimationMode::NO_ANIMATION) {
1931 needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
1932
1933 if (GetMaxDisplayCount() > 0) {
1934 SetIndicatorChangeIndexStatus(false);
1935 }
1936
1937 SwipeToWithoutAnimation(GetLoopIndex(targetIndex));
1938 } else if (mode == SwiperAnimationMode::DEFAULT_ANIMATION) {
1939 if (GetMaxDisplayCount() > 0) {
1940 SetIndicatorChangeIndexStatus(true);
1941 }
1942 SwipeTo(targetIndex);
1943 } else if (mode == SwiperAnimationMode::FAST_ANIMATION) {
1944 // skip to the tab near 3 to target
1945 FastAnimation(targetIndex);
1946 if (GetMaxDisplayCount() > 0) {
1947 SetIndicatorChangeIndexStatus(true);
1948 }
1949 SwipeTo(targetIndex);
1950 }
1951 }
1952
ComputeTargetIndex(int32_t index,int32_t & targetIndex) const1953 bool SwiperPattern::ComputeTargetIndex(int32_t index, int32_t& targetIndex) const
1954 {
1955 auto displayCount = GetDisplayCount();
1956 if (RealTotalCount() <= 0 || displayCount == 0 || index < 0 || index >= RealTotalCount()) {
1957 return false;
1958 }
1959 auto itemCount = TotalCount();
1960 auto loopCount = itemCount == 0 ? 0 : std::abs(currentIndex_ / itemCount);
1961 targetIndex = currentIndex_ >= 0 ? loopCount * itemCount + index : -(loopCount + 1) * itemCount + index;
1962 targetIndex = IsSwipeByGroup() ? SwiperUtils::ComputePageIndex(targetIndex, displayCount) : targetIndex;
1963 if (targetIndex_.has_value() && targetIndex_.value() == targetIndex) {
1964 return false;
1965 }
1966 return true;
1967 }
1968
ChangeIndex(int32_t index,bool useAnimation)1969 void SwiperPattern::ChangeIndex(int32_t index, bool useAnimation)
1970 {
1971 int32_t targetIndex = 0;
1972 if (!ComputeTargetIndex(index, targetIndex)) {
1973 return;
1974 }
1975
1976 targetIndex = CheckTargetIndex(targetIndex);
1977 if (useAnimation) {
1978 if (GetMaxDisplayCount() > 0) {
1979 SetIndicatorChangeIndexStatus(true);
1980 }
1981
1982 SwipeTo(targetIndex);
1983 } else {
1984 needFireCustomAnimationEvent_ = translateAnimationIsRunning_;
1985
1986 if (GetMaxDisplayCount() > 0) {
1987 SetIndicatorChangeIndexStatus(false);
1988 }
1989
1990 SwipeToWithoutAnimation(GetLoopIndex(targetIndex));
1991 }
1992 }
1993
FinishAnimation()1994 void SwiperPattern::FinishAnimation()
1995 {
1996 if (translateAnimationIsRunning_) {
1997 isFinishAnimation_ = true;
1998 StopTranslateAnimation();
1999 }
2000 StopSpringAnimation();
2001 StopFadeAnimation();
2002 StopIndicatorAnimation(true);
2003 if (usePropertyAnimation_) {
2004 isFinishAnimation_ = true;
2005 StopPropertyTranslateAnimation(isFinishAnimation_);
2006 }
2007 if (isUserFinish_) {
2008 if (swiperController_ && swiperController_->GetFinishCallback()) {
2009 auto finishCallback = swiperController_->GetFinishCallback();
2010 finishCallback();
2011 swiperController_->SetFinishCallback(nullptr);
2012 }
2013 } else {
2014 isUserFinish_ = true;
2015 }
2016 }
2017
PreloadItems(const std::set<int32_t> & indexSet)2018 void SwiperPattern::PreloadItems(const std::set<int32_t>& indexSet)
2019 {
2020 std::set<int32_t> validIndexSet;
2021 auto childrenSize = RealTotalCount();
2022 for (const auto& index : indexSet) {
2023 if (index < 0 || index >= childrenSize) {
2024 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
2025 "BusinessError 401: Parameter error. Each value in indices must be valid index value of tab content.");
2026 return;
2027 }
2028 validIndexSet.emplace(index);
2029 }
2030
2031 if (validIndexSet.empty()) {
2032 FirePreloadFinishEvent(ERROR_CODE_PARAM_INVALID,
2033 "BusinessError 401: Parameter error. The parameter indices must be a non-empty array.");
2034 return;
2035 }
2036
2037 auto preloadTask = [weak = WeakClaim(this), indexSet]() {
2038 auto swiperPattern = weak.Upgrade();
2039 CHECK_NULL_VOID(swiperPattern);
2040 auto host = swiperPattern->GetHost();
2041 CHECK_NULL_VOID(host);
2042 auto parent = host->GetParent();
2043 if (AceType::InstanceOf<TabsNode>(parent)) {
2044 swiperPattern->DoTabsPreloadItems(indexSet);
2045 } else {
2046 swiperPattern->DoSwiperPreloadItems(indexSet);
2047 }
2048
2049 swiperPattern->FirePreloadFinishEvent(ERROR_CODE_NO_ERROR);
2050 };
2051 auto host = GetHost();
2052 CHECK_NULL_VOID(host);
2053 auto pipeline = host->GetContext();
2054 CHECK_NULL_VOID(pipeline);
2055 auto taskExecutor = pipeline->GetTaskExecutor();
2056 CHECK_NULL_VOID(taskExecutor);
2057 taskExecutor->PostTask(preloadTask, TaskExecutor::TaskType::UI, "ArkUIFirePreloadFinish");
2058 }
2059
FirePreloadFinishEvent(int32_t errorCode,std::string message)2060 void SwiperPattern::FirePreloadFinishEvent(int32_t errorCode, std::string message)
2061 {
2062 if (swiperController_ && swiperController_->GetPreloadFinishCallback()) {
2063 auto preloadFinishCallback = swiperController_->GetPreloadFinishCallback();
2064 swiperController_->SetPreloadFinishCallback(nullptr);
2065 preloadFinishCallback(errorCode, message);
2066 }
2067 }
2068
DoTabsPreloadItems(const std::set<int32_t> & indexSet)2069 void SwiperPattern::DoTabsPreloadItems(const std::set<int32_t>& indexSet)
2070 {
2071 auto host = GetHost();
2072 CHECK_NULL_VOID(host);
2073 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
2074 CHECK_NULL_VOID(props);
2075 auto geometryNode = host->GetGeometryNode();
2076 CHECK_NULL_VOID(geometryNode);
2077 auto contentConstraint = props->GetContentLayoutConstraint();
2078 auto frameSize = OptionalSizeF(geometryNode->GetPaddingSize());
2079 auto childConstraint = SwiperUtils::CreateChildConstraint(props, frameSize, false);
2080 for (auto index : indexSet) {
2081 auto tabContent = GetCurrentFrameNode(index);
2082 if (!tabContent) {
2083 continue;
2084 }
2085 if (!tabContent->GetChildren().empty()) {
2086 continue;
2087 }
2088 auto tabContentPattern = tabContent->GetPattern<TabContentPattern>();
2089 if (!tabContentPattern) {
2090 continue;
2091 }
2092 tabContentPattern->BeforeCreateLayoutWrapper();
2093
2094 for (const auto& child : tabContent->GetChildren()) {
2095 child->Build(nullptr);
2096 }
2097 if (contentConstraint.has_value() && tabContent->GetGeometryNode()) {
2098 tabContent->GetGeometryNode()->SetParentLayoutConstraint(childConstraint);
2099 FrameNode::ProcessOffscreenNode(tabContent);
2100 }
2101 }
2102 }
2103
DoSwiperPreloadItems(const std::set<int32_t> & indexSet)2104 void SwiperPattern::DoSwiperPreloadItems(const std::set<int32_t>& indexSet)
2105 {
2106 auto host = GetHost();
2107 CHECK_NULL_VOID(host);
2108 auto targetNode = FindLazyForEachNode(host);
2109 if (targetNode.has_value()) {
2110 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
2111 CHECK_NULL_VOID(lazyForEachNode);
2112 for (auto index : indexSet) {
2113 if (lazyForEachNode) {
2114 lazyForEachNode->GetFrameChildByIndex(index, true);
2115 }
2116 }
2117 }
2118 const auto& children = host->GetChildren();
2119 for (const auto& child : children) {
2120 if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
2121 continue;
2122 }
2123
2124 auto forEachNode = AceType::DynamicCast<ForEachNode>(child);
2125 for (auto index : indexSet) {
2126 if (forEachNode && forEachNode->GetChildAtIndex(index)) {
2127 forEachNode->GetChildAtIndex(index)->Build(nullptr);
2128 continue;
2129 }
2130 }
2131 }
2132 }
2133
OnTranslateAnimationFinish()2134 void SwiperPattern::OnTranslateAnimationFinish()
2135 {
2136 if (!translateAnimationIsRunning_) {
2137 return;
2138 }
2139 translateAnimationIsRunning_ = false;
2140 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
2141 }
2142
StopTranslateAnimation()2143 void SwiperPattern::StopTranslateAnimation()
2144 {
2145 if (translateAnimationIsRunning_) {
2146 auto host = GetHost();
2147 CHECK_NULL_VOID(host);
2148 translateAnimationIsRunning_ = false;
2149
2150 if (NearZero(translateAnimationEndPos_ - currentOffset_)) {
2151 AnimationUtils::StopAnimation(translateAnimation_);
2152 targetIndex_.reset();
2153 } else {
2154 AnimationOption option;
2155 option.SetCurve(Curves::LINEAR);
2156 option.SetDuration(0);
2157 translateAnimation_ = AnimationUtils::StartAnimation(option, [host, weak = WeakClaim(this)]() {
2158 auto swiper = weak.Upgrade();
2159 CHECK_NULL_VOID(swiper);
2160 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, swiper->currentOffset_);
2161 });
2162 }
2163
2164 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_, true);
2165 }
2166 }
2167
StopSpringAnimationImmediately()2168 void SwiperPattern::StopSpringAnimationImmediately()
2169 {
2170 if (!springAnimationIsRunning_) {
2171 return;
2172 }
2173 AnimationOption option;
2174 option.SetCurve(Curves::LINEAR);
2175 option.SetDuration(0);
2176 springAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
2177 auto swiper = weak.Upgrade();
2178 CHECK_NULL_VOID(swiper);
2179 auto host = swiper->GetHost();
2180 CHECK_NULL_VOID(host);
2181 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, swiper->currentIndexOffset_);
2182 });
2183 OnSpringAnimationFinish();
2184 }
2185
StopSpringAnimation()2186 void SwiperPattern::StopSpringAnimation()
2187 {
2188 if (springAnimationIsRunning_) {
2189 AnimationUtils::StopAnimation(springAnimation_);
2190 }
2191 }
2192
StopFadeAnimation()2193 void SwiperPattern::StopFadeAnimation()
2194 {
2195 AnimationUtils::StopAnimation(fadeAnimation_);
2196 if (fadeAnimationIsRunning_) {
2197 fadeAnimationIsRunning_ = false;
2198 }
2199 }
2200
InitIndicator()2201 void SwiperPattern::InitIndicator()
2202 {
2203 auto swiperNode = GetHost();
2204 CHECK_NULL_VOID(swiperNode);
2205 RefPtr<FrameNode> indicatorNode;
2206 if (!HasIndicatorNode()) {
2207 if (!IsShowIndicator()) {
2208 return;
2209 }
2210 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
2211 []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
2212 swiperNode->AddChild(indicatorNode);
2213 } else {
2214 indicatorNode =
2215 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetIndicatorId())));
2216 CHECK_NULL_VOID(indicatorNode);
2217 if (!IsShowIndicator()) {
2218 RemoveIndicatorNode();
2219 return;
2220 }
2221 if (GetIndicatorType() == SwiperIndicatorType::DIGIT && lastSwiperIndicatorType_ == SwiperIndicatorType::DOT) {
2222 RemoveIndicatorNode();
2223 indicatorNode = FrameNode::GetOrCreateFrameNode(V2::SWIPER_INDICATOR_ETS_TAG, GetIndicatorId(),
2224 []() { return AceType::MakeRefPtr<SwiperIndicatorPattern>(); });
2225 swiperNode->AddChild(indicatorNode);
2226 }
2227 }
2228 lastSwiperIndicatorType_ = GetIndicatorType();
2229 CHECK_NULL_VOID(indicatorNode);
2230 auto props = GetLayoutProperty<SwiperLayoutProperty>();
2231 CHECK_NULL_VOID(props);
2232 if (props->GetIndicatorTypeValue(SwiperIndicatorType::DOT) == SwiperIndicatorType::DOT) {
2233 SwiperHelper::SaveDotIndicatorProperty(indicatorNode, *this);
2234 } else {
2235 SwiperHelper::SaveDigitIndicatorProperty(indicatorNode, *this);
2236 }
2237
2238 auto renderContext = indicatorNode->GetRenderContext();
2239 CHECK_NULL_VOID(renderContext);
2240 BorderRadiusProperty radius;
2241 radius.SetRadius(INDICATOR_BORDER_RADIUS);
2242 renderContext->UpdateBorderRadius(radius);
2243
2244 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
2245 indicatorPattern->SetIndicatorInteractive(isIndicatorInteractive_);
2246
2247 indicatorNode->MarkModifyDone();
2248 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2249 }
2250
InitArrow()2251 void SwiperPattern::InitArrow()
2252 {
2253 auto swiperNode = GetHost();
2254 CHECK_NULL_VOID(swiperNode);
2255 RefPtr<FrameNode> leftArrow;
2256 RefPtr<FrameNode> rightArrow;
2257 if (!HasLeftButtonNode() && !HasRightButtonNode()) {
2258 if (!IsShowArrow()) {
2259 return;
2260 }
2261 leftArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_LEFT_ARROW_ETS_TAG, GetLeftButtonId(),
2262 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2263 swiperNode->AddChild(leftArrow);
2264 rightArrow = FrameNode::GetOrCreateFrameNode(V2::SWIPER_RIGHT_ARROW_ETS_TAG, GetRightButtonId(),
2265 []() { return AceType::MakeRefPtr<SwiperArrowPattern>(); });
2266 swiperNode->AddChild(rightArrow);
2267 } else {
2268 leftArrow =
2269 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
2270 CHECK_NULL_VOID(leftArrow);
2271 rightArrow =
2272 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
2273 CHECK_NULL_VOID(rightArrow);
2274 if (!IsShowArrow()) {
2275 RemoveLeftButtonNode();
2276 RemoveRightButtonNode();
2277 return;
2278 }
2279 }
2280
2281 SaveArrowProperty(leftArrow);
2282 SaveArrowProperty(rightArrow);
2283
2284 leftArrow->MarkModifyDone();
2285 rightArrow->MarkModifyDone();
2286 }
2287
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)2288 void SwiperPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
2289 {
2290 if (direction_ == GetDirection() && panEvent_) {
2291 return;
2292 }
2293 // fade offset need to be reset when is still dragging
2294 if (direction_ != GetDirection()) {
2295 fadeOffset_ = 0.f;
2296 }
2297 direction_ = GetDirection();
2298
2299 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2300 auto pattern = weak.Upgrade();
2301 pattern->InitIndexCanChangeMap();
2302 if (pattern) {
2303 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag start. SourceTool: %{public}d", info.GetSourceTool());
2304 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2305 pattern->isFirstAxisAction_ = true;
2306 return;
2307 }
2308 pattern->FireAndCleanScrollingListener();
2309 pattern->HandleDragStart(info);
2310 // notify scrollStart upwards
2311 pattern->NotifyParentScrollStart(weak, pattern->direction_ == Axis::HORIZONTAL ?
2312 info.GetGlobalLocation().GetX() : info.GetGlobalLocation().GetY());
2313 }
2314 };
2315
2316 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2317 auto pattern = weak.Upgrade();
2318 if (pattern) {
2319 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2320 if (pattern->isFirstAxisAction_) {
2321 pattern->isFirstAxisAction_ = false;
2322 } else if (pattern->pageFlipMode_ == PageFlipMode::SINGLE &&
2323 (pattern->usePropertyAnimation_ || pattern->translateAnimationIsRunning_)) {
2324 return;
2325 }
2326 if (!pattern->CheckSwiperPanEvent(info.GetMainDelta())) {
2327 return;
2328 }
2329 if (GreatNotEqual(info.GetMainDelta(), 0.0)) {
2330 pattern->ShowPrevious(true);
2331 } else if (LessNotEqual(info.GetMainDelta(), 0.0)) {
2332 pattern->ShowNext(true);
2333 }
2334 } else {
2335 pattern->HandleDragUpdate(info);
2336 }
2337 }
2338 };
2339
2340 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2341 auto pattern = weak.Upgrade();
2342 if (pattern) {
2343 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag end. Velocity: %{public}f px/s, SourceTool: %{public}d",
2344 info.GetMainVelocity(), info.GetSourceTool());
2345 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
2346 return;
2347 }
2348 pattern->HandleDragEnd(info.GetMainVelocity(), info.GetMainDelta());
2349 auto velocity = info.GetMainVelocity();
2350 if (std::abs(velocity) <= NEW_MIN_TURN_PAGE_VELOCITY &&
2351 std::abs(velocity) > MIN_DUMP_VELOCITY_THRESHOLD) {
2352 auto host = pattern->GetHost();
2353 CHECK_NULL_VOID(host);
2354 auto eventHub = host->GetEventHub<EventHub>();
2355 CHECK_NULL_VOID(eventHub);
2356 auto gestureEventHub = eventHub->GetOrCreateGestureEventHub();
2357 CHECK_NULL_VOID(gestureEventHub);
2358 gestureEventHub->DumpVelocityInfoFroPanEvent(info.GetPointerId());
2359 }
2360 }
2361 };
2362
2363 auto actionCancelTask = [weak = WeakClaim(this)]() {
2364 auto pattern = weak.Upgrade();
2365 if (pattern) {
2366 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper drag cancel");
2367 pattern->HandleDragEnd(0.0);
2368 }
2369 };
2370
2371 AddPanEvent(gestureHub, std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask),
2372 std::move(actionCancelTask));
2373 }
2374
AddPanEvent(const RefPtr<GestureEventHub> & gestureHub,GestureEventFunc && actionStart,GestureEventFunc && actionUpdate,GestureEventFunc && actionEnd,GestureEventNoParameter && actionCancel)2375 void SwiperPattern::AddPanEvent(const RefPtr<GestureEventHub>& gestureHub, GestureEventFunc&& actionStart,
2376 GestureEventFunc&& actionUpdate, GestureEventFunc&& actionEnd, GestureEventNoParameter&& actionCancel)
2377 {
2378 if (GetDirection() == Axis::VERTICAL) {
2379 panDirection_.type = PanDirection::VERTICAL;
2380 } else {
2381 panDirection_.type = PanDirection::HORIZONTAL;
2382 }
2383 if (panEvent_) {
2384 gestureHub->RemovePanEvent(panEvent_);
2385 }
2386
2387 panEvent_ = MakeRefPtr<PanEvent>(
2388 std::move(actionStart), std::move(actionUpdate), std::move(actionEnd), std::move(actionCancel));
2389 gestureHub->AddPanEvent(panEvent_, panDirection_, 1, DEFAULT_PAN_DISTANCE);
2390 }
2391
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)2392 void SwiperPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
2393 {
2394 if (touchEvent_) {
2395 return;
2396 }
2397
2398 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2399 auto pattern = weak.Upgrade();
2400 if (pattern) {
2401 pattern->HandleTouchEvent(info);
2402 }
2403 };
2404
2405 if (touchEvent_) {
2406 gestureHub->RemoveTouchEvent(touchEvent_);
2407 }
2408 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2409 gestureHub->AddTouchEvent(touchEvent_);
2410 }
2411
InitOnFocusInternal(const RefPtr<FocusHub> & focusHub)2412 void SwiperPattern::InitOnFocusInternal(const RefPtr<FocusHub>& focusHub)
2413 {
2414 auto focusTask = [weak = WeakClaim(this)]() {
2415 auto pattern = weak.Upgrade();
2416 if (pattern) {
2417 pattern->HandleFocusInternal();
2418 }
2419 };
2420 focusHub->SetOnFocusInternal(std::move(focusTask));
2421 }
2422
HandleFocusInternal()2423 void SwiperPattern::HandleFocusInternal()
2424 {
2425 currentFocusIndex_ = currentIndex_;
2426 }
2427
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)2428 void SwiperPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
2429 {
2430 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
2431 auto pattern = wp.Upgrade();
2432 if (pattern) {
2433 return pattern->OnKeyEvent(event);
2434 }
2435 return false;
2436 };
2437 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
2438 }
2439
IsContentFocused()2440 bool SwiperPattern::IsContentFocused()
2441 {
2442 auto swiperHost = GetHost();
2443 CHECK_NULL_RETURN(swiperHost, true);
2444 auto swiperFocusHub = swiperHost->GetFocusHub();
2445 CHECK_NULL_RETURN(swiperFocusHub, true);
2446 bool ret = true;
2447 swiperFocusHub->AnyChildFocusHub([&ret](const RefPtr<FocusHub>& child) {
2448 if (!child || !child->IsCurrentFocus()) {
2449 return false;
2450 }
2451 auto frameName = child->GetFrameName();
2452 if (frameName == V2::SWIPER_INDICATOR_ETS_TAG || frameName == V2::SWIPER_RIGHT_ARROW_ETS_TAG ||
2453 frameName == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
2454 ret = false;
2455 }
2456 return true;
2457 });
2458 return ret;
2459 }
2460
OnKeyEvent(const KeyEvent & event)2461 bool SwiperPattern::OnKeyEvent(const KeyEvent& event)
2462 {
2463 if (event.action != KeyAction::DOWN) {
2464 return false;
2465 }
2466 if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
2467 (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
2468 auto onlyFlushFocus = IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ > currentIndex_;
2469 if (onlyFlushFocus) {
2470 currentFocusIndex_ =
2471 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2472 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2473 } else {
2474 ShowPrevious(true);
2475 currentFocusIndex_ =
2476 IsLoop() ? currentFocusIndex_ - 1 : std::clamp(currentFocusIndex_ - 1, 0, TotalCount() - 1);
2477 }
2478
2479 return true;
2480 }
2481 if ((GetDirection() == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
2482 (GetDirection() == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
2483 auto onlyFlushFocus =
2484 IsContentFocused() && GetDisplayCount() > 1 && currentFocusIndex_ < currentIndex_ + GetDisplayCount() - 1;
2485 if (onlyFlushFocus) {
2486 currentFocusIndex_ =
2487 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2488 FlushFocus(GetCurrentFrameNode(currentFocusIndex_));
2489 } else {
2490 ShowNext(true);
2491 currentFocusIndex_ =
2492 IsLoop() ? currentFocusIndex_ + 1 : std::clamp(currentFocusIndex_ + 1, 0, TotalCount() - 1);
2493 }
2494
2495 return true;
2496 }
2497 return false;
2498 }
2499
StopAutoPlay()2500 void SwiperPattern::StopAutoPlay()
2501 {
2502 if (IsAutoPlay()) {
2503 isInAutoPlay_ = false;
2504 translateTask_.Cancel();
2505 }
2506 }
2507
StartAutoPlay()2508 void SwiperPattern::StartAutoPlay()
2509 {
2510 if (NeedAutoPlay() && !translateAnimationIsRunning_ && !usePropertyAnimation_) {
2511 PostTranslateTask(GetInterval());
2512 }
2513 }
2514
OnVisibleChange(bool isVisible)2515 void SwiperPattern::OnVisibleChange(bool isVisible)
2516 {
2517 isVisible_ = isVisible;
2518 if (isInit_) {
2519 return;
2520 }
2521
2522 if (!isVisible_) {
2523 StopAutoPlay();
2524 return;
2525 }
2526
2527 if (NeedStartAutoPlay()) {
2528 StartAutoPlay();
2529 }
2530 }
2531
UpdateCurrentOffset(float offset)2532 void SwiperPattern::UpdateCurrentOffset(float offset)
2533 {
2534 if (itemPosition_.empty()) {
2535 MarkDirtyNodeSelf();
2536 return;
2537 }
2538 if (!IsLoop() && (isDragging_ || childScrolling_)) {
2539 // handle edge effects
2540 if (CheckOverScroll(offset)) {
2541 return;
2542 }
2543 }
2544 if (!IsLoop() && GetEdgeEffect() != EdgeEffect::SPRING && IsOutOfBoundary(offset)) {
2545 offset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2546 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2547 } else {
2548 offset = IsHorizontalAndRightToLeft() ? -offset : offset;
2549 }
2550 currentDelta_ -= offset;
2551 currentIndexOffset_ += offset;
2552 if (isDragging_ || childScrolling_) {
2553 AnimationCallbackInfo callbackInfo;
2554 callbackInfo.currentOffset =
2555 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2556 if (IsHorizontalAndRightToLeft()) {
2557 callbackInfo.currentOffset =
2558 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2559 }
2560 bool skipGestureSwipe = TotalCount() == 1 && GetEdgeEffect() == EdgeEffect::NONE;
2561 if (!skipGestureSwipe) {
2562 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
2563 }
2564 }
2565 HandleSwiperCustomAnimation(-currentDelta_);
2566 MarkDirtyNodeSelf();
2567 }
2568
CheckOverScroll(float offset)2569 bool SwiperPattern::CheckOverScroll(float offset)
2570 {
2571 switch (GetEdgeEffect()) {
2572 case EdgeEffect::SPRING:
2573 if (SpringOverScroll(offset)) {
2574 return true;
2575 }
2576 break;
2577 case EdgeEffect::FADE:
2578 if (FadeOverScroll(offset)) {
2579 return true;
2580 }
2581 break;
2582 case EdgeEffect::NONE:
2583 if (IsOutOfBoundary(offset)) {
2584 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2585 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2586 currentDelta_ += IsHorizontalAndRightToLeft() ? realOffset : -realOffset;
2587 HandleSwiperCustomAnimation(realOffset);
2588 MarkDirtyNodeSelf();
2589 return true;
2590 }
2591 break;
2592 }
2593 return false;
2594 }
2595
SpringOverScroll(float offset)2596 bool SwiperPattern::SpringOverScroll(float offset)
2597 {
2598 bool outOfBounds = isTouchPad_ ? IsOutOfBoundary(offset) : IsOutOfBoundary();
2599 if (!outOfBounds) {
2600 return false;
2601 }
2602 offset = IsHorizontalAndRightToLeft() ? -offset : offset;
2603 targetIndex_.reset();
2604
2605 auto visibleSize = CalculateVisibleSize();
2606 if (LessOrEqual(visibleSize, 0.0)) {
2607 return true;
2608 }
2609 auto friction = currentIndexOffset_ > 0
2610 ? CalculateFriction(itemPosition_.begin()->second.startPos / visibleSize)
2611 : CalculateFriction((visibleSize - itemPosition_.rbegin()->second.endPos) / visibleSize);
2612
2613 currentDelta_ = currentDelta_ - friction * offset;
2614 currentIndexOffset_ += friction * offset;
2615 AnimationCallbackInfo callbackInfo;
2616 callbackInfo.currentOffset =
2617 GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2618 if (IsHorizontalAndRightToLeft()) {
2619 callbackInfo.currentOffset =
2620 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
2621 }
2622
2623 FireGestureSwipeEvent(GetLoopIndex(gestureSwipeIndex_), callbackInfo);
2624 HandleSwiperCustomAnimation(friction * offset);
2625 MarkDirtyNodeSelf();
2626 return true;
2627 }
2628
FadeOverScroll(float offset)2629 bool SwiperPattern::FadeOverScroll(float offset)
2630 {
2631 if (IsOutOfBoundary(fadeOffset_ + offset)) {
2632 if (!IsVisibleChildrenSizeLessThanSwiper() && NearZero(fadeOffset_)) {
2633 UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart(offset));
2634 auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
2635 : CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
2636 currentDelta_ -= realOffset;
2637 offset -= realOffset;
2638 HandleSwiperCustomAnimation(realOffset);
2639 }
2640 fadeOffset_ += offset;
2641 auto host = GetHost();
2642 CHECK_NULL_RETURN(host, false);
2643 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2644 MarkDirtyNodeSelf();
2645 return true;
2646 }
2647 fadeOffset_ = 0.0f;
2648 return false;
2649 }
2650
IsHorizontalAndRightToLeft() const2651 bool SwiperPattern::IsHorizontalAndRightToLeft() const
2652 {
2653 auto host = GetHost();
2654 CHECK_NULL_RETURN(host, false);
2655 CHECK_NULL_RETURN(host->GetLayoutProperty(), false);
2656 return GetDirection() == Axis::HORIZONTAL &&
2657 host->GetLayoutProperty()->GetNonAutoLayoutDirection() == TextDirection::RTL;
2658 }
2659
GetNonAutoLayoutDirection() const2660 TextDirection SwiperPattern::GetNonAutoLayoutDirection() const
2661 {
2662 auto host = GetHost();
2663 CHECK_NULL_RETURN(host, TextDirection::LTR);
2664 CHECK_NULL_RETURN(host->GetLayoutProperty(), TextDirection::LTR);
2665 return host->GetLayoutProperty()->GetNonAutoLayoutDirection();
2666 }
2667
UpdateNextValidIndex()2668 void SwiperPattern::UpdateNextValidIndex()
2669 {
2670 // item may be invalid in auto linear scene, mark next valid item
2671 if (IsAutoLinear()) {
2672 currentFirstIndex_ = CheckTargetIndex(currentFirstIndex_, true);
2673 nextValidIndex_ = GetLoopIndex(CheckTargetIndex(currentFirstIndex_ + 1, true));
2674 } else {
2675 nextValidIndex_ = -1;
2676 }
2677 }
2678
CheckMarkDirtyNodeForRenderIndicator(float additionalOffset,std::optional<int32_t> nextIndex)2679 void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset, std::optional<int32_t> nextIndex)
2680 {
2681 additionalOffset = IsHorizontalAndRightToLeft() ? -additionalOffset : additionalOffset;
2682 if (!HasIndicatorNode()) {
2683 return;
2684 }
2685 auto child = GetCommonIndicatorNode();
2686 CHECK_NULL_VOID(child);
2687
2688 if (!IsIndicator(child->GetTag())) {
2689 return;
2690 }
2691
2692 int32_t preFirstIndex = currentFirstIndex_;
2693 auto currentPageStatus = (IsHorizontalAndRightToLeft() && GetMaxDisplayCount() > 0)
2694 ? CalcCurrentPageStatusOnRTL(additionalOffset)
2695 : CalcCurrentPageStatus(additionalOffset);
2696 float currentTurnPageRate = currentPageStatus.first;
2697 currentFirstIndex_ = currentPageStatus.second;
2698
2699 currentFirstIndex_ = nextIndex.value_or(currentFirstIndex_);
2700 UpdateNextValidIndex();
2701 currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
2702 auto isRtl = IsHorizontalAndRightToLeft() && GetMaxDisplayCount() <= 0;
2703 isRtl ? CalculateGestureStateOnRTL(additionalOffset, currentTurnPageRate, preFirstIndex)
2704 : CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
2705 turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
2706 turnPageRate_ = isRtl ? std::abs(turnPageRate_) - 1.0f : turnPageRate_;
2707 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
2708 CheckMarkForIndicatorBoundary();
2709 isRtl ? HandleTouchBottomLoopOnRTL() : HandleTouchBottomLoop();
2710
2711 if (IsVisibleChildrenSizeLessThanSwiper()) {
2712 turnPageRate_ = 0.0f;
2713 gestureState_ = GestureState::GESTURE_STATE_NONE;
2714 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
2715 }
2716
2717 if (!indicatorDoingAnimation_) {
2718 child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2719 }
2720 if (GetLoopIndex(currentIndex_) != currentFirstIndex_) {
2721 auto swiperEventHub = GetEventHub<SwiperEventHub>();
2722 CHECK_NULL_VOID(swiperEventHub);
2723 swiperEventHub->FireIndicatorChangeEvent(currentFirstIndex_);
2724 }
2725 }
2726
CheckMarkForIndicatorBoundary()2727 void SwiperPattern::CheckMarkForIndicatorBoundary()
2728 {
2729 bool isRtl = IsHorizontalAndRightToLeft();
2730
2731 auto startIndex = isRtl ? TotalCount() - 1 : 0;
2732 auto endIndex = isRtl ? 0 : TotalCount() - 1;
2733 if (!IsLoop() && ((currentFirstIndex_ == startIndex && GreatNotEqualCustomPrecision(turnPageRate_, 0.0f)) ||
2734 (currentFirstIndex_ == endIndex && LessNotEqualCustomPrecision(turnPageRate_, 0.0f)))) {
2735 return;
2736 }
2737 }
2738
UpdateAnimationProperty(float velocity)2739 void SwiperPattern::UpdateAnimationProperty(float velocity)
2740 {
2741 if (isDragging_ || childScrolling_) {
2742 targetIndex_ = CheckTargetIndex(ComputeNextIndexByVelocity(velocity));
2743 velocity_ = velocity;
2744 } else {
2745 targetIndex_ = pauseTargetIndex_;
2746 velocity_ = velocity;
2747 }
2748
2749 MarkDirtyNodeSelf();
2750 moveDirection_ = velocity <= 0;
2751 }
2752
HandleTouchEvent(const TouchEventInfo & info)2753 void SwiperPattern::HandleTouchEvent(const TouchEventInfo& info)
2754 {
2755 if (info.GetTouches().empty()) {
2756 return;
2757 }
2758 auto locationInfo = info.GetTouches().front();
2759 auto touchType = locationInfo.GetTouchType();
2760 if (touchType == TouchType::DOWN) {
2761 HandleTouchDown(locationInfo);
2762 } else if (touchType == TouchType::UP) {
2763 HandleTouchUp();
2764 } else if (touchType == TouchType::CANCEL) {
2765 HandleTouchUp();
2766 }
2767 }
2768
InsideIndicatorRegion(const TouchLocationInfo & locationInfo)2769 bool SwiperPattern::InsideIndicatorRegion(const TouchLocationInfo& locationInfo)
2770 {
2771 if (!HasIndicatorNode()) {
2772 return false;
2773 }
2774
2775 auto host = GetHost();
2776 CHECK_NULL_RETURN(host, false);
2777 auto indicatorNode = DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
2778 CHECK_NULL_RETURN(indicatorNode, false);
2779 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
2780 return false;
2781 }
2782
2783 auto geometryNode = indicatorNode->GetGeometryNode();
2784 CHECK_NULL_RETURN(geometryNode, false);
2785 auto hotRegion = geometryNode->GetFrameRect();
2786 auto touchPoint = PointF(static_cast<float>(locationInfo.GetLocalLocation().GetX()),
2787 static_cast<float>(locationInfo.GetLocalLocation().GetY()));
2788
2789 return hotRegion.IsInRegion(touchPoint);
2790 }
2791
HandleTouchDown(const TouchLocationInfo & locationInfo)2792 void SwiperPattern::HandleTouchDown(const TouchLocationInfo& locationInfo)
2793 {
2794 ACE_SCOPED_TRACE("Swiper HandleTouchDown");
2795 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchDown");
2796 isTouchDown_ = true;
2797 isTouchDownOnOverlong_ = true;
2798 if (InsideIndicatorRegion(locationInfo)) {
2799 return;
2800 }
2801
2802 if (childScrolling_) {
2803 // Even if the child fails to notify scrollEnd, we reset childScrolling_ flag on TouchDown to ensure its
2804 // value is correct.
2805 childScrolling_ = false;
2806 }
2807
2808 StopIndicatorAnimation(true);
2809 if (usePropertyAnimation_) {
2810 StopPropertyTranslateAnimation(isFinishAnimation_);
2811 }
2812
2813 indicatorDoingAnimation_ = false;
2814 // Stop translate animation when touch down.
2815 if (translateAnimationIsRunning_) {
2816 StopTranslateAnimation();
2817 }
2818
2819 if (springAnimationIsRunning_) {
2820 AnimationUtils::PauseAnimation(springAnimation_);
2821 isTouchDownSpringAnimation_ = true;
2822 }
2823
2824 AnimationUtils::PauseAnimation(fadeAnimation_);
2825 if (fadeAnimationIsRunning_) {
2826 isTouchDownFadeAnimation_ = true;
2827 }
2828
2829 // Stop auto play when touch down.
2830 StopAutoPlay();
2831 }
2832
HandleTouchUp()2833 void SwiperPattern::HandleTouchUp()
2834 {
2835 ACE_SCOPED_TRACE("Swiper HandleTouchUp");
2836 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper HandleTouchUp");
2837 isTouchDown_ = false;
2838 isTouchDownOnOverlong_ = false;
2839 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
2840 if (!isDragging_ && !childScrolling_ && !NearZero(firstItemInfoInVisibleArea.second.startPos) &&
2841 !isTouchDownSpringAnimation_) {
2842 UpdateAnimationProperty(0.0);
2843 }
2844
2845 if (springAnimationIsRunning_ && isTouchDownSpringAnimation_) {
2846 isTouchDownSpringAnimation_ = false;
2847 AnimationUtils::ResumeAnimation(springAnimation_);
2848 }
2849
2850 if (fadeAnimationIsRunning_ && isTouchDownFadeAnimation_) {
2851 isTouchDownFadeAnimation_ = false;
2852 AnimationUtils::ResumeAnimation(fadeAnimation_);
2853 }
2854
2855 if (!isDragging_) {
2856 StartAutoPlay();
2857 }
2858 }
2859
HandleDragStart(const GestureEvent & info)2860 void SwiperPattern::HandleDragStart(const GestureEvent& info)
2861 {
2862 if (!hasTabsAncestor_) {
2863 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_SCROLL, PerfActionType::FIRST_MOVE, "");
2864 } else {
2865 AceAsyncTraceBeginCommercial(0, APP_TABS_SCROLL);
2866 }
2867 UpdateDragFRCSceneInfo(info.GetMainVelocity(), SceneStatus::START);
2868 StopAnimationOnScrollStart(
2869 info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD);
2870 StopAutoPlay();
2871
2872 const auto& tabBarFinishCallback = swiperController_->GetTabBarFinishCallback();
2873 if (tabBarFinishCallback) {
2874 tabBarFinishCallback();
2875 }
2876
2877 const auto& removeEventCallback = swiperController_->GetRemoveTabBarEventCallback();
2878 if (removeEventCallback) {
2879 removeEventCallback();
2880 }
2881
2882 gestureSwipeIndex_ = currentIndex_;
2883 isDragging_ = true;
2884 isTouchDown_ = true;
2885 isTouchDownOnOverlong_ = true;
2886 mainDeltaSum_ = 0.0f;
2887 // in drag process, close lazy feature.
2888 SetLazyLoadFeature(false);
2889 }
2890
StopAnimationOnScrollStart(bool flushImmediately)2891 void SwiperPattern::StopAnimationOnScrollStart(bool flushImmediately)
2892 {
2893 if (usePropertyAnimation_) {
2894 StopPropertyTranslateAnimation(isFinishAnimation_);
2895 }
2896 StopIndicatorAnimation();
2897 StopTranslateAnimation();
2898 StopFadeAnimation();
2899 if (flushImmediately) {
2900 StopSpringAnimationAndFlushImmediately();
2901 } else {
2902 StopSpringAnimationImmediately();
2903 }
2904 }
2905
HandleDragUpdate(const GestureEvent & info)2906 void SwiperPattern::HandleDragUpdate(const GestureEvent& info)
2907 {
2908 auto velocity = info.GetMainVelocity();
2909 UpdateDragFRCSceneInfo(velocity, SceneStatus::RUNNING);
2910 UpdateNodeRate();
2911 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::TOUCHPAD) {
2912 isTouchPad_ = true;
2913 }
2914
2915 PointF dragPoint(
2916 static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
2917 NGGestureRecognizer::Transform(dragPoint, GetHost(), true, info.GetIsPostEventResult(), info.GetPostEventNodeId());
2918 if (IsOutOfHotRegion(dragPoint)) {
2919 isTouchPad_ = false;
2920 return;
2921 }
2922
2923 auto mainDelta = static_cast<float>(info.GetMainDelta());
2924 ProcessDelta(mainDelta, contentMainSize_, mainDeltaSum_);
2925 mainDeltaSum_ += mainDelta;
2926
2927 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(static_cast<float>(mainDelta))) {
2928 return;
2929 }
2930
2931 HandleScroll(static_cast<float>(mainDelta), SCROLL_FROM_UPDATE, NestedState::GESTURE, velocity);
2932 UpdateItemRenderGroup(true);
2933 isTouchPad_ = false;
2934 }
2935
TriggerAddTabBarEvent() const2936 void SwiperPattern::TriggerAddTabBarEvent() const
2937 {
2938 const auto& addEventCallback = swiperController_->GetAddTabBarEventCallback();
2939 if (addEventCallback) {
2940 addEventCallback();
2941 }
2942 }
2943
HandleDragEnd(double dragVelocity,float mainDelta)2944 void SwiperPattern::HandleDragEnd(double dragVelocity, float mainDelta)
2945 {
2946 if (!hasTabsAncestor_) {
2947 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_SCROLL, false);
2948 } else {
2949 AceAsyncTraceEndCommercial(0, APP_TABS_SCROLL);
2950 }
2951 isTouchDown_ = false;
2952 isTouchDownOnOverlong_ = false;
2953 if (!CheckSwiperPanEvent(dragVelocity) || !CheckContentWillScroll(dragVelocity, mainDelta)) {
2954 dragVelocity = 0.0;
2955 }
2956 if (!childScrolling_) {
2957 UpdateDragFRCSceneInfo(dragVelocity, SceneStatus::END);
2958 }
2959
2960 TriggerAddTabBarEvent();
2961
2962 auto pipeline = PipelineContext::GetCurrentContext();
2963 if (pipeline) {
2964 pipeline->FlushUITasks();
2965 }
2966 if (itemPosition_.empty()) {
2967 return;
2968 }
2969
2970 if (IsAutoLinear() && AutoLinearIsOutOfBoundary(0.0f)) {
2971 return;
2972 }
2973
2974 if (CheckDragOutOfBoundary(dragVelocity)) {
2975 return;
2976 }
2977
2978 UpdateAnimationProperty(static_cast<float>(dragVelocity));
2979 // nested and reached end (but not out of bounds), need to pass velocity to parent scrollable
2980 auto parent = GetNestedScrollParent();
2981 if (!IsLoop() && parent && NearZero(GetDistanceToEdge())) {
2982 parent->HandleScrollVelocity(dragVelocity);
2983 StartAutoPlay();
2984 } else {
2985 NotifyParentScrollEnd();
2986 }
2987 if (pipeline) {
2988 pipeline->FlushUITasks();
2989 pipeline->FlushMessages();
2990 }
2991
2992 isDragging_ = false;
2993
2994 if (currentIndex_ != pauseTargetIndex_.value_or(0)) {
2995 FireWillShowEvent(pauseTargetIndex_.value_or(0));
2996 FireWillHideEvent(currentIndex_);
2997 }
2998 }
2999
UpdateCurrentIndex(int32_t index)3000 void SwiperPattern::UpdateCurrentIndex(int32_t index)
3001 {
3002 currentIndex_ = index;
3003 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
3004 CHECK_NULL_VOID(props);
3005 props->UpdateIndexWithoutMeasure(GetLoopIndex(currentIndex_));
3006 }
3007
ComputeSwipePageNextIndex(float velocity,bool onlyDistance) const3008 int32_t SwiperPattern::ComputeSwipePageNextIndex(float velocity, bool onlyDistance) const
3009 {
3010 auto swiperWidth = CalculateVisibleSize();
3011 if (LessOrEqual(swiperWidth, 0)) {
3012 return currentIndex_;
3013 }
3014
3015 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3016 auto firstIndex = firstItemInfoInVisibleArea.first;
3017 auto displayCount = GetDisplayCount();
3018 auto endIndex = SwiperUtils::ComputePageEndIndex(firstIndex, displayCount);
3019 auto iter = itemPosition_.find(endIndex);
3020 if (iter == itemPosition_.end()) {
3021 return currentIndex_;
3022 }
3023
3024 auto dragDistance = iter->second.endPos;
3025 auto dragForward = currentIndex_ > firstIndex;
3026 auto dragThresholdFlag = dragForward ? dragDistance > swiperWidth / 2 : dragDistance < swiperWidth / 2;
3027 auto nextIndex = currentIndex_;
3028 if (dragThresholdFlag) {
3029 nextIndex = dragForward ? currentIndex_ - displayCount : currentIndex_ + displayCount;
3030 }
3031
3032 if (!onlyDistance && std::abs(velocity) > NEW_MIN_TURN_PAGE_VELOCITY && velocity != 0.0f) {
3033 auto direction = GreatNotEqual(velocity, 0.0f);
3034 if (dragForward != direction || !dragThresholdFlag) {
3035 nextIndex = velocity > 0.0f ? nextIndex - displayCount : nextIndex + displayCount;
3036 }
3037 }
3038
3039 if (!IsAutoLinear() && nextIndex > currentIndex_ + displayCount) {
3040 nextIndex = currentIndex_ + displayCount;
3041 }
3042
3043 if (!IsLoop()) {
3044 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - displayCount));
3045 }
3046
3047 return nextIndex;
3048 }
3049
ComputeNextIndexInSinglePage(float velocity,bool onlyDistance) const3050 int32_t SwiperPattern::ComputeNextIndexInSinglePage(float velocity, bool onlyDistance) const
3051 {
3052 auto firstItemInfo = GetFirstItemInfoInVisibleArea();
3053 auto swiperWidthHalf = (firstItemInfo.second.endPos - firstItemInfo.second.startPos) / SWIPER_HALF;
3054 if (LessOrEqual(swiperWidthHalf, 0)) {
3055 return currentIndex_;
3056 }
3057 // if direction is true, expected index to decrease by 1
3058 bool direction = Positive(velocity);
3059 bool overTurnPageVelocity =
3060 !onlyDistance && (std::abs(velocity) > (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)
3061 ? NEW_MIN_TURN_PAGE_VELOCITY
3062 : MIN_TURN_PAGE_VELOCITY));
3063
3064 auto firstIndex = firstItemInfo.first;
3065 auto baseIndex = -firstItemInfo.second.startPos < swiperWidthHalf ? firstIndex : firstIndex + 1;
3066 if (overTurnPageVelocity) {
3067 return direction ? baseIndex - 1 : baseIndex + 1;
3068 }
3069 return baseIndex;
3070 }
3071
ComputeNextIndexByVelocity(float velocity,bool onlyDistance) const3072 int32_t SwiperPattern::ComputeNextIndexByVelocity(float velocity, bool onlyDistance) const
3073 {
3074 velocity = IsHorizontalAndRightToLeft() ? -velocity : velocity;
3075 if (IsSwipeByGroup()) {
3076 return ComputeSwipePageNextIndex(velocity, onlyDistance);
3077 }
3078
3079 auto nextIndex = currentIndex_;
3080 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
3081 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
3082 if (LessOrEqual(firstItemLength, 0)) {
3083 return nextIndex;
3084 }
3085
3086 auto firstIndex = firstItemInfoInVisibleArea.first;
3087 auto dragDistance = firstItemInfoInVisibleArea.second.endPos;
3088 if (firstIndex == currentIndex_ && firstItemInfoInVisibleArea.second.startPos > 0) {
3089 firstIndex--;
3090 dragDistance = firstItemInfoInVisibleArea.second.startPos;
3091 }
3092 auto direction = GreatNotEqual(velocity, 0.0);
3093 auto dragThresholdFlag =
3094 direction ? dragDistance > firstItemLength / 2 : firstItemInfoInVisibleArea.second.endPos < firstItemLength / 2;
3095 auto turnVelocity = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? NEW_MIN_TURN_PAGE_VELOCITY
3096 : MIN_TURN_PAGE_VELOCITY;
3097 if ((!onlyDistance && std::abs(velocity) > turnVelocity) || dragThresholdFlag) {
3098 nextIndex = direction ? firstIndex : firstItemInfoInVisibleArea.first + 1;
3099 } else {
3100 nextIndex = direction ? firstIndex + 1 : firstItemInfoInVisibleArea.first;
3101 }
3102
3103 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3104 // don't run this in nested scroll. Parallel nested scroll can deviate > 1 page from currentIndex_
3105 if (!childScrolling_ && SwiperUtils::IsStretch(props) && GetDisplayCount() == 1) {
3106 nextIndex =
3107 std::clamp(ComputeNextIndexInSinglePage(velocity, onlyDistance), currentIndex_ - 1, currentIndex_ + 1);
3108 }
3109
3110 if (!IsAutoLinear() && nextIndex > currentIndex_ + GetDisplayCount()) {
3111 nextIndex = currentIndex_ + GetDisplayCount();
3112 }
3113
3114 if (!IsLoop()) {
3115 nextIndex = std::clamp(nextIndex, 0, std::max(0, TotalCount() - GetDisplayCount()));
3116 }
3117 return nextIndex;
3118 }
3119
NeedStartNewAnimation(const OffsetF & offset) const3120 bool SwiperPattern::NeedStartNewAnimation(const OffsetF& offset) const
3121 {
3122 if (itemPositionInAnimation_.empty()) {
3123 return true;
3124 }
3125
3126 for (const auto& animationItem : itemPositionInAnimation_) {
3127 auto iter = itemPosition_.find(animationItem.first);
3128 if (iter == itemPosition_.end()) {
3129 return true;
3130 }
3131 if ((animationItem.second.node && animationItem.second.finalOffset != offset) ||
3132 !NearEqual(animationItem.second.startPos, iter->second.startPos) ||
3133 !NearEqual(animationItem.second.endPos, iter->second.endPos)) {
3134 return true;
3135 }
3136 }
3137
3138 return false;
3139 }
3140
UpdateCurrentFocus()3141 void SwiperPattern::UpdateCurrentFocus()
3142 {
3143 do {
3144 auto curChildFrame = GetCurrentFrameNode(currentIndex_);
3145 if (!curChildFrame) {
3146 break;
3147 }
3148 FlushFocus(curChildFrame);
3149 currentFocusIndex_ = currentIndex_;
3150 } while (0);
3151 }
3152
CheckDragOutOfBoundary(double dragVelocity)3153 bool SwiperPattern::CheckDragOutOfBoundary(double dragVelocity)
3154 {
3155 if (IsLoop()) {
3156 return false;
3157 }
3158
3159 auto edgeEffect = GetEdgeEffect();
3160 // edge effect is NONE and reached boundary
3161 const bool noneOutOfBoundary =
3162 (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) &&
3163 NearZero(GetDistanceToEdge()) && edgeEffect == EdgeEffect::NONE;
3164 if (IsOutOfBoundary() || !NearZero(fadeOffset_) || noneOutOfBoundary) {
3165 isDragging_ = false;
3166
3167 if (edgeEffect == EdgeEffect::SPRING) {
3168 PlaySpringAnimation(dragVelocity);
3169 return true;
3170 }
3171
3172 if (edgeEffect == EdgeEffect::FADE) {
3173 PlayFadeAnimation();
3174 return true;
3175 }
3176
3177 auto nextIndex = ComputeNextIndexByVelocity(static_cast<float>(dragVelocity), true);
3178 if (currentIndex_ != nextIndex) {
3179 FireWillShowEvent(nextIndex_);
3180 FireWillHideEvent(currentIndex_);
3181
3182 UpdateCurrentIndex(nextIndex);
3183 UpdateCurrentFocus();
3184 OnIndexChange();
3185 oldIndex_ = currentIndex_;
3186 }
3187
3188 if (edgeEffect == EdgeEffect::NONE) {
3189 auto parent = GetNestedScrollParent();
3190 const bool isForward = NonPositive(dragVelocity);
3191 if (parent && GetNestedScroll().NeedParent(isForward)) {
3192 parent->HandleScrollVelocity(dragVelocity);
3193 }
3194 StartAutoPlay();
3195 UpdateItemRenderGroup(false);
3196 return true;
3197 }
3198 }
3199
3200 return false;
3201 }
3202
PlayPropertyTranslateAnimation(float translate,int32_t nextIndex,float velocity,bool stopAutoPlay)3203 void SwiperPattern::PlayPropertyTranslateAnimation(
3204 float translate, int32_t nextIndex, float velocity, bool stopAutoPlay)
3205 {
3206 if (IsHorizontalAndRightToLeft()) {
3207 translate = -translate;
3208 }
3209 if (NearZero(translate)) {
3210 SetIndicatorChangeIndexStatus(false, GetLoopIndex(currentIndex_));
3211 OnAnimationTranslateZero(nextIndex, stopAutoPlay);
3212 return;
3213 }
3214
3215 AnimationOption option;
3216 option.SetDuration(GetDuration());
3217 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
3218 if (iter != frameRateRange_.end()) {
3219 TAG_LOGI(AceLogTag::ACE_SWIPER,
3220 "Property translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}",
3221 iter->second->min_, iter->second->max_, iter->second->preferred_);
3222 iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
3223 option.SetFrameRateRange(iter->second);
3224 } else {
3225 option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
3226 }
3227 motionVelocity_ = velocity / translate;
3228 auto curve = GetCurveIncludeMotion();
3229 auto minimumAmplitudeRatio = DEFAULT_MINIMUM_AMPLITUDE_PX / translate;
3230 if (InstanceOf<InterpolatingSpring>(curve) &&
3231 LessNotEqualCustomPrecision(
3232 minimumAmplitudeRatio, InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO)) {
3233 auto interpolatingSpring = AceType::DynamicCast<InterpolatingSpring>(curve);
3234 interpolatingSpring->UpdateMinimumAmplitudeRatio(minimumAmplitudeRatio);
3235 }
3236 option.SetCurve(curve);
3237 option.SetFinishCallbackType(GetFinishCallbackType());
3238 OffsetF offset;
3239 if (GetDirection() == Axis::HORIZONTAL) {
3240 offset.AddX(translate);
3241 } else {
3242 offset.AddY(translate);
3243 }
3244 if (usePropertyAnimation_) {
3245 if (!NeedStartNewAnimation(offset)) {
3246 stopIndicatorAnimation_ = false;
3247 return;
3248 }
3249 std::optional<int32_t> targetIndex;
3250 if (targetIndex_) {
3251 targetIndex = targetIndex_;
3252 }
3253 StopPropertyTranslateAnimation(isFinishAnimation_);
3254 StopIndicatorAnimation();
3255
3256 if (targetIndex) {
3257 targetIndex_ = targetIndex;
3258 MarkDirtyNodeSelf();
3259 return;
3260 }
3261 }
3262 auto finishCallback = [weak = WeakClaim(this), offset]() {
3263 auto swiper = weak.Upgrade();
3264 CHECK_NULL_VOID(swiper);
3265 #ifdef OHOS_PLATFORM
3266 if (swiper->isInAutoPlay_) {
3267 ResSchedReport::GetInstance().ResSchedDataReport("auto_play_off");
3268 }
3269 #endif
3270 if (!swiper->hasTabsAncestor_) {
3271 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_SWIPER_FLING, true);
3272 } else {
3273 AceAsyncTraceEndCommercial(0, APP_TABS_FLING);
3274 }
3275 OffsetF finalOffset =
3276 swiper->itemPosition_.empty() ? OffsetF()
3277 : swiper->itemPosition_.begin()->second.node
3278 ? swiper->itemPosition_.begin()->second.node->GetRenderContext()->GetTranslateXYProperty()
3279 : OffsetF();
3280 TAG_LOGI(AceLogTag::ACE_SWIPER,
3281 "Swiper finish property animation with offsetX: %{public}f, offsetY: %{public}f isVerifiedSuc %{public}d",
3282 finalOffset.GetX(), finalOffset.GetY(), !swiper->IsItemOverlay());
3283 ACE_SCOPED_TRACE_COMMERCIAL("%s finish property animation, X: %f, Y: %f isVerifiedSuc %d",
3284 swiper->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, finalOffset.GetX(), finalOffset.GetY(),
3285 !swiper->IsItemOverlay());
3286 swiper->OnPropertyTranslateAnimationFinish(offset);
3287 };
3288 // initial translate info.
3289 for (auto& item : itemPosition_) {
3290 auto frameNode = item.second.node;
3291 if (frameNode) {
3292 frameNode->GetRenderContext()->UpdateTranslateInXY(item.second.finalOffset);
3293 }
3294 }
3295 if (IsCaptureNodeValid()) {
3296 GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(captureFinalOffset_);
3297 GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(captureFinalOffset_);
3298 }
3299 // property callback will call immediately.
3300 auto propertyUpdateCallback = [swiper = WeakClaim(this), offset]() {
3301 auto swiperPattern = swiper.Upgrade();
3302 CHECK_NULL_VOID(swiperPattern);
3303 #ifdef OHOS_PLATFORM
3304 if (swiperPattern->isInAutoPlay_) {
3305 ResSchedReport::GetInstance().ResSchedDataReport("auto_play_on");
3306 }
3307 #endif
3308 if (!swiperPattern->hasTabsAncestor_) {
3309 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_SWIPER_FLING, PerfActionType::LAST_UP, "");
3310 } else {
3311 AceAsyncTraceBeginCommercial(0, APP_TABS_FLING);
3312 }
3313 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper start property animation with offsetX: %{public}f, offsetY: %{public}f",
3314 offset.GetX(), offset.GetY());
3315 ACE_SCOPED_TRACE_COMMERCIAL("%s start property animation, X: %f, Y: %f",
3316 swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, offset.GetX(), offset.GetY());
3317 for (auto& item : swiperPattern->itemPosition_) {
3318 auto frameNode = item.second.node;
3319 if (frameNode) {
3320 frameNode->GetRenderContext()->UpdateTranslateInXY(offset);
3321 item.second.finalOffset = offset;
3322 }
3323 }
3324 swiperPattern->itemPositionInAnimation_ = swiperPattern->itemPosition_;
3325 if (swiperPattern->IsCaptureNodeValid()) {
3326 swiperPattern->GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(offset);
3327 swiperPattern->GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(offset);
3328 swiperPattern->captureFinalOffset_ = offset;
3329 }
3330 };
3331 usePropertyAnimation_ = true;
3332 propertyAnimationIndex_ = nextIndex;
3333 ElementRegister::GetInstance()->ReSyncGeometryTransition(GetHost(), option);
3334 AnimationUtils::Animate(option, propertyUpdateCallback, finishCallback);
3335 AnimationCallbackInfo info;
3336 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3337 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3338 info.targetOffset = GetCustomPropertyTargetOffset() - Dimension(translate, DimensionUnit::PX).ConvertToVp();
3339 if (IsHorizontalAndRightToLeft()) {
3340 info.currentOffset =
3341 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3342 }
3343
3344 auto pipeline = PipelineContext::GetCurrentContext();
3345 CHECK_NULL_VOID(pipeline);
3346 if (GetDuration() == 0) {
3347 // if the duration is 0, the animation will be end immediately, so the start event should be triggered
3348 // after Layout Task to ensure the timing of events.
3349 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3350 auto swiper = weak.Upgrade();
3351 CHECK_NULL_VOID(swiper);
3352 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
3353 swiper->FireAndCleanScrollingListener();
3354 });
3355 } else {
3356 pipeline->AddAfterRenderTask([weak = WeakClaim(this), info, nextIndex = GetLoopIndex(nextIndex)]() {
3357 auto swiper = weak.Upgrade();
3358 CHECK_NULL_VOID(swiper);
3359 swiper->FireAnimationStartEvent(swiper->GetLoopIndex(swiper->currentIndex_), nextIndex, info);
3360 swiper->FireAndCleanScrollingListener();
3361 });
3362 }
3363
3364 // enable lazy load feature.
3365 SetLazyLoadFeature(true);
3366 UpdateItemRenderGroup(true);
3367 }
3368
UpdateOffsetAfterPropertyAnimation(float offset)3369 void SwiperPattern::UpdateOffsetAfterPropertyAnimation(float offset)
3370 {
3371 UpdateCurrentOffset(offset);
3372 auto host = GetHost();
3373 CHECK_NULL_VOID(host);
3374 host->SetLayoutDirtyMarked(true);
3375 auto context = host->GetContext();
3376 if (context) {
3377 context->FlushUITaskWithSingleDirtyNode(host);
3378 context->FlushSyncGeometryNodeTasks();
3379 }
3380 }
3381
OnPropertyTranslateAnimationFinish(const OffsetF & offset)3382 void SwiperPattern::OnPropertyTranslateAnimationFinish(const OffsetF& offset)
3383 {
3384 if (!usePropertyAnimation_) {
3385 // force stop.
3386 return;
3387 }
3388
3389 usePropertyAnimation_ = false;
3390 targetIndex_.reset();
3391 // reset translate.
3392 for (auto& item : itemPositionInAnimation_) {
3393 auto frameNode = item.second.node;
3394 if (frameNode) {
3395 frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3396 }
3397 item.second.finalOffset = OffsetF();
3398 }
3399 itemPositionInAnimation_.clear();
3400 if (IsCaptureNodeValid()) {
3401 GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3402 GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3403 captureFinalOffset_ = OffsetF();
3404 }
3405 // update postion info.
3406 UpdateOffsetAfterPropertyAnimation(offset.GetMainOffset(GetDirection()));
3407 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation_);
3408 }
3409
StopPropertyTranslateAnimation(bool isFinishAnimation,bool isBeforeCreateLayoutWrapper,bool isInterrupt)3410 void SwiperPattern::StopPropertyTranslateAnimation(
3411 bool isFinishAnimation, bool isBeforeCreateLayoutWrapper, bool isInterrupt)
3412 {
3413 if (!usePropertyAnimation_) {
3414 return;
3415 }
3416 usePropertyAnimation_ = false;
3417 ACE_SCOPED_TRACE("Swiper stop property animation");
3418 // Stop CurrentAnimationProperty.
3419 AnimationOption option;
3420 option.SetDuration(0);
3421 option.SetCurve(Curves::LINEAR);
3422 auto propertyUpdateCallback = [weak = WeakClaim(this)]() {
3423 auto swiper = weak.Upgrade();
3424 CHECK_NULL_VOID(swiper);
3425 for (auto& item : swiper->itemPositionInAnimation_) {
3426 auto frameNode = item.second.node;
3427 if (!frameNode) {
3428 continue;
3429 }
3430 frameNode->GetRenderContext()->CancelTranslateXYAnimation();
3431 }
3432 if (swiper->IsCaptureNodeValid()) {
3433 swiper->GetLeftCaptureNode()->GetRenderContext()->CancelTranslateXYAnimation();
3434 swiper->GetRightCaptureNode()->GetRenderContext()->CancelTranslateXYAnimation();
3435 }
3436 };
3437 AnimationUtils::Animate(option, propertyUpdateCallback);
3438 targetIndex_.reset();
3439 OffsetF currentOffset;
3440 for (auto& item : itemPositionInAnimation_) {
3441 auto frameNode = item.second.node;
3442 if (!frameNode) {
3443 continue;
3444 }
3445 currentOffset = frameNode->GetRenderContext()->GetTranslateXYProperty();
3446 frameNode->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3447 item.second.finalOffset = OffsetF();
3448 }
3449 itemPositionInAnimation_.clear();
3450 if (IsCaptureNodeValid()) {
3451 GetLeftCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3452 GetRightCaptureNode()->GetRenderContext()->UpdateTranslateInXY(OffsetF());
3453 captureFinalOffset_ = OffsetF();
3454 }
3455 if (!isBeforeCreateLayoutWrapper) {
3456 UpdateOffsetAfterPropertyAnimation(currentOffset.GetMainOffset(GetDirection()));
3457 }
3458 OnTranslateFinish(propertyAnimationIndex_, false, isFinishAnimation, true, isInterrupt);
3459 }
3460
GetCurveIncludeMotion()3461 RefPtr<Curve> SwiperPattern::GetCurveIncludeMotion()
3462 {
3463 auto curve = GetCurve();
3464 auto container = Container::Current();
3465 bool isLauncherFeature = container ? container->IsLauncherContainer() : false;
3466 if (isLauncherFeature) {
3467 finishCallbackType_ = FinishCallbackType::LOGICALLY;
3468 }
3469
3470 if (curve) {
3471 if (InstanceOf<SpringCurve>(curve)) {
3472 auto springCurve = DynamicCast<SpringCurve>(curve);
3473 // check velocity to judge if this current velocity.
3474 if (springCurve->GetCurrentVelocity() < 0) {
3475 return AceType::MakeRefPtr<SpringCurve>(
3476 motionVelocity_, springCurve->GetMass(), springCurve->GetStiffness(), springCurve->GetDamping());
3477 }
3478 }
3479 if (InstanceOf<InterpolatingSpring>(curve)) {
3480 auto interpolatingSpring = DynamicCast<InterpolatingSpring>(curve);
3481 // check velocity to judge if this current velocity.
3482 if (interpolatingSpring->GetVelocity() < 0) {
3483 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, interpolatingSpring->GetMass(),
3484 interpolatingSpring->GetStiffness(), interpolatingSpring->GetDamping());
3485 }
3486 }
3487 return curve;
3488 }
3489 // use spring motion feature.
3490 // interpolatingSpring: (mass: 1, stiffness:328, damping: 34)
3491 return AceType::MakeRefPtr<InterpolatingSpring>(motionVelocity_, MASS, STIFFNESS, DAMPING);
3492 }
3493
PlayIndicatorTranslateAnimation(float translate,std::optional<int32_t> nextIndex)3494 void SwiperPattern::PlayIndicatorTranslateAnimation(float translate, std::optional<int32_t> nextIndex)
3495 {
3496 if (!stopIndicatorAnimation_) {
3497 stopIndicatorAnimation_ = true;
3498 return;
3499 }
3500 const auto& turnPageRateCallback = swiperController_->GetTurnPageRateCallback();
3501 if (!HasIndicatorNode() && !turnPageRateCallback) {
3502 return;
3503 }
3504 CheckMarkDirtyNodeForRenderIndicator(translate, nextIndex);
3505 AnimationUtils::StopAnimation(indicatorAnimation_);
3506 indicatorAnimationIsRunning_ = false;
3507 if (itemPosition_.empty()) {
3508 return;
3509 }
3510
3511 auto host = GetHost();
3512 CHECK_NULL_VOID(host);
3513 auto weak = AceType::WeakClaim(this);
3514 host->CreateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0, [weak](float value) {
3515 auto swiper = weak.Upgrade();
3516 CHECK_NULL_VOID(swiper);
3517 const auto& turnPageRateCallback = swiper->swiperController_->GetTurnPageRateCallback();
3518 auto firstItem = swiper->GetFirstItemInfoInVisibleArea();
3519 auto translateLength = firstItem.second.endPos - firstItem.second.startPos;
3520 if (turnPageRateCallback && !NearZero(translateLength)) {
3521 turnPageRateCallback(firstItem.first, (-firstItem.second.startPos - value) / translateLength);
3522 }
3523 });
3524
3525 AnimationOption option;
3526 option.SetDuration(GetDuration());
3527 option.SetCurve(Curves::LINEAR);
3528
3529 host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, 0);
3530 indicatorAnimationIsRunning_ = true;
3531 indicatorAnimation_ = AnimationUtils::StartAnimation(
3532 option, [host, translate]() { host->UpdateAnimatablePropertyFloat(INDICATOR_PROPERTY_NAME, translate); },
3533 [weak]() {
3534 auto swiperPattern = weak.Upgrade();
3535 CHECK_NULL_VOID(swiperPattern);
3536 swiperPattern->indicatorAnimationIsRunning_ = false;
3537 });
3538 }
3539
PlayTranslateAnimation(float startPos,float endPos,int32_t nextIndex,bool restartAutoPlay,float velocity)3540 void SwiperPattern::PlayTranslateAnimation(
3541 float startPos, float endPos, int32_t nextIndex, bool restartAutoPlay, float velocity)
3542 {
3543 if (translateAnimationIsRunning_) {
3544 return;
3545 }
3546 if (NearZero(endPos - startPos)) {
3547 OnAnimationTranslateZero(nextIndex, restartAutoPlay);
3548 return;
3549 }
3550
3551 if (HasIndicatorNode()) {
3552 CheckMarkDirtyNodeForRenderIndicator(endPos - startPos, nextIndex);
3553 }
3554
3555 auto host = GetHost();
3556 CHECK_NULL_VOID(host);
3557 auto weak = AceType::WeakClaim(this);
3558 host->CreateAnimatablePropertyFloat(
3559 TRANSLATE_PROPERTY_NAME, 0,
3560 [weak](float value) {
3561 auto swiper = weak.Upgrade();
3562 CHECK_NULL_VOID(swiper);
3563 if (swiper->IsHorizontalAndRightToLeft()) {
3564 swiper->UpdateCurrentOffset(-static_cast<float>(value - swiper->currentOffset_));
3565 } else {
3566 swiper->UpdateCurrentOffset(static_cast<float>(value - swiper->currentOffset_));
3567 }
3568 },
3569 PropertyUnit::PIXEL_POSITION);
3570
3571 AnimationOption option;
3572 auto duration = GetDuration();
3573 bool finishAnimation = (duration == 0);
3574 motionVelocity_ = velocity / (endPos - startPos);
3575 option.SetCurve(GetCurveIncludeMotion());
3576 option.SetDuration(duration);
3577 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::ANIMATE);
3578 if (iter != frameRateRange_.end()) {
3579 TAG_LOGI(AceLogTag::ACE_SWIPER,
3580 "Translate animation frame rate range: {min: %{public}d, max: %{public}d, expected: %{public}d}",
3581 iter->second->min_, iter->second->max_, iter->second->preferred_);
3582 iter->second->componentScene_ = COMPONENT_SWIPER_FLING;
3583 option.SetFrameRateRange(iter->second);
3584 } else {
3585 option.SetFrameRateRange(SWIPER_DEFAULT_FRAME_RATE);
3586 }
3587 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, startPos);
3588 translateAnimationIsRunning_ = true;
3589 propertyAnimationIndex_ = nextIndex;
3590 translateAnimationEndPos_ = endPos;
3591 translateAnimation_ = AnimationUtils::StartAnimation(
3592 option,
3593 [host, weak, startPos, endPos, nextIndex, velocity]() {
3594 host->UpdateAnimatablePropertyFloat(TRANSLATE_PROPERTY_NAME, endPos);
3595 auto swiper = weak.Upgrade();
3596 CHECK_NULL_VOID(swiper);
3597 AceAsyncTraceBeginCommercial(
3598 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
3599 AnimationCallbackInfo info;
3600 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3601 info.currentOffset = swiper->GetCustomPropertyOffset() +
3602 Dimension(swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3603 info.targetOffset =
3604 swiper->GetCustomPropertyTargetOffset() + Dimension(startPos - endPos, DimensionUnit::PX).ConvertToVp();
3605 if (swiper->IsHorizontalAndRightToLeft()) {
3606 info.currentOffset = swiper->GetCustomPropertyOffset() +
3607 Dimension(-swiper->currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3608 }
3609 swiper->FireAnimationStartEvent(
3610 swiper->GetLoopIndex(swiper->currentIndex_), swiper->GetLoopIndex(nextIndex), info);
3611 swiper->FireAndCleanScrollingListener();
3612 },
3613 [weak, nextIndex, restartAutoPlay, finishAnimation]() {
3614 auto swiper = weak.Upgrade();
3615 CHECK_NULL_VOID(swiper);
3616 AceAsyncTraceEndCommercial(
3617 0, swiper->hasTabsAncestor_ ? APP_TABS_FRAME_ANIMATION : APP_SWIPER_FRAME_ANIMATION);
3618 if (finishAnimation && swiper->translateAnimationIsRunning_) {
3619 swiper->isFinishAnimation_ = true;
3620 }
3621 swiper->targetIndex_.reset();
3622 swiper->OnTranslateAnimationFinish();
3623 });
3624
3625 SetLazyLoadFeature(true);
3626 UpdateItemRenderGroup(true);
3627 }
3628
OnSpringAnimationStart(float velocity)3629 void SwiperPattern::OnSpringAnimationStart(float velocity)
3630 {
3631 AnimationCallbackInfo info;
3632 info.velocity = Dimension(velocity, DimensionUnit::PX).ConvertToVp();
3633 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3634 if (IsHorizontalAndRightToLeft()) {
3635 info.currentOffset =
3636 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3637 }
3638
3639 nextIndex_ = ComputeNextIndexByVelocity(velocity, true);
3640 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
3641 info.targetOffset = info.currentOffset;
3642 } else {
3643 FireWillShowEvent(nextIndex_);
3644 FireWillHideEvent(currentIndex_);
3645 auto iter = itemPosition_.find(nextIndex_);
3646 auto nextOffset = iter != itemPosition_.end() ? iter->second.startPos : 0.0f;
3647 info.targetOffset = GetCustomPropertyTargetOffset() + Dimension(nextOffset, DimensionUnit::PX).ConvertToVp();
3648 }
3649
3650 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
3651 }
3652
OnSpringAnimationFinish()3653 void SwiperPattern::OnSpringAnimationFinish()
3654 {
3655 if (!springAnimationIsRunning_) {
3656 return;
3657 }
3658 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_LIST_FLING, false);
3659 AceAsyncTraceEndCommercial(0, TRAILING_ANIMATION);
3660 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper finish spring animation offset %{public}f",
3661 currentIndexOffset_);
3662 ACE_SCOPED_TRACE_COMMERCIAL("%s finish spring animation, offset: %f",
3663 hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG, currentIndexOffset_);
3664 springAnimationIsRunning_ = false;
3665 isTouchDownSpringAnimation_ = false;
3666 OnSpringAndFadeAnimationFinish();
3667 }
3668
OnSpringAndFadeAnimationFinish()3669 void SwiperPattern::OnSpringAndFadeAnimationFinish()
3670 {
3671 auto itemInfoInVisibleArea = std::make_pair(0, SwiperItemInfo {});
3672 if (!itemPosition_.empty()) {
3673 auto item = itemPosition_.find(nextIndex_);
3674 itemInfoInVisibleArea =
3675 std::make_pair(item->first, SwiperItemInfo { item->second.startPos, item->second.endPos });
3676 }
3677 if (GetLoopIndex(currentIndex_) != GetLoopIndex(nextIndex_)) {
3678 UpdateCurrentIndex(nextIndex_);
3679 UpdateCurrentFocus();
3680 OnIndexChange();
3681 oldIndex_ = currentIndex_;
3682 }
3683 AnimationCallbackInfo info;
3684 auto indexStartPos = itemInfoInVisibleArea.second.startPos;
3685 info.currentOffset = GetCustomPropertyOffset() + Dimension(indexStartPos, DimensionUnit::PX).ConvertToVp();
3686 if (IsHorizontalAndRightToLeft()) {
3687 info.currentOffset = GetCustomPropertyOffset() + Dimension(-indexStartPos, DimensionUnit::PX).ConvertToVp();
3688 }
3689 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
3690 currentIndexOffset_ = indexStartPos;
3691 UpdateItemRenderGroup(false);
3692 NotifyParentScrollEnd();
3693
3694 if (!isTouchDown_) {
3695 StartAutoPlay();
3696 }
3697
3698 fadeAnimationIsRunning_ = false;
3699 isTouchDownFadeAnimation_ = false;
3700 }
3701
OnFadeAnimationStart()3702 void SwiperPattern::OnFadeAnimationStart()
3703 {
3704 AnimationCallbackInfo info;
3705 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3706 if (IsHorizontalAndRightToLeft()) {
3707 info.currentOffset =
3708 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
3709 }
3710 nextIndex_ = ComputeNextIndexByVelocity(0.0);
3711 if (GetLoopIndex(currentIndex_) == GetLoopIndex(nextIndex_)) {
3712 info.targetOffset = info.currentOffset;
3713 } else {
3714 FireWillShowEvent(nextIndex_);
3715 FireWillHideEvent(currentIndex_);
3716 info.targetOffset = GetCustomPropertyTargetOffset();
3717 }
3718
3719 FireAnimationStartEvent(GetLoopIndex(currentIndex_), GetLoopIndex(nextIndex_), info);
3720 fadeAnimationIsRunning_ = true;
3721 }
3722
PlayFadeAnimation()3723 void SwiperPattern::PlayFadeAnimation()
3724 {
3725 if (NearZero(fadeOffset_)) {
3726 fadeAnimationIsRunning_ = false;
3727 return;
3728 }
3729
3730 auto host = GetHost();
3731 CHECK_NULL_VOID(host);
3732 auto weak = AceType::WeakClaim(this);
3733 host->CreateAnimatablePropertyFloat(FADE_PROPERTY_NAME, 0, Animation<double>::ValueCallback([weak](float value) {
3734 auto swiper = weak.Upgrade();
3735 if (swiper && swiper->GetHost() && !swiper->isTouchDown_) {
3736 swiper->fadeOffset_ = value;
3737 swiper->GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3738 }
3739 }));
3740
3741 AnimationOption option;
3742 option.SetDuration(FADE_DURATION);
3743 option.SetCurve(Curves::LINEAR);
3744
3745 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, fadeOffset_);
3746 constexpr float end = 0.0f;
3747 nextIndex_ = currentIndex_;
3748 fadeAnimation_ = AnimationUtils::StartAnimation(
3749 option,
3750 [weak, host, end]() {
3751 auto swiperPattern = weak.Upgrade();
3752 CHECK_NULL_VOID(swiperPattern);
3753 swiperPattern->OnFadeAnimationStart();
3754 host->UpdateAnimatablePropertyFloat(FADE_PROPERTY_NAME, end);
3755 },
3756 [weak]() {
3757 auto swiperPattern = weak.Upgrade();
3758 CHECK_NULL_VOID(swiperPattern);
3759 swiperPattern->OnSpringAndFadeAnimationFinish();
3760 });
3761 }
3762
CreateSpringProperty()3763 void SwiperPattern::CreateSpringProperty()
3764 {
3765 auto host = GetHost();
3766 CHECK_NULL_VOID(host);
3767 host->CreateAnimatablePropertyFloat(
3768 SPRING_PROPERTY_NAME, 0,
3769 [weak = AceType::WeakClaim(this)](float position) {
3770 auto swiper = weak.Upgrade();
3771 CHECK_NULL_VOID(swiper);
3772 auto positionDelta = static_cast<float>(position) - swiper->currentIndexOffset_;
3773 if (swiper->IsHorizontalAndRightToLeft()) {
3774 positionDelta = -positionDelta;
3775 }
3776 swiper->UpdateCurrentOffset(positionDelta);
3777 if (LessNotEqual(std::abs(positionDelta), 1) && !NearZero(positionDelta)) {
3778 AceAsyncTraceBeginCommercial(0, TRAILING_ANIMATION);
3779 }
3780 },
3781 PropertyUnit::PIXEL_POSITION);
3782 }
3783
PlaySpringAnimation(double dragVelocity)3784 void SwiperPattern::PlaySpringAnimation(double dragVelocity)
3785 {
3786 UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart());
3787 if (springAnimationIsRunning_) {
3788 return;
3789 }
3790 auto host = GetHost();
3791 CHECK_NULL_VOID(host);
3792 auto mainSize = CalculateVisibleSize();
3793 if (LessOrEqual(mainSize, 0) || itemPosition_.empty()) {
3794 return;
3795 }
3796 childScrolling_ = false;
3797 auto leading = currentIndexOffset_ + mainSize - itemPosition_.rbegin()->second.endPos;
3798 auto trailing = currentIndexOffset_ - itemPosition_.begin()->second.startPos;
3799 ExtentPair extentPair = ExtentPair(leading, trailing);
3800 CreateSpringProperty();
3801 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, currentIndexOffset_);
3802 auto delta = currentIndexOffset_ < 0.0f ? extentPair.Leading() : extentPair.Trailing();
3803 if (IsVisibleChildrenSizeLessThanSwiper()) {
3804 delta = extentPair.Trailing();
3805 }
3806 // spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
3807 auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
3808 AnimationOption option;
3809 option.SetCurve(springCurve);
3810 option.SetDuration(SPRING_DURATION);
3811 nextIndex_ = currentIndex_;
3812 springAnimation_ = AnimationUtils::StartAnimation(
3813 option,
3814 [weak = AceType::WeakClaim(this), dragVelocity, host, delta]() {
3815 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_LIST_FLING, PerfActionType::FIRST_MOVE, "");
3816 TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper start spring animation with offset:%{public}f", delta);
3817 auto swiperPattern = weak.Upgrade();
3818 CHECK_NULL_VOID(swiperPattern);
3819 ACE_SCOPED_TRACE_COMMERCIAL(
3820 "%s start spring animation", swiperPattern->hasTabsAncestor_ ? V2::TABS_ETS_TAG : V2::SWIPER_ETS_TAG);
3821 host->UpdateAnimatablePropertyFloat(SPRING_PROPERTY_NAME, delta);
3822 },
3823 [weak = AceType::WeakClaim(this)]() {
3824 auto swiperPattern = weak.Upgrade();
3825 CHECK_NULL_VOID(swiperPattern);
3826 swiperPattern->OnSpringAnimationFinish();
3827 });
3828 OnSpringAnimationStart(static_cast<float>(dragVelocity));
3829 springAnimationIsRunning_ = true;
3830 }
3831
IsOutOfBoundary(float mainOffset) const3832 bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
3833 {
3834 if (IsLoop() || itemPosition_.empty()) {
3835 return false;
3836 }
3837 if (IsHorizontalAndRightToLeft()) {
3838 mainOffset = -mainOffset;
3839 }
3840
3841 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
3842 startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
3843 auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
3844 auto visibleWindowSize = CalculateVisibleSize();
3845 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
3846 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
3847 auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
3848 return isOutOfStart || isOutOfEnd;
3849 }
3850
IsOutOfStart(float mainOffset) const3851 bool SwiperPattern::IsOutOfStart(float mainOffset) const
3852 {
3853 if (IsLoop() || itemPosition_.empty()) {
3854 return false;
3855 }
3856 if (IsHorizontalAndRightToLeft()) {
3857 mainOffset = -mainOffset;
3858 }
3859
3860 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
3861 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
3862 return itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.f);
3863 }
3864
IsOutOfEnd(float mainOffset) const3865 bool SwiperPattern::IsOutOfEnd(float mainOffset) const
3866 {
3867 if (IsLoop() || itemPosition_.empty()) {
3868 return false;
3869 }
3870 if (IsHorizontalAndRightToLeft()) {
3871 mainOffset = -mainOffset;
3872 }
3873
3874 auto visibleWindowSize = CalculateVisibleSize();
3875 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
3876 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
3877 return itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
3878 }
3879
IsAtStart() const3880 bool SwiperPattern::IsAtStart() const
3881 {
3882 if (IsLoop() || itemPosition_.empty()) {
3883 return false;
3884 }
3885
3886 auto startPos = itemPosition_.begin()->second.startPos;
3887 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
3888 return itemPosition_.begin()->first == 0 && GreatOrEqual(startPos, 0.f);
3889 }
3890
IsAtEnd() const3891 bool SwiperPattern::IsAtEnd() const
3892 {
3893 if (IsLoop() || itemPosition_.empty()) {
3894 return false;
3895 }
3896
3897 auto visibleWindowSize = CalculateVisibleSize();
3898 auto endPos = itemPosition_.rbegin()->second.endPos;
3899 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
3900 return itemPosition_.rbegin()->first == TotalCount() - 1 && LessOrEqual(endPos, visibleWindowSize);
3901 }
3902
AutoLinearIsOutOfBoundary(float mainOffset) const3903 bool SwiperPattern::AutoLinearIsOutOfBoundary(float mainOffset) const
3904 {
3905 if (itemPosition_.empty() || static_cast<int32_t>(itemPosition_.size()) < TotalCount()) {
3906 return false;
3907 }
3908
3909 auto startPos = itemPosition_.begin()->second.startPos;
3910 auto isOutOfStart = GreatNotEqual(startPos + mainOffset, 0.0);
3911
3912 auto visibleWindowSize = CalculateVisibleSize();
3913 auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
3914 auto isOutOfEnd = LessNotEqual(endPos, visibleWindowSize);
3915
3916 return isOutOfStart || isOutOfEnd;
3917 }
3918
GetDistanceToEdge() const3919 float SwiperPattern::GetDistanceToEdge() const
3920 {
3921 if (IsLoop() || itemPosition_.empty()) {
3922 return 0.0f;
3923 }
3924 if (itemPosition_.begin()->first == 0) {
3925 return -itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
3926 }
3927 auto visibleWindowSize = CalculateVisibleSize();
3928 return itemPosition_.rbegin()->second.endPos - visibleWindowSize + AdjustIgnoreBlankOverScrollOffSet(false);
3929 }
3930
MainSize() const3931 float SwiperPattern::MainSize() const
3932 {
3933 auto host = GetHost();
3934 CHECK_NULL_RETURN(host, 0.0);
3935 auto geometryNode = host->GetGeometryNode();
3936 CHECK_NULL_RETURN(geometryNode, 0.0);
3937 return geometryNode->GetFrameSize().MainSize(GetDirection());
3938 }
3939
GetMainContentSize() const3940 float SwiperPattern::GetMainContentSize() const
3941 {
3942 auto host = GetHost();
3943 CHECK_NULL_RETURN(host, 0.0);
3944 auto geometryNode = host->GetGeometryNode();
3945 CHECK_NULL_RETURN(geometryNode, 0.0);
3946 return geometryNode->GetPaddingSize().Width();
3947 }
3948
GetItemSpace() const3949 float SwiperPattern::GetItemSpace() const
3950 {
3951 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3952 CHECK_NULL_RETURN(props, 0.0f);
3953 if (props->IgnoreItemSpace()) {
3954 return 0.0f;
3955 }
3956 auto itemSpace = props->GetItemSpace().value_or(0.0_vp).ConvertToPx();
3957 auto host = GetHost();
3958 CHECK_NULL_RETURN(host, 0.0f);
3959 auto geometryNode = host->GetGeometryNode();
3960 CHECK_NULL_RETURN(geometryNode, 0.0f);
3961 auto mainSize = geometryNode->GetFrameSize().MainSize(GetDirection());
3962 if (itemSpace > mainSize) {
3963 itemSpace = 0.0f;
3964 }
3965 return itemSpace;
3966 }
3967
IsCachedShow() const3968 bool SwiperPattern::IsCachedShow() const
3969 {
3970 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3971 CHECK_NULL_RETURN(props, false);
3972 return props->GetCachedIsShown().value_or(false);
3973 }
3974
GetPrevMargin() const3975 float SwiperPattern::GetPrevMargin() const
3976 {
3977 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3978 CHECK_NULL_RETURN(props, 0.0f);
3979 return props->GetCalculatedPrevMargin();
3980 }
3981
GetNextMargin() const3982 float SwiperPattern::GetNextMargin() const
3983 {
3984 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3985 CHECK_NULL_RETURN(props, 0.0f);
3986 return props->GetCalculatedNextMargin();
3987 }
3988
GetDirection() const3989 Axis SwiperPattern::GetDirection() const
3990 {
3991 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3992 CHECK_NULL_RETURN(props, Axis::HORIZONTAL);
3993 return props->GetDirection().value_or(Axis::HORIZONTAL);
3994 }
3995
CurrentIndex() const3996 int32_t SwiperPattern::CurrentIndex() const
3997 {
3998 auto props = GetLayoutProperty<SwiperLayoutProperty>();
3999 CHECK_NULL_RETURN(props, 0);
4000 return props->GetIndex().value_or(0);
4001 }
4002
GetDisplayCount() const4003 int32_t SwiperPattern::GetDisplayCount() const
4004 {
4005 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4006 CHECK_NULL_RETURN(props, 1);
4007 auto displayCount = CalculateDisplayCount();
4008 return displayCount;
4009 }
4010
CalculateDisplayCount() const4011 int32_t SwiperPattern::CalculateDisplayCount() const
4012 {
4013 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4014 CHECK_NULL_RETURN(props, 1);
4015 bool isAutoFill = IsAutoFill();
4016 if (isAutoFill) {
4017 auto minSize = props->GetMinSize()->ConvertToPx();
4018 float contentWidth = GetMainContentSize();
4019 auto displayCount =
4020 CalculateCount(contentWidth, minSize, SWIPER_MARGIN.ConvertToPx(), SWIPER_GUTTER.ConvertToPx());
4021 if (LessOrEqual(minSize, 0)) {
4022 displayCount = 1;
4023 }
4024
4025 displayCount = displayCount > 0 ? displayCount : 1;
4026 auto totalCount = TotalCount();
4027 displayCount = displayCount > totalCount ? totalCount : displayCount;
4028 auto displayCountProperty = props->GetDisplayCount().value_or(1);
4029 if (displayCountProperty != displayCount) {
4030 props->UpdateDisplayCount(displayCount);
4031 auto host = GetHost();
4032 CHECK_NULL_RETURN(host, 1);
4033 host->MarkDirtyNode(
4034 (crossMatchChild_ ? PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD : PROPERTY_UPDATE_MEASURE_SELF) |
4035 PROPERTY_UPDATE_RENDER);
4036 }
4037 return displayCount;
4038 } else {
4039 return props->GetDisplayCount().value_or(1);
4040 }
4041 }
4042
CalculateCount(float contentWidth,float minSize,float margin,float gutter,float swiperPadding) const4043 int32_t SwiperPattern::CalculateCount(
4044 float contentWidth, float minSize, float margin, float gutter, float swiperPadding) const
4045 {
4046 return static_cast<int32_t>(floor((contentWidth - 2 * margin + gutter - 2 * swiperPadding) / (minSize + gutter)));
4047 }
4048
IsAutoFill() const4049 bool SwiperPattern::IsAutoFill() const
4050 {
4051 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4052 CHECK_NULL_RETURN(props, false);
4053 return props->GetMinSize().has_value();
4054 }
4055
IsAutoPlay() const4056 bool SwiperPattern::IsAutoPlay() const
4057 {
4058 auto props = GetPaintProperty<SwiperPaintProperty>();
4059 CHECK_NULL_RETURN(props, false);
4060 return props->GetAutoPlay().value_or(false);
4061 }
4062
GetDuration() const4063 int32_t SwiperPattern::GetDuration() const
4064 {
4065 const int32_t DEFAULT_DURATION = 400;
4066 auto props = GetPaintProperty<SwiperPaintProperty>();
4067 CHECK_NULL_RETURN(props, DEFAULT_DURATION);
4068 return props->GetDuration().value_or(DEFAULT_DURATION);
4069 }
4070
GetInterval() const4071 int32_t SwiperPattern::GetInterval() const
4072 {
4073 const int32_t DEFAULT_INTERVAL = 3000;
4074 auto props = GetPaintProperty<SwiperPaintProperty>();
4075 CHECK_NULL_RETURN(props, DEFAULT_INTERVAL);
4076 return props->GetAutoPlayInterval().value_or(DEFAULT_INTERVAL);
4077 }
4078
GetCurve() const4079 RefPtr<Curve> SwiperPattern::GetCurve() const
4080 {
4081 auto props = GetPaintProperty<SwiperPaintProperty>();
4082 CHECK_NULL_RETURN(props, nullptr);
4083 return props->GetCurve().value_or(nullptr);
4084 }
4085
IsLoop() const4086 bool SwiperPattern::IsLoop() const
4087 {
4088 if (hasCachedCapture_) {
4089 return true;
4090 }
4091 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4092 CHECK_NULL_RETURN(props, true);
4093 if (TotalDisPlayCount() > TotalCount() ||
4094 (TotalDisPlayCount() == TotalCount() && SwiperUtils::IsStretch(props) &&
4095 (NonPositive(props->GetCalculatedPrevMargin()) || NonPositive(props->GetCalculatedNextMargin())))) {
4096 return false;
4097 }
4098 return props->GetLoop().value_or(true);
4099 }
4100
IsEnabled() const4101 bool SwiperPattern::IsEnabled() const
4102 {
4103 auto props = GetPaintProperty<SwiperPaintProperty>();
4104 CHECK_NULL_RETURN(props, true);
4105 return props->GetEnabled().value_or(true);
4106 }
4107
GetEdgeEffect() const4108 EdgeEffect SwiperPattern::GetEdgeEffect() const
4109 {
4110 auto props = GetPaintProperty<SwiperPaintProperty>();
4111 CHECK_NULL_RETURN(props, EdgeEffect::SPRING);
4112 return props->GetEdgeEffect().value_or(EdgeEffect::SPRING);
4113 }
4114
IsDisableSwipe() const4115 bool SwiperPattern::IsDisableSwipe() const
4116 {
4117 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4118 CHECK_NULL_RETURN(props, false);
4119 return props->GetDisableSwipe().value_or(false);
4120 }
4121
IsShowIndicator() const4122 bool SwiperPattern::IsShowIndicator() const
4123 {
4124 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4125 CHECK_NULL_RETURN(props, true);
4126 return props->GetShowIndicatorValue(true);
4127 }
4128
IsShowArrow() const4129 bool SwiperPattern::IsShowArrow() const
4130 {
4131 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4132 CHECK_NULL_RETURN(props, true);
4133 return props->GetDisplayArrowValue(false);
4134 }
4135
GetIndicatorType() const4136 SwiperIndicatorType SwiperPattern::GetIndicatorType() const
4137 {
4138 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4139 CHECK_NULL_RETURN(props, SwiperIndicatorType::DOT);
4140 return props->GetIndicatorTypeValue(SwiperIndicatorType::DOT);
4141 }
4142
GetSwiperParameters() const4143 std::shared_ptr<SwiperParameters> SwiperPattern::GetSwiperParameters() const
4144 {
4145 if (swiperParameters_ == nullptr) {
4146 swiperParameters_ = std::make_shared<SwiperParameters>();
4147 auto pipelineContext = PipelineBase::GetCurrentContext();
4148 CHECK_NULL_RETURN(pipelineContext, swiperParameters_);
4149 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4150 CHECK_NULL_RETURN(swiperIndicatorTheme, swiperParameters_);
4151 swiperParameters_->itemWidth = swiperIndicatorTheme->GetSize();
4152 swiperParameters_->itemHeight = swiperIndicatorTheme->GetSize();
4153 swiperParameters_->selectedItemWidth = swiperIndicatorTheme->GetSize();
4154 swiperParameters_->selectedItemHeight = swiperIndicatorTheme->GetSize();
4155 swiperParameters_->maskValue = false;
4156 swiperParameters_->colorVal = swiperIndicatorTheme->GetColor();
4157 swiperParameters_->selectedColorVal = swiperIndicatorTheme->GetSelectedColor();
4158 swiperParameters_->maxDisplayCountVal = 0;
4159 }
4160 return swiperParameters_;
4161 }
4162
GetSwiperDigitalParameters() const4163 std::shared_ptr<SwiperDigitalParameters> SwiperPattern::GetSwiperDigitalParameters() const
4164 {
4165 if (swiperDigitalParameters_ == nullptr) {
4166 swiperDigitalParameters_ = std::make_shared<SwiperDigitalParameters>();
4167 auto pipelineContext = PipelineBase::GetCurrentContext();
4168 CHECK_NULL_RETURN(pipelineContext, swiperDigitalParameters_);
4169 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4170 swiperDigitalParameters_->fontColor = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
4171 swiperDigitalParameters_->selectedFontColor =
4172 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
4173 swiperDigitalParameters_->fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
4174 swiperDigitalParameters_->selectedFontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
4175 swiperDigitalParameters_->fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
4176 swiperDigitalParameters_->selectedFontWeight =
4177 swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
4178 }
4179 return swiperDigitalParameters_;
4180 }
4181
TotalCount() const4182 int32_t SwiperPattern::TotalCount() const
4183 {
4184 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4185 CHECK_NULL_RETURN(props, 1);
4186 auto displayCount = props->GetDisplayCount().value_or(1);
4187 auto totalCount = RealTotalCount();
4188 if (IsSwipeByGroup() && displayCount != 0) {
4189 totalCount =
4190 static_cast<int32_t>(std::ceil(static_cast<float>(totalCount) / static_cast<float>(displayCount))) *
4191 displayCount;
4192 }
4193
4194 return totalCount;
4195 }
4196
RealTotalCount() const4197 int32_t SwiperPattern::RealTotalCount() const
4198 {
4199 auto host = GetHost();
4200 CHECK_NULL_RETURN(host, 0);
4201 // last child is swiper indicator
4202 int num = 0;
4203 if (!isBindIndicator_ && IsShowIndicator() && HasIndicatorNode()) {
4204 num += 1;
4205 }
4206 if (HasLeftButtonNode()) {
4207 num += 1;
4208 }
4209 if (HasRightButtonNode()) {
4210 num += 1;
4211 }
4212 if (hasCachedCapture_ && leftCaptureId_.has_value() && rightCaptureId_.has_value()) {
4213 num += CAPTURE_COUNT;
4214 }
4215 return host->TotalChildCount() - num;
4216 }
4217
GetFirstItemInfoInVisibleArea() const4218 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetFirstItemInfoInVisibleArea() const
4219 {
4220 if (itemPosition_.empty()) {
4221 return std::make_pair(0, SwiperItemInfo {});
4222 }
4223 for (const auto& item : itemPosition_) {
4224 if (item.second.startPos < 0 && item.second.endPos < 0) {
4225 continue;
4226 }
4227 if (item.second.startPos <= 0 && item.second.endPos > 0) {
4228 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
4229 }
4230 if (item.second.startPos > 0 && item.second.endPos > 0) {
4231 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, item.second.endPos });
4232 }
4233 }
4234 return std::make_pair(itemPosition_.begin()->first,
4235 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
4236 }
4237
GetLastItemInfoInVisibleArea() const4238 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetLastItemInfoInVisibleArea() const
4239 {
4240 if (itemPosition_.empty()) {
4241 return std::make_pair(0, SwiperItemInfo {});
4242 }
4243 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4244 auto lastItemIndex = firstItemInfoInVisibleArea.first + GetDisplayCount() - 1;
4245 auto iter = itemPosition_.find(lastItemIndex);
4246 if (iter != itemPosition_.end()) {
4247 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
4248 }
4249 return std::make_pair(itemPosition_.rbegin()->first,
4250 SwiperItemInfo { itemPosition_.rbegin()->second.startPos, itemPosition_.rbegin()->second.endPos });
4251 }
4252
GetSecondItemInfoInVisibleArea() const4253 std::pair<int32_t, SwiperItemInfo> SwiperPattern::GetSecondItemInfoInVisibleArea() const
4254 {
4255 if (itemPosition_.empty()) {
4256 return std::make_pair(0, SwiperItemInfo {});
4257 }
4258 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4259 auto secondItemIndex = firstItemInfoInVisibleArea.first + 1;
4260 auto iter = itemPosition_.find(secondItemIndex);
4261 if (iter != itemPosition_.end()) {
4262 return std::make_pair(iter->first, SwiperItemInfo { iter->second.startPos, iter->second.endPos });
4263 }
4264 return std::make_pair(itemPosition_.begin()->first,
4265 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
4266 }
4267
IsOutOfHotRegion(const PointF & dragPoint) const4268 bool SwiperPattern::IsOutOfHotRegion(const PointF& dragPoint) const
4269 {
4270 auto host = GetHost();
4271 CHECK_NULL_RETURN(host, true);
4272 auto context = host->GetRenderContext();
4273 CHECK_NULL_RETURN(context, true);
4274
4275 auto hotRegion = context->GetPaintRectWithoutTransform();
4276 return !hotRegion.IsInRegion(dragPoint + OffsetF(hotRegion.GetX(), hotRegion.GetY()));
4277 }
4278
UpdatePaintProperty(const RefPtr<FrameNode> & indicatorNode)4279 void SwiperPattern::UpdatePaintProperty(const RefPtr<FrameNode>& indicatorNode)
4280 {
4281 CHECK_NULL_VOID(indicatorNode);
4282 auto paintProperty = indicatorNode->GetPaintProperty<DotIndicatorPaintProperty>();
4283 CHECK_NULL_VOID(paintProperty);
4284 auto pipelineContext = PipelineBase::GetCurrentContext();
4285 CHECK_NULL_VOID(pipelineContext);
4286 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
4287 CHECK_NULL_VOID(swiperIndicatorTheme);
4288 auto swiperParameters = GetSwiperParameters();
4289 CHECK_NULL_VOID(swiperParameters);
4290 paintProperty->UpdateItemWidth(swiperParameters->itemWidth.value_or(swiperIndicatorTheme->GetSize()));
4291 paintProperty->UpdateItemHeight(swiperParameters->itemHeight.value_or(swiperIndicatorTheme->GetSize()));
4292 paintProperty->UpdateSelectedItemWidth(
4293 swiperParameters->selectedItemWidth.value_or(swiperIndicatorTheme->GetSize()));
4294 paintProperty->UpdateSelectedItemHeight(
4295 swiperParameters->selectedItemHeight.value_or(swiperIndicatorTheme->GetSize()));
4296 paintProperty->UpdateIndicatorMask(swiperParameters->maskValue.value_or(false));
4297 paintProperty->UpdateColor(swiperParameters->colorVal.value_or(swiperIndicatorTheme->GetColor()));
4298 paintProperty->UpdateSelectedColor(
4299 swiperParameters->selectedColorVal.value_or(swiperIndicatorTheme->GetSelectedColor()));
4300 paintProperty->UpdateIsCustomSize(isCustomSize_);
4301
4302 MarkDirtyNodeSelf();
4303 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4304 }
4305
SetDigitStartAndEndProperty(const RefPtr<FrameNode> & indicatorNode)4306 void SwiperPattern::SetDigitStartAndEndProperty(const RefPtr<FrameNode>& indicatorNode)
4307 {
4308 CHECK_NULL_VOID(indicatorNode);
4309 auto indicatorProps = indicatorNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
4310 CHECK_NULL_VOID(indicatorProps);
4311 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4312 CHECK_NULL_VOID(props);
4313 const auto digitalParams = GetSwiperDigitalParameters();
4314 CHECK_NULL_VOID(digitalParams);
4315 bool isRtl = GetNonAutoLayoutDirection() == TextDirection::RTL;
4316 if (digitalParams->dimStart.has_value()) {
4317 auto dimValue = digitalParams->dimStart.value().Value() >= 0.0 ? digitalParams->dimStart.value()
4318 : Dimension(0.0, DimensionUnit::VP);
4319 isRtl ? indicatorProps->UpdateRight(dimValue) : indicatorProps->UpdateLeft(dimValue);
4320 isRtl ? props->UpdateRight(dimValue) : props->UpdateLeft(digitalParams->dimLeft.value_or(0.0_vp));
4321 ;
4322 } else if (digitalParams->dimEnd.has_value()) {
4323 auto dimValue = digitalParams->dimEnd.value().Value() >= 0.0 ? digitalParams->dimEnd.value()
4324 : Dimension(0.0, DimensionUnit::VP);
4325 isRtl ? indicatorProps->UpdateLeft(dimValue) : indicatorProps->UpdateRight(dimValue);
4326 isRtl ? props->UpdateLeft(dimValue) : props->UpdateRight(digitalParams->dimRight.value_or(0.0_vp));
4327 }
4328 }
4329
PostTranslateTask(uint32_t delayTime)4330 void SwiperPattern::PostTranslateTask(uint32_t delayTime)
4331 {
4332 auto pipeline = PipelineContext::GetCurrentContext();
4333 CHECK_NULL_VOID(pipeline);
4334 auto taskExecutor = pipeline->GetTaskExecutor();
4335 CHECK_NULL_VOID(taskExecutor);
4336
4337 if (translateTask_) {
4338 translateTask_.Cancel();
4339 }
4340
4341 auto weak = AceType::WeakClaim(this);
4342 translateTask_.Reset([weak, delayTime] {
4343 auto swiper = weak.Upgrade();
4344 if (swiper) {
4345 swiper->isInAutoPlay_ = true;
4346 auto childrenSize = swiper->TotalCount();
4347 auto displayCount = swiper->GetDisplayCount();
4348 if (childrenSize <= 0 || displayCount <= 0 || swiper->itemPosition_.empty()) {
4349 return;
4350 }
4351 if (!swiper->IsLoop() && swiper->GetLoopIndex(swiper->currentIndex_) + 1 > (childrenSize - displayCount)) {
4352 return;
4353 }
4354 auto stepItems = swiper->IsSwipeByGroup() ? displayCount : 1;
4355 swiper->targetIndex_ = swiper->CheckTargetIndex(swiper->currentIndex_ + stepItems);
4356 ACE_SCOPED_TRACE("Swiper autoPlay delayTime %d targetIndex %d isVisibleArea_ %d isWindowShow_ %d",
4357 delayTime, swiper->targetIndex_.value(), swiper->isVisibleArea_, swiper->isWindowShow_);
4358 swiper->MarkDirtyNodeSelf();
4359 auto pipeline = PipelineContext::GetCurrentContext();
4360 if (pipeline) {
4361 pipeline->FlushUITasks();
4362 }
4363 }
4364 });
4365
4366 taskExecutor->PostDelayedTask(translateTask_, TaskExecutor::TaskType::UI, delayTime, "ArkUISwiperTranslate");
4367 }
4368
HandleVisibleChange(bool visible)4369 void SwiperPattern::HandleVisibleChange(bool visible)
4370 {
4371 isVisibleArea_ = visible;
4372 if (!visible) {
4373 translateTask_.Cancel();
4374 isInAutoPlay_ = false;
4375 return;
4376 }
4377
4378 if (NeedStartAutoPlay()) {
4379 StartAutoPlay();
4380 }
4381 }
4382
RegisterVisibleAreaChange()4383 void SwiperPattern::RegisterVisibleAreaChange()
4384 {
4385 auto pipeline = PipelineContext::GetCurrentContext();
4386 CHECK_NULL_VOID(pipeline);
4387 auto host = GetHost();
4388 CHECK_NULL_VOID(host);
4389 pipeline->AddWindowStateChangedCallback(host->GetId());
4390
4391 if (hasVisibleChangeRegistered_) {
4392 return;
4393 }
4394
4395 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
4396 auto swiperPattern = weak.Upgrade();
4397 CHECK_NULL_VOID(swiperPattern);
4398 swiperPattern->HandleVisibleChange(visible);
4399 };
4400 pipeline->RemoveVisibleAreaChangeNode(host->GetId());
4401 std::vector<double> ratioList = { 0.0 };
4402 pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, true);
4403 hasVisibleChangeRegistered_ = true;
4404
4405 auto isFormRender = pipeline->IsFormRender();
4406 auto formMgr = pipeline->GetFormVisibleManager();
4407 if (!isFormRender || !formMgr) {
4408 return;
4409 }
4410 formMgr->RemoveFormVisibleChangeNode(host->GetId());
4411 auto formCallback = [weak = WeakClaim(this)](bool visible) {
4412 auto swiperPattern = weak.Upgrade();
4413 CHECK_NULL_VOID(swiperPattern);
4414 swiperPattern->HandleVisibleChange(visible);
4415 };
4416 formMgr->AddFormVisibleChangeNode(host, formCallback);
4417 }
4418
NeedAutoPlay() const4419 bool SwiperPattern::NeedAutoPlay() const
4420 {
4421 bool reachEnd = GetLoopIndex(CurrentIndex()) >= TotalCount() - 1 && !IsLoop();
4422 return IsAutoPlay() && !reachEnd && NeedStartAutoPlay() && !isIndicatorLongPress_;
4423 }
4424
TriggerAnimationEndOnSwipeToLeft()4425 void SwiperPattern::TriggerAnimationEndOnSwipeToLeft()
4426 {
4427 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4428 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
4429 auto firstIndexStartPos = firstItemInfoInVisibleArea.second.startPos;
4430 if (std::abs(firstIndexStartPos) < (firstItemLength / 2)) {
4431 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
4432 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
4433 } else {
4434 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
4435 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
4436 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
4437 }
4438 }
4439
TriggerAnimationEndOnSwipeToRight()4440 void SwiperPattern::TriggerAnimationEndOnSwipeToRight()
4441 {
4442 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4443 auto firstItemLength = firstItemInfoInVisibleArea.second.endPos - firstItemInfoInVisibleArea.second.startPos;
4444 auto secondItemInfoInVisibleArea = GetSecondItemInfoInVisibleArea();
4445 auto secondIndexStartPos = secondItemInfoInVisibleArea.second.startPos;
4446 if (std::abs(secondIndexStartPos) < (firstItemLength / 2)) {
4447 currentIndexOffset_ = secondItemInfoInVisibleArea.second.startPos;
4448 UpdateCurrentIndex(secondItemInfoInVisibleArea.first);
4449 } else {
4450 currentIndexOffset_ = firstItemInfoInVisibleArea.second.startPos;
4451 UpdateCurrentIndex(firstItemInfoInVisibleArea.first);
4452 }
4453 }
4454
UpdateIndexOnAnimationStop()4455 void SwiperPattern::UpdateIndexOnAnimationStop()
4456 {
4457 auto firstItemInfoInVisibleArea = GetFirstItemInfoInVisibleArea();
4458 if (currentIndex_ == firstItemInfoInVisibleArea.first) {
4459 // swipe to left
4460 TriggerAnimationEndOnSwipeToLeft();
4461 } else {
4462 // swipe to right
4463 TriggerAnimationEndOnSwipeToRight();
4464 }
4465 }
4466
UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)4467 void SwiperPattern::UpdateIndexOnSwipePageStop(int32_t pauseTargetIndex)
4468 {
4469 auto iter = itemPosition_.find(currentIndex_);
4470 if (iter == itemPosition_.end()) {
4471 UpdateCurrentIndex(pauseTargetIndex);
4472 if (itemPosition_.find(pauseTargetIndex) != itemPosition_.end()) {
4473 currentIndexOffset_ = itemPosition_.find(pauseTargetIndex)->second.startPos;
4474 }
4475 return;
4476 }
4477
4478 auto swiperWidth = MainSize();
4479 auto currentOffset = iter->second.startPos;
4480 if (std::abs(currentOffset) < (swiperWidth / SWIPER_HALF)) {
4481 return;
4482 }
4483
4484 if (currentOffset < 0.0f) {
4485 auto nextPageIndex = currentIndex_ + GetDisplayCount();
4486 auto nextIter = itemPosition_.find(nextPageIndex);
4487 if (nextIter == itemPosition_.end()) {
4488 return;
4489 }
4490
4491 auto nextPageOffset = nextIter->second.startPos;
4492 currentIndexOffset_ = nextPageOffset;
4493 UpdateCurrentIndex(nextPageIndex);
4494 } else {
4495 auto prevPageIndex = currentIndex_ - GetDisplayCount();
4496 auto prevIter = itemPosition_.find(prevPageIndex);
4497 if (prevIter == itemPosition_.end()) {
4498 return;
4499 }
4500
4501 auto prevPageOffset = prevIter->second.startPos;
4502 currentIndexOffset_ = prevPageOffset;
4503 UpdateCurrentIndex(prevPageIndex);
4504 }
4505 }
4506
TriggerAnimationEndOnForceStop(bool isInterrupt)4507 void SwiperPattern::TriggerAnimationEndOnForceStop(bool isInterrupt)
4508 {
4509 auto pauseTargetIndex = pauseTargetIndex_.has_value() ? pauseTargetIndex_.value() : currentIndex_;
4510 if (currentIndex_ != pauseTargetIndex) {
4511 if (IsSwipeByGroup()) {
4512 UpdateIndexOnSwipePageStop(pauseTargetIndex);
4513 } else {
4514 UpdateIndexOnAnimationStop();
4515 }
4516
4517 UpdateCurrentFocus();
4518 OnIndexChange();
4519 oldIndex_ = currentIndex_;
4520 }
4521 AnimationCallbackInfo info;
4522 info.isForceStop = true;
4523 info.currentOffset = GetCustomPropertyOffset() + Dimension(currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4524 if (IsHorizontalAndRightToLeft()) {
4525 info.currentOffset =
4526 GetCustomPropertyOffset() + Dimension(-currentIndexOffset_, DimensionUnit::PX).ConvertToVp();
4527 }
4528 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info, isInterrupt);
4529 UpdateItemRenderGroup(false);
4530 }
4531
TriggerEventOnFinish(int32_t nextIndex)4532 void SwiperPattern::TriggerEventOnFinish(int32_t nextIndex)
4533 {
4534 ResetAndUpdateIndexOnAnimationEnd(nextIndex);
4535
4536 AnimationCallbackInfo info;
4537 info.isForceStop = false;
4538 info.currentOffset = GetCustomPropertyOffset();
4539 FireAnimationEndEvent(GetLoopIndex(currentIndex_), info);
4540 }
4541
GetCachedCount() const4542 int32_t SwiperPattern::GetCachedCount() const
4543 {
4544 auto host = GetHost();
4545 CHECK_NULL_RETURN(host, 1);
4546 auto props = host->GetLayoutProperty<SwiperLayoutProperty>();
4547 CHECK_NULL_RETURN(props, 1);
4548 auto cachedCount = props->GetCachedCount().value_or(1);
4549
4550 if (IsSwipeByGroup()) {
4551 cachedCount *= GetDisplayCount();
4552 }
4553
4554 return cachedCount;
4555 }
4556
SetLazyLoadFeature(bool useLazyLoad)4557 void SwiperPattern::SetLazyLoadFeature(bool useLazyLoad)
4558 {
4559 requestLongPredict_ = useLazyLoad;
4560 SetLazyForEachLongPredict(useLazyLoad);
4561
4562 if (!useLazyLoad) {
4563 return;
4564 }
4565 auto cacheCount = std::min(GetCachedCount(), RealTotalCount());
4566 std::set<int32_t> forEachIndexSet;
4567 for (auto count = 1; count <= cacheCount; count++) {
4568 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ + count));
4569 forEachIndexSet.emplace(GetLoopIndex(currentIndex_ - count));
4570 }
4571 if (forEachIndexSet.empty()) {
4572 return;
4573 }
4574
4575 auto host = GetHost();
4576 CHECK_NULL_VOID(host);
4577 const auto& children = host->GetChildren();
4578 for (const auto& child : children) {
4579 if (child->GetTag() != V2::JS_FOR_EACH_ETS_TAG) {
4580 continue;
4581 }
4582 auto pipeline = GetContext();
4583 CHECK_NULL_VOID(pipeline);
4584 auto taskExecutor = pipeline->GetTaskExecutor();
4585 CHECK_NULL_VOID(taskExecutor);
4586 taskExecutor->PostTask(
4587 [weak = WeakClaim(RawPtr(child)), forEachIndexSet]() {
4588 auto node = weak.Upgrade();
4589 CHECK_NULL_VOID(node);
4590 auto forEachNode = AceType::DynamicCast<ForEachNode>(node);
4591 CHECK_NULL_VOID(forEachNode);
4592 for (auto index : forEachIndexSet) {
4593 auto childNode = forEachNode->GetChildAtIndex(index);
4594 CHECK_NULL_VOID(childNode);
4595 childNode->Build(nullptr);
4596 }
4597 },
4598 TaskExecutor::TaskType::UI, "ArkUISwiperSetLazyLoadFeature");
4599 }
4600 }
4601
SetLazyForEachLongPredict(bool useLazyLoad) const4602 void SwiperPattern::SetLazyForEachLongPredict(bool useLazyLoad) const
4603 {
4604 // lazyBuild feature.
4605 auto host = GetHost();
4606 CHECK_NULL_VOID(host);
4607 auto targetNode = FindLazyForEachNode(host);
4608 if (targetNode.has_value()) {
4609 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
4610 CHECK_NULL_VOID(lazyForEachNode);
4611 lazyForEachNode->SetRequestLongPredict(useLazyLoad);
4612 }
4613 }
4614
SetLazyLoadIsLoop() const4615 void SwiperPattern::SetLazyLoadIsLoop() const
4616 {
4617 auto host = GetHost();
4618 CHECK_NULL_VOID(host);
4619 auto targetNode = FindLazyForEachNode(host);
4620 if (targetNode.has_value()) {
4621 auto lazyForEachNode = AceType::DynamicCast<LazyForEachNode>(targetNode.value());
4622 if (lazyForEachNode) {
4623 lazyForEachNode->SetIsLoop(IsLoop());
4624 }
4625 auto repeatVirtualNode = AceType::DynamicCast<RepeatVirtualScrollNode>(targetNode.value());
4626 if (repeatVirtualNode) {
4627 repeatVirtualNode->SetIsLoop(IsLoop());
4628 }
4629 }
4630 }
4631
PostIdleTask(const RefPtr<FrameNode> & frameNode)4632 void SwiperPattern::PostIdleTask(const RefPtr<FrameNode>& frameNode)
4633 {
4634 if (cachedItems_.empty()) {
4635 return;
4636 }
4637 auto pipelineContext = GetContext();
4638 CHECK_NULL_VOID(pipelineContext);
4639 pipelineContext->AddPredictTask(
4640 [weak = WeakClaim(RawPtr(frameNode))](int64_t deadline, bool canUseLongPredictTask) {
4641 auto frameNode = weak.Upgrade();
4642 CHECK_NULL_VOID(frameNode);
4643 auto pattern = frameNode->GetPattern<SwiperPattern>();
4644 CHECK_NULL_VOID(pattern);
4645 if (!canUseLongPredictTask || !pattern->GetRequestLongPredict()) {
4646 pattern->PostIdleTask(frameNode);
4647 return;
4648 }
4649 auto cachedItems = pattern->GetCachedItems();
4650 for (auto it = cachedItems.begin(); it != cachedItems.end();) {
4651 if (GetSysTimestamp() > deadline) {
4652 break;
4653 }
4654 ACE_SCOPED_TRACE("Swiper cached self index: %d", *it);
4655 auto wrapper = frameNode->GetOrCreateChildByIndex(*it, false, true);
4656 if (!wrapper) {
4657 it = cachedItems.erase(it);
4658 continue;
4659 }
4660 auto childNode = wrapper->GetHostNode();
4661 if (childNode) {
4662 childNode->GetGeometryNode()->SetParentLayoutConstraint(pattern->GetLayoutConstraint());
4663 FrameNode::ProcessOffscreenNode(childNode);
4664 }
4665 it = cachedItems.erase(it);
4666 }
4667 pattern->SetCachedItems(cachedItems);
4668 if (!cachedItems.empty()) {
4669 pattern->PostIdleTask(frameNode);
4670 }
4671 });
4672 }
4673
IsVisibleChildrenSizeLessThanSwiper() const4674 bool SwiperPattern::IsVisibleChildrenSizeLessThanSwiper() const
4675 {
4676 if (itemPosition_.empty() || GetDisplayCount() > TotalCount()) {
4677 return true;
4678 }
4679 const auto firstItem = GetFirstItemInfoInVisibleArea();
4680 const auto lastItem = GetLastItemInfoInVisibleArea();
4681 const int32_t visibleItemCnt = lastItem.first - firstItem.first + 1;
4682 if (TotalCount() != visibleItemCnt) {
4683 return false;
4684 }
4685 const float childrenLength = lastItem.second.endPos - firstItem.second.startPos;
4686 if (NonPositive(childrenLength)) {
4687 return true;
4688 }
4689 return LessOrEqual(childrenLength, CalculateVisibleSize());
4690 }
4691
UpdateItemRenderGroup(bool itemRenderGroup)4692 void SwiperPattern::UpdateItemRenderGroup(bool itemRenderGroup)
4693 {
4694 for (auto& item : itemPosition_) {
4695 if (auto frameNode = item.second.node) {
4696 groupedItems_.insert(frameNode);
4697 }
4698 }
4699 auto host = GetHost();
4700 CHECK_NULL_VOID(host);
4701 for (auto child : host->GetChildren()) {
4702 auto frameNode = DynamicCast<FrameNode>(child);
4703 if (!frameNode || child->GetTag() == V2::SWIPER_INDICATOR_ETS_TAG) {
4704 continue;
4705 }
4706 groupedItems_.insert(frameNode);
4707 }
4708 for (auto iter = groupedItems_.begin(); iter != groupedItems_.end();) {
4709 if (auto node = iter->Upgrade()) {
4710 auto context = node->GetRenderContext();
4711 CHECK_NULL_VOID(context);
4712 context->UpdateSuggestedRenderGroup(itemRenderGroup);
4713 ++iter;
4714 } else {
4715 iter = groupedItems_.erase(iter);
4716 }
4717 }
4718 }
4719
OnTranslateFinish(int32_t nextIndex,bool restartAutoPlay,bool isFinishAnimation,bool forceStop,bool isInterrupt)4720 void SwiperPattern::OnTranslateFinish(
4721 int32_t nextIndex, bool restartAutoPlay, bool isFinishAnimation, bool forceStop, bool isInterrupt)
4722 {
4723 if (forceStop && !isFinishAnimation) {
4724 TriggerAnimationEndOnForceStop(isInterrupt);
4725 } else {
4726 TriggerEventOnFinish(nextIndex);
4727 }
4728
4729 auto host = GetHost();
4730 CHECK_NULL_VOID(host);
4731 if (HasIndicatorNode()) {
4732 auto indicatorNode = GetCommonIndicatorNode();
4733 CHECK_NULL_VOID(indicatorNode);
4734 if (IsIndicator(indicatorNode->GetTag())) {
4735 indicatorNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4736 MarkDirtyNodeSelf();
4737 }
4738 }
4739
4740 auto delayTime = GetInterval() - GetDuration();
4741 delayTime = std::clamp(delayTime, 0, delayTime);
4742 if (NeedAutoPlay() && isUserFinish_ && !forceStop) {
4743 PostTranslateTask(delayTime);
4744 }
4745 UpdateItemRenderGroup(false);
4746 }
4747
OnWindowShow()4748 void SwiperPattern::OnWindowShow()
4749 {
4750 if (!isParentHiddenChange_) {
4751 FireWillShowEvent(currentIndex_);
4752 }
4753 isWindowShow_ = true;
4754 if (NeedStartAutoPlay()) {
4755 StartAutoPlay();
4756 }
4757 }
4758
OnWindowHide()4759 void SwiperPattern::OnWindowHide()
4760 {
4761 if (!isParentHiddenChange_) {
4762 FireWillHideEvent(currentIndex_);
4763 }
4764 isWindowShow_ = false;
4765 StopAutoPlay();
4766
4767 if (isDragging_) {
4768 HandleDragEnd(0.0);
4769 }
4770
4771 StopSpringAnimationAndFlushImmediately();
4772 }
4773
ArrowHover(bool isHover,SwiperHoverFlag flag)4774 void SwiperPattern::ArrowHover(bool isHover, SwiperHoverFlag flag)
4775 {
4776 if (isHover) {
4777 hoverFlag_ |= flag;
4778 } else {
4779 hoverFlag_ &= (~flag);
4780 }
4781 if (HasLeftButtonNode() && HasRightButtonNode()) {
4782 auto swiperNode = GetHost();
4783 CHECK_NULL_VOID(swiperNode);
4784 auto leftArrowNode =
4785 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetLeftButtonId())));
4786 CHECK_NULL_VOID(leftArrowNode);
4787 auto leftArrowPattern = leftArrowNode->GetPattern<SwiperArrowPattern>();
4788 CHECK_NULL_VOID(leftArrowPattern);
4789 leftArrowPattern->SetButtonVisible(hoverFlag_ != HOVER_NONE);
4790 auto rightArrowNode =
4791 DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(GetRightButtonId())));
4792 CHECK_NULL_VOID(rightArrowNode);
4793 auto rightArrowPattern = rightArrowNode->GetPattern<SwiperArrowPattern>();
4794 CHECK_NULL_VOID(rightArrowPattern);
4795 rightArrowPattern->SetButtonVisible(hoverFlag_ != HOVER_NONE);
4796 }
4797 }
4798
SaveArrowProperty(const RefPtr<FrameNode> & arrowNode)4799 void SwiperPattern::SaveArrowProperty(const RefPtr<FrameNode>& arrowNode)
4800 {
4801 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4802 CHECK_NULL_VOID(props);
4803 const auto paintProps = GetPaintProperty<SwiperPaintProperty>();
4804 CHECK_NULL_VOID(props);
4805 const auto arrowProps = arrowNode->GetLayoutProperty<SwiperArrowLayoutProperty>();
4806 CHECK_NULL_VOID(arrowProps);
4807 arrowProps->UpdateDirection(props->GetDirection().value_or(Axis::HORIZONTAL));
4808 arrowProps->UpdateIndex(props->GetIndex().value_or(0));
4809 arrowProps->UpdateLoop(props->GetLoop().value_or(true));
4810 arrowProps->UpdateEnabled(paintProps->GetEnabled().value_or(true));
4811 arrowProps->UpdateDisplayArrow(props->GetDisplayArrowValue());
4812 arrowProps->UpdateHoverShow(props->GetHoverShowValue());
4813 arrowProps->UpdateIsShowBackground(props->GetIsShowBackgroundValue());
4814 arrowProps->UpdateBackgroundSize(props->GetBackgroundSizeValue());
4815 arrowProps->UpdateBackgroundColor(props->GetBackgroundColorValue());
4816 arrowProps->UpdateArrowSize(props->GetArrowSizeValue());
4817 arrowProps->UpdateArrowColor(props->GetArrowColorValue());
4818 arrowProps->UpdateIsSidebarMiddle(props->GetIsSidebarMiddleValue());
4819 }
4820
SetAccessibilityAction()4821 void SwiperPattern::SetAccessibilityAction()
4822 {
4823 auto host = GetHost();
4824 CHECK_NULL_VOID(host);
4825 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
4826 CHECK_NULL_VOID(accessibilityProperty);
4827 accessibilityProperty->SetActionScrollForward(
4828 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
4829 const auto& pattern = weakPtr.Upgrade();
4830 CHECK_NULL_VOID(pattern);
4831 const auto& accessibilityProperty = accessibility.Upgrade();
4832 CHECK_NULL_VOID(accessibilityProperty);
4833 if (!accessibilityProperty->IsScrollable()) {
4834 return;
4835 }
4836 pattern->ShowNext(true);
4837 });
4838
4839 accessibilityProperty->SetActionScrollBackward(
4840 [weakPtr = WeakClaim(this), accessibility = WeakClaim(RawPtr(accessibilityProperty))]() {
4841 const auto& pattern = weakPtr.Upgrade();
4842 CHECK_NULL_VOID(pattern);
4843 const auto& accessibilityProperty = accessibility.Upgrade();
4844 CHECK_NULL_VOID(accessibilityProperty);
4845 if (!accessibilityProperty->IsScrollable()) {
4846 return;
4847 }
4848 pattern->ShowPrevious(true);
4849 });
4850 }
4851
NeedStartAutoPlay() const4852 bool SwiperPattern::NeedStartAutoPlay() const
4853 {
4854 return isWindowShow_ && isVisibleArea_;
4855 }
4856
ProvideRestoreInfo()4857 std::string SwiperPattern::ProvideRestoreInfo()
4858 {
4859 auto jsonObj = JsonUtil::Create(true);
4860 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4861 CHECK_NULL_RETURN(props, "");
4862 jsonObj->Put("Index", props->GetIndex().value_or(0));
4863 return jsonObj->ToString();
4864 }
4865
OnRestoreInfo(const std::string & restoreInfo)4866 void SwiperPattern::OnRestoreInfo(const std::string& restoreInfo)
4867 {
4868 auto props = GetLayoutProperty<SwiperLayoutProperty>();
4869 CHECK_NULL_VOID(props);
4870 auto info = JsonUtil::ParseJsonString(restoreInfo);
4871 if (!info->IsValid() || !info->IsObject()) {
4872 return;
4873 }
4874 auto jsonIsOn = info->GetValue("Index");
4875 props->UpdateIndex(jsonIsOn->GetInt());
4876 OnModifyDone();
4877 }
4878
InitHoverMouseEvent()4879 void SwiperPattern::InitHoverMouseEvent()
4880 {
4881 auto host = GetHost();
4882 CHECK_NULL_VOID(host);
4883 auto eventHub = host->GetEventHub<EventHub>();
4884 CHECK_NULL_VOID(eventHub);
4885 auto inputHub = eventHub->GetOrCreateInputEventHub();
4886 CHECK_NULL_VOID(inputHub);
4887
4888 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
4889 auto pattern = weak.Upgrade();
4890 CHECK_NULL_VOID(pattern);
4891 if (!pattern->IsShowIndicator()) {
4892 pattern->ArrowHover(isHover, HOVER_SWIPER);
4893 }
4894 };
4895
4896 if (!hoverEvent_) {
4897 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
4898 inputHub->AddOnHoverEvent(hoverEvent_);
4899 }
4900
4901 auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
4902 auto pattern = weak.Upgrade();
4903 if (pattern) {
4904 pattern->HandleMouseEvent(info);
4905 }
4906 };
4907 if (mouseEvent_) {
4908 inputHub->RemoveOnMouseEvent(mouseEvent_);
4909 }
4910 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
4911 inputHub->AddOnMouseEvent(mouseEvent_);
4912 }
4913
HandleMouseEvent(const MouseInfo & info)4914 void SwiperPattern::HandleMouseEvent(const MouseInfo& info)
4915 {
4916 auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
4917 auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
4918 auto mousePoint = PointF(mouseOffsetX, mouseOffsetY);
4919 if (IsShowIndicator()) {
4920 CheckAndSetArrowHoverState(mousePoint);
4921 }
4922 }
4923
CheckAndSetArrowHoverState(const PointF & mousePoint)4924 void SwiperPattern::CheckAndSetArrowHoverState(const PointF& mousePoint)
4925 {
4926 if (!HasLeftButtonNode() || !HasRightButtonNode() || !HasIndicatorNode()) {
4927 return;
4928 }
4929
4930 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4931 CHECK_NULL_VOID(props);
4932 if (props->GetIsSidebarMiddleValue(false)) {
4933 return;
4934 }
4935
4936 RectF leftNodeRect;
4937 RectF rightNodeRect;
4938
4939 leftNodeRect = GetArrowFrameRect(GetLeftButtonId());
4940 rightNodeRect = GetArrowFrameRect(GetRightButtonId());
4941
4942 if (!IsLoop() && GetLoopIndex(currentIndex_) == 0) {
4943 leftNodeRect = GetArrowFrameRect(GetIndicatorId());
4944 }
4945
4946 if (!IsLoop() && GetLoopIndex(currentIndex_) == TotalCount() - 1) {
4947 rightNodeRect = GetArrowFrameRect(GetIndicatorId());
4948 }
4949 RectF newNodeRect;
4950 if (GetDirection() == Axis::HORIZONTAL) {
4951 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(), rightNodeRect.Right() - leftNodeRect.Left(),
4952 std::min(rightNodeRect.Height(), leftNodeRect.Height()));
4953 } else {
4954 newNodeRect = RectF(leftNodeRect.Left(), leftNodeRect.Top(),
4955 std::min(rightNodeRect.Width(), leftNodeRect.Width()), rightNodeRect.Bottom() - leftNodeRect.Top());
4956 }
4957
4958 isAtHotRegion_ = newNodeRect.IsInRegion(mousePoint);
4959 ArrowHover(isAtHotRegion_, HOVER_SWIPER);
4960 }
4961
GetArrowFrameRect(const int32_t index) const4962 RectF SwiperPattern::GetArrowFrameRect(const int32_t index) const
4963 {
4964 auto swiperNode = GetHost();
4965 CHECK_NULL_RETURN(swiperNode, RectF(0, 0, 0, 0));
4966 auto arrowNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperNode->GetChildIndexById(index)));
4967 CHECK_NULL_RETURN(arrowNode, RectF(0, 0, 0, 0));
4968 auto arrowGeometryNode = arrowNode->GetGeometryNode();
4969 CHECK_NULL_RETURN(arrowGeometryNode, RectF(0, 0, 0, 0));
4970 return arrowGeometryNode->GetFrameRect();
4971 }
4972
GetCustomPropertyOffset() const4973 float SwiperPattern::GetCustomPropertyOffset() const
4974 {
4975 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4976 CHECK_NULL_RETURN(props, 0.0);
4977 auto paddingAndBorder = props->CreatePaddingAndBorder();
4978 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
4979 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
4980 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
4981 return Dimension(paddingAndBorderValue + GetPrevMarginWithItemSpace(), DimensionUnit::PX).ConvertToVp();
4982 }
4983
GetCustomPropertyTargetOffset() const4984 float SwiperPattern::GetCustomPropertyTargetOffset() const
4985 {
4986 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
4987 CHECK_NULL_RETURN(props, 0.0);
4988 auto paddingAndBorder = props->CreatePaddingAndBorder();
4989 auto paddingAndBorderValue = GetDirection() == Axis::HORIZONTAL
4990 ? paddingAndBorder.left.value_or(0.0) + tabsPaddingAndBorder_.left.value_or(0.0)
4991 : paddingAndBorder.top.value_or(0.0) + tabsPaddingAndBorder_.top.value_or(0.0);
4992
4993 auto preMarginPX = GetPrevMarginWithItemSpace();
4994 if (IsHorizontalAndRightToLeft()) {
4995 return Dimension(paddingAndBorderValue - preMarginPX, DimensionUnit::PX).ConvertToVp();
4996 }
4997 return Dimension(paddingAndBorderValue + preMarginPX, DimensionUnit::PX).ConvertToVp();
4998 }
4999
TotalDisPlayCount() const5000 int32_t SwiperPattern::TotalDisPlayCount() const
5001 {
5002 auto props = GetLayoutProperty<SwiperLayoutProperty>();
5003 CHECK_NULL_RETURN(props, 1);
5004 auto displayCount = GetDisplayCount();
5005 if (SwiperUtils::IsStretch(props)) {
5006 if (Positive(props->GetCalculatedPrevMargin())) {
5007 displayCount++;
5008 }
5009 if (Positive(props->GetCalculatedNextMargin())) {
5010 displayCount++;
5011 }
5012 }
5013 return displayCount;
5014 }
5015
MarkDirtyNodeSelf()5016 void SwiperPattern::MarkDirtyNodeSelf()
5017 {
5018 auto host = GetHost();
5019 CHECK_NULL_VOID(host);
5020 if (!crossMatchChild_) {
5021 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5022 } else {
5023 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5024 }
5025 }
5026
ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)5027 void SwiperPattern::ResetAndUpdateIndexOnAnimationEnd(int32_t nextIndex)
5028 {
5029 auto host = GetHost();
5030 CHECK_NULL_VOID(host);
5031 targetIndex_.reset();
5032 if (preTargetIndex_.has_value()) {
5033 preTargetIndex_.reset();
5034 }
5035
5036 if (isFinishAnimation_) {
5037 currentDelta_ = 0.0f;
5038 itemPosition_.clear();
5039 isVoluntarilyClear_ = true;
5040 jumpIndex_ = nextIndex;
5041 MarkDirtyNodeSelf();
5042 auto pipeline = PipelineContext::GetCurrentContext();
5043 if (pipeline) {
5044 pipeline->FlushUITasks();
5045 }
5046 isFinishAnimation_ = false;
5047 } else if (currentIndex_ != nextIndex) {
5048 UpdateCurrentIndex(nextIndex);
5049 if (currentFocusIndex_ < currentIndex_ || currentFocusIndex_ >= currentIndex_ + GetDisplayCount()) {
5050 currentFocusIndex_ = currentIndex_;
5051 }
5052 do {
5053 auto curChildFrame =
5054 DynamicCast<FrameNode>(host->GetOrCreateChildByIndex(GetLoopIndex(currentFocusIndex_)));
5055 if (!curChildFrame || !IsContentFocused()) {
5056 break;
5057 }
5058 FlushFocus(curChildFrame);
5059 } while (0);
5060 auto tempOldIndex = oldIndex_;
5061 oldIndex_ = nextIndex;
5062 currentFirstIndex_ = GetLoopIndex(nextIndex);
5063 turnPageRate_ = 0.0f;
5064 currentIndexOffset_ = 0.0f;
5065 auto pipeline = PipelineContext::GetCurrentContext();
5066 if (pipeline) {
5067 if (pipeline->IsLayouting()) {
5068 pipeline->FlushUITaskWithSingleDirtyNode(host);
5069 pipeline->FlushSyncGeometryNodeTasks();
5070 } else {
5071 pipeline->FlushUITasks();
5072 pipeline->FlushMessages();
5073 }
5074 }
5075 FireChangeEvent(tempOldIndex, GetLoopIndex(currentIndex_));
5076 // lazyBuild feature.
5077 SetLazyLoadFeature(true);
5078 }
5079 }
5080
OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child,float position,float)5081 void SwiperPattern::OnScrollStartRecursive(WeakPtr<NestableScrollContainer> child, float position, float /* velocity */)
5082 {
5083 SetIsNestedInterrupt(false);
5084 if (IsDisableSwipe()) {
5085 return;
5086 }
5087 childScrolling_ = true;
5088 gestureSwipeIndex_ = currentIndex_;
5089 StopAnimationOnScrollStart(false);
5090 NotifyParentScrollStart(child, position);
5091 }
5092
NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child,float position)5093 void SwiperPattern::NotifyParentScrollStart(WeakPtr<NestableScrollContainer> child, float position)
5094 {
5095 if (!GetIsFixedNestedScrollMode()) {
5096 SetParentScrollable();
5097 }
5098 auto parent = GetNestedScrollParent();
5099 CHECK_NULL_VOID(parent);
5100 const auto& nestedScroll = GetNestedScroll();
5101 if (parent && nestedScroll.NeedParent()) {
5102 parent->OnScrollStartRecursive(child, position);
5103 }
5104 }
5105
OnScrollEndRecursive(const std::optional<float> & velocity)5106 void SwiperPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
5107 {
5108 if (IsDisableSwipe()) {
5109 return;
5110 }
5111 // in case child didn't call swiper's HandleScrollVelocity
5112 if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
5113 HandleDragEnd(velocity.value_or(0.0f));
5114 }
5115 SetIsNestedInterrupt(false);
5116 childScrolling_ = false;
5117 InitIndexCanChangeMap();
5118 }
5119
OnScrollDragEndRecursive()5120 void SwiperPattern::OnScrollDragEndRecursive()
5121 {
5122 NestableScrollContainer::OnScrollDragEndRecursive();
5123 if (IsDisableSwipe()) {
5124 return;
5125 }
5126 // Swiper and child handle drag end event together.
5127 if (!DuringTranslateAnimation() && !DuringFadeAnimation()) {
5128 HandleDragEnd(0.0f);
5129 }
5130 }
5131
NotifyParentScrollEnd()5132 void SwiperPattern::NotifyParentScrollEnd()
5133 {
5134 auto parent = GetNestedScrollParent();
5135 const auto& nestedScroll = GetNestedScroll();
5136 if (parent && (nestedScroll.NeedParent() || GetIsNestedInterrupt())) {
5137 parent->OnScrollEndRecursive(std::nullopt);
5138 }
5139 }
5140
DuringTranslateAnimation() const5141 inline bool SwiperPattern::DuringTranslateAnimation() const
5142 {
5143 return (springAnimation_ && springAnimationIsRunning_ && !isTouchDownSpringAnimation_) || targetIndex_ ||
5144 usePropertyAnimation_ || translateAnimationIsRunning_;
5145 }
5146
RunningTranslateAnimation() const5147 inline bool SwiperPattern::RunningTranslateAnimation() const
5148 {
5149 return springAnimationIsRunning_ || usePropertyAnimation_ || translateAnimationIsRunning_;
5150 }
5151
DuringFadeAnimation() const5152 inline bool SwiperPattern::DuringFadeAnimation() const
5153 {
5154 return fadeAnimation_ && fadeAnimationIsRunning_ && !isTouchDownFadeAnimation_;
5155 }
5156
HandleScrollVelocity(float velocity,const RefPtr<NestableScrollContainer> & child)5157 bool SwiperPattern::HandleScrollVelocity(float velocity, const RefPtr<NestableScrollContainer>& child)
5158 {
5159 if (IsDisableSwipe()) {
5160 return false;
5161 }
5162 if (IsHorizontalAndRightToLeft()) {
5163 velocity = -velocity;
5164 }
5165 DestructSetter<bool> scope(childScrolling_, false);
5166 // haven't reached edge
5167 if (GetDistanceToEdge() > 0.0f || IsLoop()) {
5168 HandleDragEnd(velocity);
5169 return true;
5170 }
5171
5172 auto parent = GetNestedScrollParent();
5173 const auto nestedScroll = GetNestedScroll();
5174 if (parent && nestedScroll.NeedParent(NonPositive(velocity))) {
5175 // after reach end, parent handle velocity first
5176 if (parent->HandleScrollVelocity(velocity)) {
5177 return true;
5178 }
5179 }
5180 HandleDragEnd(velocity);
5181 // after reached end, NONE doesn't consume velocity, other edge effects do
5182 return GetEdgeEffect() != EdgeEffect::NONE;
5183 }
5184
HandleOutBoundary(float offset,int32_t source,float velocity)5185 ScrollResult SwiperPattern::HandleOutBoundary(float offset, int32_t source, float velocity)
5186 {
5187 float selfOffset = 0.0f;
5188 float remainOffset = offset;
5189 if (!IsLoop() && !itemPosition_.empty()) {
5190 if (Negative(offset) && itemPosition_.begin()->first == 0) {
5191 auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
5192 startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
5193 if (Positive(startPos)) {
5194 selfOffset = -std::min(startPos, -offset);
5195 remainOffset -= selfOffset;
5196 }
5197 } else if (Positive(offset) && itemPosition_.rbegin()->first == TotalCount() - 1) {
5198 auto visibleWindowSize = CalculateVisibleSize();
5199 auto endPos = itemPosition_.rbegin()->second.endPos + AdjustIgnoreBlankOverScrollOffSet(false);
5200 endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
5201 if (LessNotEqual(endPos, visibleWindowSize)) {
5202 selfOffset = std::min(visibleWindowSize - endPos, offset);
5203 remainOffset -= selfOffset;
5204 }
5205 }
5206 }
5207 auto parent = GetNestedScrollParent();
5208 if (!NearZero(remainOffset) && parent) {
5209 auto res = parent->HandleScroll(remainOffset, source, NestedState::CHILD_CHECK_OVER_SCROLL, velocity);
5210 remainOffset = res.remain;
5211 }
5212 if (!NearZero(selfOffset)) {
5213 UpdateCurrentOffset(selfOffset);
5214 }
5215 return { remainOffset, true };
5216 }
5217
HandleScroll(float offset,int32_t source,NestedState state,float velocity)5218 ScrollResult SwiperPattern::HandleScroll(float offset, int32_t source, NestedState state, float velocity)
5219 {
5220 if (state == NestedState::CHILD_CHECK_OVER_SCROLL) {
5221 return HandleOutBoundary(offset, source, velocity);
5222 }
5223 if (IsHorizontalAndRightToLeft() && state != NestedState::GESTURE) {
5224 offset = -offset;
5225 }
5226 if (IsDisableSwipe()) {
5227 return { offset, true };
5228 }
5229 if (source == SCROLL_FROM_ANIMATION && DuringTranslateAnimation()) {
5230 // deny conflicting animation from child
5231 return { offset, true };
5232 }
5233 if (!CheckSwiperPanEvent(offset) || !CheckContentWillScroll(offset, offset)) {
5234 return { offset, true };
5235 }
5236 if (state != NestedState::GESTURE) {
5237 // handle situations when multiple children are notifying scrollStart / scrollEnd
5238 // reset flag and animations to correct states when scroll happens
5239 childScrolling_ = true;
5240 if (DuringTranslateAnimation()) {
5241 StopAnimationOnScrollStart(false);
5242 }
5243 }
5244 // mouse scroll triggers showNext / showPrev instead of updating offset
5245 if (source == SCROLL_FROM_AXIS) {
5246 auto targetBfr = targetIndex_;
5247 (offset > 0) ? ShowPrevious() : ShowNext();
5248 if (targetBfr == targetIndex_) {
5249 // unchanged targetIndex_ implies Swiper has reached the edge and the mouse scroll isn't consumed.
5250 return { offset, true };
5251 }
5252 return { 0.0f, false };
5253 }
5254 auto parent = GetNestedScrollParent();
5255 auto nestedScroll = GetNestedScroll();
5256 if (!parent || !nestedScroll.NeedParent()) {
5257 if (IsOutOfBoundary(offset) && ChildFirst(state)) {
5258 CloseTheGap(offset);
5259 return { offset, true };
5260 }
5261 UpdateCurrentOffset(offset);
5262 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5263 }
5264 ScrollResult result = { 0.f, !IsLoop() && GetDistanceToEdge() <= 0.f };
5265 if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::PARENT_FIRST) ||
5266 (Positive(offset) && nestedScroll.backward == NestedScrollMode::PARENT_FIRST))) {
5267 result = HandleScrollParentFirst(offset, source, state, velocity);
5268 } else if (parent && ((Negative(offset) && nestedScroll.forward == NestedScrollMode::SELF_FIRST) ||
5269 (Positive(offset) && nestedScroll.backward == NestedScrollMode::SELF_FIRST))) {
5270 result = HandleScrollSelfFirst(offset, source, state, velocity);
5271 }
5272 return result;
5273 }
5274
HandleScrollParentFirst(float offset,int32_t source,NestedState state,float velocity)5275 ScrollResult SwiperPattern::HandleScrollParentFirst(float offset, int32_t source, NestedState state, float velocity)
5276 {
5277 // priority: parent scroll > self scroll > self overScroll > parent overScroll
5278 auto parent = GetNestedScrollParent();
5279 // skip CHECK_NULL, already checked in HandleScroll
5280 auto result = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
5281 offset = result.remain;
5282 if (IsOutOfBoundary(offset)) {
5283 if (NearZero(offset)) {
5284 return { 0.f, true };
5285 }
5286 CloseTheGap(offset);
5287 if (ChildFirst(state)) {
5288 if (result.reachEdge) {
5289 result = parent->HandleScroll(offset, source, NestedState::CHILD_OVER_SCROLL, velocity);
5290 }
5291 return { result.remain, true };
5292 }
5293 }
5294 // self Scroll && self overScroll
5295 UpdateCurrentOffset(offset);
5296 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5297 }
5298
HandleScrollSelfFirst(float offset,int32_t source,NestedState state,float velocity)5299 ScrollResult SwiperPattern::HandleScrollSelfFirst(float offset, int32_t source, NestedState state, float velocity)
5300 {
5301 // priority: self scroll > parent scroll > parent overScroll > self overScroll
5302 if ((IsOutOfStart(offset) && Positive(offset)) || (IsOutOfEnd(offset) && Negative(offset))) {
5303 CloseTheGap(offset);
5304 // skip CHECK_NULL, already checked in HandleScroll
5305 auto parent = GetNestedScrollParent();
5306
5307 // reached edge, pass offset to parent
5308 auto res = parent->HandleScroll(offset, source, NestedState::CHILD_SCROLL, velocity);
5309 if (res.remain == 0.0f) {
5310 return { 0.0f, true };
5311 }
5312 // parent handle overScroll first
5313 if (res.reachEdge) {
5314 res = parent->HandleScroll(res.remain, source, NestedState::CHILD_OVER_SCROLL, velocity);
5315 }
5316 if (ChildFirst(state)) {
5317 return { res.remain, true };
5318 }
5319 if (res.remain != 0.0f) {
5320 // self overScroll
5321 UpdateCurrentOffset(res.remain);
5322 }
5323 } else {
5324 // regular scroll
5325 UpdateCurrentOffset(offset);
5326 }
5327 return { 0.0f, !IsLoop() && GetDistanceToEdge() <= 0.0f };
5328 }
5329
CloseTheGap(float & offset)5330 void SwiperPattern::CloseTheGap(float& offset)
5331 {
5332 float distanceToEdge = GetDistanceToEdge();
5333 if (Positive(distanceToEdge)) {
5334 if (GreatOrEqual(std::abs(offset), distanceToEdge)) {
5335 UpdateCurrentOffset(Positive(offset) ? distanceToEdge : -distanceToEdge);
5336 offset = Positive(offset) ? offset - distanceToEdge : offset + distanceToEdge;
5337 }
5338 }
5339 }
5340
ChildFirst(NestedState state)5341 inline bool SwiperPattern::ChildFirst(NestedState state)
5342 {
5343 // SELF/CHILD priority: self scroll > child scroll > self overScroll > child overScroll
5344 return state == NestedState::CHILD_SCROLL // child hasn't reach edge
5345 || GetEdgeEffect() == EdgeEffect::NONE;
5346 }
5347
UpdateDragFRCSceneInfo(float speed,SceneStatus sceneStatus)5348 void SwiperPattern::UpdateDragFRCSceneInfo(float speed, SceneStatus sceneStatus)
5349 {
5350 auto host = GetHost();
5351 CHECK_NULL_VOID(host);
5352 host->AddFRCSceneInfo(SWIPER_DRAG_SCENE, speed, sceneStatus);
5353 }
5354
GetLoopIndex(int32_t index,int32_t childrenSize) const5355 int32_t SwiperPattern::GetLoopIndex(int32_t index, int32_t childrenSize) const
5356 {
5357 if (childrenSize <= 0) {
5358 return index;
5359 }
5360 auto loopIndex = index;
5361 while (loopIndex < 0) {
5362 loopIndex = loopIndex + childrenSize;
5363 }
5364 loopIndex %= childrenSize;
5365 return loopIndex;
5366 }
5367
DumpAdvanceInfo()5368 void SwiperPattern::DumpAdvanceInfo()
5369 {
5370 SwiperHelper::DumpAdvanceInfo(*this);
5371 }
5372
RegisterScrollingListener(const RefPtr<ScrollingListener> listener)5373 void SwiperPattern::RegisterScrollingListener(const RefPtr<ScrollingListener> listener)
5374 {
5375 CHECK_NULL_VOID(listener);
5376 scrollingListener_.emplace_back(listener);
5377 }
5378
FireAndCleanScrollingListener()5379 void SwiperPattern::FireAndCleanScrollingListener()
5380 {
5381 for (auto listener : scrollingListener_) {
5382 CHECK_NULL_VOID(listener);
5383 listener->NotifyScrollingEvent();
5384 }
5385 scrollingListener_.clear();
5386 }
5387
CleanScrollingListener()5388 void SwiperPattern::CleanScrollingListener()
5389 {
5390 scrollingListener_.clear();
5391 }
5392
IsSwipeByGroup() const5393 bool SwiperPattern::IsSwipeByGroup() const
5394 {
5395 auto layoutProperty = GetLayoutProperty<SwiperLayoutProperty>();
5396 CHECK_NULL_RETURN(layoutProperty, false);
5397 return layoutProperty->GetSwipeByGroup().value_or(false);
5398 }
5399
GetCurrentFrameNode(int32_t currentIndex) const5400 RefPtr<FrameNode> SwiperPattern::GetCurrentFrameNode(int32_t currentIndex) const
5401 {
5402 auto host = GetHost();
5403 CHECK_NULL_RETURN(host, nullptr);
5404 auto currentLayoutWrapper = host->GetChildByIndex(GetLoopIndex(currentIndex), true);
5405 CHECK_NULL_RETURN(currentLayoutWrapper, nullptr);
5406 return currentLayoutWrapper->GetHostNode();
5407 }
5408
OnCustomContentTransition(int32_t toIndex)5409 void SwiperPattern::OnCustomContentTransition(int32_t toIndex)
5410 {
5411 if (!currentProxyInAnimation_ && toIndex == CurrentIndex()) {
5412 return;
5413 }
5414
5415 customAnimationToIndex_ = toIndex;
5416 indexsInAnimation_.insert(toIndex);
5417 auto fromIndex = CurrentIndex();
5418 if (currentProxyInAnimation_) {
5419 fromIndex = currentProxyInAnimation_->GetToIndex();
5420
5421 FireChangeEvent(CurrentIndex(), fromIndex);
5422
5423 UpdateCurrentIndex(fromIndex);
5424 oldIndex_ = fromIndex;
5425
5426 AnimationCallbackInfo info;
5427 info.currentOffset = GetCustomPropertyOffset();
5428 FireAnimationEndEvent(fromIndex, info);
5429
5430 currentProxyInAnimation_->SetHasOnChanged(true);
5431 }
5432 if (fromIndex != toIndex) {
5433 FireWillShowEvent(toIndex);
5434 FireWillHideEvent(fromIndex);
5435 }
5436 auto pipelineContext = PipelineContext::GetCurrentContext();
5437 CHECK_NULL_VOID(pipelineContext);
5438
5439 pipelineContext->AddAfterLayoutTask([weak = WeakClaim(this), fromIndex, toIndex]() {
5440 auto swiperPattern = weak.Upgrade();
5441 CHECK_NULL_VOID(swiperPattern);
5442 swiperPattern->TriggerCustomContentTransitionEvent(fromIndex, toIndex);
5443 });
5444
5445 MarkDirtyNodeSelf();
5446 }
5447
TriggerCustomContentTransitionEvent(int32_t fromIndex,int32_t toIndex)5448 void SwiperPattern::TriggerCustomContentTransitionEvent(int32_t fromIndex, int32_t toIndex)
5449 {
5450 CHECK_NULL_VOID(onTabsCustomContentTransition_);
5451
5452 auto tabContentAnimatedTransition = (*onTabsCustomContentTransition_)(fromIndex, toIndex);
5453 auto transition = tabContentAnimatedTransition.transition;
5454
5455 if (!transition) {
5456 OnCustomAnimationFinish(fromIndex, toIndex, false);
5457 return;
5458 }
5459
5460 auto proxy = AceType::MakeRefPtr<TabContentTransitionProxy>();
5461 proxy->SetFromIndex(fromIndex);
5462 proxy->SetToIndex(toIndex);
5463 proxy->SetFinishTransitionEvent([weak = WeakClaim(this), fromIndex, toIndex](bool hasOnChanged) {
5464 auto swiperPattern = weak.Upgrade();
5465 CHECK_NULL_VOID(swiperPattern);
5466 swiperPattern->OnCustomAnimationFinish(fromIndex, toIndex, hasOnChanged);
5467 });
5468
5469 transition(proxy);
5470 currentProxyInAnimation_ = proxy;
5471
5472 AnimationCallbackInfo info;
5473 info.currentOffset = GetCustomPropertyOffset();
5474 info.targetOffset = GetCustomPropertyTargetOffset();
5475 FireAnimationStartEvent(fromIndex, toIndex, info);
5476
5477 auto pipeline = PipelineContext::GetCurrentContext();
5478 CHECK_NULL_VOID(pipeline);
5479 auto taskExecutor = pipeline->GetTaskExecutor();
5480 CHECK_NULL_VOID(taskExecutor);
5481
5482 auto timeout = tabContentAnimatedTransition.timeout;
5483 auto timeoutTask = [weak = AceType::WeakClaim(AceType::RawPtr(proxy)), fromIndex, toIndex] {
5484 auto transitionProxy = weak.Upgrade();
5485 CHECK_NULL_VOID(transitionProxy);
5486 transitionProxy->FinishTransition();
5487 };
5488
5489 taskExecutor->PostDelayedTask(timeoutTask, TaskExecutor::TaskType::UI, timeout, "ArkUISwiperFinishTransition");
5490 }
5491
OnCustomAnimationFinish(int32_t fromIndex,int32_t toIndex,bool hasOnChanged)5492 void SwiperPattern::OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged)
5493 {
5494 customAnimationToIndex_.reset();
5495 needUnmountIndexs_.insert(fromIndex);
5496 indexsInAnimation_.erase(toIndex);
5497
5498 if (!hasOnChanged) {
5499 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
5500 CHECK_NULL_VOID(props);
5501 props->UpdateIndexWithoutMeasure(GetLoopIndex(toIndex));
5502 oldIndex_ = fromIndex;
5503
5504 AnimationCallbackInfo info;
5505 info.currentOffset = GetCustomPropertyOffset();
5506 FireAnimationEndEvent(toIndex, info);
5507 }
5508
5509 if (indexsInAnimation_.empty()) {
5510 currentProxyInAnimation_ = nullptr;
5511 }
5512 auto curChildFrame = GetCurrentFrameNode(toIndex);
5513 if (curChildFrame) {
5514 FlushFocus(curChildFrame);
5515 }
5516 auto host = GetHost();
5517 CHECK_NULL_VOID(host);
5518 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5519 auto pipeline = PipelineContext::GetCurrentContext();
5520 if (pipeline) {
5521 pipeline->FlushUITasks();
5522 pipeline->FlushMessages();
5523 }
5524 }
5525
SetSwiperEventCallback(bool disableSwipe)5526 void SwiperPattern::SetSwiperEventCallback(bool disableSwipe)
5527 {
5528 CHECK_NULL_VOID(swiperController_);
5529 auto removeSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
5530 auto swiperPattern = weak.Upgrade();
5531 CHECK_NULL_VOID(swiperPattern);
5532 auto host = swiperPattern->GetHost();
5533 CHECK_NULL_VOID(host);
5534 auto hub = host->GetEventHub<EventHub>();
5535 CHECK_NULL_VOID(hub);
5536 auto gestureHub = hub->GetOrCreateGestureEventHub();
5537 CHECK_NULL_VOID(gestureHub);
5538 gestureHub->RemoveTouchEvent(swiperPattern->touchEvent_);
5539 if (!disableSwipe) {
5540 gestureHub->RemovePanEvent(swiperPattern->panEvent_);
5541 }
5542 };
5543 swiperController_->SetRemoveSwiperEventCallback(std::move(removeSwiperEventCallback));
5544
5545 auto addSwiperEventCallback = [weak = WeakClaim(this), disableSwipe]() {
5546 auto swiperPattern = weak.Upgrade();
5547 CHECK_NULL_VOID(swiperPattern);
5548 auto host = swiperPattern->GetHost();
5549 CHECK_NULL_VOID(host);
5550 auto hub = host->GetEventHub<EventHub>();
5551 CHECK_NULL_VOID(hub);
5552 auto gestureHub = hub->GetOrCreateGestureEventHub();
5553 CHECK_NULL_VOID(gestureHub);
5554 gestureHub->AddTouchEvent(swiperPattern->touchEvent_);
5555 if (!disableSwipe) {
5556 gestureHub->AddPanEvent(swiperPattern->panEvent_, swiperPattern->panDirection_, 1, DEFAULT_PAN_DISTANCE);
5557 }
5558 };
5559 swiperController_->SetAddSwiperEventCallback(std::move(addSwiperEventCallback));
5560 }
5561
UpdateSwiperPanEvent(bool disableSwipe)5562 void SwiperPattern::UpdateSwiperPanEvent(bool disableSwipe)
5563 {
5564 auto host = GetHost();
5565 CHECK_NULL_VOID(host);
5566 auto hub = host->GetEventHub<EventHub>();
5567 CHECK_NULL_VOID(hub);
5568 auto gestureHub = hub->GetOrCreateGestureEventHub();
5569 CHECK_NULL_VOID(gestureHub);
5570
5571 if (!disableSwipe) {
5572 InitPanEvent(gestureHub);
5573 } else if (panEvent_) {
5574 gestureHub->RemovePanEvent(panEvent_);
5575 panEvent_.Reset();
5576 if (isDragging_) {
5577 HandleDragEnd(0.0);
5578 }
5579 }
5580 }
5581
ProcessDelta(float & delta,float mainSize,float deltaSum)5582 void SwiperPattern::ProcessDelta(float& delta, float mainSize, float deltaSum)
5583 {
5584 if (std::abs(delta) > mainSize) {
5585 delta = delta > 0 ? mainSize : -mainSize;
5586 }
5587
5588 if ((std::abs(deltaSum + delta)) > mainSize) {
5589 delta = GreatNotEqual((deltaSum + delta), 0) ? (mainSize - deltaSum) : (-deltaSum - mainSize);
5590 }
5591 }
5592
ContentWillChange(int32_t comingIndex)5593 bool SwiperPattern::ContentWillChange(int32_t comingIndex)
5594 {
5595 return ContentWillChange(GetCurrentIndex(), comingIndex);
5596 }
5597
ContentWillChange(int32_t currentIndex,int32_t comingIndex)5598 bool SwiperPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
5599 {
5600 auto host = GetHost();
5601 CHECK_NULL_RETURN(host, true);
5602 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
5603 CHECK_NULL_RETURN(tabsNode, true);
5604 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
5605 CHECK_NULL_RETURN(tabsPattern, true);
5606 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
5607 CHECK_NULL_RETURN(tabBarNode, true);
5608 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
5609 CHECK_NULL_RETURN(tabBarPattern, true);
5610 if (!tabBarPattern->GetTabContentWillChangeFlag() && tabsPattern->GetInterceptStatus() &&
5611 currentIndex != comingIndex) {
5612 tabBarPattern->ResetTabContentWillChangeFlag();
5613 auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
5614 return ret.has_value() ? ret.value() : true;
5615 }
5616 tabBarPattern->ResetTabContentWillChangeFlag();
5617 return true;
5618 }
5619
ParseTabsIsRtl()5620 bool SwiperPattern::ParseTabsIsRtl()
5621 {
5622 auto host = GetHost();
5623 CHECK_NULL_RETURN(host, false);
5624 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
5625 CHECK_NULL_RETURN(tabsNode, false);
5626 auto tabLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
5627 CHECK_NULL_RETURN(tabLayoutProperty, false);
5628 bool isRTL = tabLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
5629 return isRTL;
5630 }
5631
CheckSwiperPanEvent(float mainDeltaOrVelocity)5632 bool SwiperPattern::CheckSwiperPanEvent(float mainDeltaOrVelocity)
5633 {
5634 int32_t currentIndex = GetCurrentIndex();
5635 int32_t comingIndex = currentIndex;
5636 auto isRtl = ParseTabsIsRtl();
5637 if (isRtl) {
5638 mainDeltaOrVelocity = -mainDeltaOrVelocity;
5639 }
5640 if (GreatNotEqual(mainDeltaOrVelocity, 0.0)) {
5641 comingIndex = comingIndex < 1 ? 0 : comingIndex - 1;
5642 } else if (LessNotEqual(mainDeltaOrVelocity, 0.0)) {
5643 comingIndex = comingIndex > TotalCount() - INDEX_DIFF_TWO ? TotalCount() - 1 : comingIndex + 1;
5644 }
5645
5646 auto iter = indexCanChangeMap_.find(comingIndex);
5647 if (iter != indexCanChangeMap_.end()) {
5648 return iter->second;
5649 }
5650 bool ret = ContentWillChange(currentIndex, comingIndex);
5651 indexCanChangeMap_.emplace(comingIndex, ret);
5652 return ret;
5653 }
5654
CalcFirstItemWithoutItemSpace() const5655 std::pair<int32_t, SwiperItemInfo> SwiperPattern::CalcFirstItemWithoutItemSpace() const
5656 {
5657 if (itemPosition_.empty()) {
5658 return std::make_pair(0, SwiperItemInfo {});
5659 }
5660 for (const auto& item : itemPosition_) {
5661 auto startPos = item.second.startPos;
5662 auto endPos = item.second.endPos;
5663 auto itemSpace = GetItemSpace();
5664 startPos -= itemSpace;
5665 if (startPos < 0 && endPos < 0) {
5666 continue;
5667 }
5668 if (startPos <= 0 && endPos > 0) {
5669 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, endPos });
5670 }
5671 if (startPos > 0 && endPos > 0) {
5672 return std::make_pair(item.first, SwiperItemInfo { item.second.startPos, endPos });
5673 }
5674 }
5675 return std::make_pair(itemPosition_.begin()->first,
5676 SwiperItemInfo { itemPosition_.begin()->second.startPos, itemPosition_.begin()->second.endPos });
5677 }
5678
CalcComingIndex(float mainDelta) const5679 int32_t SwiperPattern::CalcComingIndex(float mainDelta) const
5680 {
5681 auto firstItemInfoInVisibleArea = CalcFirstItemWithoutItemSpace();
5682 auto firstStartPos = firstItemInfoInVisibleArea.second.startPos;
5683 auto firstEndPos = firstItemInfoInVisibleArea.second.endPos;
5684 auto firstItemLength = firstEndPos - firstStartPos;
5685 if (LessOrEqual(firstItemLength, 0)) {
5686 return true;
5687 }
5688
5689 auto firstIndex = firstItemInfoInVisibleArea.first;
5690 auto step = 0;
5691 auto displayCount = GetDisplayCount();
5692 if (GreatNotEqual(mainDelta, 0.0)) {
5693 if (IsSwipeByGroup()) {
5694 step = -displayCount;
5695 } else if (firstIndex >= currentIndex_) {
5696 step = -1;
5697 } else {
5698 step = firstEndPos > firstItemLength ? firstIndex - currentIndex_ - 1 : firstIndex - currentIndex_;
5699 }
5700 } else if (LessNotEqual(mainDelta, 0.0)) {
5701 if (IsSwipeByGroup()) {
5702 step = displayCount;
5703 } else if (firstIndex <= currentIndex_) {
5704 step = 1;
5705 } else {
5706 step = firstIndex - currentIndex_;
5707 step += static_cast<int32_t>(std::ceil(std::abs(firstStartPos) / firstItemLength));
5708 }
5709 }
5710
5711 auto comingIndex = IsLoop() ? GetLoopIndex(currentIndex_ + step)
5712 : std::clamp(GetLoopIndex(currentIndex_) + step, 0, RealTotalCount() - 1);
5713 return comingIndex;
5714 }
5715
CalcWillScrollOffset(int32_t comingIndex)5716 float SwiperPattern::CalcWillScrollOffset(int32_t comingIndex)
5717 {
5718 if (itemPosition_.empty()) {
5719 return 0.0f;
5720 }
5721
5722 auto itemMainSize = CalculateVisibleSize();
5723 if (GetDisplayCount() > 1 && !IsSwipeByGroup()) {
5724 itemMainSize /= GetDisplayCount();
5725 }
5726
5727 if (NeedEnableIgnoreBlankOffset()) {
5728 auto currentIndex = GetLoopIndex(currentIndex_);
5729 comingIndex = GetLoopIndex(comingIndex);
5730 auto realLastIndex = RealTotalCount() - 1;
5731 auto secondIndex = 1;
5732 auto lastIndex = realLastIndex;
5733 auto penultimateIndex = realLastIndex - 1;
5734 if (IsSwipeByGroup()) {
5735 auto displayCount = GetDisplayCount();
5736 secondIndex = displayCount;
5737 lastIndex = SwiperUtils::ComputePageIndex(realLastIndex, displayCount);
5738 penultimateIndex = GetLoopIndex(lastIndex - displayCount);
5739 }
5740
5741 if (((currentIndex == 0 && comingIndex == secondIndex) || (currentIndex == secondIndex && comingIndex == 0)) &&
5742 prevMarginIgnoreBlank_) {
5743 auto offset = itemMainSize - GetPrevMargin();
5744 return offset;
5745 }
5746
5747 if (((currentIndex == penultimateIndex && comingIndex == lastIndex) ||
5748 (currentIndex == lastIndex && comingIndex == penultimateIndex)) &&
5749 nextMarginIgnoreBlank_) {
5750 auto offset = itemMainSize - GetNextMargin();
5751 return offset;
5752 }
5753 }
5754
5755 auto offset = itemMainSize + GetItemSpace();
5756 return offset;
5757 }
5758
CheckContentWillScroll(float checkValue,float mainDelta)5759 bool SwiperPattern::CheckContentWillScroll(float checkValue, float mainDelta)
5760 {
5761 if (itemPosition_.empty()) {
5762 return true;
5763 }
5764
5765 if (!HasOnContentWillScroll()) {
5766 return true;
5767 }
5768
5769 if (IsHorizontalAndRightToLeft()) {
5770 checkValue = -checkValue;
5771 mainDelta = -mainDelta;
5772 }
5773
5774 auto comingIndex = CalcComingIndex(checkValue);
5775 bool willScroll = ContentWillScroll(GetLoopIndex(currentIndex_), comingIndex, mainDelta);
5776 return willScroll;
5777 }
5778
ContentWillScroll(int32_t currentIndex,int32_t comingIndex,float offset)5779 bool SwiperPattern::ContentWillScroll(int32_t currentIndex, int32_t comingIndex, float offset)
5780 {
5781 currentIndex = GetLoopIndex(currentIndex);
5782 comingIndex = GetLoopIndex(comingIndex);
5783 auto result = OnContentWillScroll(currentIndex, comingIndex, offset);
5784 if (result && !result.value()) {
5785 return false;
5786 }
5787
5788 return true;
5789 }
5790
OnContentWillScroll(int32_t currentIndex,int32_t comingIndex,float offset) const5791 std::optional<bool> SwiperPattern::OnContentWillScroll(int32_t currentIndex, int32_t comingIndex, float offset) const
5792 {
5793 std::optional<bool> ret;
5794 if (!HasOnContentWillScroll()) {
5795 return ret;
5796 }
5797
5798 if (currentIndex != comingIndex) {
5799 auto event = *onContentWillScroll_;
5800 SwiperContentWillScrollResult result;
5801 result.currentIndex = currentIndex;
5802 result.comingIndex = comingIndex;
5803 result.offset = offset;
5804 ret = event(result);
5805 }
5806 return ret;
5807 }
5808
HandleTouchBottomLoopOnRTL()5809 void SwiperPattern::HandleTouchBottomLoopOnRTL()
5810 {
5811 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5812 auto currentIndex = GetLoopIndex(currentIndex_);
5813 bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
5814 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
5815 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
5816 if (followTouchBottom) {
5817 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
5818 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5819 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
5820 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5821 }
5822 return;
5823 }
5824
5825 if (currentFirstIndex == 0 && currentIndex == TotalCount() - 1 &&
5826 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT) {
5827 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5828 return;
5829 }
5830
5831 if (currentFirstIndex == TotalCount() - 1 && currentIndex == 0 &&
5832 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
5833 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5834 return;
5835 }
5836 }
5837
HandleTouchBottomLoop()5838 void SwiperPattern::HandleTouchBottomLoop()
5839 {
5840 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5841 auto currentIndex = GetLoopIndex(currentIndex_);
5842 if (IsHorizontalAndRightToLeft()) {
5843 currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
5844 currentIndex = TotalCount() - 1 - currentIndex;
5845 }
5846
5847 bool commTouchBottom = (currentFirstIndex == TotalCount() - 1);
5848 bool followTouchBottom = (commTouchBottom && (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT ||
5849 gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT));
5850 if (followTouchBottom) {
5851 if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
5852 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5853 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
5854 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5855 }
5856 return;
5857 }
5858
5859 bool leftReleaseTouchBottom = (commTouchBottom && (currentIndex == 0 && gestureState_ ==
5860 GestureState::GESTURE_STATE_RELEASE_LEFT));
5861 bool rightReleaseTouchBottom = ((currentFirstIndex == 0) && (currentIndex == TotalCount() - 1) &&
5862 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT);
5863 if (leftReleaseTouchBottom || rightReleaseTouchBottom) {
5864 if (currentIndex == 0) {
5865 // left bottom
5866 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT;
5867 } else if (currentIndex == TotalCount() - 1) {
5868 // right bottom
5869 touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT;
5870 }
5871 }
5872 return;
5873 }
5874
CalculateGestureStateOnRTL(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)5875 void SwiperPattern::CalculateGestureStateOnRTL(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
5876 {
5877 if (GreatNotEqual(additionalOffset, 0.0f)) {
5878 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
5879 needTurn_ = false;
5880 return;
5881 }
5882
5883 if (LessNotEqual(additionalOffset, 0.0f)) {
5884 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
5885 needTurn_ = false;
5886 return;
5887 }
5888
5889 auto currentIndex = GetLoopIndex(currentIndex_);
5890 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5891 if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
5892 needTurn_ = true;
5893 if (isTouchDown_ && GreatOrEqual(mainDeltaSum_, 0.0f)) {
5894 needTurn_ = false;
5895 }
5896 } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
5897 needTurn_ = true;
5898 if (isTouchDown_ && (LessOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
5899 needTurn_ = false;
5900 }
5901 }
5902
5903 if (!IsLoop()) {
5904 needTurn_ = false;
5905 }
5906
5907 if (currentFirstIndex >= currentIndex) {
5908 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
5909 return;
5910 }
5911
5912 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
5913 }
5914
CalculateGestureState(float additionalOffset,float currentTurnPageRate,int32_t preFirstIndex)5915 void SwiperPattern::CalculateGestureState(float additionalOffset, float currentTurnPageRate, int32_t preFirstIndex)
5916 {
5917 auto currentIndex = GetLoopIndex(currentIndex_);
5918 auto currentFirstIndex = GetLoopIndex(currentFirstIndex_);
5919 if (IsHorizontalAndRightToLeft()) {
5920 preFirstIndex = TotalCount() - 1 - preFirstIndex;
5921 currentFirstIndex = TotalCount() - 1 - currentFirstIndex;
5922 currentIndex = TotalCount() - 1 - currentIndex;
5923 }
5924
5925 // Keep follow hand
5926 if (preFirstIndex == 0 && currentFirstIndex == TotalCount() - 1) {
5927 needTurn_ = true;
5928 if (isTouchDown_ && LessOrEqual(mainDeltaSum_, 0.0f)) {
5929 needTurn_ = false;
5930 }
5931 } else if (preFirstIndex == TotalCount() - 1 && currentFirstIndex == 0) {
5932 needTurn_ = true;
5933 if (isTouchDown_ && (GreatOrEqual(mainDeltaSum_, 0.0f) || currentIndex == 0)) {
5934 needTurn_ = false;
5935 }
5936 }
5937
5938 if (GreatNotEqual(additionalOffset, 0.0f)) {
5939 gestureState_ = GestureState::GESTURE_STATE_RELEASE_LEFT;
5940 needTurn_ = false;
5941 } else if (LessNotEqual(additionalOffset, 0.0f)) {
5942 gestureState_ = GestureState::GESTURE_STATE_RELEASE_RIGHT;
5943 needTurn_ = false;
5944 } else if (currentFirstIndex >= currentIndex) {
5945 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_LEFT : GestureState::GESTURE_STATE_FOLLOW_RIGHT;
5946
5947 if (!IsLoop() && currentFirstIndex == 0 && GreatOrEqual(mainDeltaSum_, 0.0f)) {
5948 gestureState_ = GestureState::GESTURE_STATE_FOLLOW_LEFT;
5949 needTurn_ = false;
5950 }
5951
5952 if (!IsLoop() && currentFirstIndex == TotalCount() - 1 && LessOrEqual(mainDeltaSum_, 0.0f)) {
5953 gestureState_ = GestureState::GESTURE_STATE_FOLLOW_RIGHT;
5954 needTurn_ = false;
5955 }
5956 } else if (currentFirstIndex < currentIndex) {
5957 gestureState_ = needTurn_ ? GestureState::GESTURE_STATE_FOLLOW_RIGHT : GestureState::GESTURE_STATE_FOLLOW_LEFT;
5958 }
5959 return;
5960 }
5961
CalcCurrentPageStatusOnRTL(float additionalOffset) const5962 std::pair<float, float> SwiperPattern::CalcCurrentPageStatusOnRTL(float additionalOffset) const
5963 {
5964 float currentTurnPageRate = FLT_MAX;
5965 auto firstIndex = currentFirstIndex_;
5966 auto itemMainSize = CalculateVisibleSize();
5967 for (auto iter = itemPosition_.rbegin(); iter != itemPosition_.rend(); iter++) {
5968 auto startPos = itemMainSize - iter->second.endPos;
5969 auto endPos = itemMainSize - iter->second.startPos;
5970 if (LessNotEqual((startPos + additionalOffset), 0) && LessNotEqual((endPos + additionalOffset), 0)) {
5971 continue;
5972 }
5973 if (GreatOrEqual((startPos + additionalOffset), 0) && GreatNotEqual((endPos + additionalOffset), 0)) {
5974 firstIndex = iter->first;
5975 currentTurnPageRate = 0.0f;
5976 break;
5977 }
5978 if (GreatNotEqual((endPos + additionalOffset), 0)) {
5979 firstIndex = iter->first;
5980 currentTurnPageRate =
5981 (NearEqual(endPos, startPos) ? 0 : ((startPos + additionalOffset) / (endPos - startPos)));
5982 break;
5983 }
5984 }
5985
5986 return std::make_pair(currentTurnPageRate, firstIndex);
5987 }
5988
CalcCurrentPageStatus(float additionalOffset) const5989 std::pair<float, float> SwiperPattern::CalcCurrentPageStatus(float additionalOffset) const
5990 {
5991 float currentTurnPageRate = FLT_MAX;
5992 auto firstIndex = currentFirstIndex_;
5993 for (const auto& iter : itemPosition_) {
5994 if (LessNotEqual((iter.second.startPos + additionalOffset), 0) &&
5995 LessNotEqual((iter.second.endPos + additionalOffset), 0)) {
5996 continue;
5997 }
5998 if (GreatOrEqual((iter.second.startPos + additionalOffset), 0) &&
5999 GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
6000 firstIndex = iter.first;
6001 currentTurnPageRate = 0.0f;
6002 break;
6003 }
6004 if (GreatNotEqual((iter.second.endPos + additionalOffset), 0)) {
6005 firstIndex = iter.first;
6006 currentTurnPageRate =
6007 (NearEqual(iter.second.endPos, iter.second.startPos)
6008 ? 0
6009 : ((iter.second.startPos + additionalOffset) / (iter.second.endPos - iter.second.startPos)));
6010 break;
6011 }
6012 }
6013
6014 return std::make_pair(currentTurnPageRate, firstIndex);
6015 }
6016
StopIndicatorAnimation(bool ifImmediately)6017 void SwiperPattern::StopIndicatorAnimation(bool ifImmediately)
6018 {
6019 AnimationUtils::StopAnimation(indicatorAnimation_);
6020
6021 if (stopIndicatorAnimationFunc_) {
6022 stopIndicatorAnimationFunc_(ifImmediately);
6023 }
6024 }
6025
FireWillHideEvent(int32_t willHideIndex) const6026 void SwiperPattern::FireWillHideEvent(int32_t willHideIndex) const
6027 {
6028 if (!hasTabsAncestor_) {
6029 return;
6030 }
6031 auto host = GetHost();
6032 CHECK_NULL_VOID(host);
6033 auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willHideIndex));
6034 CHECK_NULL_VOID(tabContentNode);
6035 auto tabContentEventHub = tabContentNode->GetEventHub<TabContentEventHub>();
6036 CHECK_NULL_VOID(tabContentEventHub);
6037 tabContentEventHub->FireWillHideEvent();
6038 }
6039
FireWillShowEvent(int32_t willShowIndex) const6040 void SwiperPattern::FireWillShowEvent(int32_t willShowIndex) const
6041 {
6042 if (!hasTabsAncestor_) {
6043 return;
6044 }
6045 auto host = GetHost();
6046 CHECK_NULL_VOID(host);
6047 auto tabContentNode = AceType::DynamicCast<TabContentNode>(host->GetChildByIndex(willShowIndex));
6048 CHECK_NULL_VOID(tabContentNode);
6049 auto tabContentEventHub = tabContentNode->GetEventHub<TabContentEventHub>();
6050 CHECK_NULL_VOID(tabContentEventHub);
6051 tabContentEventHub->FireWillShowEvent();
6052 }
6053
SetOnHiddenChangeForParent()6054 void SwiperPattern::SetOnHiddenChangeForParent()
6055 {
6056 auto host = GetHost();
6057 CHECK_NULL_VOID(host);
6058 auto parent = host->GetAncestorNodeOfFrame(false);
6059 CHECK_NULL_VOID(parent);
6060 while (parent) {
6061 if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6062 break;
6063 }
6064 parent = parent->GetAncestorNodeOfFrame(false);
6065 }
6066 auto onHiddenChange = [weak = WeakClaim(this)](bool isShow) {
6067 auto swiperPattern = weak.Upgrade();
6068 CHECK_NULL_VOID(swiperPattern);
6069 auto index = swiperPattern->GetCurrentIndex();
6070
6071 if (isShow) {
6072 swiperPattern->FireWillShowEvent(index);
6073 } else {
6074 swiperPattern->FireWillHideEvent(index);
6075 }
6076 swiperPattern->isParentHiddenChange_ = true;
6077 };
6078 CHECK_NULL_VOID(parent);
6079 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
6080 auto pagePattern = parent->GetPattern<PagePattern>();
6081 CHECK_NULL_VOID(pagePattern);
6082 pagePattern->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
6083 }
6084
6085 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6086 auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
6087 CHECK_NULL_VOID(navDestinationePattern);
6088 auto navDestinationEventHub = navDestinationePattern->GetEventHub<NavDestinationEventHub>();
6089 CHECK_NULL_VOID(navDestinationEventHub);
6090 navDestinationEventHub->AddOnHiddenChange(host->GetId(), std::move(onHiddenChange));
6091 }
6092 }
6093
RemoveOnHiddenChange()6094 void SwiperPattern::RemoveOnHiddenChange()
6095 {
6096 auto host = GetHost();
6097 CHECK_NULL_VOID(host);
6098 auto parent = host->GetAncestorNodeOfFrame(false);
6099 CHECK_NULL_VOID(parent);
6100 while (parent) {
6101 if (parent->GetTag() == V2::PAGE_ETS_TAG || parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6102 break;
6103 }
6104 parent = parent->GetAncestorNodeOfFrame(false);
6105 }
6106 CHECK_NULL_VOID(parent);
6107 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
6108 auto pagePattern = parent->GetPattern<PagePattern>();
6109 CHECK_NULL_VOID(pagePattern);
6110 pagePattern->RemoveOnHiddenChange(host->GetId());
6111 }
6112 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
6113 auto navDestinationePattern = parent->GetPattern<NavDestinationPattern>();
6114 CHECK_NULL_VOID(navDestinationePattern);
6115 auto navDestinationEventHub = navDestinationePattern->GetEventHub<NavDestinationEventHub>();
6116 CHECK_NULL_VOID(navDestinationEventHub);
6117 navDestinationEventHub->RemoveOnHiddenChange(host->GetId());
6118 }
6119 }
6120
FindLazyForEachNode(RefPtr<UINode> baseNode,bool isSelfNode) const6121 std::optional<RefPtr<UINode>> SwiperPattern::FindLazyForEachNode(RefPtr<UINode> baseNode, bool isSelfNode) const
6122 {
6123 if (AceType::DynamicCast<LazyForEachNode>(baseNode)) {
6124 return baseNode;
6125 }
6126 if (AceType::DynamicCast<RepeatVirtualScrollNode>(baseNode)) {
6127 return baseNode;
6128 }
6129 if (!isSelfNode && AceType::DynamicCast<FrameNode>(baseNode)) {
6130 return std::nullopt;
6131 }
6132 for (const auto& child : baseNode->GetChildren()) {
6133 auto targetNode = FindLazyForEachNode(child, false);
6134 if (targetNode.has_value()) {
6135 return targetNode;
6136 }
6137 }
6138 return std::nullopt;
6139 }
6140
CreateNodePaintMethod()6141 RefPtr<NodePaintMethod> SwiperPattern::CreateNodePaintMethod()
6142 {
6143 const auto props = GetLayoutProperty<SwiperLayoutProperty>();
6144 CHECK_NULL_RETURN(props, nullptr);
6145 const auto& paddingProperty = props->GetPaddingProperty();
6146 bool needClipPadding = paddingProperty != nullptr;
6147 bool needPaintFade = !IsLoop() && GetEdgeEffect() == EdgeEffect::FADE && !NearZero(fadeOffset_);
6148 auto paintMethod = MakeRefPtr<SwiperPaintMethod>(GetDirection(), fadeOffset_);
6149 paintMethod->SetNeedPaintFade(needPaintFade);
6150 paintMethod->SetNeedClipPadding(needClipPadding);
6151 return paintMethod;
6152 }
6153
UpdateNodeRate()6154 void SwiperPattern::UpdateNodeRate()
6155 {
6156 auto host = GetHost();
6157 CHECK_NULL_VOID(host);
6158 auto pipelineContext = host->GetContext();
6159 CHECK_NULL_VOID(pipelineContext);
6160 auto frameRateManager = pipelineContext->GetFrameRateManager();
6161 CHECK_NULL_VOID(frameRateManager);
6162 auto nodeId = host->GetId();
6163 auto iter = frameRateRange_.find(SwiperDynamicSyncSceneType::GESTURE);
6164 if (iter != frameRateRange_.end() && iter->second->IsValid()) {
6165 auto expectedRate = iter->second->preferred_;
6166 TAG_LOGI(AceLogTag::ACE_SWIPER, "Expected gesture frame rate is: %{public}d", expectedRate);
6167 frameRateManager->UpdateNodeRate(nodeId, expectedRate);
6168 }
6169 }
6170
GetMaxDisplayCount() const6171 int32_t SwiperPattern::GetMaxDisplayCount() const
6172 {
6173 if (!swiperParameters_ || !swiperParameters_->maxDisplayCountVal.has_value()) {
6174 return 0;
6175 }
6176
6177 auto maxDisplayCount = swiperParameters_->maxDisplayCountVal.value();
6178 if (maxDisplayCount < MAX_DISPLAY_COUNT_MIN || maxDisplayCount > MAX_DISPLAY_COUNT_MAX) {
6179 return 0;
6180 }
6181
6182 auto childrenSize = RealTotalCount();
6183 if (childrenSize <= maxDisplayCount) {
6184 return 0;
6185 }
6186
6187 return maxDisplayCount;
6188 }
6189
SetIndicatorChangeIndexStatus(bool withAnimation,std::optional<int32_t> startIndex)6190 void SwiperPattern::SetIndicatorChangeIndexStatus(bool withAnimation, std::optional<int32_t> startIndex)
6191 {
6192 auto indicatorNode = GetCommonIndicatorNode();
6193 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
6194 return;
6195 }
6196
6197 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
6198 CHECK_NULL_VOID(indicatorPattern);
6199
6200 indicatorPattern->SetChangeIndexWithAnimation(withAnimation);
6201 indicatorPattern->SetStartIndex(startIndex);
6202 }
6203
SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)6204 void SwiperPattern::SetIndicatorJumpIndex(std::optional<int32_t> jumpIndex)
6205 {
6206 if (GetMaxDisplayCount() <= 0) {
6207 return;
6208 }
6209 auto indicatorNode = GetCommonIndicatorNode();
6210 if (!indicatorNode || !IsIndicator(indicatorNode->GetTag())) {
6211 return;
6212 }
6213
6214 auto indicatorPattern = indicatorNode->GetPattern<SwiperIndicatorPattern>();
6215 CHECK_NULL_VOID(indicatorPattern);
6216
6217 indicatorPattern->SetJumpIndex(jumpIndex);
6218 }
6219
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const6220 void SwiperPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
6221 {
6222 Pattern::ToJsonValue(json, filter);
6223 /* no fixed attr below, just return */
6224 if (filter.IsFastFilter()) {
6225 return;
6226 }
6227
6228 auto nestedScroll = GetNestedScroll().forward;
6229 json->PutExtAttr("nestedScroll",
6230 nestedScroll == NestedScrollMode::SELF_ONLY ? "SwiperNestedScrollMode.SELF_ONLY"
6231 : "SwiperNestedScrollMode.SELF_FIRST",
6232 filter);
6233 json->PutExtAttr("currentIndex", currentIndex_, filter);
6234 json->PutExtAttr("currentOffset", currentOffset_, filter);
6235 json->PutExtAttr("uiCastJumpIndex", uiCastJumpIndex_.value_or(-1), filter);
6236
6237 if (indicatorIsBoolean_) {
6238 return;
6239 }
6240
6241 auto indicatorType = GetIndicatorType();
6242 if (indicatorType == SwiperIndicatorType::DOT) {
6243 json->PutExtAttr("indicator", SwiperHelper::GetDotIndicatorStyle(GetSwiperParameters()).c_str(), filter);
6244 } else {
6245 json->PutExtAttr(
6246 "indicator", SwiperHelper::GetDigitIndicatorStyle(GetSwiperDigitalParameters()).c_str(), filter);
6247 }
6248 }
6249
FromJson(const std::unique_ptr<JsonValue> & json)6250 void SwiperPattern::FromJson(const std::unique_ptr<JsonValue>& json)
6251 {
6252 currentIndex_ = json->GetInt("currentIndex");
6253 auto currentOffset = json->GetDouble("currentOffset");
6254 auto jumpIndex = json->GetInt("uiCastJumpIndex");
6255 if (currentOffset != currentOffset_) {
6256 auto delta = currentOffset - currentOffset_;
6257 UpdateCurrentOffset(delta);
6258 } else if (jumpIndex >= 0) {
6259 jumpIndex_ = jumpIndex;
6260 MarkDirtyNodeSelf();
6261 }
6262 Pattern::FromJson(json);
6263 }
6264
GetGestureState()6265 GestureState SwiperPattern::GetGestureState()
6266 {
6267 auto gestureState = gestureState_;
6268 if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
6269 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
6270 gestureState_ = GestureState::GESTURE_STATE_NONE;
6271 }
6272
6273 return gestureState;
6274 }
6275
SetSwiperController(const RefPtr<SwiperController> & controller)6276 void SwiperPattern::SetSwiperController(const RefPtr<SwiperController>& controller)
6277 {
6278 swiperController_ = controller;
6279 SwiperHelper::InitSwiperController(controller, WeakClaim(this));
6280 }
6281
IsItemOverlay() const6282 bool SwiperPattern::IsItemOverlay() const
6283 {
6284 if (itemPosition_.empty()) {
6285 return false;
6286 }
6287 float lastItemEndPos = 0.0f;
6288 for (auto& item : itemPosition_) {
6289 auto frameNode = item.second.node;
6290 if (!frameNode) {
6291 continue;
6292 }
6293 auto renderContext = frameNode->GetRenderContext();
6294 if (!renderContext) {
6295 continue;
6296 }
6297 RectF rect = renderContext->GetPaintRectWithoutTransform();
6298 if (item.first == itemPosition_.begin()->first) {
6299 lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
6300 continue;
6301 }
6302 float currentItemStartPos = direction_ == Axis::HORIZONTAL ? rect.Left() : rect.Top();
6303 if (GreatNotEqual(lastItemEndPos, currentItemStartPos)) {
6304 return true;
6305 }
6306 lastItemEndPos = direction_ == Axis::HORIZONTAL ? rect.Right() : rect.Bottom();
6307 }
6308 return false;
6309 }
6310
CheckSpecialItemCount() const6311 void SwiperPattern::CheckSpecialItemCount() const
6312 {
6313 auto swiperNode = AceType::DynamicCast<SwiperNode>(GetHost());
6314 CHECK_NULL_VOID(swiperNode);
6315 swiperNode->SetSpecialItemCount(indicatorId_.has_value() + leftButtonId_.has_value() + rightButtonId_.has_value() +
6316 leftCaptureId_.has_value() + rightCaptureId_.has_value());
6317 }
6318
GetCommonIndicatorNode()6319 RefPtr<FrameNode> SwiperPattern::GetCommonIndicatorNode()
6320 {
6321 if (isBindIndicator_) {
6322 return GetIndicatorNode();
6323 } else {
6324 CHECK_NULL_RETURN(indicatorId_.has_value(), nullptr);
6325 auto host = GetHost();
6326 CHECK_NULL_RETURN(host, nullptr);
6327 return DynamicCast<FrameNode>(host->GetChildAtIndex(host->GetChildIndexById(GetIndicatorId())));
6328 }
6329 }
6330
SetIndicatorNode(const WeakPtr<NG::UINode> & indicatorNode)6331 void SwiperPattern::SetIndicatorNode(const WeakPtr<NG::UINode>& indicatorNode)
6332 {
6333 if (isBindIndicator_) {
6334 indicatorNode_ = indicatorNode;
6335 auto host = GetHost();
6336 CHECK_NULL_VOID(host);
6337 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6338
6339 auto frameIndicatorNode = GetIndicatorNode();
6340 CHECK_NULL_VOID(frameIndicatorNode);
6341 frameIndicatorNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6342 }
6343 }
6344
SetPageFlipMode(int32_t pageFlipMode)6345 void SwiperPattern::SetPageFlipMode(int32_t pageFlipMode)
6346 {
6347 if (pageFlipMode < 0 || pageFlipMode > PAGE_FLIP_MODE_SIZE - 1) {
6348 pageFlipMode_ = PageFlipMode::CONTINUOUS;
6349 return;
6350 }
6351 pageFlipMode_ = static_cast<PageFlipMode>(pageFlipMode);
6352 }
6353 } // namespace OHOS::Ace::NG
6354