• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/scroll_bar/render_scroll_bar.h"
17 
18 #include "base/utils/string_utils.h"
19 #include "core/animation/curve_animation.h"
20 #include "core/animation/keyframe.h"
21 #include "core/animation/keyframe_animation.h"
22 #include "core/components/display/render_display.h"
23 #include "core/components/scroll_bar/scroll_bar_element.h"
24 
25 namespace OHOS::Ace {
26 namespace {
27 
28 constexpr int32_t STOP_DURATION = 2000; // 2000ms
29 constexpr double KEYTIME_START = 0.0;
30 constexpr double KEYTIME_MIDDLE = 0.7;
31 constexpr double KEYTIME_END = 1.0;
32 
33 } // namespace
34 
~RenderScrollBar()35 RenderScrollBar::~RenderScrollBar()
36 {
37     if (proxy_) {
38         proxy_->UnRegisterScrollableNode(AceType::WeakClaim(this));
39     }
40 }
41 
Update(const RefPtr<Component> & component)42 void RenderScrollBar::Update(const RefPtr<Component>& component)
43 {
44     auto scrollBarComponent = AceType::DynamicCast<ScrollBarComponent>(component);
45     if (!scrollBarComponent) {
46         LOGE("Type of component is not ScrollBarComponent.");
47         return;
48     }
49     isAxisChanged_ = (axis_ == scrollBarComponent->GetAxis());
50     axis_ = scrollBarComponent->GetAxis();
51     displayMode_ = scrollBarComponent->GetDisplayMode();
52     proxy_ = scrollBarComponent->GetScrollBarProxy();
53     if (proxy_) {
54         proxy_->UnRegisterScrollBar(AceType::WeakClaim(this));
55         proxy_->RegisterScrollBar(AceType::WeakClaim(this));
56     }
57     InitOpacity();
58     InitRecognizer();
59     InitAnimator();
60     InitChildPosition();
61     MarkNeedLayout();
62 }
63 
InitRecognizer()64 void RenderScrollBar::InitRecognizer()
65 {
66     if (!isAxisChanged_ && dragRecognizer_) {
67         LOGW("Axis is not change and DragRecognizer is already exist.");
68         return;
69     }
70     dragRecognizer_ = AceType::MakeRefPtr<DragRecognizer>(axis_);
71     dragRecognizer_->SetOnDragStart([weak = WeakClaim(this)](const DragStartInfo& startInfo) {
72         auto scrollBar = weak.Upgrade();
73         if (scrollBar) {
74             scrollBar->HandleDragStart(startInfo);
75         }
76     });
77     dragRecognizer_->SetOnDragUpdate([weak = WeakClaim(this)](const DragUpdateInfo& updateInfo) {
78         auto scrollBar = weak.Upgrade();
79         if (scrollBar) {
80             scrollBar->HandleDragUpdate(updateInfo);
81         }
82     });
83     dragRecognizer_->SetOnDragEnd([weak = WeakClaim(this)](const DragEndInfo& endInfo) {
84         auto scrollBar = weak.Upgrade();
85         if (scrollBar) {
86             scrollBar->HandleDragFinish();
87         }
88     });
89     dragRecognizer_->SetOnDragCancel([weak = WeakClaim(this)]() {
90         auto scrollBar = weak.Upgrade();
91         if (scrollBar) {
92             scrollBar->HandleDragFinish();
93         }
94     });
95 }
96 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)97 void RenderScrollBar::OnTouchTestHit(
98     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
99 {
100     if (axis_ != Axis::NONE && displayMode_ != DisplayMode::OFF) {
101         dragRecognizer_->SetCoordinateOffset(coordinateOffset);
102         result.emplace_back(dragRecognizer_);
103     }
104 }
105 
HandleDragStart(const DragStartInfo & info)106 void RenderScrollBar::HandleDragStart(const DragStartInfo& info)
107 {
108     auto child = GetChildren().front();
109     if (!child) {
110         return;
111     }
112 
113     StopAnimator();
114 }
115 
HandleDragUpdate(const DragUpdateInfo & info)116 void RenderScrollBar::HandleDragUpdate(const DragUpdateInfo& info)
117 {
118     auto child = GetChildren().front();
119     if (!child) {
120         return;
121     }
122     StopAnimator();
123     if (axis_ == Axis::HORIZONTAL) {
124         auto localX = info.GetLocalLocation().GetX();
125         if (GreatOrEqual(localX, GetTouchRect().Left()) && LessOrEqual(localX, GetTouchRect().Right())) {
126             double positionX = std::clamp(child->GetPosition().GetX() + info.GetDelta().GetX(), 0.0,
127                 (GetLayoutSize() - child->GetLayoutSize()).Width());
128             child->SetPosition(Offset(positionX, child->GetPosition().GetY()));
129             MarkNeedRender();
130             if (proxy_) {
131                 proxy_->NotifyScrollableNode(-info.GetMainDelta(), AceType::WeakClaim(this));
132             }
133         }
134     } else {
135         auto localY = info.GetLocalLocation().GetY();
136         if (GreatOrEqual(localY, GetTouchRect().Top()) && LessOrEqual(localY, GetTouchRect().Bottom())) {
137             double positionY = std::clamp(child->GetPosition().GetY() + info.GetDelta().GetY(), 0.0,
138                 (GetLayoutSize() - child->GetLayoutSize()).Height());
139             child->SetPosition(Offset(child->GetPosition().GetX(), positionY));
140             MarkNeedRender();
141             if (proxy_) {
142                 proxy_->NotifyScrollableNode(-info.GetMainDelta(), AceType::WeakClaim(this));
143             }
144         }
145     }
146     childPosition_ = child->GetPosition();
147 }
148 
HandleDragFinish()149 void RenderScrollBar::HandleDragFinish()
150 {
151     if (displayMode_ == DisplayMode::AUTO && disappearAnimator_) {
152         if (!disappearAnimator_->IsStopped()) {
153             disappearAnimator_->Stop();
154         }
155         disappearAnimator_->Play();
156     }
157 }
158 
InitOpacity()159 void RenderScrollBar::InitOpacity()
160 {
161     switch (displayMode_) {
162         case DisplayMode::OFF:
163             opacity_ = 0;
164             break;
165         case DisplayMode::ON:
166             opacity_ = UINT8_MAX;
167             break;
168         case DisplayMode::AUTO:
169             opacity_ = 0;
170             break;
171         default:
172             break;
173     }
174     UpdateDisplayOpacity(opacity_);
175 }
176 
InitChildPosition()177 void RenderScrollBar::InitChildPosition()
178 {
179     auto child = GetLastChild();
180     if (!child) {
181         return;
182     }
183     auto childPosition = child->GetPosition();
184     if (axis_ == Axis::VERTICAL) {
185         childPosition.SetX(0.0);
186     } else if (axis_ == Axis::HORIZONTAL) {
187         childPosition.SetY(0.0);
188     } else {
189         LOGD("Axis of ScrollBar is not support: %{public}d", axis_);
190         return;
191     }
192     childPosition_ = childPosition;
193 }
194 
InitAnimator()195 void RenderScrollBar::InitAnimator()
196 {
197     if (disappearAnimator_ && !disappearAnimator_->IsStopped()) {
198         disappearAnimator_->Stop();
199     }
200     if (displayMode_ != DisplayMode::AUTO) {
201         LOGE("DisplayMode is not auto, don't need animator.");
202         return;
203     }
204     if (disappearAnimator_) {
205         disappearAnimator_->Play();
206         return;
207     }
208 
209     disappearAnimator_ = CREATE_ANIMATOR(context_);
210     auto hiddenStartKeyframe = AceType::MakeRefPtr<Keyframe<int32_t>>(KEYTIME_START, UINT8_MAX);
211     auto hiddenMiddleKeyframe = AceType::MakeRefPtr<Keyframe<int32_t>>(KEYTIME_MIDDLE, UINT8_MAX);
212     auto hiddenEndKeyframe = AceType::MakeRefPtr<Keyframe<int32_t>>(KEYTIME_END, 0);
213     hiddenMiddleKeyframe->SetCurve(Curves::LINEAR);
214     hiddenEndKeyframe->SetCurve(Curves::FRICTION);
215 
216     auto animation = AceType::MakeRefPtr<KeyframeAnimation<int32_t>>();
217     animation->AddKeyframe(hiddenStartKeyframe);
218     animation->AddKeyframe(hiddenMiddleKeyframe);
219     animation->AddKeyframe(hiddenEndKeyframe);
220     animation->AddListener([weakBar = AceType::WeakClaim(this)](int32_t value) {
221         auto scrollBar = weakBar.Upgrade();
222         if (scrollBar) {
223             scrollBar->opacity_ = value;
224             scrollBar->UpdateDisplayOpacity(value);
225         }
226     });
227     disappearAnimator_->AddInterpolator(animation);
228     disappearAnimator_->SetDuration(STOP_DURATION);
229     disappearAnimator_->Play();
230 }
231 
StopAnimator()232 void RenderScrollBar::StopAnimator()
233 {
234     if (disappearAnimator_ && !disappearAnimator_->IsStopped()) {
235         disappearAnimator_->Stop();
236     }
237     if (displayMode_ != DisplayMode::OFF) {
238         UpdateDisplayOpacity(UINT8_MAX);
239     }
240     MarkNeedRender();
241 }
242 
StartAnimator()243 void RenderScrollBar::StartAnimator()
244 {
245     if (!disappearAnimator_) {
246         LOGE("Animator is not exist.");
247         return;
248     }
249     if (!disappearAnimator_->IsStopped()) {
250         disappearAnimator_->Stop();
251     }
252     disappearAnimator_->Play();
253 }
254 
UpdateDisplayOpacity(int32_t opacity)255 void RenderScrollBar::UpdateDisplayOpacity(int32_t opacity)
256 {
257     auto parent = GetParent().Upgrade();
258     while (parent) {
259         auto display = AceType::DynamicCast<RenderDisplay>(parent);
260         if (display) {
261             display->UpdateOpacity(opacity);
262             break;
263         }
264         parent = parent->GetParent().Upgrade();
265     }
266 }
267 
PerformLayout()268 void RenderScrollBar::PerformLayout()
269 {
270     if (!GetChildren().empty()) {
271         const auto& child = GetChildren().front();
272         child->Layout(LayoutParam(GetLayoutParam().GetMaxSize(), Size()));
273         child->SetPosition(childPosition_);
274         childRect_ = Rect(child->GetPosition(), child->GetLayoutSize());
275     }
276     SetLayoutSize(GetLayoutParam().GetMaxSize());
277 }
278 
OnPaintFinish()279 void RenderScrollBar::OnPaintFinish()
280 {
281     auto child = GetLastChild();
282     if (child) {
283         childRect_ = Rect(child->GetPosition(), child->GetLayoutSize());
284     }
285 }
286 
287 } // namespace OHOS::Ace
288