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