1 /*
2 * Copyright (c) 2022 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/refresh/refresh_pattern.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/memory/ace_type.h"
21 #include "base/utils/utils.h"
22 #include "core/animation/spring_curve.h"
23 #include "core/common/container.h"
24 #include "core/components/common/properties/animation_option.h"
25 #include "core/components/refresh/refresh_theme.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/pattern/loading_progress/loading_progress_layout_property.h"
28 #include "core/components_ng/pattern/loading_progress/loading_progress_paint_property.h"
29 #include "core/components_ng/pattern/refresh/refresh_layout_property.h"
30 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
31 #include "core/components_ng/property/property.h"
32 #include "core/components_ng/render/animation_utils.h"
33 #include "core/pipeline/base/element_register.h"
34 #include "core/pipeline_ng/pipeline_context.h"
35 #include "frameworks/base/i18n/localization.h"
36 #include "frameworks/base/utils/time_util.h"
37 #include "frameworks/base/utils/utils.h"
38 #include "frameworks/core/components/common/layout/constants.h"
39 #include "frameworks/core/components_ng/pattern/loading_progress/loading_progress_pattern.h"
40 #include "frameworks/core/components_ng/pattern/text/text_pattern.h"
41
42 namespace OHOS::Ace::NG {
43
44 namespace {
45 constexpr float PERCENT = 0.01; // Percent
46 constexpr float FOLLOW_TO_RECYCLE_DURATION = 600;
47 constexpr float LOADING_EXIT_DURATION = 350;
48 constexpr Dimension TRIGGER_LOADING_DISTANCE = 16.0_vp;
49 constexpr Dimension TRIGGER_REFRESH_DISTANCE = 64.0_vp;
50 constexpr Dimension MAX_SCROLL_DISTANCE = 128.0_vp;
51 constexpr Dimension LOADING_PROGRESS_SIZE = 32.0_vp;
52 constexpr float DEFAULT_FRICTION = 64.0f;
53 constexpr int32_t STATE_PROGRESS_LOADING = 1;
54 constexpr int32_t STATE_PROGRESS_RECYCLE = 2;
55 constexpr int32_t STATE_PROGRESS_DRAG = 3;
56 } // namespace
57
OnModifyDone()58 void RefreshPattern::OnModifyDone()
59 {
60 auto host = GetHost();
61 CHECK_NULL_VOID(host);
62 auto hub = host->GetEventHub<EventHub>();
63 CHECK_NULL_VOID(hub);
64 auto gestureHub = hub->GetOrCreateGestureEventHub();
65 CHECK_NULL_VOID(gestureHub);
66 auto layoutProperty = GetLayoutProperty<RefreshLayoutProperty>();
67 CHECK_NULL_VOID(layoutProperty);
68 triggerLoadingDistance_ = static_cast<float>(
69 std::clamp(layoutProperty->GetIndicatorOffset().value_or(TRIGGER_LOADING_DISTANCE).ConvertToPx(),
70 -1.0f * TRIGGER_LOADING_DISTANCE.ConvertToPx(), TRIGGER_REFRESH_DISTANCE.ConvertToPx()));
71 InitPanEvent(gestureHub);
72 CheckCoordinationEvent();
73 if (!progressChild_) {
74 progressChild_ = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(host->TotalChildCount() - 1));
75 LoadingProgressReset();
76 }
77
78 auto paintProperty = GetPaintProperty<RefreshRenderProperty>();
79 CHECK_NULL_VOID(paintProperty);
80 auto refreshingProp = paintProperty->GetIsRefreshing().value_or(false);
81 if (isRefreshing_ != refreshingProp) {
82 if (refreshingProp) {
83 ReplaceLoadingProgressNode();
84 TriggerRefresh();
85 LoadingProgressAppear();
86 } else {
87 LoadingProgressExit();
88 }
89 }
90 }
91
CheckCoordinationEvent()92 void RefreshPattern::CheckCoordinationEvent()
93 {
94 auto host = GetHost();
95 CHECK_NULL_VOID(host);
96 auto scrollableNode = FindScrollableChild();
97 scrollableNode_ = WeakClaim(AceType::RawPtr(scrollableNode));
98 CHECK_NULL_VOID(scrollableNode);
99 auto scrollablePattern = scrollableNode->GetPattern<ScrollablePattern>();
100 CHECK_NULL_VOID(scrollablePattern);
101 auto coordinationEvent = AceType::MakeRefPtr<ScrollableCoordinationEvent>();
102 auto onScrollEvent = [weak = WeakClaim(this)](double offset) {
103 auto pattern = weak.Upgrade();
104 CHECK_NULL_VOID(pattern);
105 pattern->HandleDragUpdate(static_cast<float>(offset));
106 };
107 coordinationEvent->SetOnScrollEvent(onScrollEvent);
108 auto onScrollStartEvent = [weak = WeakClaim(this)]() {
109 auto pattern = weak.Upgrade();
110 CHECK_NULL_VOID(pattern);
111 pattern->HandleDragStart();
112 };
113 coordinationEvent->SetOnScrollStartEvent(onScrollStartEvent);
114 auto onScrollEndEvent = [weak = WeakClaim(this)]() {
115 auto pattern = weak.Upgrade();
116 CHECK_NULL_VOID(pattern);
117 pattern->HandleDragEnd();
118 };
119 coordinationEvent->SetOnScrollEndEvent(onScrollEndEvent);
120 scrollablePattern->SetCoordinationEvent(coordinationEvent);
121 }
122
FindScrollableChild()123 RefPtr<FrameNode> RefreshPattern::FindScrollableChild()
124 {
125 auto host = GetHost();
126 CHECK_NULL_RETURN(host, nullptr);
127 std::queue<RefPtr<FrameNode>> frameNodeQueue;
128 frameNodeQueue.push(host);
129 while (!frameNodeQueue.empty()) {
130 auto size = frameNodeQueue.size();
131 while (size > 0) {
132 auto node = frameNodeQueue.front();
133 CHECK_NULL_RETURN(node, nullptr);
134 if (AceType::InstanceOf<ScrollablePattern>(node->GetPattern())) {
135 return node;
136 }
137 frameNodeQueue.pop();
138 auto children = node->GetChildren();
139 for (auto const& child : children) {
140 auto childNode = DynamicCast<FrameNode>(child);
141 if (childNode) {
142 frameNodeQueue.push(childNode);
143 }
144 }
145 size--;
146 }
147 }
148 return nullptr;
149 }
150
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> &,bool,bool)151 bool RefreshPattern::OnDirtyLayoutWrapperSwap(
152 const RefPtr<LayoutWrapper>& /*dirty*/, bool /*skipMeasure*/, bool /*skipLayout*/)
153 {
154 return false;
155 }
156
TriggerRefresh()157 void RefreshPattern::TriggerRefresh()
158 {
159 isRefreshing_ = true;
160 FireChangeEvent("true");
161 FireRefreshing();
162 TriggerStatusChange(RefreshStatus::REFRESH);
163 }
164
LoadingProgressRecycle()165 void RefreshPattern::LoadingProgressRecycle()
166 {
167 CHECK_NULL_VOID(progressChild_);
168 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
169 CHECK_NULL_VOID(progressPaintProperty);
170 progressPaintProperty->UpdateRefreshAnimationState(static_cast<int32_t>(RefreshAnimationState::RECYCLE));
171 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
172 }
173
ReplaceLoadingProgressNode()174 void RefreshPattern::ReplaceLoadingProgressNode()
175 {
176 auto host = GetHost();
177 CHECK_NULL_VOID(host);
178 if (progressChild_) {
179 host->RemoveChild(progressChild_);
180 }
181 auto loadingProgressChild = FrameNode::CreateFrameNode(V2::LOADING_PROGRESS_ETS_TAG,
182 ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<LoadingProgressPattern>());
183 CHECK_NULL_VOID(loadingProgressChild);
184 host->AddChild(loadingProgressChild);
185 progressChild_ = loadingProgressChild;
186 host->RebuildRenderContextTree();
187 LoadingProgressReset();
188 }
189
LoadingProgressReset()190 void RefreshPattern::LoadingProgressReset()
191 {
192 CHECK_NULL_VOID(progressChild_);
193 UpdateLoadingProgress(STATE_PROGRESS_LOADING, 0.0f);
194 auto progressLayoutProperty = progressChild_->GetLayoutProperty<LoadingProgressLayoutProperty>();
195 CHECK_NULL_VOID(progressLayoutProperty);
196 progressLayoutProperty->UpdateUserDefinedIdealSize(
197 CalcSize(CalcLength(LOADING_PROGRESS_SIZE.ConvertToPx()), CalcLength(LOADING_PROGRESS_SIZE.ConvertToPx())));
198 ResetLoadingProgressColor();
199 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
200 CHECK_NULL_VOID(progressPaintProperty);
201 progressPaintProperty->UpdateLoadingProgressOwner(LoadingProgressOwner::REFRESH);
202 scrollOffset_.SetY(0.0f);
203 progressChild_->MarkDirtyNode();
204 }
205
OnExitAnimationFinish()206 void RefreshPattern::OnExitAnimationFinish()
207 {
208 ReplaceLoadingProgressNode();
209 TriggerFinish();
210 CHECK_NULL_VOID(progressChild_);
211 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
212 }
213
TriggerInActive()214 void RefreshPattern::TriggerInActive()
215 {
216 isRefreshing_ = false;
217 FireChangeEvent("false");
218 TriggerStatusChange(RefreshStatus::INACTIVE);
219 }
220
TriggerDone()221 void RefreshPattern::TriggerDone()
222 {
223 isRefreshing_ = false;
224 FireChangeEvent("false");
225 TriggerStatusChange(RefreshStatus::DONE);
226 }
227
TriggerFinish()228 void RefreshPattern::TriggerFinish()
229 {
230 if (refreshStatus_ == RefreshStatus::REFRESH) {
231 TriggerDone();
232 } else {
233 TriggerInActive();
234 }
235 }
236
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)237 void RefreshPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
238 {
239 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& /*info*/) {
240 auto pattern = weak.Upgrade();
241 CHECK_NULL_VOID(pattern);
242 pattern->HandleDragStart();
243 };
244 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
245 auto pattern = weak.Upgrade();
246 CHECK_NULL_VOID(pattern);
247 pattern->HandleDragUpdate(static_cast<float>(info.GetMainDelta()));
248 };
249 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& /*info*/) {
250 auto pattern = weak.Upgrade();
251 CHECK_NULL_VOID(pattern);
252 pattern->HandleDragEnd();
253 };
254 auto actionCancelTask = [weak = WeakClaim(this)]() {
255 auto pattern = weak.Upgrade();
256 CHECK_NULL_VOID(pattern);
257 pattern->HandleDragCancel();
258 };
259 PanDirection panDirection;
260 panDirection.type = PanDirection::VERTICAL;
261 if (panEvent_) {
262 gestureHub->RemovePanEvent(panEvent_);
263 }
264
265 float distance = static_cast<float>(Dimension(DEFAULT_PAN_DISTANCE, DimensionUnit::VP).ConvertToPx());
266 panEvent_ = MakeRefPtr<PanEvent>(
267 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
268 gestureHub->AddPanEvent(panEvent_, panDirection, 1, distance);
269 }
270
HandleDragStart()271 void RefreshPattern::HandleDragStart()
272 {
273 if (isRefreshing_) {
274 return;
275 }
276 TriggerStatusChange(RefreshStatus::DRAG);
277 CHECK_NULL_VOID(progressChild_);
278 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
279 CHECK_NULL_VOID(progressPaintProperty);
280 progressPaintProperty->UpdateRefreshAnimationState(static_cast<int32_t>(RefreshAnimationState::FOLLOW_HAND));
281 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
282 }
283
HandleDragUpdate(float delta)284 void RefreshPattern::HandleDragUpdate(float delta)
285 {
286 if (NearZero(delta) || isRefreshing_) {
287 LOGI("Delta is near zero or isRefreshing!");
288 return;
289 }
290 CHECK_NULL_VOID(progressChild_);
291 scrollOffset_.SetY(GetScrollOffset(delta));
292 if (scrollOffset_.GetY() > triggerLoadingDistance_) {
293 auto refreshFollowRadio = GetFollowRatio();
294 UpdateLoadingProgress(STATE_PROGRESS_DRAG, refreshFollowRadio);
295 UpdateLoadingMarginTop(scrollOffset_.GetY());
296 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
297 CHECK_NULL_VOID(progressPaintProperty);
298 progressPaintProperty->UpdateRefreshFollowRatio(refreshFollowRadio);
299 }
300
301 if (scrollOffset_.GetY() > TRIGGER_REFRESH_DISTANCE.ConvertToPx()) {
302 TriggerStatusChange(RefreshStatus::OVER_DRAG);
303 }
304 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
305 }
306
UpdateLoadingProgress(int32_t state,float ratio)307 void RefreshPattern::UpdateLoadingProgress(int32_t state, float ratio)
308 {
309 CHECK_NULL_VOID(progressChild_);
310 auto progressLayoutProperty = progressChild_->GetLayoutProperty<LoadingProgressLayoutProperty>();
311 CHECK_NULL_VOID(progressLayoutProperty);
312 auto scale = std::clamp(ratio, 0.0f, 1.0f);
313 switch (state) {
314 case STATE_PROGRESS_LOADING:
315 scale = 0.0f;
316 UpdateLoadingMarginTop(triggerLoadingDistance_);
317 break;
318 case STATE_PROGRESS_RECYCLE:
319 scale = 1.0f;
320 UpdateLoadingMarginTop(TRIGGER_REFRESH_DISTANCE.ConvertToPx());
321 break;
322 default:;
323 }
324 auto progressContext = progressChild_->GetRenderContext();
325 CHECK_NULL_VOID_NOLOG(progressContext);
326 progressContext->UpdateOpacity(scale);
327 }
328
GetFollowRatio()329 float RefreshPattern::GetFollowRatio()
330 {
331 auto triggerLoading = std::clamp(triggerLoadingDistance_, 0.0f,
332 static_cast<float>(TRIGGER_REFRESH_DISTANCE.ConvertToPx()));
333 if (GreatNotEqual(TRIGGER_REFRESH_DISTANCE.ConvertToPx(), triggerLoading)) {
334 return (scrollOffset_.GetY() - triggerLoading) / (TRIGGER_REFRESH_DISTANCE.ConvertToPx() - triggerLoading);
335 }
336 return 1.0f;
337 }
338
GetFadeAwayRatio()339 float RefreshPattern::GetFadeAwayRatio()
340 {
341 CHECK_NULL_RETURN(progressChild_, 0.0f);
342 auto progressLayoutProperty = progressChild_->GetLayoutProperty<LoadingProgressLayoutProperty>();
343 CHECK_NULL_RETURN(progressLayoutProperty, 0.0f);
344 auto& marginProperty = progressLayoutProperty->GetMarginProperty();
345 CHECK_NULL_RETURN(marginProperty, 0.0f);
346 auto triggerLoading = std::clamp(triggerLoadingDistance_, 0.0f,
347 static_cast<float>(TRIGGER_REFRESH_DISTANCE.ConvertToPx()));
348 if (GreatNotEqual(TRIGGER_REFRESH_DISTANCE.ConvertToPx(), triggerLoading)) {
349 return (marginProperty->top->GetDimension().ConvertToPx() - triggerLoading) /
350 (TRIGGER_REFRESH_DISTANCE.ConvertToPx() - triggerLoading);
351 }
352 return 0.0f;
353 }
354
TransitionPeriodAnimation()355 void RefreshPattern::TransitionPeriodAnimation()
356 {
357 auto pipeline = PipelineContext::GetCurrentContext();
358 CHECK_NULL_VOID(pipeline);
359 CHECK_NULL_VOID(progressChild_);
360 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
361 CHECK_NULL_VOID(progressPaintProperty);
362
363 auto progressLayoutProperty = progressChild_->GetLayoutProperty<LoadingProgressLayoutProperty>();
364 CHECK_NULL_VOID(progressLayoutProperty);
365 progressPaintProperty->UpdateRefreshAnimationState(static_cast<int32_t>(RefreshAnimationState::FOLLOW_TO_RECYCLE));
366 progressPaintProperty->UpdateRefreshTransitionRatio(0.0f);
367 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
368 pipeline->FlushUITasks();
369
370 auto curve = AceType::MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
371 AnimationOption option;
372 option.SetDuration(FOLLOW_TO_RECYCLE_DURATION);
373 option.SetCurve(curve);
374 option.SetIteration(1);
375
376 AnimationUtils::OpenImplicitAnimation(option, curve, [weak = AceType::WeakClaim(this)]() {
377 auto pattern = weak.Upgrade();
378 CHECK_NULL_VOID(pattern);
379 pattern->LoadingProgressRecycle();
380 });
381 auto distance = TRIGGER_REFRESH_DISTANCE.ConvertToPx();
382 scrollOffset_.SetY(distance);
383 UpdateLoadingMarginTop(distance);
384 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
385 pipeline->FlushUITasks();
386 AnimationUtils::CloseImplicitAnimation();
387 }
388
LoadingProgressAppear()389 void RefreshPattern::LoadingProgressAppear()
390 {
391 CHECK_NULL_VOID(progressChild_);
392 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
393 CHECK_NULL_VOID(progressPaintProperty);
394 progressPaintProperty->UpdateRefreshAnimationState(static_cast<int32_t>(RefreshAnimationState::RECYCLE));
395 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
396 auto pipeline = PipelineContext::GetCurrentContext();
397 CHECK_NULL_VOID(pipeline);
398 pipeline->FlushUITasks();
399
400 AnimationOption option;
401 option.SetDuration(LOADING_EXIT_DURATION);
402 auto curve = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
403 AnimationUtils::OpenImplicitAnimation(option, curve, nullptr);
404 scrollOffset_.SetY(TRIGGER_REFRESH_DISTANCE.ConvertToPx());
405 UpdateLoadingProgress(STATE_PROGRESS_RECYCLE, 1.0f);
406 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
407 pipeline->FlushUITasks();
408 AnimationUtils::CloseImplicitAnimation();
409 }
410
LoadingProgressExit()411 void RefreshPattern::LoadingProgressExit()
412 {
413 CHECK_NULL_VOID(progressChild_);
414 auto progressPaintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
415 CHECK_NULL_VOID(progressPaintProperty);
416 progressPaintProperty->UpdateRefreshAnimationState(static_cast<int32_t>(RefreshAnimationState::FADEAWAY));
417 progressPaintProperty->UpdateRefreshFadeAwayRatio(GetFadeAwayRatio());
418 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
419 auto pipeline = PipelineContext::GetCurrentContext();
420 CHECK_NULL_VOID(pipeline);
421 pipeline->FlushUITasks();
422
423 AnimationOption option;
424 option.SetDuration(LOADING_EXIT_DURATION);
425 auto curve = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
426 AnimationUtils::OpenImplicitAnimation(option, curve, [weak = AceType::WeakClaim(this)]() {
427 auto pattern = weak.Upgrade();
428 CHECK_NULL_VOID(pattern);
429 pattern->OnExitAnimationFinish();
430 });
431
432 scrollOffset_.SetY(0.0f);
433 UpdateLoadingProgress(STATE_PROGRESS_LOADING, 0.0f);
434 progressPaintProperty->UpdateRefreshFadeAwayRatio(0.0f);
435 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
436 pipeline->FlushUITasks();
437 AnimationUtils::CloseImplicitAnimation();
438 }
439
HandleDragEnd()440 void RefreshPattern::HandleDragEnd()
441 {
442 if (isRefreshing_) {
443 return;
444 }
445 auto triggerRefreshDistance = TRIGGER_REFRESH_DISTANCE.ConvertToPx();
446 if (scrollOffset_.GetY() >= triggerRefreshDistance) {
447 TriggerRefresh();
448 TransitionPeriodAnimation();
449 return;
450 }
451 LoadingProgressExit();
452 }
453
TriggerStatusChange(RefreshStatus newStatus)454 void RefreshPattern::TriggerStatusChange(RefreshStatus newStatus)
455 {
456 if (refreshStatus_ == newStatus) {
457 return;
458 }
459 refreshStatus_ = newStatus;
460 FireStateChange(static_cast<int>(refreshStatus_));
461 }
462
HandleDragCancel()463 void RefreshPattern::HandleDragCancel()
464 {
465 LoadingProgressExit();
466 }
467
FireStateChange(int32_t value)468 void RefreshPattern::FireStateChange(int32_t value)
469 {
470 auto refreshEventHub = GetEventHub<RefreshEventHub>();
471 CHECK_NULL_VOID(refreshEventHub);
472 refreshEventHub->FireOnStateChange(value);
473 }
474
FireRefreshing()475 void RefreshPattern::FireRefreshing()
476 {
477 auto refreshEventHub = GetEventHub<RefreshEventHub>();
478 CHECK_NULL_VOID(refreshEventHub);
479 refreshEventHub->FireOnRefreshing();
480 }
481
FireChangeEvent(const std::string & value)482 void RefreshPattern::FireChangeEvent(const std::string& value)
483 {
484 auto refreshEventHub = GetEventHub<RefreshEventHub>();
485 CHECK_NULL_VOID(refreshEventHub);
486 refreshEventHub->FireChangeEvent(value);
487 }
488
GetScrollOffset(float delta)489 float RefreshPattern::GetScrollOffset(float delta)
490 {
491 auto layoutProperty = GetLayoutProperty<RefreshLayoutProperty>();
492 CHECK_NULL_RETURN(layoutProperty, 0.0f);
493 auto frictionRatio = static_cast<float>(layoutProperty->GetFriction().value_or(DEFAULT_FRICTION)) * PERCENT;
494 auto scrollY = delta * frictionRatio;
495 auto scrollOffset = std::clamp(scrollOffset_.GetY() + scrollY, static_cast<float>(0.0f),
496 static_cast<float>(MAX_SCROLL_DISTANCE.ConvertToPx()));
497 return scrollOffset;
498 }
499
ResetLoadingProgressColor()500 void RefreshPattern::ResetLoadingProgressColor()
501 {
502 auto pipeline = PipelineContext::GetCurrentContext();
503 CHECK_NULL_VOID(pipeline);
504 auto themeManager = pipeline->GetThemeManager();
505 CHECK_NULL_VOID(themeManager);
506 auto theme = themeManager->GetTheme<RefreshTheme>();
507 CHECK_NULL_VOID(theme);
508 CHECK_NULL_VOID(progressChild_);
509 auto paintProperty = progressChild_->GetPaintProperty<LoadingProgressPaintProperty>();
510 CHECK_NULL_VOID(paintProperty);
511 paintProperty->UpdateColor(theme->GetProgressColor());
512 progressChild_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
513 }
514
UpdateLoadingMarginTop(float top)515 void RefreshPattern::UpdateLoadingMarginTop(float top)
516 {
517 if (LessNotEqual(top, 0.0)) {
518 return;
519 }
520 CHECK_NULL_VOID(progressChild_);
521 auto progressLayoutProperty = progressChild_->GetLayoutProperty<LoadingProgressLayoutProperty>();
522 CHECK_NULL_VOID(progressLayoutProperty);
523 MarginProperty marginProperty;
524 if (progressLayoutProperty->GetMarginProperty()) {
525 const auto& originMargin = (*progressLayoutProperty->GetMarginProperty());
526 marginProperty.left = originMargin.left;
527 marginProperty.right = originMargin.right;
528 marginProperty.bottom = originMargin.bottom;
529 }
530 marginProperty.top = CalcLength(top);
531 progressLayoutProperty->UpdateMargin(marginProperty);
532 }
533 } // namespace OHOS::Ace::NG
534