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_bar/scroll_bar_pattern.h"
17
18 #include "base/log/dump_log.h"
19 #include "core/components/common/layout/constants.h"
20 #include "core/components_ng/event/event_hub.h"
21 #include "core/components_ng/property/measure_utils.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t BAR_DISAPPEAR_DELAY_DURATION = 2000; // 2000ms
27 constexpr int32_t BAR_DISAPPEAR_DURATION = 300; // 300ms
28 constexpr int32_t BAR_APPEAR_DURATION = 100; // 100ms
29 constexpr int32_t BAR_DISAPPEAR_FRAME_RATE = 15; // 15fps, the expected frame rate of opacity animation
30 constexpr int32_t BAR_DISAPPEAR_MIN_FRAME_RATE = 0;
31 constexpr int32_t BAR_DISAPPEAR_MAX_FRAME_RATE = 90;
32 constexpr int32_t SCROLL_BAR_LAYOUT_INFO_COUNT = 120;
33 } // namespace
34
OnAttachToFrameNode()35 void ScrollBarPattern::OnAttachToFrameNode()
36 {
37 auto host = GetHost();
38 CHECK_NULL_VOID(host);
39
40 host->GetRenderContext()->SetClipToFrame(true);
41 }
42
SendAccessibilityEvent(AccessibilityEventType eventType)43 void ScrollBarPattern::SendAccessibilityEvent(AccessibilityEventType eventType)
44 {
45 auto frameNode = GetHost();
46 CHECK_NULL_VOID(frameNode);
47 frameNode->OnAccessibilityEvent(eventType);
48 }
49
OnModifyDone()50 void ScrollBarPattern::OnModifyDone()
51 {
52 Pattern::OnModifyDone();
53 auto host = GetHost();
54 CHECK_NULL_VOID(host);
55 auto layoutProperty = host->GetLayoutProperty<ScrollBarLayoutProperty>();
56 CHECK_NULL_VOID(layoutProperty);
57
58 auto oldDisplayMode = displayMode_;
59 displayMode_ = layoutProperty->GetDisplayMode().value_or(DisplayMode::AUTO);
60 if (oldDisplayMode != displayMode_ && scrollBarProxy_) {
61 if (displayMode_ == DisplayMode::ON) {
62 StopDisappearAnimator();
63 } else if (displayMode_ == DisplayMode::AUTO) {
64 StartDisappearAnimator();
65 }
66 }
67 auto axis = layoutProperty->GetAxis().value_or(Axis::VERTICAL);
68 if (axis_ == axis && scrollableEvent_) {
69 return;
70 }
71
72 axis_ = axis;
73 // scrollPosition callback
74 scrollPositionCallback_ = [weak = WeakClaim(this)](double offset, int32_t source) {
75 auto pattern = weak.Upgrade();
76 CHECK_NULL_RETURN(pattern, false);
77 if (source == SCROLL_FROM_START) {
78 pattern->StopDisappearAnimator();
79 // AccessibilityEventType::SCROLL_START
80 return true;
81 }
82 return pattern->UpdateCurrentOffset(offset, source);
83 };
84 scrollEndCallback_ = [weak = WeakClaim(this)]() {
85 auto pattern = weak.Upgrade();
86 CHECK_NULL_VOID(pattern);
87 if (pattern->GetDisplayMode() == DisplayMode::AUTO) {
88 pattern->StartDisappearAnimator();
89 }
90 // AccessibilityEventType::SCROLL_END
91 };
92
93 auto hub = host->GetEventHub<EventHub>();
94 CHECK_NULL_VOID(hub);
95 auto gestureHub = hub->GetOrCreateGestureEventHub();
96 CHECK_NULL_VOID(gestureHub);
97 if (scrollableEvent_) {
98 gestureHub->RemoveScrollableEvent(scrollableEvent_);
99 }
100 scrollableEvent_ = MakeRefPtr<ScrollableEvent>(axis);
101 scrollableEvent_->SetInBarRegionCallback([weak = AceType::WeakClaim(this)]
102 (const PointF& point, SourceType source) {
103 auto scrollBarPattern = weak.Upgrade();
104 CHECK_NULL_RETURN(scrollBarPattern, false);
105 if (!scrollBarPattern->HasChild()
106 && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
107 auto scrollBar = scrollBarPattern->scrollBar_;
108 CHECK_NULL_RETURN(scrollBar, false);
109 if (source == SourceType::MOUSE) {
110 return scrollBar->InBarHoverRegion(Point(point.GetX(), point.GetY()));
111 }
112 return scrollBar->InBarTouchRegion(Point(point.GetX(), point.GetY()));
113 } else {
114 return scrollBarPattern->childRect_.IsInRegion(point);
115 }
116 }
117 );
118 scrollableEvent_->SetBarCollectTouchTargetCallback(
119 [weak = AceType::WeakClaim(this)](const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
120 TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
121 ResponseLinkResult& responseLinkResult) {
122 auto scrollBarPattern = weak.Upgrade();
123 CHECK_NULL_VOID(scrollBarPattern);
124 if (!scrollBarPattern->HasChild()
125 && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
126 auto scrollBar = scrollBarPattern->scrollBar_;
127 CHECK_NULL_VOID(scrollBar);
128 scrollBar->OnCollectTouchTarget(
129 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
130 } else {
131 scrollBarPattern->OnCollectTouchTarget(
132 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
133 }
134 });
135 gestureHub->AddScrollableEvent(scrollableEvent_);
136 SetAccessibilityAction();
137 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
138 SetScrollBar(DisplayMode::ON);
139 }
140 if (!panRecognizer_) {
141 InitPanRecognizer();
142 }
143 }
144
SetScrollBar(DisplayMode displayMode)145 void ScrollBarPattern::SetScrollBar(DisplayMode displayMode)
146 {
147 auto host = GetHost();
148 CHECK_NULL_VOID(host);
149 if (displayMode == DisplayMode::OFF) {
150 if (scrollBar_) {
151 auto gestureHub = GetGestureHub();
152 if (gestureHub) {
153 gestureHub->RemoveTouchEvent(scrollBar_->GetTouchEvent());
154 }
155 scrollBar_.Reset();
156 if (scrollBarOverlayModifier_) {
157 scrollBarOverlayModifier_->SetOpacity(0);
158 }
159 }
160 return;
161 }
162 DisplayMode oldDisplayMode = DisplayMode::OFF;
163 if (!scrollBar_) {
164 scrollBar_ = AceType::MakeRefPtr<ScrollBar>();
165 // set the scroll bar style
166 if (GetAxis() == Axis::HORIZONTAL) {
167 scrollBar_->SetPositionMode(PositionMode::BOTTOM);
168 if (scrollBarOverlayModifier_) {
169 scrollBarOverlayModifier_->SetPositionMode(PositionMode::BOTTOM);
170 }
171 }
172 RegisterScrollBarEventTask();
173 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
174 } else {
175 oldDisplayMode = scrollBar_->GetDisplayMode();
176 }
177
178 if (oldDisplayMode != displayMode) {
179 scrollBar_->SetDisplayMode(displayMode);
180 if (scrollBarOverlayModifier_ && scrollBar_->IsScrollable()) {
181 scrollBarOverlayModifier_->SetOpacity(UINT8_MAX);
182 }
183 scrollBar_->ScheduleDisappearDelayTask();
184 }
185 }
186
HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent)187 void ScrollBarPattern::HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent)
188 {
189 CHECK_NULL_VOID(scrollBar_ && scrollBar_->NeedScrollBar());
190 scrollBar_->SetOutBoundary(std::abs(scrollBarOutBoundaryExtent));
191 }
192
UpdateScrollBarOffset()193 void ScrollBarPattern::UpdateScrollBarOffset()
194 {
195 CHECK_NULL_VOID(scrollBar_);
196 auto host = GetHost();
197 CHECK_NULL_VOID(host);
198 auto geometryNode = host->GetGeometryNode();
199 auto viewSize = geometryNode->GetFrameSize();
200
201 auto layoutProperty = host->GetLayoutProperty<ScrollBarLayoutProperty>();
202 CHECK_NULL_VOID(layoutProperty);
203 auto estimatedHeight = GetControlDistance() + (GetAxis() == Axis::VERTICAL ? viewSize.Height() : viewSize.Width());
204
205 UpdateScrollBarRegion(scrollableNodeOffset_, estimatedHeight,
206 Size(viewSize.Width(), viewSize.Height()), Offset(0.0f, 0.0f));
207 }
208
UpdateScrollBarRegion(float offset,float estimatedHeight,Size viewPort,Offset viewOffset)209 void ScrollBarPattern::UpdateScrollBarRegion(float offset, float estimatedHeight, Size viewPort, Offset viewOffset)
210 {
211 // outer scrollbar, viewOffset is padding offset
212 if (scrollBar_) {
213 auto mainSize = axis_ == Axis::VERTICAL ? viewPort.Height() : viewPort.Width();
214 bool scrollable = GreatNotEqual(estimatedHeight, mainSize);
215 if (scrollBar_->IsScrollable() != scrollable) {
216 scrollBar_->SetScrollable(scrollable);
217 if (scrollBarOverlayModifier_) {
218 scrollBarOverlayModifier_->SetOpacity(scrollable ? UINT8_MAX : 0);
219 }
220 if (scrollable) {
221 scrollBar_->ScheduleDisappearDelayTask();
222 }
223 }
224 Offset scrollOffset = { offset, offset };
225 scrollBar_->SetReverse(IsReverse());
226 scrollBar_->UpdateScrollBarRegion(viewOffset, viewPort, scrollOffset, estimatedHeight);
227 scrollBar_->MarkNeedRender();
228 }
229 }
230
RegisterScrollBarEventTask()231 void ScrollBarPattern::RegisterScrollBarEventTask()
232 {
233 CHECK_NULL_VOID(scrollBar_);
234 auto host = GetHost();
235 CHECK_NULL_VOID(host);
236 auto gestureHub = GetGestureHub();
237 auto inputHub = GetInputHub();
238 CHECK_NULL_VOID(gestureHub);
239 CHECK_NULL_VOID(inputHub);
240 scrollBar_->SetGestureEvent();
241 scrollBar_->SetMouseEvent();
242 scrollBar_->SetHoverEvent();
243 scrollBar_->SetMarkNeedRenderFunc([weak = AceType::WeakClaim(AceType::RawPtr(host))]() {
244 auto host = weak.Upgrade();
245 CHECK_NULL_VOID(host);
246 host->MarkNeedRenderOnly();
247 });
248
249 auto scrollCallback = [weak = WeakClaim(this)](double offset, int32_t source) {
250 auto pattern = weak.Upgrade();
251 CHECK_NULL_RETURN(pattern, false);
252 pattern->scrollBarProxy_->NotifyScrollBarNode(offset, source);
253 pattern->scrollPositionCallback_(0.0, SCROLL_FROM_START);
254 return true;
255 };
256 scrollBar_->SetScrollPositionCallback(std::move(scrollCallback));
257
258 auto scrollEnd = [weak = WeakClaim(this)]() {
259 auto pattern = weak.Upgrade();
260 CHECK_NULL_VOID(pattern);
261 pattern->scrollBarProxy_->NotifyScrollStop();
262 };
263 scrollBar_->SetScrollEndCallback(std::move(scrollEnd));
264
265 gestureHub->AddTouchEvent(scrollBar_->GetTouchEvent());
266 inputHub->AddOnMouseEvent(scrollBar_->GetMouseEvent());
267 inputHub->AddOnHoverEvent(scrollBar_->GetHoverEvent());
268 }
269
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)270 bool ScrollBarPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
271 {
272 if (config.skipMeasure && config.skipLayout) {
273 return false;
274 }
275 bool updateFlag = false;
276 if (!HasChild() && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
277 updateFlag = true;
278 } else {
279 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
280 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
281 auto layoutAlgorithm = DynamicCast<ScrollBarLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
282 CHECK_NULL_RETURN(layoutAlgorithm, false);
283 scrollableDistance_ = layoutAlgorithm->GetScrollableDistance();
284 }
285 if (displayMode_ != DisplayMode::OFF) {
286 updateFlag = UpdateScrollBarDisplay() || updateFlag;
287 }
288 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
289 updateFlag = CheckChildState() || updateFlag;
290 }
291 return updateFlag;
292 }
293
OnColorConfigurationUpdate()294 void ScrollBarPattern::OnColorConfigurationUpdate()
295 {
296 CHECK_NULL_VOID(scrollBar_);
297 auto pipelineContext = GetContext();
298 CHECK_NULL_VOID(pipelineContext);
299 auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
300 CHECK_NULL_VOID(theme);
301 scrollBar_->SetForegroundColor(theme->GetForegroundColor());
302 scrollBar_->SetBackgroundColor(theme->GetBackgroundColor());
303 }
304
UpdateScrollBarDisplay()305 bool ScrollBarPattern::UpdateScrollBarDisplay()
306 {
307 auto host = GetHost();
308 CHECK_NULL_RETURN(host, false);
309 auto renderContext = host->GetRenderContext();
310 CHECK_NULL_RETURN(renderContext, false);
311 if (controlDistanceChanged_) {
312 controlDistanceChanged_ = false;
313 if (!Positive(controlDistance_)) {
314 SetOpacity(0);
315 return true;
316 }
317 SetOpacity(UINT8_MAX);
318 if (displayMode_ == DisplayMode::AUTO) {
319 StartDisappearAnimator();
320 }
321 return true;
322 }
323 if (!Positive(controlDistance_)) {
324 SetOpacity(0);
325 return true;
326 }
327 return false;
328 }
329
IsAtTop() const330 bool ScrollBarPattern::IsAtTop() const
331 {
332 return LessOrEqual(currentOffset_, 0.0);
333 }
334
IsAtBottom() const335 bool ScrollBarPattern::IsAtBottom() const
336 {
337 return GreatOrEqual(currentOffset_, scrollableDistance_);
338 }
339
ValidateOffset()340 void ScrollBarPattern::ValidateOffset()
341 {
342 if (scrollableDistance_ <= 0.0f) {
343 return;
344 }
345 currentOffset_ = std::clamp(currentOffset_, 0.0f, scrollableDistance_);
346 }
347
UpdateCurrentOffset(float delta,int32_t source)348 bool ScrollBarPattern::UpdateCurrentOffset(float delta, int32_t source)
349 {
350 auto host = GetHost();
351 CHECK_NULL_RETURN(host, false);
352 if (NearZero(delta) || axis_ == Axis::NONE) {
353 return false;
354 }
355
356 lastOffset_ = currentOffset_;
357 currentOffset_ += delta;
358 if (scrollBarProxy_ && lastOffset_ != currentOffset_) {
359 scrollBarProxy_->NotifyScrollableNode(-delta, source, AceType::WeakClaim(this));
360 }
361 AddScrollBarLayoutInfo();
362 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
363 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
364 } else {
365 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
366 }
367 return true;
368 }
369
AddScrollBarLayoutInfo()370 void ScrollBarPattern::AddScrollBarLayoutInfo()
371 {
372 if (outerScrollBarLayoutInfos_.size() >= SCROLL_BAR_LAYOUT_INFO_COUNT) {
373 outerScrollBarLayoutInfos_.pop_front();
374 }
375 outerScrollBarLayoutInfos_.push_back(OuterScrollBarLayoutInfo({
376 .layoutTime_ = GetSysTimestamp(),
377 .currentOffset_ = currentOffset_,
378 .scrollableNodeOffset_ = scrollableNodeOffset_,
379 }));
380 }
381
GetAxisDumpInfo()382 void ScrollBarPattern::GetAxisDumpInfo()
383 {
384 switch (axis_) {
385 case Axis::NONE: {
386 DumpLog::GetInstance().AddDesc("Axis: NONE");
387 break;
388 }
389 case Axis::VERTICAL: {
390 DumpLog::GetInstance().AddDesc("Axis: VERTICAL");
391 break;
392 }
393 case Axis::HORIZONTAL: {
394 DumpLog::GetInstance().AddDesc("Axis: HORIZONTAL");
395 break;
396 }
397 case Axis::FREE: {
398 DumpLog::GetInstance().AddDesc("Axis: FREE");
399 break;
400 }
401 default: {
402 break;
403 }
404 }
405 }
406
GetDisplayModeDumpInfo()407 void ScrollBarPattern::GetDisplayModeDumpInfo()
408 {
409 switch (displayMode_) {
410 case DisplayMode::OFF: {
411 DumpLog::GetInstance().AddDesc("outerScrollBarState: OFF");
412 break;
413 }
414 case DisplayMode::AUTO: {
415 DumpLog::GetInstance().AddDesc("outerScrollBarState: AUTO");
416 break;
417 }
418 case DisplayMode::ON: {
419 DumpLog::GetInstance().AddDesc("outerScrollBarState: ON");
420 break;
421 }
422 default: {
423 break;
424 }
425 }
426 }
427
GetPanDirectionDumpInfo()428 void ScrollBarPattern::GetPanDirectionDumpInfo()
429 {
430 if (panRecognizer_) {
431 switch (panRecognizer_->GetAxisDirection()) {
432 case Axis::NONE: {
433 DumpLog::GetInstance().AddDesc("panDirection: NONE");
434 break;
435 }
436 case Axis::VERTICAL: {
437 DumpLog::GetInstance().AddDesc("panDirection: VERTICAL");
438 break;
439 }
440 case Axis::HORIZONTAL: {
441 DumpLog::GetInstance().AddDesc("panDirection: HORIZONTAL");
442 break;
443 }
444 case Axis::FREE: {
445 DumpLog::GetInstance().AddDesc("panDirection: FREE");
446 break;
447 }
448 default: {
449 break;
450 }
451 }
452 } else {
453 DumpLog::GetInstance().AddDesc("panDirection is null");
454 }
455 }
456
DumpAdvanceInfo()457 void ScrollBarPattern::DumpAdvanceInfo()
458 {
459 GetAxisDumpInfo();
460 GetDisplayModeDumpInfo();
461 GetPanDirectionDumpInfo();
462 hasChild_ ? DumpLog::GetInstance().AddDesc("hasChild: true") : DumpLog::GetInstance().AddDesc("hasChild: false");
463 preFrameChildState_ ? DumpLog::GetInstance().AddDesc("preFrameChildState: true")
464 : DumpLog::GetInstance().AddDesc("preFrameChildState: false");
465 if (!hasChild_ && scrollBar_) {
466 scrollBar_->DumpAdvanceInfo();
467 }
468 DumpLog::GetInstance().AddDesc(std::string("childRect: ").append(childRect_.ToString()));
469 DumpLog::GetInstance().AddDesc(std::string("scrollableDistance: ").append(std::to_string(scrollableDistance_)));
470 DumpLog::GetInstance().AddDesc(std::string("controlDistance_: ").append(std::to_string(controlDistance_)));
471 DumpLog::GetInstance().AddDesc("==========================outerScrollBarLayoutInfos==========================");
472 for (const auto& info : outerScrollBarLayoutInfos_) {
473 DumpLog::GetInstance().AddDesc(info.ToString());
474 }
475 DumpLog::GetInstance().AddDesc("==========================outerScrollBarLayoutInfos==========================");
476 }
477
StartDisappearAnimator()478 void ScrollBarPattern::StartDisappearAnimator()
479 {
480 if (!Positive(controlDistance_)) {
481 return;
482 }
483 if (disapplearDelayTask_) {
484 disapplearDelayTask_.Cancel();
485 }
486 auto context = GetContext();
487 CHECK_NULL_VOID(context);
488 auto taskExecutor = context->GetTaskExecutor();
489 CHECK_NULL_VOID(taskExecutor);
490 SetOpacity(UINT8_MAX);
491 disapplearDelayTask_.Reset([weak = WeakClaim(this)] {
492 auto scrollBar = weak.Upgrade();
493 CHECK_NULL_VOID(scrollBar);
494 AnimationOption option;
495 if (!scrollBar->HasChild()
496 && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
497 option.SetCurve(Curves::SHARP);
498 } else {
499 option.SetCurve(Curves::FRICTION);
500 }
501 option.SetDuration(BAR_DISAPPEAR_DURATION);
502 option.SetFrameRateRange(AceType::MakeRefPtr<FrameRateRange>(
503 BAR_DISAPPEAR_MIN_FRAME_RATE, BAR_DISAPPEAR_MAX_FRAME_RATE, BAR_DISAPPEAR_FRAME_RATE));
504 auto disappearAnimation = AnimationUtils::StartAnimation(option, [weak]() {
505 auto scrollBar = weak.Upgrade();
506 CHECK_NULL_VOID(scrollBar);
507 scrollBar->SetOpacity(0);
508 });
509 scrollBar->SetDisappearAnimation(disappearAnimation);
510 });
511 taskExecutor->PostDelayedTask(disapplearDelayTask_, TaskExecutor::TaskType::UI, BAR_DISAPPEAR_DELAY_DURATION,
512 "ArkUIScrollBarDisappearAnimation");
513 }
514
StopDisappearAnimator()515 void ScrollBarPattern::StopDisappearAnimator()
516 {
517 if (!Positive(controlDistance_)) {
518 return;
519 }
520 if (disapplearDelayTask_) {
521 disapplearDelayTask_.Cancel();
522 }
523 if (disappearAnimation_) {
524 AnimationUtils::StopAnimation(disappearAnimation_);
525 }
526 if (!HasChild()
527 && Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
528 AnimationOption option;
529 option.SetCurve(Curves::SHARP);
530 option.SetDuration(BAR_APPEAR_DURATION);
531 option.SetFrameRateRange(AceType::MakeRefPtr<FrameRateRange>(
532 BAR_DISAPPEAR_MIN_FRAME_RATE, BAR_DISAPPEAR_MAX_FRAME_RATE, BAR_DISAPPEAR_FRAME_RATE));
533 AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
534 auto scrollBar = weak.Upgrade();
535 CHECK_NULL_VOID(scrollBar);
536 scrollBar->SetOpacity(UINT8_MAX);
537 });
538 } else {
539 SetOpacity(UINT8_MAX);
540 }
541 }
542
SetOpacity(uint8_t value)543 void ScrollBarPattern::SetOpacity(uint8_t value)
544 {
545 auto host = GetHost();
546 CHECK_NULL_VOID(host);
547 auto renderContext = host->GetRenderContext();
548 CHECK_NULL_VOID(renderContext);
549 opacity_ = value;
550 renderContext->UpdateOpacity(static_cast<double>(value) / UINT8_MAX);
551 host->MarkNeedRenderOnly();
552 }
553
SetAccessibilityAction()554 void ScrollBarPattern::SetAccessibilityAction()
555 {
556 auto host = GetHost();
557 CHECK_NULL_VOID(host);
558 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
559 CHECK_NULL_VOID(accessibilityProperty);
560 accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
561 const auto& pattern = weakPtr.Upgrade();
562 CHECK_NULL_VOID(pattern);
563 if (pattern->GetAxis() == Axis::NONE || pattern->GetScrollableDistance() == 0.0f) {
564 return;
565 }
566 pattern->UpdateCurrentOffset(pattern->GetChildOffset(), SCROLL_FROM_BAR);
567 // AccessibilityEventType::SCROLL_END
568 });
569
570 accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
571 const auto& pattern = weakPtr.Upgrade();
572 CHECK_NULL_VOID(pattern);
573 if (pattern->GetAxis() == Axis::NONE || pattern->GetScrollableDistance() == 0.0f) {
574 return;
575 }
576 pattern->UpdateCurrentOffset(-pattern->GetChildOffset(), SCROLL_FROM_BAR);
577 // AccessibilityEventType::SCROLL_END
578 });
579 }
580
InitPanRecognizer()581 void ScrollBarPattern::InitPanRecognizer()
582 {
583 PanDirection panDirection;
584 panDirection.type = axis_ == Axis::HORIZONTAL ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
585 const static int32_t PLATFORM_VERSION_TEN = 10;
586 float distance = DEFAULT_PAN_DISTANCE.Value();
587 auto context = PipelineContext::GetCurrentContext();
588 if (context && (context->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN)) {
589 distance = DEFAULT_PAN_DISTANCE.ConvertToPx();
590 }
591 panRecognizer_ = MakeRefPtr<PanRecognizer>(1, panDirection, distance);
592 panRecognizer_->SetOnActionUpdate([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
593 auto scrollBar = weakBar.Upgrade();
594 if (scrollBar) {
595 scrollBar->HandleDragUpdate(info);
596 }
597 });
598 panRecognizer_->SetOnActionEnd([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
599 auto scrollBar = weakBar.Upgrade();
600 if (scrollBar) {
601 scrollBar->HandleDragEnd(info);
602 }
603 });
604 panRecognizer_->SetOnActionStart([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
605 auto scrollBar = weakBar.Upgrade();
606 if (scrollBar) {
607 scrollBar->HandleDragStart(info);
608 }
609 });
610 panRecognizer_->SetOnActionCancel([weakBar = AceType::WeakClaim(this)]() {
611 auto scrollBar = weakBar.Upgrade();
612 if (scrollBar) {
613 GestureEvent info;
614 scrollBar->HandleDragEnd(info);
615 }
616 });
617 }
618
HandleDragStart(const GestureEvent & info)619 void ScrollBarPattern::HandleDragStart(const GestureEvent& info)
620 {
621 StopMotion();
622 SetDragStartPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
623 TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "outer scrollBar drag start");
624 ACE_SCOPED_TRACE("outer scrollBar HandleDragStart");
625 if (scrollPositionCallback_) {
626 if (scrollBarProxy_) {
627 scrollBarProxy_->NotifyScrollStart();
628 scrollBarProxy_->SetScrollSnapTrigger_(true);
629 }
630 scrollPositionCallback_(0, SCROLL_FROM_START);
631 }
632 }
633
HandleDragUpdate(const GestureEvent & info)634 void ScrollBarPattern::HandleDragUpdate(const GestureEvent& info)
635 {
636 if (scrollPositionCallback_) {
637 auto offset = info.GetMainDelta();
638 if (IsReverse()) {
639 offset = -offset;
640 }
641 // The offset of the mouse wheel and gesture is opposite.
642 if (info.GetInputEventType() == InputEventType::AXIS && !NearZero(controlDistance_)) {
643 offset = - offset * scrollableDistance_ / controlDistance_;
644 }
645 ACE_SCOPED_TRACE("outer scrollBar HandleDragUpdate offset:%f", offset);
646 scrollPositionCallback_(offset, SCROLL_FROM_BAR);
647 }
648 }
649
HandleDragEnd(const GestureEvent & info)650 void ScrollBarPattern::HandleDragEnd(const GestureEvent& info)
651 {
652 auto velocity = IsReverse() ? -info.GetMainVelocity() : info.GetMainVelocity();
653 TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "outer scrollBar drag end, velocity is %{public}f", velocity);
654 ACE_SCOPED_TRACE("outer scrollBar HandleDragEnd velocity:%f", velocity);
655 SetDragEndPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
656 if (NearZero(velocity) || info.GetInputEventType() == InputEventType::AXIS) {
657 if (scrollEndCallback_) {
658 if (scrollBarProxy_) {
659 scrollBarProxy_->NotifyScrollStop();
660 scrollBarProxy_->SetScrollSnapTrigger_(false);
661 }
662 scrollEndCallback_();
663 }
664 return;
665 }
666 frictionPosition_ = 0.0;
667 if (frictionMotion_) {
668 frictionMotion_->Reset(friction_, 0, velocity);
669 } else {
670 frictionMotion_ = AceType::MakeRefPtr<FrictionMotion>(friction_, 0, velocity);
671 frictionMotion_->AddListener([weakBar = AceType::WeakClaim(this)](double value) {
672 auto scrollBar = weakBar.Upgrade();
673 CHECK_NULL_VOID(scrollBar);
674 scrollBar->ProcessFrictionMotion(value);
675 });
676 }
677 CHECK_NULL_VOID(!scrollBarProxy_ || !scrollBarProxy_->NotifySnapScroll(-(frictionMotion_->GetFinalPosition()),
678 velocity, GetScrollableDistance(), static_cast<float>(GetDragOffset())));
679 scrollBarProxy_->SetScrollSnapTrigger_(false);
680 if (!frictionController_) {
681 frictionController_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
682 frictionController_->AddStopListener([weakBar = AceType::WeakClaim(this)]() {
683 auto scrollBar = weakBar.Upgrade();
684 CHECK_NULL_VOID(scrollBar);
685 scrollBar->ProcessFrictionMotionStop();
686 });
687 }
688 frictionController_->PlayMotion(frictionMotion_);
689 }
690
ProcessFrictionMotion(double value)691 void ScrollBarPattern::ProcessFrictionMotion(double value)
692 {
693 if (scrollPositionCallback_) {
694 auto offset = value - frictionPosition_;
695 scrollPositionCallback_(offset, SCROLL_FROM_BAR_FLING);
696 }
697 frictionPosition_ = value;
698 }
699
ProcessFrictionMotionStop()700 void ScrollBarPattern::ProcessFrictionMotionStop()
701 {
702 if (scrollEndCallback_) {
703 if (scrollBarProxy_) {
704 scrollBarProxy_->NotifyScrollStop();
705 }
706 scrollEndCallback_();
707 }
708 }
709
OnCollectTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)710 void ScrollBarPattern::OnCollectTouchTarget(const OffsetF& coordinateOffset,
711 const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result, const RefPtr<FrameNode>& frameNode,
712 const RefPtr<TargetComponent>& targetComponent, ResponseLinkResult& responseLinkResult)
713 {
714 if (panRecognizer_) {
715 panRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
716 panRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
717 panRecognizer_->SetNodeId(frameNode->GetId());
718 panRecognizer_->AttachFrameNode(frameNode);
719 panRecognizer_->SetTargetComponent(targetComponent);
720 panRecognizer_->SetIsSystemGesture(true);
721 panRecognizer_->SetRecognizerType(GestureTypeName::PAN_GESTURE);
722 result.emplace_front(panRecognizer_);
723 responseLinkResult.emplace_back(panRecognizer_);
724 }
725 }
726
IsReverse() const727 bool ScrollBarPattern::IsReverse() const
728 {
729 return isReverse_;
730 }
731
SetReverse(bool reverse)732 void ScrollBarPattern::SetReverse(bool reverse)
733 {
734 isReverse_ = reverse;
735 }
736 } // namespace OHOS::Ace::NG
737