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