1 /* 2 * Copyright (c) 2021-2022 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_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_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/gestures/recognizers/pan_recognizer.h" 26 #include "core/components_ng/pattern/scrollable/scrollable_properties.h" 27 #include "core/event/axis_event.h" 28 #include "core/event/touch_event.h" 29 #include "core/gestures/pan_recognizer.h" 30 #include "core/gestures/raw_recognizer.h" 31 #include "core/gestures/timeout_recognizer.h" 32 #include "core/pipeline/base/related_node.h" 33 #include "core/pipeline/base/render_node.h" 34 35 namespace OHOS::Ace { 36 enum class NestedState { 37 GESTURE = 0, 38 CHILD_SCROLL, 39 CHILD_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 = std::function<std::optional<float>(float delta)>; 64 using NeedScrollSnapToSideCallback = std::function<bool(float delta)>; 65 66 class Scrollable : public TouchEventTarget, public RelatedChild { 67 DECLARE_ACE_TYPE(Scrollable, TouchEventTarget); 68 69 public: 70 Scrollable() = default; Scrollable(ScrollPositionCallback && callback,Axis axis)71 Scrollable(ScrollPositionCallback&& callback, Axis axis) : callback_(std::move(callback)), axis_(axis) {} Scrollable(const ScrollPositionCallback & callback,Axis axis)72 Scrollable(const ScrollPositionCallback& callback, Axis axis) : callback_(callback), axis_(axis) {} 73 ~Scrollable() override; 74 75 static void SetVelocityScale(double sVelocityScale); 76 static void SetFriction(double sFriction); 77 78 void Initialize(const WeakPtr<PipelineBase>& context); 79 IsMotionStop()80 bool IsMotionStop() const 81 { 82 return (springController_ ? (!springController_->IsRunning()) : true) && 83 (controller_ ? (!controller_->IsRunning()) : true) && !moved_; 84 } 85 IsSpringMotionRunning()86 bool IsSpringMotionRunning() const 87 { 88 return springController_ ? springController_->IsRunning() : false; 89 } 90 IsDragging()91 bool IsDragging() const 92 { 93 return isTouching_ && controller_->IsRunning(); 94 } 95 96 void SetAxis(Axis axis); 97 SetScrollableNode(const WeakPtr<RenderNode> & node)98 void SetScrollableNode(const WeakPtr<RenderNode>& node) 99 { 100 scrollableNode_ = node; 101 } 102 GetMainOffset(const Offset & offset)103 double GetMainOffset(const Offset& offset) const 104 { 105 return axis_ == Axis::HORIZONTAL ? offset.GetX() : offset.GetY(); 106 } 107 GetMainSize(const Size & size)108 double GetMainSize(const Size& size) const 109 { 110 return axis_ == Axis::HORIZONTAL ? size.Width() : size.Height(); 111 } 112 SetCallback(const ScrollPositionCallback & callback)113 void SetCallback(const ScrollPositionCallback& callback) 114 { 115 callback_ = callback; 116 } 117 SetCoordinateOffset(const Offset & offset)118 void SetCoordinateOffset(const Offset& offset) const 119 { 120 if (panRecognizer_) { 121 panRecognizer_->SetCoordinateOffset(offset); 122 } 123 124 if (panRecognizerNG_) { 125 panRecognizerNG_->SetCoordinateOffset(offset); 126 } 127 128 if (rawRecognizer_) { 129 rawRecognizer_->SetCoordinateOffset(offset); 130 } 131 } 132 OnCollectTouchTarget(TouchTestResult & result)133 void OnCollectTouchTarget(TouchTestResult& result) 134 { 135 if (panRecognizerNG_) { 136 result.emplace_back(panRecognizerNG_); 137 } 138 139 if (rawRecognizer_) { 140 result.emplace_back(rawRecognizer_); 141 } 142 } 143 SetDragTouchRestrict(const TouchRestrict & touchRestrict)144 void SetDragTouchRestrict(const TouchRestrict& touchRestrict) 145 { 146 if (panRecognizer_) { 147 panRecognizer_->SetTouchRestrict(touchRestrict); 148 } 149 if (panRecognizerNG_) { 150 panRecognizerNG_->SetTouchRestrict(touchRestrict); 151 } 152 } 153 SetScrollEndCallback(const ScrollEventCallback & scrollEndCallback)154 void SetScrollEndCallback(const ScrollEventCallback& scrollEndCallback) 155 { 156 scrollEndCallback_ = scrollEndCallback; 157 } 158 SetScrollTouchUpCallback(const ScrollEventCallback & scrollTouchUpCallback)159 void SetScrollTouchUpCallback(const ScrollEventCallback& scrollTouchUpCallback) 160 { 161 scrollTouchUpCallback_ = scrollTouchUpCallback; 162 } 163 SetUnstaticFriction(double friction)164 void SetUnstaticFriction(double friction) 165 { 166 friction_ = friction; 167 } 168 169 void HandleTouchDown(); 170 void HandleTouchUp(); 171 void HandleTouchCancel(); 172 void HandleDragStart(const GestureEvent& info); 173 void HandleDragUpdate(const GestureEvent& info); 174 void HandleDragEnd(const GestureEvent& info); 175 void HandleScrollEnd(); 176 bool HandleOverScroll(double velocity); 177 ScrollResult HandleScroll(double offset, int32_t source, NestedState state); 178 ScrollResult HandleScrollParentFirst(double& offset, int32_t source, NestedState state); 179 ScrollResult HandleScrollSelfFirst(double& offset, int32_t source, NestedState state); 180 ScrollResult HandleScrollSelfOnly(double& offset, int32_t source, NestedState state); 181 ScrollResult HandleScrollParallel(double& offset, int32_t source, NestedState state); 182 183 void ProcessScrollMotionStop(); 184 DispatchEvent(const TouchEvent & point)185 bool DispatchEvent(const TouchEvent& point) override 186 { 187 return true; 188 } HandleEvent(const TouchEvent & event)189 bool HandleEvent(const TouchEvent& event) override 190 { 191 if (!available_) { 192 return true; 193 } 194 if (panRecognizer_) { 195 panRecognizer_->HandleEvent(event); 196 } 197 if (rawRecognizer_) { 198 return rawRecognizer_->HandleEvent(event); 199 } 200 return true; 201 } HandleEvent(const AxisEvent & event)202 bool HandleEvent(const AxisEvent& event) override 203 { 204 if (panRecognizer_) { 205 return panRecognizer_->HandleEvent(event); 206 } 207 return false; 208 } 209 SetScrollEnd(const ScrollEventCallback & scrollEnd)210 void SetScrollEnd(const ScrollEventCallback& scrollEnd) 211 { 212 scrollEnd_ = scrollEnd; 213 } 214 SetScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)215 void SetScrollOverCallBack(const ScrollOverCallback& scrollOverCallback) 216 { 217 scrollOverCallback_ = scrollOverCallback; 218 } 219 SetNotifyScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)220 void SetNotifyScrollOverCallBack(const ScrollOverCallback& scrollOverCallback) 221 { 222 notifyScrollOverCallback_ = scrollOverCallback; 223 } 224 SetOutBoundaryCallback(const OutBoundaryCallback & outBoundaryCallback)225 void SetOutBoundaryCallback(const OutBoundaryCallback& outBoundaryCallback) 226 { 227 outBoundaryCallback_ = outBoundaryCallback; 228 } 229 SetDragEndCallback(const DragEndForRefreshCallback & dragEndCallback)230 void SetDragEndCallback(const DragEndForRefreshCallback& dragEndCallback) 231 { 232 dragEndCallback_ = dragEndCallback; 233 } 234 SetDragCancelCallback(const DragCancelRefreshCallback & dragCancelCallback)235 void SetDragCancelCallback(const DragCancelRefreshCallback& dragCancelCallback) 236 { 237 dragCancelCallback_ = dragCancelCallback; 238 } 239 GetDragEndCallback()240 const DragEndForRefreshCallback& GetDragEndCallback() const 241 { 242 return dragEndCallback_; 243 } 244 GetDragCancelCallback()245 const DragCancelRefreshCallback& GetDragCancelCallback() const 246 { 247 return dragCancelCallback_; 248 } 249 SetWatchFixCallback(const WatchFixCallback & watchFixCallback)250 void SetWatchFixCallback(const WatchFixCallback& watchFixCallback) 251 { 252 watchFixCallback_ = watchFixCallback; 253 } 254 MarkNeedCenterFix(bool needFix)255 void MarkNeedCenterFix(bool needFix) 256 { 257 needCenterFix_ = needFix; 258 } 259 GetCurrentVelocity()260 double GetCurrentVelocity() const 261 { 262 return currentVelocity_; 263 }; 264 265 void OnAnimateStop(); 266 void ProcessScrollSnapStop(); 267 void StartSpringMotion( 268 double mainPosition, double mainVelocity, const ExtentPair& extent, const ExtentPair& initExtent); 269 270 void UpdateScrollSnapStartOffset(double offset); 271 void StartScrollSnapMotion(float predictSnapOffset, float scrollSnapVelocity); 272 273 bool IsAnimationNotRunning() const; 274 275 bool Idle() const; 276 277 bool IsStopped() const; 278 279 bool IsSpringStopped() const; 280 281 bool IsSnapStopped() const; 282 283 void StopScrollable(); 284 Available()285 bool Available() const 286 { 287 return available_; 288 } 289 MarkAvailable(bool available)290 void MarkAvailable(bool available) 291 { 292 available_ = available; 293 } 294 GetContext()295 WeakPtr<PipelineBase> GetContext() const 296 { 297 return context_; 298 } 299 SetNodeId(int32_t nodeId)300 void SetNodeId(int32_t nodeId) 301 { 302 nodeId_ = nodeId; 303 } 304 305 void ProcessScrollOverCallback(double velocity); 306 307 void SetSlipFactor(double SlipFactor); 308 SetOverSpringProperty(const RefPtr<SpringProperty> & property)309 void SetOverSpringProperty(const RefPtr<SpringProperty>& property) 310 { 311 if (property && property->IsValid()) { 312 spring_ = property; 313 } 314 } 315 ChangeMoveStatus(bool flag)316 void ChangeMoveStatus(bool flag) 317 { 318 moved_ = flag; 319 } 320 321 static const RefPtr<SpringProperty>& GetDefaultOverSpringProperty(); 322 GetPanRecognizer()323 RefPtr<PanRecognizer> GetPanRecognizer() const 324 { 325 return panRecognizer_; 326 } 327 SetOnScrollBegin(const ScrollBeginCallback & scrollBeginCallback)328 void SetOnScrollBegin(const ScrollBeginCallback& scrollBeginCallback) 329 { 330 scrollBeginCallback_ = scrollBeginCallback; 331 } 332 SetOnScrollFrameBegin(const ScrollFrameBeginCallback & scrollFrameBeginCallback)333 void SetOnScrollFrameBegin(const ScrollFrameBeginCallback& scrollFrameBeginCallback) 334 { 335 scrollFrameBeginCallback_ = scrollFrameBeginCallback; 336 } 337 SetOnContinuousSliding(const ContinuousSlidingCallback & continuousSlidingCallback)338 void SetOnContinuousSliding(const ContinuousSlidingCallback& continuousSlidingCallback) 339 { 340 continuousSlidingCallback_ = continuousSlidingCallback; 341 } 342 343 void OnFlushTouchEventsBegin() override; 344 void OnFlushTouchEventsEnd() override; 345 SetNestedScrollOptions(NestedScrollOptions opt)346 void SetNestedScrollOptions(NestedScrollOptions opt) 347 { 348 nestedOpt_ = opt; 349 } SetOverScrollOffsetCallback(std::function<OverScrollOffset (double)> && overScroll)350 void SetOverScrollOffsetCallback(std::function<OverScrollOffset(double)>&& overScroll) 351 { 352 overScrollOffsetCallback_ = std::move(overScroll); 353 } SetParent(RefPtr<Scrollable> parent)354 void SetParent(RefPtr<Scrollable> parent) 355 { 356 parent_ = AceType::WeakClaim(AceType::RawPtr(parent)); 357 } SetEdgeEffect(EdgeEffect effect)358 void SetEdgeEffect(EdgeEffect effect) 359 { 360 edgeEffect_ = effect; 361 } 362 SetOnScrollSnapCallback(const ScrollSnapCallback & scrollSnapCallback)363 void SetOnScrollSnapCallback(const ScrollSnapCallback& scrollSnapCallback) 364 { 365 scrollSnapCallback_ = scrollSnapCallback; 366 } SetContinuousDragStatus(bool status)367 void SetContinuousDragStatus(bool status) 368 { 369 continuousDragStatus_ = status; 370 } IncreaseContinueDragCount()371 void IncreaseContinueDragCount() 372 { 373 dragCount_++; 374 } ResetContinueDragCount()375 void ResetContinueDragCount() 376 { 377 dragCount_ = 1; 378 } SetDragStartPosition(double position)379 void SetDragStartPosition(double position) 380 { 381 dragStartPosition_ = position; 382 } SetDragEndPosition(double position)383 void SetDragEndPosition(double position) 384 { 385 dragEndPosition_ = position; 386 } GetDragOffset()387 double GetDragOffset() 388 { 389 return dragEndPosition_ - dragStartPosition_; 390 } 391 SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback && calePredictSnapOffsetCallback)392 void SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback&& calePredictSnapOffsetCallback) 393 { 394 calePredictSnapOffsetCallback_ = std::move(calePredictSnapOffsetCallback); 395 } 396 SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback && needScrollSnapToSideCallback)397 void SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback&& needScrollSnapToSideCallback) 398 { 399 needScrollSnapToSideCallback_ = std::move(needScrollSnapToSideCallback); 400 } 401 402 void ProcessScrollSnapSpringMotion(float scrollSnapDelta, float scrollSnapVelocity); 403 StopSnapController()404 void StopSnapController() 405 { 406 if (snapController_ && !snapController_->IsStopped()) { 407 snapController_->Stop(); 408 } 409 } 410 GetCurrentPos()411 double GetCurrentPos() const 412 { 413 return currentPos_; 414 } 415 GetNeedScrollSnapChange()416 bool GetNeedScrollSnapChange() const 417 { 418 return needScrollSnapChange_; 419 } 420 421 private: 422 bool UpdateScrollPosition(double offset, int32_t source) const; 423 void ProcessSpringMotion(double position); 424 void ProcessScrollMotion(double position); 425 void ProcessScrollSnapMotion(double position); 426 void FixScrollMotion(double position); 427 void ExecuteScrollBegin(double& mainDelta); 428 void ExecuteScrollFrameBegin(double& mainDelta, ScrollState state); 429 double ComputeCap(int dragCount); 430 double GetGain(double delta); 431 void SetDelayedTask(); 432 433 ScrollPositionCallback callback_; 434 ScrollEventCallback scrollEnd_; 435 ScrollEventCallback scrollEndCallback_; 436 ScrollEventCallback scrollTouchUpCallback_; 437 ScrollOverCallback scrollOverCallback_; // scroll motion controller when edge set to spring 438 ScrollOverCallback notifyScrollOverCallback_; // scroll motion controller when edge set to spring 439 OutBoundaryCallback outBoundaryCallback_; // whether out of boundary check when edge set to spring 440 441 WatchFixCallback watchFixCallback_; 442 ScrollBeginCallback scrollBeginCallback_; 443 ScrollFrameBeginCallback scrollFrameBeginCallback_; 444 ScrollSnapCallback scrollSnapCallback_; 445 DragEndForRefreshCallback dragEndCallback_; 446 DragCancelRefreshCallback dragCancelCallback_; 447 ContinuousSlidingCallback continuousSlidingCallback_; 448 Axis axis_; 449 RefPtr<PanRecognizer> panRecognizer_; 450 451 // used for ng structure. 452 RefPtr<NG::PanRecognizer> panRecognizerNG_; 453 454 RefPtr<RawRecognizer> rawRecognizer_; 455 RefPtr<Animator> controller_; 456 RefPtr<Animator> springController_; 457 RefPtr<Animator> scrollSnapController_; 458 RefPtr<Animator> snapController_; 459 RefPtr<FrictionMotion> motion_; 460 RefPtr<ScrollMotion> scrollMotion_; 461 RefPtr<SpringMotion> scrollSnapMotion_; 462 RefPtr<SpringMotion> snapMotion_; 463 RefPtr<SpringProperty> spring_; 464 WeakPtr<PipelineBase> context_; 465 WeakPtr<RenderNode> scrollableNode_; 466 double currentPos_ = 0.0; 467 double currentVelocity_ = 0.0; 468 bool scrollPause_ = false; 469 bool touchUp_ = false; 470 bool moved_ = false; 471 bool isTouching_ = false; 472 bool available_ = true; 473 bool needCenterFix_ = false; 474 bool isDragUpdateStop_ = false; 475 int32_t nodeId_ = 0; 476 double slipFactor_ = 0.0; 477 static double sFriction_; 478 static double sVelocityScale_; 479 bool continuousDragStatus_ = false; 480 CancelableCallback<void()> task_; 481 int32_t dragCount_ = 0; 482 double lastPos_ = 0.0; 483 double dragStartPosition_ = 0.0; 484 double dragEndPosition_ = 0.0; 485 double lastVelocity_ = 0.0; 486 double friction_ = -1.0; 487 #ifdef OHOS_PLATFORM 488 int64_t startIncreaseTime_ = 0; 489 #endif 490 491 // nested scroll 492 WeakPtr<Scrollable> parent_; 493 NestedScrollOptions nestedOpt_ = { NestedScrollMode::SELF_ONLY, NestedScrollMode::SELF_ONLY }; 494 std::function<OverScrollOffset(double)> overScrollOffsetCallback_; 495 EdgeEffect edgeEffect_ = EdgeEffect::NONE; 496 bool canOverScroll_ = true; 497 498 // scrollSnap 499 bool needScrollSnapChange_ = false; 500 CalePredictSnapOffsetCallback calePredictSnapOffsetCallback_; 501 NeedScrollSnapToSideCallback needScrollSnapToSideCallback_; 502 }; 503 504 } // namespace OHOS::Ace 505 506 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_H 507