• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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/utils/utils.h"
21 #include "core/animation/curve_animation.h"
22 #include "core/animation/curves.h"
23 #include "core/common/container.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr int32_t BAR_DISAPPRAE_DELAY_DURATION = 2000; // 2000ms
29 constexpr double BAR_ADAPT_EPSLION = 1.0;
30 } // namespace
31 
ScrollBar()32 ScrollBar::ScrollBar()
33 {
34     InitTheme();
35 }
36 
ScrollBar(DisplayMode displayMode,ShapeMode shapeMode,PositionMode positionMode)37 ScrollBar::ScrollBar(DisplayMode displayMode, ShapeMode shapeMode, PositionMode positionMode) : ScrollBar()
38 {
39     displayMode_ = displayMode;
40     shapeMode_ = shapeMode;
41     positionMode_ = positionMode;
42 }
43 
InitTheme()44 void ScrollBar::InitTheme()
45 {
46     auto pipelineContext = PipelineContext::GetCurrentContext();
47     CHECK_NULL_VOID(pipelineContext);
48     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
49     CHECK_NULL_VOID(theme);
50     SetInactiveWidth(theme->GetNormalWidth());
51     SetNormalWidth(theme->GetNormalWidth());
52     SetActiveWidth(theme->GetActiveWidth());
53     SetTouchWidth(theme->GetTouchWidth());
54     SetMinHeight(theme->GetMinHeight());
55     SetMinDynamicHeight(theme->GetMinDynamicHeight());
56     SetBackgroundColor(theme->GetBackgroundColor());
57     SetForegroundColor(theme->GetForegroundColor());
58     SetPadding(theme->GetPadding());
59     SetHoverWidth(theme);
60 }
61 
InBarTouchRegion(const Point & point) const62 bool ScrollBar::InBarTouchRegion(const Point& point) const
63 {
64     if (NeedScrollBar() && shapeMode_ == ShapeMode::RECT) {
65         return touchRegion_.IsInRegion(point);
66     }
67     return false;
68 }
69 
InBarHoverRegion(const Point & point) const70 bool ScrollBar::InBarHoverRegion(const Point& point) const
71 {
72     if (NeedScrollBar() && shapeMode_ == ShapeMode::RECT) {
73         return hoverRegion_.IsInRegion(point);
74     }
75     return false;
76 }
77 
InBarRectRegion(const Point & point) const78 bool ScrollBar::InBarRectRegion(const Point& point) const
79 {
80     if (NeedScrollBar() && shapeMode_ == ShapeMode::RECT) {
81         return barRect_.IsInRegion(point);
82     }
83     return false;
84 }
85 
FlushBarWidth()86 void ScrollBar::FlushBarWidth()
87 {
88     SetBarRegion(paintOffset_, viewPortSize_);
89     if (shapeMode_ == ShapeMode::RECT) {
90         SetRectTrickRegion(paintOffset_, viewPortSize_, lastOffset_, estimatedHeight_);
91     } else {
92         SetRoundTrickRegion(paintOffset_, viewPortSize_, lastOffset_, estimatedHeight_);
93     }
94 }
95 
UpdateScrollBarRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)96 void ScrollBar::UpdateScrollBarRegion(
97     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
98 {
99     // return if nothing changes to avoid changing opacity
100     if (!positionModeUpdate_ && !normalWidthUpdate_ && paintOffset_ == offset && viewPortSize_ == size &&
101         lastOffset_ == lastOffset && NearEqual(estimatedHeight_, estimatedHeight, 0.000001f)) {
102         return;
103     }
104     if (!NearZero(estimatedHeight)) {
105         paintOffset_ = offset;
106         viewPortSize_ = size;
107         lastOffset_ = lastOffset;
108         estimatedHeight_ = estimatedHeight;
109         SetBarRegion(offset, size);
110         if (shapeMode_ == ShapeMode::RECT) {
111             SetRectTrickRegion(offset, size, lastOffset, estimatedHeight);
112         } else {
113             SetRoundTrickRegion(offset, size, lastOffset, estimatedHeight);
114         }
115         positionModeUpdate_ = false;
116         normalWidthUpdate_ = false;
117     }
118 }
119 
UpdateActiveRectSize(double activeSize)120 void ScrollBar::UpdateActiveRectSize(double activeSize)
121 {
122     if (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT) {
123         activeRect_.SetHeight(activeSize);
124         touchRegion_.SetHeight(activeSize);
125         hoverRegion_.SetHeight(activeSize);
126     } else if (positionMode_ == PositionMode::BOTTOM) {
127         activeRect_.SetWidth(activeSize);
128         touchRegion_.SetWidth(activeSize);
129         hoverRegion_.SetWidth(activeSize);
130     }
131 }
132 
UpdateActiveRectOffset(double activeMainOffset)133 void ScrollBar::UpdateActiveRectOffset(double activeMainOffset)
134 {
135     if (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT) {
136         activeMainOffset = std::min(activeMainOffset, barRegionSize_ - activeRect_.Height());
137         activeRect_.SetTop(activeMainOffset);
138         touchRegion_.SetTop(activeMainOffset);
139         hoverRegion_.SetTop(activeMainOffset);
140     } else if (positionMode_ == PositionMode::BOTTOM) {
141         activeMainOffset = std::min(activeMainOffset, barRegionSize_ - activeRect_.Width());
142         activeRect_.SetLeft(activeMainOffset);
143         touchRegion_.SetLeft(activeMainOffset);
144         hoverRegion_.SetLeft(activeMainOffset);
145     }
146 }
147 
SetBarRegion(const Offset & offset,const Size & size)148 void ScrollBar::SetBarRegion(const Offset& offset, const Size& size)
149 {
150     double normalWidth = NormalizeToPx(normalWidth_);
151     if (shapeMode_ == ShapeMode::RECT) {
152         double height =
153             std::max(size.Height() - NormalizeToPx(startReservedHeight_) - NormalizeToPx(endReservedHeight_), 0.0);
154         if (positionMode_ == PositionMode::LEFT) {
155             barRect_ = Rect(0.0, 0.0, normalWidth, height) + offset;
156         } else if (positionMode_ == PositionMode::RIGHT) {
157             barRect_ =
158                 Rect(size.Width() - normalWidth - NormalizeToPx(padding_.Right()), 0.0, normalWidth, height) + offset;
159         } else if (positionMode_ == PositionMode::BOTTOM) {
160             auto scrollBarWidth =
161                 std::max(size.Width() - NormalizeToPx(startReservedHeight_) - NormalizeToPx(endReservedHeight_), 0.0);
162             barRect_ =
163                 Rect(0.0, size.Height() - normalWidth - NormalizeToPx(padding_.Bottom()), scrollBarWidth, normalWidth) +
164                 offset;
165         }
166     }
167 }
168 
SetRectTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)169 void ScrollBar::SetRectTrickRegion(
170     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
171 {
172     double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
173     barRegionSize_ = std::max(mainSize - NormalizeToPx(endReservedHeight_) - NormalizeToPx(startReservedHeight_), 0.0);
174     if (LessOrEqual(estimatedHeight, 0.0)) {
175         return;
176     }
177     double activeSize = barRegionSize_ * mainSize / estimatedHeight - outBoundary_;
178 
179     if (!NearZero(outBoundary_)) {
180         activeSize = std::max(
181             std::max(activeSize, NormalizeToPx(minHeight_) - outBoundary_), NormalizeToPx(minDynamicHeight_));
182     } else {
183         activeSize = std::max(activeSize, NormalizeToPx(minHeight_));
184     }
185     double normalWidth = NormalizeToPx(normalWidth_);
186     if (LessOrEqual(activeSize, normalWidth)) {
187         if (GreatNotEqual(normalWidth, mainSize)) {
188             auto pipelineContext = PipelineContext::GetCurrentContext();
189             CHECK_NULL_VOID(pipelineContext);
190             auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
191             CHECK_NULL_VOID(theme);
192             normalWidth_ = theme->GetNormalWidth();
193             normalWidth = NormalizeToPx(normalWidth_);
194         } else {
195             activeSize = normalWidth;
196         }
197     }
198     double lastMainOffset =
199         std::max(positionMode_ == PositionMode::BOTTOM ? lastOffset.GetX() : lastOffset.GetY(), 0.0);
200     if (NearEqual(mainSize, estimatedHeight)) {
201         offsetScale_ = 0.0;
202     } else {
203         offsetScale_ = (barRegionSize_ - activeSize) / (estimatedHeight - mainSize);
204     }
205     // Avoid crossing the top or bottom boundary.
206     double activeMainOffset = std::min(offsetScale_ * lastMainOffset, barRegionSize_ - activeSize)
207                                 + NormalizeToPx(startReservedHeight_);
208     activeMainOffset = !isReverse_ ? activeMainOffset : barRegionSize_ - activeSize - activeMainOffset;
209     bool canUseAnimation = !isOutOfBoundary_ && !positionModeUpdate_;
210     double inactiveSize = 0.0;
211     double inactiveMainOffset = 0.0;
212     scrollableOffset_ = activeMainOffset;
213     if (positionMode_ == PositionMode::LEFT) {
214         inactiveSize = activeRect_.Height();
215         inactiveMainOffset = activeRect_.Top();
216         activeRect_ = Rect(-NormalizeToPx(position_), activeMainOffset, normalWidth, activeSize) + offset;
217         if (isUserNormalWidth_) {
218             touchRegion_ = activeRect_;
219             hoverRegion_ = activeRect_;
220         } else {
221             touchRegion_ = activeRect_ + Size(NormalizeToPx(touchWidth_), 0);
222             hoverRegion_ = activeRect_ + Size(NormalizeToPx(hoverWidth_), 0);
223         }
224     } else if (positionMode_ == PositionMode::RIGHT) {
225         inactiveSize = activeRect_.Height();
226         inactiveMainOffset = activeRect_.Top();
227         double x = size.Width() - normalWidth - NormalizeToPx(padding_.Right()) + NormalizeToPx(position_);
228         activeRect_ = Rect(x, activeMainOffset, normalWidth, activeSize) + offset;
229         // Update the hot region
230         if (isUserNormalWidth_) {
231             touchRegion_ = activeRect_;
232             hoverRegion_ = activeRect_;
233         } else {
234             touchRegion_ =
235                 activeRect_ -
236                 Offset(NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Right()),
237                     0.0) +
238                 Size(NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_), 0);
239             hoverRegion_ =
240                 activeRect_ -
241                 Offset(NormalizeToPx(hoverWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Right()),
242                     0.0) +
243                 Size(NormalizeToPx(hoverWidth_) - NormalizeToPx(normalWidth_), 0);
244         }
245     } else if (positionMode_ == PositionMode::BOTTOM) {
246         inactiveSize = activeRect_.Width();
247         inactiveMainOffset = activeRect_.Left();
248         auto positionY = size.Height() - normalWidth - NormalizeToPx(padding_.Bottom()) + NormalizeToPx(position_);
249         activeRect_ = Rect(activeMainOffset, positionY, activeSize, normalWidth) + offset;
250         if (isUserNormalWidth_) {
251             touchRegion_ = activeRect_;
252             hoverRegion_ = activeRect_;
253         } else {
254             auto hotRegionOffset = Offset(
255                 0.0, NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Bottom()));
256             auto hotRegionSize = Size(0, NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_));
257             touchRegion_ = activeRect_ - hotRegionOffset + hotRegionSize;
258 
259             auto hoverRegionOffset = Offset(
260                 0.0, NormalizeToPx(hoverWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Bottom()));
261             auto hoverRegionSize = Size(0, NormalizeToPx(hoverWidth_) - NormalizeToPx(normalWidth_));
262             hoverRegion_ = activeRect_ - hoverRegionOffset + hoverRegionSize;
263         }
264     }
265     // If the scrollBar length changes, start the adaptation animation
266     if (!NearZero(inactiveSize) && !NearEqual(activeSize, inactiveSize, BAR_ADAPT_EPSLION) && canUseAnimation &&
267         !Negative(inactiveMainOffset) && !normalWidthUpdate_) {
268         PlayScrollBarAdaptAnimation();
269     } else {
270         needAdaptAnimation_ = false;
271     }
272 }
273 
SetRoundTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)274 void ScrollBar::SetRoundTrickRegion(
275     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
276 {
277     double diameter = std::min(size.Width(), size.Height());
278     if (!NearEqual(estimatedHeight, diameter)) {
279         double maxAngle = bottomAngle_ - topAngle_;
280         trickSweepAngle_ = std::max(diameter * maxAngle / estimatedHeight, minAngle_);
281         double lastOffsetY = std::max(lastOffset.GetY(), 0.0);
282         double trickStartAngle = (maxAngle - trickSweepAngle_) * lastOffsetY / (estimatedHeight - diameter);
283         trickStartAngle = std::clamp(0.0, trickStartAngle, maxAngle) - maxAngle * FACTOR_HALF;
284         if (positionMode_ == PositionMode::LEFT) {
285             if (trickStartAngle > 0.0) {
286                 trickStartAngle_ = STRAIGHT_ANGLE - trickStartAngle;
287             } else {
288                 trickStartAngle_ = -(trickStartAngle + STRAIGHT_ANGLE);
289             }
290             trickSweepAngle_ = -trickSweepAngle_;
291         } else {
292             trickStartAngle_ = trickStartAngle;
293         }
294     }
295 }
296 
NeedScrollBar() const297 bool ScrollBar::NeedScrollBar() const
298 {
299     return displayMode_ == DisplayMode::AUTO || displayMode_ == DisplayMode::ON;
300 }
301 
NeedPaint() const302 bool ScrollBar::NeedPaint() const
303 {
304     return NeedScrollBar() && isScrollable_;
305 }
306 
GetNormalWidthToPx() const307 double ScrollBar::GetNormalWidthToPx() const
308 {
309     return NormalizeToPx(normalWidth_);
310 }
311 
CalcPatternOffset(float scrollBarOffset) const312 float ScrollBar::CalcPatternOffset(float scrollBarOffset) const
313 {
314     if (!isDriving_ || NearZero(barRegionSize_ - activeRect_.Height())) {
315         return scrollBarOffset;
316     }
317     auto mainSize = (positionMode_ == PositionMode::BOTTOM ? viewPortSize_.Width() : viewPortSize_.Height());
318     return -scrollBarOffset * (estimatedHeight_ - mainSize) / (barRegionSize_ - activeRect_.Height());
319 }
320 
NormalizeToPx(const Dimension & dimension) const321 double ScrollBar::NormalizeToPx(const Dimension& dimension) const
322 {
323     auto pipelineContext = PipelineContext::GetCurrentContext();
324     CHECK_NULL_RETURN(pipelineContext, 0.0);
325     return pipelineContext->NormalizeToPx(dimension);
326 }
327 
SetGestureEvent()328 void ScrollBar::SetGestureEvent()
329 {
330     if (!touchEvent_) {
331         touchEvent_ = MakeRefPtr<TouchEventImpl>([weak = WeakClaim(this)](const TouchEventInfo& info) {
332             auto scrollBar = weak.Upgrade();
333             CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
334             if (info.GetTouches().empty()) {
335                 return;
336             }
337             auto touch = info.GetTouches().front();
338             if (touch.GetTouchType() == TouchType::DOWN) {
339                 Point point(touch.GetLocalLocation().GetX(), touch.GetLocalLocation().GetY());
340                 bool inRegion = false;
341                 if (info.GetSourceDevice() == SourceType::TOUCH) {
342                     inRegion = scrollBar->InBarTouchRegion(point);
343                 } else if (info.GetSourceDevice() == SourceType::MOUSE) {
344                     inRegion = scrollBar->InBarHoverRegion(point);
345                     scrollBar->MarkNeedRender();
346                 }
347                 scrollBar->SetPressed(inRegion);
348                 if (inRegion && !scrollBar->IsHover()) {
349                     scrollBar->PlayScrollBarGrowAnimation();
350                 }
351             }
352             if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
353                 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
354                 if (scrollBar->IsPressed() && !scrollBar->IsHover()) {
355                     scrollBar->PlayScrollBarShrinkAnimation();
356                     scrollBar->ScheduleDisappearDelayTask();
357                 }
358                 scrollBar->SetPressed(false);
359                 scrollBar->MarkNeedRender();
360             }
361         });
362     }
363     if (!panRecognizer_) {
364         InitPanRecognizer();
365     }
366 }
367 
SetMouseEvent()368 void ScrollBar::SetMouseEvent()
369 {
370     if (mouseEvent_) {
371         return;
372     }
373     mouseEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](MouseInfo& info) {
374         auto scrollBar = weak.Upgrade();
375         CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
376         Point point(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY());
377         bool inBarRegion = scrollBar->InBarRectRegion(point);
378         bool inHoverRegion = scrollBar->InBarHoverRegion(point);
379         if (inBarRegion) {
380             scrollBar->PlayScrollBarAppearAnimation();
381         } else if (!scrollBar->IsPressed()) {
382             scrollBar->ScheduleDisappearDelayTask();
383         }
384         if (inHoverRegion && !scrollBar->IsHover()) {
385             if (!scrollBar->IsPressed()) {
386                 scrollBar->PlayScrollBarGrowAnimation();
387             }
388             scrollBar->SetHover(true);
389         }
390         if (scrollBar->IsHover() && !inHoverRegion) {
391             scrollBar->SetHover(false);
392             if (!scrollBar->IsPressed()) {
393                 scrollBar->PlayScrollBarShrinkAnimation();
394             }
395         }
396     });
397 }
398 
SetHoverEvent()399 void ScrollBar::SetHoverEvent()
400 {
401     CHECK_NULL_VOID(!hoverEvent_);
402     hoverEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](bool isHover) {
403         auto scrollBar = weak.Upgrade();
404         CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
405         if (scrollBar->IsHover() && !isHover) {
406             scrollBar->SetHover(false);
407             if (!scrollBar->IsPressed()) {
408                 scrollBar->PlayScrollBarShrinkAnimation();
409                 scrollBar->ScheduleDisappearDelayTask();
410             }
411         }
412     });
413 }
414 
CalcReservedHeight()415 void ScrollBar::CalcReservedHeight()
416 {
417     auto pipelineContext = PipelineContext::GetCurrentContext();
418     CHECK_NULL_VOID(pipelineContext);
419     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
420         auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
421         CHECK_NULL_VOID(theme);
422         startReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
423         endReservedHeight_ = theme->GetReservedHeight();
424         FlushBarWidth();
425         return;
426     }
427     float startRadius = 0.0;
428     float endRadius = 0.0;
429     float barMargin = 0.0;
430     float padding = 0.0;
431     float startRadiusHeight = 0.0;
432     float endRadiusHeight = 0.0;
433     switch (positionMode_) {
434         case PositionMode::LEFT:
435             startRadius = hostBorderRadius_.radiusTopLeft->ConvertToPx();
436             endRadius = hostBorderRadius_.radiusBottomLeft->ConvertToPx();
437             padding = NormalizeToPx(padding_.Left());
438             break;
439         case PositionMode::RIGHT:
440             startRadius = hostBorderRadius_.radiusTopRight->ConvertToPx();
441             endRadius = hostBorderRadius_.radiusBottomRight->ConvertToPx();
442             padding = NormalizeToPx(padding_.Right());
443             break;
444         case PositionMode::BOTTOM:
445             startRadius = hostBorderRadius_.radiusBottomLeft->ConvertToPx();
446             endRadius = hostBorderRadius_.radiusBottomRight->ConvertToPx();
447             padding = NormalizeToPx(padding_.Bottom());
448             break;
449         default:
450             break;
451     }
452     if (std::isnan(startRadius)) {
453         startRadius = 0.0f;
454     }
455     if (std::isnan(endRadius)) {
456         endRadius = 0.0f;
457     }
458     barMargin = padding + NormalizeToPx(normalWidth_) / 2;
459     if (LessOrEqual(startRadius, barMargin)) {
460         startReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
461     } else {
462         startRadiusHeight = startRadius - std::sqrt(2 * padding * startRadius - padding * padding);
463         startReservedHeight_ = Dimension(startRadiusHeight + (startRadius / barMargin), DimensionUnit::PX);
464     }
465 
466     if (LessOrEqual(endRadius, barMargin)) {
467         endReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
468     } else {
469         endRadiusHeight = endRadius - std::sqrt(2 * padding * endRadius - padding * padding);
470         endReservedHeight_ = Dimension(endRadiusHeight + (endRadius / barMargin), DimensionUnit::PX);
471     }
472     FlushBarWidth();
473 }
474 
InitPanRecognizer()475 void ScrollBar::InitPanRecognizer()
476 {
477     PanDirection panDirection;
478     panDirection.type = positionMode_ == PositionMode::BOTTOM ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
479     panRecognizer_ = MakeRefPtr<PanRecognizer>(1, panDirection, DEFAULT_PAN_DISTANCE.ConvertToPx());
480     panRecognizer_->SetMouseDistance(DRAG_PAN_DISTANCE_MOUSE.ConvertToPx());
481     panRecognizer_->SetOnActionUpdate([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
482         auto scrollBar = weakBar.Upgrade();
483         if (scrollBar) {
484             scrollBar->HandleDragUpdate(info);
485         }
486     });
487     panRecognizer_->SetOnActionEnd([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
488         auto scrollBar = weakBar.Upgrade();
489         if (scrollBar) {
490             scrollBar->HandleDragEnd(info);
491         }
492     });
493     panRecognizer_->SetOnActionStart([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
494         auto scrollBar = weakBar.Upgrade();
495         if (scrollBar) {
496             scrollBar->HandleDragStart(info);
497         }
498     });
499 }
500 
HandleDragStart(const GestureEvent & info)501 void ScrollBar::HandleDragStart(const GestureEvent& info)
502 {
503     if (frictionController_ && frictionController_->IsRunning()) {
504         frictionController_->Stop();
505     }
506     if (scrollPositionCallback_) {
507         scrollPositionCallback_(0, SCROLL_FROM_START);
508         if (dragFRCSceneCallback_) {
509             dragFRCSceneCallback_(0, NG::SceneStatus::START);
510         }
511     }
512     SetDragStartPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
513     isDriving_ = true;
514 }
515 
HandleDragUpdate(const GestureEvent & info)516 void ScrollBar::HandleDragUpdate(const GestureEvent& info)
517 {
518     if (scrollPositionCallback_) {
519         // The offset of the mouse wheel and gesture is opposite.
520         auto offset = info.GetInputEventType() == InputEventType::AXIS ?
521                       info.GetMainDelta() : CalcPatternOffset(info.GetMainDelta());
522         scrollPositionCallback_(offset, SCROLL_FROM_BAR);
523         if (dragFRCSceneCallback_) {
524             dragFRCSceneCallback_(NearZero(info.GetMainDelta()) ? info.GetMainVelocity()
525                                                                 : info.GetMainVelocity() / info.GetMainDelta() * offset,
526                 NG::SceneStatus::RUNNING);
527         }
528     }
529 }
530 
HandleDragEnd(const GestureEvent & info)531 void ScrollBar::HandleDragEnd(const GestureEvent& info)
532 {
533     if (dragFRCSceneCallback_) {
534         dragFRCSceneCallback_(0, NG::SceneStatus::END);
535     }
536     auto velocity = info.GetMainVelocity();
537     if (NearZero(velocity) || info.GetInputEventType() == InputEventType::AXIS) {
538         if (scrollEndCallback_) {
539             scrollEndCallback_();
540         }
541         isDriving_ = false;
542         return;
543     }
544     SetDragEndPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
545     frictionPosition_ = 0.0;
546     if (frictionMotion_) {
547         frictionMotion_->Reset(friction_, 0, velocity);
548     } else {
549         frictionMotion_ = AceType::MakeRefPtr<FrictionMotion>(friction_, 0, velocity);
550         frictionMotion_->AddListener([weakBar = AceType::WeakClaim(this)](double value) {
551             auto scrollBar = weakBar.Upgrade();
552             CHECK_NULL_VOID(scrollBar);
553             scrollBar->ProcessFrictionMotion(value);
554         });
555     }
556     if (calePredictSnapOffsetCallback_ && startScrollSnapMotionCallback_) {
557         auto predictSnapOffset = calePredictSnapOffsetCallback_(CalcPatternOffset(frictionMotion_->GetFinalPosition()),
558                                                                 CalcPatternOffset(GetDragOffset()), -velocity);
559         // If snap scrolling, predictSnapOffset will has a value.
560         if (predictSnapOffset.has_value() && !NearZero(predictSnapOffset.value())) {
561             startScrollSnapMotionCallback_(predictSnapOffset.value(), velocity);
562             return;
563         }
564     }
565 
566     if (!frictionController_) {
567         frictionController_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
568         frictionController_->AddStopListener([weakBar = AceType::WeakClaim(this)]() {
569             auto scrollBar = weakBar.Upgrade();
570             CHECK_NULL_VOID(scrollBar);
571             scrollBar->ProcessFrictionMotionStop();
572         });
573     }
574     frictionController_->PlayMotion(frictionMotion_);
575 }
576 
ProcessFrictionMotion(double value)577 void ScrollBar::ProcessFrictionMotion(double value)
578 {
579     if (scrollPositionCallback_) {
580         auto offset = CalcPatternOffset(value - frictionPosition_);
581         if (!scrollPositionCallback_(offset, SCROLL_FROM_BAR_FLING)) {
582             if (frictionController_ && frictionController_->IsRunning()) {
583                 frictionController_->Stop();
584             }
585         }
586     }
587     frictionPosition_ = value;
588 }
589 
ProcessFrictionMotionStop()590 void ScrollBar::ProcessFrictionMotionStop()
591 {
592     if (scrollEndCallback_) {
593         scrollEndCallback_();
594     }
595     isDriving_ = false;
596 }
597 
OnCollectTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent)598 void ScrollBar::OnCollectTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
599     TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent)
600 {
601     if (panRecognizer_ && isScrollable_) {
602         panRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
603         panRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
604         panRecognizer_->SetNodeId(frameNode->GetId());
605         panRecognizer_->AttachFrameNode(frameNode);
606         panRecognizer_->SetTargetComponent(targetComponent);
607         panRecognizer_->SetIsSystemGesture(true);
608         result.emplace_front(panRecognizer_);
609     }
610 }
611 
ScheduleDisappearDelayTask()612 void ScrollBar::ScheduleDisappearDelayTask()
613 {
614     if (displayMode_ == DisplayMode::AUTO && isScrollable_ && !isHover_) {
615         disappearDelayTask_.Cancel();
616         auto context = PipelineContext::GetCurrentContext();
617         CHECK_NULL_VOID(context);
618         auto taskExecutor = context->GetTaskExecutor();
619         CHECK_NULL_VOID(taskExecutor);
620         disappearDelayTask_.Reset([weak = WeakClaim(this)] {
621             auto scrollBar = weak.Upgrade();
622             CHECK_NULL_VOID(scrollBar);
623             scrollBar->PlayScrollBarDisappearAnimation();
624         });
625         taskExecutor->PostDelayedTask(disappearDelayTask_, TaskExecutor::TaskType::UI, BAR_DISAPPRAE_DELAY_DURATION);
626     }
627 }
628 } // namespace OHOS::Ace::NG
629