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