1 /* 2 * Copyright (c) 2023-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_NG_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_NG_H 18 19 #include <functional> 20 21 #include "base/geometry/dimension.h" 22 #include "core/animation/animator.h" 23 #include "core/animation/friction_motion.h" 24 #include "core/animation/scroll_motion.h" 25 #include "core/components_ng/base/frame_scene_status.h" 26 #include "core/components_ng/gestures/recognizers/pan_recognizer.h" 27 #include "core/components_ng/pattern/scrollable/scrollable_properties.h" 28 #include "core/components_ng/render/animation_utils.h" 29 #include "core/event/axis_event.h" 30 #include "core/event/touch_event.h" 31 #include "core/gestures/raw_recognizer.h" 32 #include "core/gestures/timeout_recognizer.h" 33 34 namespace OHOS::Ace::NG { 35 enum class NestedState { 36 GESTURE = 0, 37 CHILD_SCROLL, 38 CHILD_OVER_SCROLL, 39 CHILD_CHECK_OVER_SCROLL, 40 }; 41 42 struct OverScrollOffset { 43 double start; 44 double end; 45 }; 46 47 struct ScrollResult { 48 double remain; 49 bool reachEdge; 50 }; 51 52 using ScrollEventCallback = std::function<void()>; 53 using OutBoundaryCallback = std::function<bool()>; 54 using ScrollOverCallback = std::function<void(double velocity)>; 55 using WatchFixCallback = std::function<double(double final, double current)>; 56 using ScrollBeginCallback = std::function<ScrollInfo(Dimension, Dimension)>; 57 using ScrollFrameBeginCallback = std::function<ScrollFrameResult(Dimension, ScrollState)>; 58 using DragEndForRefreshCallback = std::function<void()>; 59 using DragCancelRefreshCallback = std::function<void()>; 60 using MouseLeftButtonScroll = std::function<bool()>; 61 using ScrollSnapCallback = std::function<bool(double targetOffset, double velocity)>; 62 using ContinuousSlidingCallback = std::function<double()>; 63 using CalePredictSnapOffsetCallback = 64 std::function<std::optional<float>(float delta, float dragDistance, float velocity)>; 65 using NeedScrollSnapToSideCallback = std::function<bool(float delta)>; 66 using NestableScrollCallback = std::function<ScrollResult(float, int32_t, NestedState)>; 67 using DragFRCSceneCallback = std::function<void(double velocity, NG::SceneStatus sceneStatus)>; 68 using IsReverseCallback = std::function<bool()>; 69 using RemainVelocityCallback = std::function<bool(float)>; 70 71 class FrameNode; 72 class PipelineContext; 73 74 class Scrollable : public TouchEventTarget { 75 DECLARE_ACE_TYPE(Scrollable, TouchEventTarget); 76 77 public: 78 Scrollable(); 79 Scrollable(ScrollPositionCallback&& callback, Axis axis); 80 Scrollable(const ScrollPositionCallback& callback, Axis axis); 81 ~Scrollable() override; 82 83 static void SetVelocityScale(double sVelocityScale); 84 static double GetVelocityScale(); 85 static void SetFriction(double sFriction); 86 87 void Initialize(const WeakPtr<PipelineBase>& context); 88 89 void Initialize(PipelineContext* context); 90 IsMotionStop()91 bool IsMotionStop() const 92 { 93 return isSpringAnimationStop_ && isFrictionAnimationStop_ && !moved_; 94 } 95 IsSpringMotionRunning()96 bool IsSpringMotionRunning() const 97 { 98 return !isSpringAnimationStop_; 99 } 100 IsDragging()101 bool IsDragging() const 102 { 103 return isTouching_ && !isFrictionAnimationStop_; 104 } 105 106 void SetAxis(Axis axis); 107 GetMainOffset(const Offset & offset)108 double GetMainOffset(const Offset& offset) const 109 { 110 return axis_ == Axis::HORIZONTAL ? offset.GetX() : offset.GetY(); 111 } 112 GetMainSize(const Size & size)113 double GetMainSize(const Size& size) const 114 { 115 return axis_ == Axis::HORIZONTAL ? size.Width() : size.Height(); 116 } 117 SetCallback(const ScrollPositionCallback & callback)118 void SetCallback(const ScrollPositionCallback& callback) 119 { 120 callback_ = callback; 121 } 122 SetCoordinateOffset(const Offset & offset)123 void SetCoordinateOffset(const Offset& offset) const 124 { 125 if (panRecognizerNG_) { 126 panRecognizerNG_->SetCoordinateOffset(offset); 127 } 128 } 129 130 void OnCollectTouchTarget(TouchTestResult& result, const RefPtr<FrameNode>& frameNode, 131 const RefPtr<TargetComponent>& targetComponent, ResponseLinkResult& responseLinkResult); 132 SetDragTouchRestrict(const TouchRestrict & touchRestrict)133 void SetDragTouchRestrict(const TouchRestrict& touchRestrict) 134 { 135 if (panRecognizerNG_) { 136 panRecognizerNG_->SetTouchRestrict(touchRestrict); 137 } 138 } 139 SetScrollEndCallback(const ScrollEventCallback & scrollEndCallback)140 void SetScrollEndCallback(const ScrollEventCallback& scrollEndCallback) 141 { 142 scrollEndCallback_ = scrollEndCallback; 143 } 144 SetScrollTouchUpCallback(const ScrollEventCallback & scrollTouchUpCallback)145 void SetScrollTouchUpCallback(const ScrollEventCallback& scrollTouchUpCallback) 146 { 147 scrollTouchUpCallback_ = scrollTouchUpCallback; 148 } 149 SetUnstaticFriction(double friction)150 void SetUnstaticFriction(double friction) 151 { 152 friction_ = friction; 153 } 154 155 void HandleTouchDown(); 156 void HandleTouchUp(); 157 void HandleTouchCancel(); 158 void HandleDragStart(const GestureEvent& info); 159 void HandleDragUpdate(const GestureEvent& info); 160 void HandleDragEnd(const GestureEvent& info); 161 void HandleScrollEnd(const std::optional<float>& velocity); 162 bool HandleOverScroll(double velocity); 163 ScrollResult HandleScroll(double offset, int32_t source, NestedState state); 164 void LayoutDirectionEst(double& correctVelocity); 165 SetMoved(bool value)166 void SetMoved(bool value) 167 { 168 moved_ = value; 169 } SetCanOverScroll(bool value)170 void SetCanOverScroll(bool value) 171 { 172 canOverScroll_ = value; 173 } CanOverScroll()174 bool CanOverScroll() const 175 { 176 return canOverScroll_; 177 } 178 179 void ProcessScrollMotionStop(bool StopFriction); 180 DispatchEvent(const TouchEvent & point)181 bool DispatchEvent(const TouchEvent& point) override 182 { 183 return true; 184 } HandleEvent(const TouchEvent & event)185 bool HandleEvent(const TouchEvent& event) override 186 { 187 if (!available_) { 188 return true; 189 } 190 return true; 191 } HandleEvent(const AxisEvent & event)192 bool HandleEvent(const AxisEvent& event) override 193 { 194 return false; 195 } 196 SetScrollEnd(const ScrollEventCallback & scrollEnd)197 void SetScrollEnd(const ScrollEventCallback& scrollEnd) 198 { 199 scrollEnd_ = scrollEnd; 200 } 201 SetRemainVelocityCallback(const RemainVelocityCallback & remainVelocityCallback)202 void SetRemainVelocityCallback(const RemainVelocityCallback& remainVelocityCallback) 203 { 204 remainVelocityCallback_ = remainVelocityCallback; 205 } 206 SetScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)207 void SetScrollOverCallBack(const ScrollOverCallback& scrollOverCallback) 208 { 209 scrollOverCallback_ = scrollOverCallback; 210 } 211 SetNotifyScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)212 void SetNotifyScrollOverCallBack(const ScrollOverCallback& scrollOverCallback) 213 { 214 notifyScrollOverCallback_ = scrollOverCallback; 215 } 216 SetCurrentPositionCallback(const std::function<double ()> & currentPositionCallback)217 void SetCurrentPositionCallback(const std::function<double()>& currentPositionCallback) 218 { 219 currentPositionCallback_ = currentPositionCallback; 220 } 221 SetOutBoundaryCallback(const OutBoundaryCallback & outBoundaryCallback)222 void SetOutBoundaryCallback(const OutBoundaryCallback& outBoundaryCallback) 223 { 224 outBoundaryCallback_ = outBoundaryCallback; 225 } 226 SetDragEndCallback(const DragEndForRefreshCallback & dragEndCallback)227 void SetDragEndCallback(const DragEndForRefreshCallback& dragEndCallback) 228 { 229 dragEndCallback_ = dragEndCallback; 230 } 231 SetDragCancelCallback(const DragCancelRefreshCallback & dragCancelCallback)232 void SetDragCancelCallback(const DragCancelRefreshCallback& dragCancelCallback) 233 { 234 dragCancelCallback_ = dragCancelCallback; 235 } 236 GetDragEndCallback()237 const DragEndForRefreshCallback& GetDragEndCallback() const 238 { 239 return dragEndCallback_; 240 } 241 GetDragCancelCallback()242 const DragCancelRefreshCallback& GetDragCancelCallback() const 243 { 244 return dragCancelCallback_; 245 } 246 SetWatchFixCallback(const WatchFixCallback & watchFixCallback)247 void SetWatchFixCallback(const WatchFixCallback& watchFixCallback) 248 { 249 watchFixCallback_ = watchFixCallback; 250 } 251 MarkNeedCenterFix(bool needFix)252 void MarkNeedCenterFix(bool needFix) 253 { 254 needCenterFix_ = needFix; 255 } 256 GetCurrentVelocity()257 double GetCurrentVelocity() const 258 { 259 return currentVelocity_; 260 }; 261 SetIsReverseCallback(const IsReverseCallback & isReverseCallback)262 void SetIsReverseCallback(const IsReverseCallback& isReverseCallback) 263 { 264 isReverseCallback_ = isReverseCallback; 265 } 266 267 void OnAnimateStop(); 268 void ProcessScrollSnapStop(); 269 void StartSpringMotion( 270 double mainPosition, double mainVelocity, const ExtentPair& extent, const ExtentPair& initExtent); 271 void UpdateSpringMotion(double mainPosition, const ExtentPair& extent, const ExtentPair& initExtent); 272 273 void UpdateScrollSnapStartOffset(double offset); 274 void StartScrollSnapMotion(float predictSnapOffset, float scrollSnapVelocity); 275 void UpdateScrollSnapEndWithOffset(double offset); 276 277 bool IsAnimationNotRunning() const; 278 279 bool Idle() const; 280 281 bool IsStopped() const; 282 283 bool IsSpringStopped() const; 284 285 bool IsSnapStopped() const; 286 287 void StopScrollable(); 288 Available()289 bool Available() const 290 { 291 return available_; 292 } 293 MarkAvailable(bool available)294 void MarkAvailable(bool available) 295 { 296 available_ = available; 297 } 298 GetContext()299 WeakPtr<PipelineBase> GetContext() const 300 { 301 return context_; 302 } 303 SetNodeId(int32_t nodeId)304 void SetNodeId(int32_t nodeId) 305 { 306 nodeId_ = nodeId; 307 } 308 SetNodeTag(const std::string & nodeTag)309 void SetNodeTag(const std::string& nodeTag) 310 { 311 nodeTag_ = nodeTag; 312 } 313 314 void ProcessScrollOverCallback(double velocity); 315 316 void SetSlipFactor(double SlipFactor); 317 ChangeMoveStatus(bool flag)318 void ChangeMoveStatus(bool flag) 319 { 320 moved_ = flag; 321 } 322 SetOnScrollBegin(const ScrollBeginCallback & scrollBeginCallback)323 void SetOnScrollBegin(const ScrollBeginCallback& scrollBeginCallback) 324 { 325 scrollBeginCallback_ = scrollBeginCallback; 326 } 327 SetOnContinuousSliding(const ContinuousSlidingCallback & continuousSlidingCallback)328 void SetOnContinuousSliding(const ContinuousSlidingCallback& continuousSlidingCallback) 329 { 330 continuousSlidingCallback_ = continuousSlidingCallback; 331 } 332 SetHandleScrollCallback(NestableScrollCallback && func)333 void SetHandleScrollCallback(NestableScrollCallback&& func) 334 { 335 handleScrollCallback_ = std::move(func); 336 } SetOverScrollCallback(std::function<bool (float)> && func)337 void SetOverScrollCallback(std::function<bool(float)>&& func) 338 { 339 overScrollCallback_ = std::move(func); 340 } 341 void StartScrollAnimation(float mainPosition, float velocity); SetOnScrollStartRec(std::function<void (float)> && func)342 void SetOnScrollStartRec(std::function<void(float)>&& func) 343 { 344 onScrollStartRec_ = std::move(func); 345 } SetOnScrollEndRec(std::function<void (const std::optional<float> &)> && func)346 void SetOnScrollEndRec(std::function<void(const std::optional<float>&)>&& func) 347 { 348 onScrollEndRec_ = std::move(func); 349 } 350 SetEdgeEffect(EdgeEffect effect)351 void SetEdgeEffect(EdgeEffect effect) 352 { 353 edgeEffect_ = effect; 354 } 355 SetOnScrollSnapCallback(const ScrollSnapCallback & scrollSnapCallback)356 void SetOnScrollSnapCallback(const ScrollSnapCallback& scrollSnapCallback) 357 { 358 scrollSnapCallback_ = scrollSnapCallback; 359 } SetContinuousDragStatus(bool status)360 void SetContinuousDragStatus(bool status) 361 { 362 continuousDragStatus_ = status; 363 } IncreaseContinueDragCount()364 void IncreaseContinueDragCount() 365 { 366 dragCount_++; 367 } ResetContinueDragCount()368 void ResetContinueDragCount() 369 { 370 dragCount_ = 1; 371 } SetDragStartPosition(double position)372 void SetDragStartPosition(double position) 373 { 374 dragStartPosition_ = position; 375 } SetDragEndPosition(double position)376 void SetDragEndPosition(double position) 377 { 378 dragEndPosition_ = position; 379 } GetDragOffset()380 double GetDragOffset() 381 { 382 return dragEndPosition_ - dragStartPosition_; 383 } 384 SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback && calePredictSnapOffsetCallback)385 void SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback&& calePredictSnapOffsetCallback) 386 { 387 calePredictSnapOffsetCallback_ = std::move(calePredictSnapOffsetCallback); 388 } 389 SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback && needScrollSnapToSideCallback)390 void SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback&& needScrollSnapToSideCallback) 391 { 392 needScrollSnapToSideCallback_ = std::move(needScrollSnapToSideCallback); 393 } 394 395 void ProcessScrollSnapSpringMotion(float scrollSnapDelta, float scrollSnapVelocity); 396 StopSnapController()397 void StopSnapController() 398 { 399 if (!isSnapAnimationStop_) { 400 StopSnapAnimation(); 401 } 402 } 403 GetCurrentPos()404 double GetCurrentPos() const 405 { 406 return currentPos_; 407 } 408 GetNeedScrollSnapChange()409 bool GetNeedScrollSnapChange() const 410 { 411 return needScrollSnapChange_; 412 } 413 AddPreviewMenuHandleDragEnd(GestureEventFunc && actionEnd)414 void AddPreviewMenuHandleDragEnd(GestureEventFunc&& actionEnd) 415 { 416 AddPanActionEndEvent(std::move(actionEnd)); 417 } 418 GetIsDragging()419 bool GetIsDragging() const 420 { 421 return isDragging_; 422 } 423 SetDragFRCSceneCallback(DragFRCSceneCallback && dragFRCSceneCallback)424 void SetDragFRCSceneCallback(DragFRCSceneCallback&& dragFRCSceneCallback) 425 { 426 dragFRCSceneCallback_ = std::move(dragFRCSceneCallback); 427 } 428 GetFinalPosition()429 float GetFinalPosition() 430 { 431 return finalPosition_; 432 } 433 GetSnapFinalPosition()434 float GetSnapFinalPosition() 435 { 436 return endPos_; 437 } 438 SetMaxFlingVelocity(double max)439 void SetMaxFlingVelocity(double max) 440 { 441 double density = PipelineBase::GetCurrentDensity(); 442 maxFlingVelocity_ = max * density; 443 } 444 GetMaxFlingVelocity()445 double GetMaxFlingVelocity() const 446 { 447 return maxFlingVelocity_; 448 } 449 450 void StopFrictionAnimation(); 451 void StopSpringAnimation(bool reachFinalPosition = false); 452 void StopSnapAnimation(); 453 454 RefPtr<NodeAnimatablePropertyFloat> GetFrictionProperty(); 455 RefPtr<NodeAnimatablePropertyFloat> GetSpringProperty(); 456 RefPtr<NodeAnimatablePropertyFloat> GetSnapProperty(); 457 GetPanDirection()458 Axis GetPanDirection() const 459 { 460 CHECK_NULL_RETURN(panRecognizerNG_, Axis::NONE); 461 return panRecognizerNG_->GetAxisDirection(); 462 } 463 SetNestedScrolling(bool nestedScrolling)464 void SetNestedScrolling(bool nestedScrolling) 465 { 466 nestedScrolling_ = nestedScrolling; 467 } 468 GetNestedScrolling()469 bool GetNestedScrolling() const 470 { 471 return nestedScrolling_; 472 } 473 AddPanActionEndEvent(GestureEventFunc && event)474 void AddPanActionEndEvent(GestureEventFunc&& event) 475 { 476 panActionEndEvents_.emplace_back(event); 477 } 478 479 private: 480 bool UpdateScrollPosition(double offset, int32_t source) const; 481 void ProcessSpringMotion(double position); 482 void ProcessScrollMotion(double position); 483 void ProcessScrollSnapMotion(double position); 484 void FixScrollMotion(float position, float initVelocity); 485 void ExecuteScrollBegin(double& mainDelta); 486 double ComputeCap(int dragCount); 487 double GetGain(double delta); 488 void SetDelayedTask(); 489 void MarkNeedFlushAnimationStartTime(); 490 float GetFrictionVelocityByFinalPosition( 491 float final, float position, float signum, float friction, float threshold = DEFAULT_MULTIPLIER); 492 493 /** 494 * @brief Checks if the scroll event is caused by a mouse wheel. 495 * 496 * @param info The GestureEvent containing the scroll event information. 497 * @return true if the scroll event is caused by a mouse wheel, false otherwise. 498 */ 499 static inline bool IsMouseWheelScroll(const GestureEvent& info); 500 501 ScrollPositionCallback callback_; 502 ScrollEventCallback scrollEnd_; 503 ScrollEventCallback scrollEndCallback_; 504 ScrollEventCallback scrollTouchUpCallback_; 505 ScrollOverCallback scrollOverCallback_; // scroll motion controller when edge set to spring 506 ScrollOverCallback notifyScrollOverCallback_; // scroll motion controller when edge set to spring 507 OutBoundaryCallback outBoundaryCallback_; // whether out of boundary check when edge set to spring 508 std::function<double()> currentPositionCallback_; 509 IsReverseCallback isReverseCallback_; 510 511 WatchFixCallback watchFixCallback_; 512 ScrollBeginCallback scrollBeginCallback_; 513 ScrollSnapCallback scrollSnapCallback_; 514 DragEndForRefreshCallback dragEndCallback_; 515 DragCancelRefreshCallback dragCancelCallback_; 516 ContinuousSlidingCallback continuousSlidingCallback_; 517 Axis axis_ = Axis::VERTICAL; 518 // used for ng structure. 519 RefPtr<NG::PanRecognizer> panRecognizerNG_; 520 521 WeakPtr<PipelineBase> context_; 522 double currentPos_ = 0.0; 523 double currentVelocity_ = 0.0; 524 double maxFlingVelocity_ = 0.0; 525 bool scrollPause_ = false; 526 bool touchUp_ = false; 527 bool moved_ = false; 528 bool isTouching_ = false; 529 bool isDragging_ = false; 530 bool available_ = true; 531 bool needCenterFix_ = false; 532 bool isDragUpdateStop_ = false; 533 bool isFadingAway_ = false; 534 // The accessibilityId of UINode 535 int32_t nodeId_ = 0; 536 // The tag of UINode 537 std::string nodeTag_ = "Scrollable"; 538 double slipFactor_ = 0.0; 539 static std::optional<double> sFriction_; 540 static std::optional<double> sVelocityScale_; 541 bool continuousDragStatus_ = false; 542 CancelableCallback<void()> task_; 543 int32_t dragCount_ = 0; 544 double lastPos_ = 0.0; 545 double dragStartPosition_ = 0.0; 546 double dragEndPosition_ = 0.0; 547 double lastVelocity_ = 0.0; 548 double friction_ = -1.0; 549 double velocityScale_ = 0.0; 550 double preGain_ = 1.0; 551 #ifdef OHOS_PLATFORM 552 int64_t startIncreaseTime_ = 0; 553 #endif 554 555 // ScrollablePattern::HandleScroll 556 NestableScrollCallback handleScrollCallback_; 557 // ScrollablePattern::HandleOverScroll 558 std::function<bool(float)> overScrollCallback_; 559 // ScrollablePattern::onScrollStartRecursiveInner 560 std::function<void(float)> onScrollStartRec_; 561 // ScrollablePattern::onScrollEndRecursiveInner 562 std::function<void(const std::optional<float>&)> onScrollEndRec_; 563 // ScrollablePattern::RemainVelocityToChild 564 RemainVelocityCallback remainVelocityCallback_; 565 566 EdgeEffect edgeEffect_ = EdgeEffect::NONE; 567 bool canOverScroll_ = true; 568 569 // scrollSnap 570 bool needScrollSnapChange_ = false; 571 CalePredictSnapOffsetCallback calePredictSnapOffsetCallback_; 572 NeedScrollSnapToSideCallback needScrollSnapToSideCallback_; 573 std::list<GestureEventFunc> panActionEndEvents_; 574 575 DragFRCSceneCallback dragFRCSceneCallback_; 576 577 uint64_t lastVsyncTime_ = 0; 578 RefPtr<NodeAnimatablePropertyFloat> frictionOffsetProperty_; 579 float finalPosition_ = 0.0f; 580 float lastPosition_ = 0.0f; 581 float initVelocity_ = 0.0f; 582 float frictionVelocity_ = 0.0f; 583 double lastMainDelta_ = 0.0; 584 bool isFrictionAnimationStop_ = true; 585 586 RefPtr<NodeAnimatablePropertyFloat> springOffsetProperty_; 587 bool isSpringAnimationStop_ = true; 588 bool skipRestartSpring_ = false; // set to true when need to skip repeated spring animation 589 uint32_t updateSnapAnimationCount_ = 0; 590 uint32_t springAnimationCount_ = 0; 591 592 RefPtr<NodeAnimatablePropertyFloat> snapOffsetProperty_; 593 bool isSnapAnimationStop_ = true; 594 bool isSnapScrollAnimationStop_ = true; 595 float snapVelocity_ = 0.0f; 596 float endPos_ = 0.0; 597 bool isSnapAnimation_ = false; 598 bool nestedScrolling_ = false; 599 bool isSlow_ = false; 600 }; 601 602 } // namespace OHOS::Ace::NG 603 604 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_NG_H 605