• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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