• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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