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