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 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h"
17 
18 #include <cmath>
19 
20 #include "base/log/dump_log.h"
21 #include "base/utils/utils.h"
22 #include "core/animation/curve_animation.h"
23 #include "core/animation/curves.h"
24 #include "core/common/container.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr int32_t BAR_DISAPPRAE_DELAY_DURATION = 2000; // 2000ms
30 constexpr double BAR_ADAPT_EPSLION = 1.0;
31 constexpr int32_t SCROLL_BAR_LAYOUT_INFO_COUNT = 30;
32 constexpr int32_t LONG_PRESS_PAGE_INTERVAL_MS = 100;
33 constexpr int32_t LONG_PRESS_TIME_THRESHOLD_MS = 500;
34 } // namespace
35 
ScrollBar()36 ScrollBar::ScrollBar()
37 {
38     InitTheme();
39 }
40 
ScrollBar(DisplayMode displayMode,ShapeMode shapeMode,PositionMode positionMode)41 ScrollBar::ScrollBar(DisplayMode displayMode, ShapeMode shapeMode, PositionMode positionMode) : ScrollBar()
42 {
43     displayMode_ = displayMode;
44     shapeMode_ = shapeMode;
45     positionMode_ = positionMode;
46 }
47 
InitTheme()48 void ScrollBar::InitTheme()
49 {
50     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
51     CHECK_NULL_VOID(pipelineContext);
52     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
53     CHECK_NULL_VOID(theme);
54     themeNormalWidth_ = theme->GetNormalWidth();
55     SetInactiveWidth(themeNormalWidth_);
56     SetNormalWidth(themeNormalWidth_);
57     SetActiveWidth(theme->GetActiveWidth());
58     SetTouchWidth(theme->GetTouchWidth());
59     SetMinHeight(theme->GetMinHeight());
60     SetMinDynamicHeight(theme->GetMinDynamicHeight());
61     SetBackgroundColor(theme->GetBackgroundColor());
62     SetForegroundColor(theme->GetForegroundColor());
63     SetPadding(theme->GetPadding());
64     SetHoverWidth(theme);
65 }
66 
InBarTouchRegion(const Point & point) const67 bool ScrollBar::InBarTouchRegion(const Point& point) const
68 {
69     if (NeedPaint() && shapeMode_ == ShapeMode::RECT) {
70         return touchRegion_.IsInRegion(point);
71     }
72     return false;
73 }
74 
InBarHoverRegion(const Point & point) const75 bool ScrollBar::InBarHoverRegion(const Point& point) const
76 {
77     if (NeedPaint() && shapeMode_ == ShapeMode::RECT) {
78         return hoverRegion_.IsInRegion(point);
79     }
80     return false;
81 }
82 
InBarRectRegion(const Point & point) const83 bool ScrollBar::InBarRectRegion(const Point& point) const
84 {
85     if (NeedPaint() && shapeMode_ == ShapeMode::RECT) {
86         return barRect_.IsInRegion(point);
87     }
88     return false;
89 }
90 
CheckBarDirection(const Point & point)91 BarDirection ScrollBar::CheckBarDirection(const Point& point)
92 {
93     if (!InBarRectRegion(point)) {
94         return BarDirection::BAR_NONE;
95     }
96     auto touchRegion = GetTouchRegion();
97     auto pointOffset = OffsetF(point.GetX(), point.GetY());
98     auto scrollBarTopOffset = OffsetF(touchRegion.Left(), touchRegion.Top());
99     auto scrollBarBottomOffset = OffsetF(touchRegion.Right(), touchRegion.Bottom());
100     auto axis = positionMode_ == PositionMode::BOTTOM ? Axis::HORIZONTAL : Axis::VERTICAL;
101     if (pointOffset.GetMainOffset(axis) < scrollBarTopOffset.GetMainOffset(axis)) {
102         return BarDirection::PAGE_UP;
103     } else if (pointOffset.GetMainOffset(axis) > scrollBarBottomOffset.GetMainOffset(axis)) {
104         return BarDirection::PAGE_DOWN;
105     } else {
106         return BarDirection::BAR_NONE;
107     }
108 }
109 
FlushBarWidth()110 void ScrollBar::FlushBarWidth()
111 {
112     if (shapeMode_ == ShapeMode::RECT) {
113         SetRectTrickRegion(paintOffset_, viewPortSize_, lastOffset_, estimatedHeight_);
114     } else {
115         SetRoundTrickRegion(paintOffset_, viewPortSize_, lastOffset_, estimatedHeight_);
116     }
117     SetBarRegion(paintOffset_, viewPortSize_);
118 }
119 
UpdateScrollBarRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)120 void ScrollBar::UpdateScrollBarRegion(
121     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
122 {
123     // return if nothing changes to avoid changing opacity
124     if (!positionModeUpdate_ && !normalWidthUpdate_ && paintOffset_ == offset && viewPortSize_ == size &&
125         lastOffset_ == lastOffset && NearEqual(estimatedHeight_, estimatedHeight, 0.000001f) && !isReverseUpdate_) {
126         return;
127     }
128     if (!NearEqual(estimatedHeight_, estimatedHeight, 0.000001f) || viewPortSize_ != size) {
129         needAddLayoutInfo = true;
130     }
131     if (!NearZero(estimatedHeight)) {
132         paintOffset_ = offset;
133         viewPortSize_ = size;
134         lastOffset_ = lastOffset;
135         estimatedHeight_ = estimatedHeight;
136         if (shapeMode_ == ShapeMode::RECT) {
137             SetRectTrickRegion(offset, size, lastOffset, estimatedHeight);
138         } else {
139             SetRoundTrickRegion(offset, size, lastOffset, estimatedHeight);
140         }
141         SetBarRegion(offset, size);
142         positionModeUpdate_ = false;
143         normalWidthUpdate_ = false;
144         isReverseUpdate_ = false;
145     }
146     needAddLayoutInfo =false;
147 }
148 
UpdateActiveRectSize(double activeSize)149 void ScrollBar::UpdateActiveRectSize(double activeSize)
150 {
151     if (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT) {
152         activeRect_.SetHeight(activeSize);
153         touchRegion_.SetHeight(activeSize);
154         hoverRegion_.SetHeight(activeSize);
155     } else if (positionMode_ == PositionMode::BOTTOM) {
156         activeRect_.SetWidth(activeSize);
157         touchRegion_.SetWidth(activeSize);
158         hoverRegion_.SetWidth(activeSize);
159     }
160 }
161 
UpdateActiveRectOffset(double activeMainOffset)162 void ScrollBar::UpdateActiveRectOffset(double activeMainOffset)
163 {
164     if (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT) {
165         activeMainOffset = std::min(activeMainOffset, barRegionSize_ - activeRect_.Height());
166         activeRect_.SetTop(activeMainOffset);
167         touchRegion_.SetTop(activeMainOffset);
168         hoverRegion_.SetTop(activeMainOffset);
169     } else if (positionMode_ == PositionMode::BOTTOM) {
170         activeMainOffset = std::min(activeMainOffset, barRegionSize_ - activeRect_.Width());
171         activeRect_.SetLeft(activeMainOffset);
172         touchRegion_.SetLeft(activeMainOffset);
173         hoverRegion_.SetLeft(activeMainOffset);
174     }
175 }
176 
SetBarRegion(const Offset & offset,const Size & size)177 void ScrollBar::SetBarRegion(const Offset& offset, const Size& size)
178 {
179     if (shapeMode_ == ShapeMode::RECT) {
180         double height =
181             std::max(size.Height() - NormalizeToPx(startReservedHeight_) - NormalizeToPx(endReservedHeight_), 0.0);
182         if (positionMode_ == PositionMode::LEFT) {
183             barRect_ = Rect(NormalizeToPx(padding_.Left()), 0.0, barWidth_, height) + offset;
184         } else if (positionMode_ == PositionMode::RIGHT) {
185             barRect_ =
186                 Rect(size.Width() - barWidth_ - NormalizeToPx(padding_.Right()), 0.0, barWidth_, height) + offset;
187         } else if (positionMode_ == PositionMode::BOTTOM) {
188             auto trackWidth =
189                 std::max(size.Width() - NormalizeToPx(startReservedHeight_) - NormalizeToPx(endReservedHeight_), 0.0);
190             barRect_ =
191                 Rect(0.0, size.Height() - barWidth_ - NormalizeToPx(padding_.Bottom()), trackWidth, barWidth_) +
192                 offset;
193         }
194     }
195 }
196 
SetRectTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)197 void ScrollBar::SetRectTrickRegion(
198     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
199 {
200     double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
201     barRegionSize_ = std::max(mainSize - NormalizeToPx(endReservedHeight_) - NormalizeToPx(startReservedHeight_), 0.0);
202     if (LessOrEqual(estimatedHeight, 0.0)) {
203         return;
204     }
205     double activeSize = barRegionSize_ * mainSize / estimatedHeight - outBoundary_;
206 
207     if (!NearZero(outBoundary_)) {
208         activeSize = std::max(
209             std::max(activeSize, NormalizeToPx(minHeight_) - outBoundary_), NormalizeToPx(minDynamicHeight_));
210     } else {
211         activeSize = std::max(activeSize, NormalizeToPx(minHeight_));
212     }
213     barWidth_  = NormalizeToPx(normalWidth_);
214     double normalWidth = NormalizeToPx(normalWidth_);
215     if (LessOrEqual(activeSize, normalWidth)) {
216         if (GreatNotEqual(normalWidth, mainSize)) {
217             normalWidth = NormalizeToPx(themeNormalWidth_);
218         } else {
219             activeSize = normalWidth;
220         }
221     }
222     double lastMainOffset =
223         std::max(positionMode_ == PositionMode::BOTTOM ? lastOffset.GetX() : lastOffset.GetY(), 0.0);
224     if (NearEqual(mainSize, estimatedHeight)) {
225         offsetScale_ = 0.0;
226     } else {
227         offsetScale_ = (barRegionSize_ - activeSize) / (estimatedHeight - mainSize);
228     }
229     // Avoid crossing the top or bottom boundary.
230     double activeMainOffset = std::min(offsetScale_ * lastMainOffset, barRegionSize_ - activeSize)
231                                 + NormalizeToPx(startReservedHeight_);
232     activeMainOffset = !isReverse_ ? activeMainOffset : barRegionSize_ - activeSize - activeMainOffset;
233     bool canUseAnimation = !isOutOfBoundary_ && !positionModeUpdate_;
234     double inactiveSize = 0.0;
235     double inactiveMainOffset = 0.0;
236     scrollableOffset_ = activeMainOffset;
237     if (positionMode_ == PositionMode::LEFT) {
238         inactiveSize = activeRect_.Height();
239         inactiveMainOffset = activeRect_.Top();
240         activeRect_ = Rect(-NormalizeToPx(position_) + NormalizeToPx(padding_.Left()),
241             activeMainOffset, normalWidth, activeSize) + offset;
242         if (isUserNormalWidth_) {
243             touchRegion_ = activeRect_;
244             hoverRegion_ = activeRect_;
245         } else {
246             touchRegion_ = activeRect_ + Size(NormalizeToPx(touchWidth_), 0);
247             hoverRegion_ = activeRect_ + Size(NormalizeToPx(hoverWidth_), 0);
248         }
249     } else if (positionMode_ == PositionMode::RIGHT) {
250         inactiveSize = activeRect_.Height();
251         inactiveMainOffset = activeRect_.Top();
252         double x = size.Width() - normalWidth - NormalizeToPx(padding_.Right()) + NormalizeToPx(position_);
253         activeRect_ = Rect(x, activeMainOffset, normalWidth, activeSize) + offset;
254         // Update the hot region
255         if (isUserNormalWidth_) {
256             touchRegion_ = activeRect_;
257             hoverRegion_ = activeRect_;
258         } else {
259             touchRegion_ =
260                 activeRect_ - Offset(NormalizeToPx(touchWidth_) - barWidth_ - NormalizeToPx(padding_.Right()), 0.0) +
261                 Size(NormalizeToPx(touchWidth_) - barWidth_, 0);
262             hoverRegion_ =
263                 activeRect_ - Offset(NormalizeToPx(hoverWidth_) - barWidth_ - NormalizeToPx(padding_.Right()), 0.0) +
264                 Size(NormalizeToPx(hoverWidth_) - barWidth_, 0);
265         }
266     } else if (positionMode_ == PositionMode::BOTTOM) {
267         inactiveSize = activeRect_.Width();
268         inactiveMainOffset = activeRect_.Left();
269         auto positionY = size.Height() - normalWidth - NormalizeToPx(padding_.Bottom()) + NormalizeToPx(position_);
270         activeRect_ = Rect(activeMainOffset, positionY, activeSize, normalWidth) + offset;
271         if (isUserNormalWidth_) {
272             touchRegion_ = activeRect_;
273             hoverRegion_ = activeRect_;
274         } else {
275             auto hotRegionOffset = Offset(
276                 0.0, NormalizeToPx(touchWidth_) - barWidth_ - NormalizeToPx(padding_.Bottom()));
277             auto hotRegionSize = Size(0, NormalizeToPx(touchWidth_) - barWidth_);
278             touchRegion_ = activeRect_ - hotRegionOffset + hotRegionSize;
279 
280             auto hoverRegionOffset = Offset(
281                 0.0, NormalizeToPx(hoverWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Bottom()));
282             auto hoverRegionSize = Size(0, NormalizeToPx(hoverWidth_) - NormalizeToPx(normalWidth_));
283             hoverRegion_ = activeRect_ - hoverRegionOffset + hoverRegionSize;
284         }
285     }
286     AddScrollBarLayoutInfo();
287     // If the scrollBar length changes, start the adaptation animation
288     if (!NearZero(inactiveSize) && !NearEqual(activeSize, inactiveSize, BAR_ADAPT_EPSLION) && canUseAnimation &&
289         !Negative(inactiveMainOffset) && !normalWidthUpdate_) {
290         PlayScrollBarAdaptAnimation();
291     } else {
292         needAdaptAnimation_ = false;
293     }
294 }
295 
SetRoundTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)296 void ScrollBar::SetRoundTrickRegion(
297     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
298 {
299     double diameter = std::min(size.Width(), size.Height());
300     if (!NearEqual(estimatedHeight, diameter)) {
301         double maxAngle = bottomAngle_ - topAngle_;
302         trickSweepAngle_ = std::max(diameter * maxAngle / estimatedHeight, minAngle_);
303         double lastOffsetY = std::max(lastOffset.GetY(), 0.0);
304         double trickStartAngle = (maxAngle - trickSweepAngle_) * lastOffsetY / (estimatedHeight - diameter);
305         trickStartAngle = std::clamp(0.0, trickStartAngle, maxAngle) - maxAngle * FACTOR_HALF;
306         if (positionMode_ == PositionMode::LEFT) {
307             if (trickStartAngle > 0.0) {
308                 trickStartAngle_ = STRAIGHT_ANGLE - trickStartAngle;
309             } else {
310                 trickStartAngle_ = -(trickStartAngle + STRAIGHT_ANGLE);
311             }
312             trickSweepAngle_ = -trickSweepAngle_;
313         } else {
314             trickStartAngle_ = trickStartAngle;
315         }
316     }
317 }
318 
NeedScrollBar() const319 bool ScrollBar::NeedScrollBar() const
320 {
321     return displayMode_ == DisplayMode::AUTO || displayMode_ == DisplayMode::ON;
322 }
323 
NeedPaint() const324 bool ScrollBar::NeedPaint() const
325 {
326     return NeedScrollBar() && isScrollable_;
327 }
328 
GetNormalWidthToPx() const329 double ScrollBar::GetNormalWidthToPx() const
330 {
331     return NormalizeToPx(normalWidth_);
332 }
333 
CalcPatternOffset(float scrollBarOffset) const334 float ScrollBar::CalcPatternOffset(float scrollBarOffset) const
335 {
336     auto activeRectLength = positionMode_ == PositionMode::BOTTOM ? activeRect_.Width() : activeRect_.Height();
337     if (!isDriving_ || NearZero(barRegionSize_ - activeRectLength)) {
338         return scrollBarOffset;
339     }
340     auto mainSize = (positionMode_ == PositionMode::BOTTOM ? viewPortSize_.Width() : viewPortSize_.Height());
341     return -scrollBarOffset * (estimatedHeight_ - mainSize) / (barRegionSize_ - activeRectLength);
342 }
343 
NormalizeToPx(const Dimension & dimension) const344 double ScrollBar::NormalizeToPx(const Dimension& dimension) const
345 {
346     auto pipelineContext = PipelineContext::GetCurrentContext();
347     CHECK_NULL_RETURN(pipelineContext, 0.0);
348     return pipelineContext->NormalizeToPx(dimension);
349 }
350 
SetGestureEvent()351 void ScrollBar::SetGestureEvent()
352 {
353     if (!touchEvent_) {
354         touchEvent_ = MakeRefPtr<TouchEventImpl>([weak = WeakClaim(this)](const TouchEventInfo& info) {
355             auto scrollBar = weak.Upgrade();
356             CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
357             if (info.GetTouches().empty()) {
358                 return;
359             }
360             auto touch = info.GetTouches().front();
361             if (touch.GetTouchType() == TouchType::DOWN) {
362                 TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "inner scrollBar touch down, panDirection: %{public}u",
363                     scrollBar->GetPanDirection());
364                 Point point(touch.GetLocalLocation().GetX(), touch.GetLocalLocation().GetY());
365                 bool inRegion = false;
366                 if (info.GetSourceDevice() == SourceType::TOUCH) {
367                     inRegion = scrollBar->InBarTouchRegion(point);
368                 } else if (info.GetSourceDevice() == SourceType::MOUSE) {
369                     inRegion = scrollBar->InBarHoverRegion(point);
370                     scrollBar->MarkNeedRender();
371                 }
372                 if (!scrollBar->IsPressed()) {
373                     scrollBar->SetPressed(inRegion);
374                 }
375                 if (inRegion && !scrollBar->IsHover()) {
376                     scrollBar->PlayScrollBarGrowAnimation();
377                 }
378             }
379             if ((info.GetTouches().front().GetTouchType() == TouchType::UP ||
380                     info.GetTouches().front().GetTouchType() == TouchType::CANCEL) &&
381                     (info.GetTouches().size() <= 1)) {
382                 if (scrollBar->IsPressed() && !scrollBar->IsHover()) {
383                     scrollBar->PlayScrollBarShrinkAnimation();
384                     scrollBar->ScheduleDisappearDelayTask();
385                 }
386                 scrollBar->SetPressed(false);
387                 scrollBar->MarkNeedRender();
388             }
389         });
390     }
391     if (!panRecognizer_) {
392         InitPanRecognizer();
393     }
394 }
395 
SetMouseEvent()396 void ScrollBar::SetMouseEvent()
397 {
398     if (mouseEvent_) {
399         return;
400     }
401     mouseEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](MouseInfo& info) {
402         auto scrollBar = weak.Upgrade();
403         CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
404         Point point(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY());
405         bool inBarRegion = scrollBar->InBarRectRegion(point);
406         bool inHoverRegion = scrollBar->InBarHoverRegion(point);
407         if (inBarRegion) {
408             scrollBar->PlayScrollBarAppearAnimation();
409             if (info.GetButton() == MouseButton::LEFT_BUTTON && info.GetAction() == MouseAction::PRESS) {
410                 scrollBar->isMousePressed_ = true;
411             } else {
412                 scrollBar->isMousePressed_ = false;
413             }
414         } else if (!scrollBar->IsPressed()) {
415             scrollBar->ScheduleDisappearDelayTask();
416         }
417         if (inHoverRegion && !scrollBar->IsHover()) {
418             if (!scrollBar->IsPressed()) {
419                 scrollBar->PlayScrollBarGrowAnimation();
420             }
421             scrollBar->SetHover(true);
422         }
423         if (scrollBar->IsHover() && !inHoverRegion) {
424             scrollBar->SetHover(false);
425             if (!scrollBar->IsPressed()) {
426                 scrollBar->PlayScrollBarShrinkAnimation();
427             }
428         }
429         scrollBar->locationInfo_ = info.GetLocalLocation();
430     });
431     if (!longPressRecognizer_) {
432         InitLongPressEvent();
433     }
434 }
435 
SetHoverEvent()436 void ScrollBar::SetHoverEvent()
437 {
438     CHECK_NULL_VOID(!hoverEvent_);
439     hoverEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](bool isHover) {
440         auto scrollBar = weak.Upgrade();
441         CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
442         if (scrollBar->IsHover() && !isHover) {
443             scrollBar->SetHover(false);
444             if (!scrollBar->IsPressed()) {
445                 scrollBar->PlayScrollBarShrinkAnimation();
446                 scrollBar->ScheduleDisappearDelayTask();
447             }
448         }
449     });
450 }
451 
OnCollectLongPressTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)452 void ScrollBar::OnCollectLongPressTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
453     TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
454     ResponseLinkResult& responseLinkResult)
455 {
456     if (longPressRecognizer_ && isScrollable_) {
457         longPressRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
458         longPressRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
459         longPressRecognizer_->SetNodeId(frameNode->GetId());
460         longPressRecognizer_->AttachFrameNode(frameNode);
461         longPressRecognizer_->SetTargetComponent(targetComponent);
462         longPressRecognizer_->SetIsSystemGesture(true);
463         longPressRecognizer_->SetRecognizerType(GestureTypeName::LONG_PRESS_GESTURE);
464         longPressRecognizer_->SetSysGestureJudge([](const RefPtr<GestureInfo>& gestureInfo,
465                                                  const std::shared_ptr<BaseGestureEvent>&) -> GestureJudgeResult {
466             const auto &inputEventType = gestureInfo->GetInputEventType();
467             TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "input event type:%{public}d", inputEventType);
468             if (inputEventType == InputEventType::MOUSE_BUTTON) {
469                 return GestureJudgeResult::CONTINUE;
470             }
471             return GestureJudgeResult::REJECT;
472         });
473         result.emplace_front(longPressRecognizer_);
474         responseLinkResult.emplace_back(longPressRecognizer_);
475     }
476 }
477 
InitLongPressEvent()478 void ScrollBar::InitLongPressEvent()
479 {
480     longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(LONG_PRESS_TIME_THRESHOLD_MS, 1, false, false);
481     longPressRecognizer_->SetOnAction([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
482         auto scrollBar = weakBar.Upgrade();
483         if (scrollBar) {
484             scrollBar->HandleLongPress(true);
485         }
486     });
487 }
488 
HandleLongPress(bool smooth)489 void ScrollBar::HandleLongPress(bool smooth)
490 {
491     Point point(locationInfo_.GetX(), locationInfo_.GetY());
492     bool reverse = false;
493     if (AnalysisUpOrDown(point, reverse) && isMousePressed_) {
494         scrollPageCallback_(reverse, smooth);
495         ScheduleCaretLongPress();
496     }
497 }
498 
AnalysisUpOrDown(Point point,bool & reverse)499 bool ScrollBar::AnalysisUpOrDown(Point point, bool& reverse)
500 {
501     switch (CheckBarDirection(point)) {
502         case BarDirection::BAR_NONE:
503             return false;
504         case BarDirection::PAGE_UP:
505             reverse = true;
506             return true;
507         case BarDirection::PAGE_DOWN:
508             reverse = false;
509             return true;
510     }
511 }
512 
ScheduleCaretLongPress()513 void ScrollBar::ScheduleCaretLongPress()
514 {
515     auto context = OHOS::Ace::PipelineContext::GetCurrentContext();
516     CHECK_NULL_VOID(context);
517     if (!context->GetTaskExecutor()) {
518         return;
519     }
520     auto taskExecutor = context->GetTaskExecutor();
521     CHECK_NULL_VOID(taskExecutor);
522     taskExecutor->PostDelayedTask(
523         [weak = WeakClaim(this)]() {
524             auto pattern = weak.Upgrade();
525             CHECK_NULL_VOID(pattern);
526             pattern->HandleLongPress(true);
527         },
528         TaskExecutor::TaskType::UI, LONG_PRESS_PAGE_INTERVAL_MS, "ArkUIScrollBarHandleLongPress");
529 }
530 
CalcReservedHeight()531 void ScrollBar::CalcReservedHeight()
532 {
533     auto pipelineContext = PipelineContext::GetCurrentContext();
534     CHECK_NULL_VOID(pipelineContext);
535     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
536         auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
537         CHECK_NULL_VOID(theme);
538         startReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
539         endReservedHeight_ = theme->GetReservedHeight();
540         FlushBarWidth();
541         return;
542     }
543     float startRadius = 0.0;
544     float endRadius = 0.0;
545     float barMargin = 0.0;
546     float padding = 0.0;
547     float startRadiusHeight = 0.0;
548     float endRadiusHeight = 0.0;
549     switch (positionMode_) {
550         case PositionMode::LEFT:
551             startRadius = hostBorderRadius_.radiusTopLeft.value_or(Dimension()).ConvertToPx();
552             endRadius = hostBorderRadius_.radiusBottomLeft.value_or(Dimension()).ConvertToPx();
553             padding = NormalizeToPx(padding_.Left());
554             break;
555         case PositionMode::RIGHT:
556             startRadius = hostBorderRadius_.radiusTopRight.value_or(Dimension()).ConvertToPx();
557             endRadius = hostBorderRadius_.radiusBottomRight.value_or(Dimension()).ConvertToPx();
558             padding = NormalizeToPx(padding_.Right());
559             break;
560         case PositionMode::BOTTOM:
561             startRadius = hostBorderRadius_.radiusBottomLeft.value_or(Dimension()).ConvertToPx();
562             endRadius = hostBorderRadius_.radiusBottomRight.value_or(Dimension()).ConvertToPx();
563             padding = NormalizeToPx(padding_.Bottom());
564             break;
565         default:
566             break;
567     }
568     if (std::isnan(startRadius)) {
569         startRadius = 0.0f;
570     }
571     if (std::isnan(endRadius)) {
572         endRadius = 0.0f;
573     }
574     barMargin = padding + NormalizeToPx(normalWidth_) / 2;
575     if (LessOrEqual(startRadius, barMargin)) {
576         startReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
577     } else {
578         startRadiusHeight = startRadius - std::sqrt(2 * padding * startRadius - padding * padding);
579         startReservedHeight_ = Dimension(startRadiusHeight + (startRadius / barMargin), DimensionUnit::PX);
580     }
581 
582     if (LessOrEqual(endRadius, barMargin)) {
583         endReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
584     } else {
585         endRadiusHeight = endRadius - std::sqrt(2 * padding * endRadius - padding * padding);
586         endReservedHeight_ = Dimension(endRadiusHeight + (endRadius / barMargin), DimensionUnit::PX);
587     }
588     FlushBarWidth();
589 }
590 
InitPanRecognizer()591 void ScrollBar::InitPanRecognizer()
592 {
593     PanDirection panDirection;
594     panDirection.type = positionMode_ == PositionMode::BOTTOM ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
595     panRecognizer_ = MakeRefPtr<PanRecognizer>(1, panDirection, DEFAULT_PAN_DISTANCE.ConvertToPx());
596     panRecognizer_->SetMouseDistance(DRAG_PAN_DISTANCE_MOUSE.ConvertToPx());
597     panRecognizer_->SetOnActionUpdate([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
598         auto scrollBar = weakBar.Upgrade();
599         if (scrollBar) {
600             scrollBar->HandleDragUpdate(info);
601         }
602     });
603     panRecognizer_->SetOnActionEnd([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
604         auto scrollBar = weakBar.Upgrade();
605         if (scrollBar) {
606             scrollBar->HandleDragEnd(info);
607         }
608     });
609     panRecognizer_->SetOnActionStart([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
610         auto scrollBar = weakBar.Upgrade();
611         if (scrollBar) {
612             scrollBar->HandleDragStart(info);
613         }
614     });
615     panRecognizer_->SetOnActionCancel([weakBar = AceType::WeakClaim(this)]() {
616         auto scrollBar = weakBar.Upgrade();
617         if (scrollBar) {
618             GestureEvent info;
619             scrollBar->HandleDragEnd(info);
620         }
621     });
622 }
623 
StopFlingAnimation()624 void ScrollBar::StopFlingAnimation()
625 {
626     if (frictionController_ && frictionController_->IsRunning()) {
627         frictionController_->Stop();
628     }
629 }
630 
HandleDragStart(const GestureEvent & info)631 void ScrollBar::HandleDragStart(const GestureEvent& info)
632 {
633     StopFlingAnimation();
634     TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "inner scrollBar drag start");
635     ACE_SCOPED_TRACE("inner scrollBar HandleDragStart");
636     if (scrollPositionCallback_) {
637         scrollPositionCallback_(0, SCROLL_FROM_START);
638         if (dragFRCSceneCallback_) {
639             dragFRCSceneCallback_(0, NG::SceneStatus::START);
640         }
641     }
642     SetDragStartPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
643     isDriving_ = true;
644 }
645 
HandleDragUpdate(const GestureEvent & info)646 void ScrollBar::HandleDragUpdate(const GestureEvent& info)
647 {
648     // if historical touch point slope is zero but delta is not zero, no need to update.
649     auto mainDelta = info.GetMainDelta();
650     if (info.IsInterpolated()) {
651         if (GetPanDirection() == Axis::VERTICAL && NearZero(info.GetInputYDeltaSlope()) && !NearZero(mainDelta)) {
652             return;
653         } else if (GetPanDirection() == Axis::HORIZONTAL && NearZero(info.GetInputXDeltaSlope()) &&
654                    !NearZero(mainDelta)) {
655             return;
656         }
657     }
658     if (scrollPositionCallback_) {
659         // The offset of the mouse wheel and gesture is opposite.
660         auto offset = info.GetInputEventType() == InputEventType::AXIS ?
661                       info.GetMainDelta() : CalcPatternOffset(info.GetMainDelta());
662         if (IsReverse()) {
663             offset = -offset;
664         }
665         ACE_SCOPED_TRACE("inner scrollBar HandleDragUpdate offset:%f", offset);
666         scrollPositionCallback_(offset, SCROLL_FROM_BAR);
667         if (dragFRCSceneCallback_) {
668             dragFRCSceneCallback_(NearZero(info.GetMainDelta()) ? info.GetMainVelocity()
669                                                                 : info.GetMainVelocity() / info.GetMainDelta() * offset,
670                 NG::SceneStatus::RUNNING);
671         }
672     }
673 }
674 
HandleDragEnd(const GestureEvent & info)675 void ScrollBar::HandleDragEnd(const GestureEvent& info)
676 {
677     if (dragFRCSceneCallback_) {
678         dragFRCSceneCallback_(0, NG::SceneStatus::END);
679     }
680     auto velocity = IsReverse() ? -info.GetMainVelocity() : info.GetMainVelocity();
681     TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "inner scrollBar drag end, velocity is %{public}f", velocity);
682     ACE_SCOPED_TRACE("inner scrollBar HandleDragEnd velocity:%f", velocity);
683     if (NearZero(velocity) || info.GetInputEventType() == InputEventType::AXIS) {
684         if (scrollEndCallback_) {
685             scrollEndCallback_();
686         }
687         isDriving_ = false;
688         return;
689     }
690     SetDragEndPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
691     frictionPosition_ = 0.0;
692     if (frictionMotion_) {
693         frictionMotion_->Reset(friction_, 0, velocity);
694     } else {
695         frictionMotion_ = AceType::MakeRefPtr<FrictionMotion>(friction_, 0, velocity);
696         frictionMotion_->AddListener([weakBar = AceType::WeakClaim(this)](double value) {
697             auto scrollBar = weakBar.Upgrade();
698             CHECK_NULL_VOID(scrollBar);
699             scrollBar->ProcessFrictionMotion(value);
700         });
701     }
702     if (calePredictSnapOffsetCallback_ && startScrollSnapMotionCallback_) {
703         auto predictSnapOffset = calePredictSnapOffsetCallback_(CalcPatternOffset(frictionMotion_->GetFinalPosition()),
704                                                                 CalcPatternOffset(GetDragOffset()), -velocity);
705         // If snap scrolling, predictSnapOffset will has a value.
706         if (predictSnapOffset.has_value() && !NearZero(predictSnapOffset.value())) {
707             startScrollSnapMotionCallback_(predictSnapOffset.value(), velocity);
708             return;
709         }
710     }
711 
712     if (!frictionController_) {
713         frictionController_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
714         frictionController_->AddStopListener([weakBar = AceType::WeakClaim(this)]() {
715             auto scrollBar = weakBar.Upgrade();
716             CHECK_NULL_VOID(scrollBar);
717             scrollBar->ProcessFrictionMotionStop();
718         });
719     }
720     frictionController_->PlayMotion(frictionMotion_);
721 }
722 
ProcessFrictionMotion(double value)723 void ScrollBar::ProcessFrictionMotion(double value)
724 {
725     if (scrollPositionCallback_) {
726         auto offset = CalcPatternOffset(value - frictionPosition_);
727         if (!scrollPositionCallback_(offset, SCROLL_FROM_BAR_FLING)) {
728             if (frictionController_ && frictionController_->IsRunning()) {
729                 frictionController_->Stop();
730             }
731         }
732     }
733     frictionPosition_ = value;
734 }
735 
ProcessFrictionMotionStop()736 void ScrollBar::ProcessFrictionMotionStop()
737 {
738     if (scrollEndCallback_) {
739         scrollEndCallback_();
740     }
741     isDriving_ = false;
742 }
743 
OnCollectTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)744 void ScrollBar::OnCollectTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
745     TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
746     ResponseLinkResult& responseLinkResult)
747 {
748     if (panRecognizer_ && isScrollable_) {
749         panRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
750         panRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
751         panRecognizer_->SetNodeId(frameNode->GetId());
752         panRecognizer_->AttachFrameNode(frameNode);
753         panRecognizer_->SetTargetComponent(targetComponent);
754         panRecognizer_->SetIsSystemGesture(true);
755         panRecognizer_->SetRecognizerType(GestureTypeName::PAN_GESTURE);
756         result.emplace_front(panRecognizer_);
757         responseLinkResult.emplace_back(panRecognizer_);
758     }
759 }
760 
ScheduleDisappearDelayTask()761 void ScrollBar::ScheduleDisappearDelayTask()
762 {
763     if (displayMode_ == DisplayMode::AUTO && isScrollable_ && !isHover_) {
764         disappearDelayTask_.Cancel();
765         auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
766         CHECK_NULL_VOID(context);
767         auto taskExecutor = context->GetTaskExecutor();
768         CHECK_NULL_VOID(taskExecutor);
769         disappearDelayTask_.Reset([weak = WeakClaim(this)] {
770             auto scrollBar = weak.Upgrade();
771             CHECK_NULL_VOID(scrollBar);
772             scrollBar->PlayScrollBarDisappearAnimation();
773         });
774         taskExecutor->PostDelayedTask(disappearDelayTask_, TaskExecutor::TaskType::UI, BAR_DISAPPRAE_DELAY_DURATION,
775             "ArkUIScrollBarInnerDisappearAnimation");
776     }
777 }
778 
AddScrollBarLayoutInfo()779 void ScrollBar::AddScrollBarLayoutInfo()
780 {
781     CHECK_NULL_VOID(needAddLayoutInfo);
782     if (innerScrollBarLayoutInfos_.size() >= SCROLL_BAR_LAYOUT_INFO_COUNT) {
783         innerScrollBarLayoutInfos_.pop_front();
784     }
785     innerScrollBarLayoutInfos_.push_back(InnerScrollBarLayoutInfo({
786         .layoutTime_ = GetSysTimestamp(),
787         .viewPortSize_ = viewPortSize_,
788         .lastOffset_ = lastOffset_,
789         .estimatedHeight_ = estimatedHeight_,
790         .outBoundary_ = outBoundary_,
791         .activeRect_ = activeRect_,
792     }));
793 }
794 
GetShapeModeDumpInfo()795 void ScrollBar::GetShapeModeDumpInfo()
796 {
797     switch (shapeMode_) {
798         case ShapeMode::RECT: {
799             DumpLog::GetInstance().AddDesc("shapeMode: RECT");
800             break;
801         }
802         case ShapeMode::ROUND: {
803             DumpLog::GetInstance().AddDesc("shapeMode: ROUND");
804             break;
805         }
806         case ShapeMode::DEFAULT: {
807             DumpLog::GetInstance().AddDesc("shapeMode: DEFAULT");
808             break;
809         }
810         default: {
811             break;
812         }
813     }
814 }
815 
GetPositionModeDumpInfo()816 void ScrollBar::GetPositionModeDumpInfo()
817 {
818     switch (positionMode_) {
819         case PositionMode::RIGHT: {
820             DumpLog::GetInstance().AddDesc("positionMode: RIGHT");
821             DumpLog::GetInstance().AddDesc(std::string("padding.right: ").append(padding_.Right().ToString()));
822             break;
823         }
824         case PositionMode::LEFT: {
825             DumpLog::GetInstance().AddDesc("positionMode: LEFT");
826             DumpLog::GetInstance().AddDesc(std::string("padding.left: ").append(padding_.Left().ToString()));
827             break;
828         }
829         case PositionMode::BOTTOM: {
830             DumpLog::GetInstance().AddDesc("positionMode: BOTTOM");
831             DumpLog::GetInstance().AddDesc(std::string("padding.bottom: ").append(padding_.Bottom().ToString()));
832             break;
833         }
834         default: {
835             break;
836         }
837     }
838 }
839 
GetAxisDumpInfo()840 void ScrollBar::GetAxisDumpInfo()
841 {
842     switch (axis_) {
843         case Axis::NONE: {
844             DumpLog::GetInstance().AddDesc("axis: NONE");
845             break;
846         }
847         case Axis::VERTICAL: {
848             DumpLog::GetInstance().AddDesc("axis: VERTICAL");
849             break;
850         }
851         case Axis::HORIZONTAL: {
852             DumpLog::GetInstance().AddDesc("axis: HORIZONTAL");
853             break;
854         }
855         case Axis::FREE: {
856             DumpLog::GetInstance().AddDesc("axis: FREE");
857             break;
858         }
859         default: {
860             break;
861         }
862     }
863 }
864 
GetPanDirectionDumpInfo()865 void ScrollBar::GetPanDirectionDumpInfo()
866 {
867     if (panRecognizer_) {
868         switch (panRecognizer_->GetAxisDirection()) {
869             case Axis::NONE: {
870                 DumpLog::GetInstance().AddDesc("panDirection: NONE");
871                 break;
872             }
873             case Axis::VERTICAL: {
874                 DumpLog::GetInstance().AddDesc("panDirection: VERTICAL");
875                 break;
876             }
877             case Axis::HORIZONTAL: {
878                 DumpLog::GetInstance().AddDesc("panDirection: HORIZONTAL");
879                 break;
880             }
881             case Axis::FREE: {
882                 DumpLog::GetInstance().AddDesc("panDirection: FREE");
883                 break;
884             }
885             default: {
886                 break;
887             }
888         }
889     } else {
890         DumpLog::GetInstance().AddDesc("panDirection is null");
891     }
892 }
893 
DumpAdvanceInfo()894 void ScrollBar::DumpAdvanceInfo()
895 {
896     DumpLog::GetInstance().AddDesc(std::string("activeRect: ").append(activeRect_.ToString()));
897     DumpLog::GetInstance().AddDesc(std::string("touchRegion: ").append(touchRegion_.ToString()));
898     DumpLog::GetInstance().AddDesc(std::string("hoverRegion: ").append(hoverRegion_.ToString()));
899     DumpLog::GetInstance().AddDesc(std::string("normalWidth: ").append(normalWidth_.ToString()));
900     DumpLog::GetInstance().AddDesc(std::string("activeWidth: ").append(activeWidth_.ToString()));
901     DumpLog::GetInstance().AddDesc(std::string("touchWidth: ").append(touchWidth_.ToString()));
902     DumpLog::GetInstance().AddDesc(std::string("hoverWidth: ").append(hoverWidth_.ToString()));
903     GetShapeModeDumpInfo();
904     GetPositionModeDumpInfo();
905     GetAxisDumpInfo();
906     GetPanDirectionDumpInfo();
907     DumpLog::GetInstance().AddDesc(std::string("hostBorderRadius: ").append(hostBorderRadius_.ToString()));
908     DumpLog::GetInstance().AddDesc(std::string("startReservedHeight: ").append(startReservedHeight_.ToString()));
909     DumpLog::GetInstance().AddDesc(std::string("endReservedHeight: ").append(endReservedHeight_.ToString()));
910     DumpLog::GetInstance().AddDesc(std::string("isScrollable: ").append(std::to_string(isScrollable_)));
911     DumpLog::GetInstance().AddDesc(std::string("isReverse: ").append(std::to_string(isReverse_)));
912     DumpLog::GetInstance().AddDesc("==========================innerScrollBarLayoutInfos==========================");
913     for (const auto& info : innerScrollBarLayoutInfos_) {
914         DumpLog::GetInstance().AddDesc(info.ToString());
915     }
916     DumpLog::GetInstance().AddDesc("==========================innerScrollBarLayoutInfos==========================");
917 }
918 
GetForegroundColor() const919 Color ScrollBar::GetForegroundColor() const
920 {
921     return IsPressed() ? foregroundColor_.BlendColor(PRESSED_BLEND_COLOR) : foregroundColor_;
922 }
923 
SetHoverWidth(const RefPtr<ScrollBarTheme> & theme)924 void ScrollBar::SetHoverWidth(const RefPtr<ScrollBarTheme>& theme)
925 {
926     hoverWidth_ = theme->GetActiveWidth() + theme->GetScrollBarMargin() * 2;
927 }
928 
SetNormalWidth(const Dimension & normalWidth)929 void ScrollBar::SetNormalWidth(const Dimension& normalWidth)
930 {
931     if (normalWidth_ != normalWidth) {
932         normalWidthUpdate_ = true;
933         normalWidth_ = normalWidth;
934         CalcReservedHeight();
935         MarkNeedRender();
936     }
937 }
938 
SetScrollable(bool isScrollable)939 void ScrollBar::SetScrollable(bool isScrollable)
940 {
941     CHECK_NULL_VOID(isScrollable_ != isScrollable);
942     isScrollable_ = isScrollable;
943 }
944 
SetPositionMode(PositionMode positionMode)945 void ScrollBar::SetPositionMode(PositionMode positionMode)
946 {
947     if (positionMode_ != positionMode) {
948         positionModeUpdate_ = true;
949         positionMode_ = positionMode;
950         if (panRecognizer_) {
951             PanDirection panDirection;
952             panDirection.type =
953                 positionMode_ == PositionMode::BOTTOM ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
954             panRecognizer_->SetDirection(panDirection);
955         }
956     }
957 }
958 
SetDisplayMode(DisplayMode displayMode)959 void ScrollBar::SetDisplayMode(DisplayMode displayMode)
960 {
961     CHECK_NULL_VOID(displayMode_ != displayMode);
962     displayMode_ = displayMode;
963 }
964 
PlayScrollBarDisappearAnimation()965 void ScrollBar::PlayScrollBarDisappearAnimation()
966 {
967     if (displayMode_ == DisplayMode::AUTO && isScrollable_ && !isHover_ && !isPressed_) {
968         opacityAnimationType_ = OpacityAnimationType::DISAPPEAR;
969         MarkNeedRender();
970     }
971 }
972 
PlayScrollBarAppearAnimation()973 void ScrollBar::PlayScrollBarAppearAnimation()
974 {
975     if (displayMode_ == DisplayMode::AUTO && isScrollable_) {
976         disappearDelayTask_.Cancel();
977         opacityAnimationType_ = OpacityAnimationType::APPEAR;
978         MarkNeedRender();
979     }
980 }
981 
PlayScrollBarGrowAnimation()982 void ScrollBar::PlayScrollBarGrowAnimation()
983 {
984     PlayScrollBarAppearAnimation();
985     normalWidth_ = activeWidth_;
986     FlushBarWidth();
987     hoverAnimationType_ = HoverAnimationType::GROW;
988     MarkNeedRender();
989 }
990 
PlayScrollBarShrinkAnimation()991 void ScrollBar::PlayScrollBarShrinkAnimation()
992 {
993     normalWidth_ = inactiveWidth_;
994     FlushBarWidth();
995     hoverAnimationType_ = HoverAnimationType::SHRINK;
996     MarkNeedRender();
997 }
998 
PlayScrollBarAdaptAnimation()999 void ScrollBar::PlayScrollBarAdaptAnimation()
1000 {
1001     needAdaptAnimation_ = true;
1002     MarkNeedRender();
1003 }
1004 
MarkNeedRender()1005 void ScrollBar::MarkNeedRender()
1006 {
1007     if (markNeedRenderFunc_) {
1008         markNeedRenderFunc_();
1009     }
1010 }
1011 
GetMainOffset(const Offset & offset) const1012 float ScrollBar::GetMainOffset(const Offset& offset) const
1013 {
1014     return positionMode_ == PositionMode::BOTTOM ? offset.GetX() : offset.GetY();
1015 }
1016 
SetReverse(bool reverse)1017 void ScrollBar::SetReverse(bool reverse)
1018 {
1019     if (isReverse_ != reverse) {
1020         isReverse_ = reverse;
1021         isReverseUpdate_ = true;
1022     }
1023 }
1024 
GetPanDirection() const1025 Axis ScrollBar::GetPanDirection() const
1026 {
1027     CHECK_NULL_RETURN(panRecognizer_, Axis::NONE);
1028     return panRecognizer_->GetAxisDirection();
1029 }
1030 } // namespace OHOS::Ace::NG
1031