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