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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_SCROLL_PATTERN_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_SCROLL_PATTERN_H 18 19 #include "base/geometry/axis.h" 20 #include "core/components/common/layout/constants.h" 21 #include "core/components_ng/pattern/scroll/scroll_accessibility_property.h" 22 #include "core/components_ng/pattern/scroll/scroll_content_modifier.h" 23 #include "core/components_ng/pattern/scroll/scroll_edge_effect.h" 24 #include "core/components_ng/pattern/scroll/scroll_event_hub.h" 25 #include "core/components_ng/pattern/scroll/scroll_layout_algorithm.h" 26 #include "core/components_ng/pattern/scroll/scroll_layout_property.h" 27 #include "core/components_ng/pattern/scroll/scroll_paint_method.h" 28 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h" 29 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h" 30 #include "core/components_ng/pattern/scrollable/scrollable_properties.h" 31 32 #ifdef SUPPORT_DIGITAL_CROWN 33 #include "core/common/vibrator/vibrator_utils.h" 34 #endif 35 36 namespace OHOS::Ace::NG { 37 class InspectorFilter; 38 39 class ScrollPattern : public ScrollablePattern { 40 DECLARE_ACE_TYPE(ScrollPattern, ScrollablePattern); 41 42 public: ScrollPattern()43 ScrollPattern() : ScrollablePattern(EdgeEffect::NONE, true) {} 44 45 ~ScrollPattern() override = default; 46 UsResRegion()47 bool UsResRegion() override 48 { 49 return false; 50 } 51 CreateLayoutProperty()52 RefPtr<LayoutProperty> CreateLayoutProperty() override 53 { 54 return MakeRefPtr<ScrollLayoutProperty>(); 55 } 56 CreateAccessibilityProperty()57 RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override 58 { 59 return MakeRefPtr<ScrollAccessibilityProperty>(); 60 } 61 CreateLayoutAlgorithm()62 RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override 63 { 64 auto layoutAlgorithm = MakeRefPtr<ScrollLayoutAlgorithm>(currentOffset_); 65 return layoutAlgorithm; 66 } 67 68 RefPtr<PaintProperty> CreatePaintProperty() override; 69 70 RefPtr<NodePaintMethod> CreateNodePaintMethod() override; 71 OpIncType()72 OPINC_TYPE_E OpIncType() override 73 { 74 return OPINC_PARENT_POSSIBLE; 75 } 76 CreateEventHub()77 RefPtr<EventHub> CreateEventHub() override 78 { 79 return MakeRefPtr<ScrollEventHub>(); 80 } 81 IsScrollable()82 bool IsScrollable() const override 83 { 84 return GetAxis() != Axis::NONE; 85 } 86 IsPositiveScrollableDistance()87 bool IsPositiveScrollableDistance() 88 { 89 return Positive(scrollableDistance_); 90 } 91 92 bool OnScrollCallback(float offset, int32_t source) override; 93 94 void OnScrollEndCallback() override; 95 GetCurrentPosition()96 double GetCurrentPosition() const 97 { 98 return currentOffset_; 99 } 100 GetTotalOffset()101 float GetTotalOffset() const override 102 { 103 return -currentOffset_; 104 } 105 106 void ResetPosition(); 107 GetCurrentOffset()108 Offset GetCurrentOffset() const 109 { 110 if (GetAxis() == Axis::HORIZONTAL) { 111 return Offset{currentOffset_, 0}; 112 } 113 return Offset{0, currentOffset_}; 114 } 115 GetScrollableDistance()116 float GetScrollableDistance() const 117 { 118 return scrollableDistance_; 119 } 120 IsRowReverse()121 bool IsRowReverse() const 122 { 123 return direction_ == FlexDirection::ROW_REVERSE; 124 } 125 IsColReverse()126 bool IsColReverse() const 127 { 128 return direction_ == FlexDirection::COLUMN_REVERSE; 129 } 130 GetScrollPositionController()131 RefPtr<ScrollableController> GetScrollPositionController() const 132 { 133 return positionController_; 134 } 135 SetDirection(FlexDirection direction)136 void SetDirection(FlexDirection direction) 137 { 138 direction_ = direction; 139 } 140 GetFocusPattern()141 FocusPattern GetFocusPattern() const override 142 { 143 return { FocusType::SCOPE, true }; 144 } 145 146 bool ScrollToNode(const RefPtr<FrameNode>& focusFrameNode) override; 147 ScrollOffsetAbility GetScrollOffsetAbility() override; 148 149 bool IsAtTop() const override; 150 bool IsAtBottom() const override; 151 bool IsOutOfBoundary(bool useCurrentDelta = true) override; 152 OverScrollOffset GetOverScrollOffset(double delta) const override; 153 154 void OnAnimateStop() override; 155 bool UpdateCurrentOffset(float offset, int32_t source) override; 156 void ScrollToEdge(ScrollEdgeType scrollEdgeType, bool smooth) override; 157 158 void CheckScrollToEdge(); 159 GetScrollEdgeType()160 ScrollEdgeType GetScrollEdgeType() const override 161 { 162 return scrollEdgeType_; 163 } 164 SetScrollEdgeType(ScrollEdgeType scrollEdgeType)165 void SetScrollEdgeType(ScrollEdgeType scrollEdgeType) override 166 { 167 scrollEdgeType_ = scrollEdgeType; 168 } 169 170 void ScrollBy(float pixelX, float pixelY, bool smooth, const std::function<void()>& onFinish = nullptr); 171 void ScrollPage(bool reverse, bool smooth = false, 172 AccessibilityScrollType scrollType = AccessibilityScrollType::SCROLL_FULL) override; 173 void ScrollTo(float position) override; 174 void JumpToPosition(float position, int32_t source = SCROLL_FROM_JUMP); GetMainContentSize()175 float GetMainContentSize() const override 176 { 177 return viewPortLength_; 178 } SupportScrollToIndex()179 bool SupportScrollToIndex() const override 180 { 181 return false; 182 } 183 bool ScrollPageCheck(float delta, int32_t source); 184 void AdjustOffset(float& delta, int32_t source); 185 Rect GetItemRect(int32_t index) const override; 186 187 // scrollSnap 188 std::optional<float> CalcPredictSnapOffset(float delta, float dragDistance = 0.f, float velocity = 0.f, 189 SnapDirection snapDirection = SnapDirection::NONE) override; 190 std::optional<float> CalcPredictNextSnapOffset(float delta, SnapDirection snapDirection); 191 bool NeedScrollSnapToSide(float delta) override; 192 void CaleSnapOffsets(); 193 void CaleSnapOffsetsByInterval(ScrollSnapAlign scrollSnapAlign); 194 void CaleSnapOffsetsByPaginations(ScrollSnapAlign scrollSnapAlign); 195 196 float GetSelectScrollWidth(); 197 IsSnapToInterval()198 bool IsSnapToInterval() const 199 { 200 return snapPaginations_.empty(); 201 } 202 GetSnapOffsets()203 std::vector<float> GetSnapOffsets() const 204 { 205 return snapOffsets_; 206 } 207 SetSnapOffsets(const std::vector<float> & snapOffset)208 void SetSnapOffsets(const std::vector<float>& snapOffset) 209 { 210 snapOffsets_ = snapOffset; 211 } 212 SetIntervalSize(const Dimension & intervalSize)213 void SetIntervalSize(const Dimension& intervalSize) 214 { 215 if (intervalSize_ != intervalSize) { 216 intervalSize_ = intervalSize; 217 TAG_LOGI(AceLogTag::ACE_SCROLL, "scroll setIntervalSize:%{public}f", intervalSize.Value()); 218 scrollSnapUpdate_ = true; 219 } 220 } 221 222 #ifdef SUPPORT_DIGITAL_CROWN 223 void StartVibrateFeedback(); 224 SetReachBoundary(bool flag)225 void SetReachBoundary(bool flag) 226 { 227 reachBoundary_ = flag; 228 } 229 #endif 230 GetIntervalSize()231 Dimension GetIntervalSize() const 232 { 233 return intervalSize_; 234 } 235 SetSnapPaginations(const std::vector<Dimension> & snapPaginations)236 void SetSnapPaginations(const std::vector<Dimension>& snapPaginations) 237 { 238 if (snapPaginations_ != snapPaginations) { 239 snapPaginations_ = snapPaginations; 240 scrollSnapUpdate_ = true; 241 } 242 } 243 GetSnapPaginations()244 std::vector<Dimension> GetSnapPaginations() const 245 { 246 return snapPaginations_; 247 } 248 SetEnableSnapToSide(const std::pair<bool,bool> & enableSnapToSide)249 void SetEnableSnapToSide(const std::pair<bool, bool>& enableSnapToSide) 250 { 251 enableSnapToSide_ = enableSnapToSide; 252 } 253 GetEnableSnapToSide()254 std::pair<bool, bool> GetEnableSnapToSide() const 255 { 256 return enableSnapToSide_; 257 } 258 SetScrollSnapUpdate(bool scrollSnapUpdate)259 void SetScrollSnapUpdate(bool scrollSnapUpdate) 260 { 261 scrollSnapUpdate_ = scrollSnapUpdate; 262 } 263 GetScrollSnapUpdate()264 bool GetScrollSnapUpdate() const 265 { 266 return scrollSnapUpdate_; 267 } 268 GetScrollSnapAlign()269 ScrollSnapAlign GetScrollSnapAlign() const 270 { 271 auto host = GetHost(); 272 CHECK_NULL_RETURN(host, ScrollSnapAlign::NONE); 273 auto scrollLayoutProperty = host->GetLayoutProperty<ScrollLayoutProperty>(); 274 CHECK_NULL_RETURN(scrollLayoutProperty, ScrollSnapAlign::NONE); 275 return scrollLayoutProperty->GetScrollSnapAlign().value_or(ScrollSnapAlign::NONE); 276 } 277 278 std::string ProvideRestoreInfo() override; 279 void OnRestoreInfo(const std::string& restoreInfo) override; 280 SetIsWidthModifiedBySelect(bool isModified)281 void SetIsWidthModifiedBySelect(bool isModified) 282 { 283 isWidthModifiedBySelect_ = isModified; 284 } 285 IsWidthModifiedBySelect()286 bool IsWidthModifiedBySelect() const 287 { 288 return isWidthModifiedBySelect_; 289 } 290 SetIsSelectScroll(bool isSelect)291 void SetIsSelectScroll(bool isSelect) 292 { 293 isSelectScroll_ = isSelect; 294 } 295 IsSelectScroll()296 bool IsSelectScroll() const 297 { 298 return isSelectScroll_; 299 } 300 SetHasOptionWidth(bool hasOptionWidth)301 void SetHasOptionWidth(bool hasOptionWidth) 302 { 303 hasOptionWidth_ = hasOptionWidth; 304 } 305 GetHasOptionWidth()306 bool GetHasOptionWidth() 307 { 308 return hasOptionWidth_; 309 } 310 SetEnablePaging(ScrollPagingStatus status)311 void SetEnablePaging(ScrollPagingStatus status) 312 { 313 enablePagingStatus_ = status; 314 } 315 GetEnablePaging()316 ScrollPagingStatus GetEnablePaging() 317 { 318 return enablePagingStatus_; 319 } 320 IsScrollSnap()321 bool IsScrollSnap() override 322 { 323 return !snapOffsets_.empty() && 324 (GetScrollSnapAlign() != ScrollSnapAlign::NONE || enablePagingStatus_ == ScrollPagingStatus::VALID); 325 } 326 GetSnapType()327 SnapType GetSnapType() override 328 { 329 return (!snapOffsets_.empty() && 330 (GetScrollSnapAlign() != ScrollSnapAlign::NONE || enablePagingStatus_ == ScrollPagingStatus::VALID)) 331 ? SnapType::SCROLL_SNAP 332 : SnapType::NONE_SNAP; 333 } 334 335 void TriggerModifyDone(); 336 SetInitialOffset(const OffsetT<CalcDimension> & offset)337 void SetInitialOffset(const OffsetT<CalcDimension>& offset) 338 { 339 initialOffset_ = offset; 340 } 341 GetInitialOffset()342 OffsetT<CalcDimension> GetInitialOffset() const 343 { 344 return initialOffset_.has_value() ? initialOffset_.value() : OffsetT(CalcDimension(), CalcDimension()); 345 } 346 NeedSetInitialOffset()347 bool NeedSetInitialOffset() 348 { 349 return !isInitialized_ && initialOffset_.has_value(); 350 } 351 352 void AddScrollMeasureInfo(const std::optional<LayoutConstraintF>& parentConstraint, 353 const std::optional<LayoutConstraintF>& childConstraint, const SizeF& selfSize, const SizeF& childSize); 354 355 void AddScrollLayoutInfo(); 356 357 void GetScrollSnapAlignDumpInfo(); 358 void GetScrollSnapAlignDumpInfo(std::unique_ptr<JsonValue>& json); 359 360 void GetScrollPagingStatusDumpInfo(); 361 void GetScrollPagingStatusDumpInfo(std::unique_ptr<JsonValue>& json); 362 void DumpAdvanceInfo() override; 363 void DumpAdvanceInfo(std::unique_ptr<JsonValue>& json) override; 364 GetViewSize()365 SizeF GetViewSize() const 366 { 367 return viewSize_; 368 } 369 GetViewPortExtent()370 SizeF GetViewPortExtent() const 371 { 372 return viewPortExtent_; 373 } 374 375 void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override; 376 377 bool StartSnapAnimation(SnapAnimationOptions snapAnimationOptions) override; 378 379 void StartScrollSnapAnimation(float scrollSnapDelta, float scrollSnapVelocity, bool fromScrollBar); 380 381 SizeF GetChildrenExpandedSize() override; 382 383 protected: 384 void DoJump(float position, int32_t source = SCROLL_FROM_JUMP); 385 386 private: 387 void OnModifyDone() override; 388 bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override; 389 390 bool IsCrashTop() const; 391 bool IsCrashBottom() const; 392 bool ReachStart(bool firstLayout) const; 393 bool ReachEnd(bool firstLayout) const; 394 bool IsScrollOutOnEdge(float delta) const; 395 void HandleCrashTop(); 396 void HandleCrashBottom(); IsEnablePagingValid()397 bool IsEnablePagingValid() const 398 { 399 return enablePagingStatus_ == ScrollPagingStatus::VALID && GetScrollSnapAlign() == ScrollSnapAlign::NONE; 400 } 401 402 void RegisterScrollBarEventTask(); 403 void HandleScrollEffect(); 404 void ValidateOffset(int32_t source); 405 float ValidateOffset(int32_t source, float willScrollOffset); 406 void HandleScrollPosition(float scroll); 407 float FireTwoDimensionOnWillScroll(float scroll); 408 void FireOnDidScroll(float scroll); 409 void FireOnReachStart(const OnReachEvent& onReachStart) override; 410 void FireOnReachEnd(const OnReachEvent& onReachEnd) override; 411 void SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect) override; 412 void UpdateScrollBarOffset() override; 413 void SetAccessibilityAction() override; 414 bool ScrollSnapTrigger(); 415 void CheckScrollable(); 416 OffsetF GetOffsetToScroll(const RefPtr<FrameNode>& childFrame) const; 417 bool SetScrollProperties(const RefPtr<LayoutWrapper>& dirty); 418 std::string GetScrollSnapPagination() const; 419 420 float currentOffset_ = 0.0f; 421 float lastOffset_ = 0.0f; 422 // keep lastOffset_ for compatibility, use prevOffset_ for onReachStart/onReachEnd 423 float prevOffset_ = 0.0f; 424 float scrollableDistance_ = 0.0f; 425 float viewPortLength_ = 0.0f; 426 SizeF viewPort_; 427 SizeF viewSize_; 428 SizeF viewPortExtent_; 429 FlexDirection direction_ { FlexDirection::COLUMN }; 430 431 // scrollSnap 432 std::vector<float> snapOffsets_; 433 std::vector<Dimension> snapPaginations_; 434 std::pair<bool, bool> enableSnapToSide_ = { true, true }; 435 Dimension intervalSize_; 436 bool scrollSnapUpdate_ = false; 437 438 bool isWidthModifiedBySelect_ = false; 439 bool isSelectScroll_ = false; 440 bool hasOptionWidth_ = false; 441 442 // enablePaging 443 ScrollPagingStatus enablePagingStatus_ = ScrollPagingStatus::NONE; 444 float lastPageLength_ = 0.0f; 445 float GetPagingOffset(float delta, float dragDistance, float velocity) const; 446 float GetPagingDelta(float dragDistance, float velocity, float pageLength) const; 447 448 RefPtr<ScrollContentModifier> scrollContentModifier_; 449 450 //initialOffset 451 std::optional<OffsetT<CalcDimension>> initialOffset_; 452 453 //scrollToEdge 454 ScrollEdgeType scrollEdgeType_ = ScrollEdgeType::SCROLL_NONE; 455 456 // dump info 457 std::list<ScrollLayoutInfo> scrollLayoutInfos_; 458 std::list<ScrollMeasureInfo> scrollMeasureInfos_; 459 460 #ifdef SUPPORT_DIGITAL_CROWN 461 int32_t crownEventNum_ = 0; 462 bool reachBoundary_ = false; 463 int64_t lastTime_ = 0; 464 #endif 465 }; 466 467 } // namespace OHOS::Ace::NG 468 469 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_SCROLL_PATTERN_H 470