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