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