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