1 /*
2 * Copyright (c) 2023 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/scrollable/scrollable_pattern.h"
17
18 #include "base/geometry/axis.h"
19 #include "base/geometry/point.h"
20 #include "base/memory/ace_type.h"
21 #include "base/utils/utils.h"
22 #include "core/components/scroll/scrollable.h"
23 #include "core/components_ng/pattern/scroll/effect/scroll_fade_effect.h"
24 #include "core/components_ng/pattern/scroll/scroll_spring_effect.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr Color SELECT_FILL_COLOR = Color(0x1A000000);
30 constexpr Color SELECT_STROKE_COLOR = Color(0x33FFFFFF);
31 } // namespace
32
SetAxis(Axis axis)33 void ScrollablePattern::SetAxis(Axis axis)
34 {
35 if (axis_ == axis) {
36 return;
37 }
38 axis_ = axis;
39 if (scrollBar_) {
40 scrollBar_->SetPositionMode(axis_ == Axis::HORIZONTAL ? PositionMode::BOTTOM : PositionMode::RIGHT);
41 }
42 auto gestureHub = GetGestureHub();
43 CHECK_NULL_VOID(gestureHub);
44 if (scrollableEvent_) {
45 gestureHub->RemoveScrollableEvent(scrollableEvent_);
46 scrollableEvent_->SetAxis(axis);
47 gestureHub->AddScrollableEvent(scrollableEvent_);
48 }
49 if (scrollEffect_) {
50 gestureHub->RemoveScrollEdgeEffect(scrollEffect_);
51 gestureHub->AddScrollEdgeEffect(GetAxis(), scrollEffect_);
52 }
53 }
54
GetGestureHub()55 RefPtr<GestureEventHub> ScrollablePattern::GetGestureHub()
56 {
57 auto host = GetHost();
58 CHECK_NULL_RETURN(host, nullptr);
59 auto hub = host->GetEventHub<EventHub>();
60 CHECK_NULL_RETURN(hub, nullptr);
61 return hub->GetOrCreateGestureEventHub();
62 }
63
GetInputHub()64 RefPtr<InputEventHub> ScrollablePattern::GetInputHub()
65 {
66 auto host = GetHost();
67 CHECK_NULL_RETURN(host, nullptr);
68 auto hub = host->GetEventHub<EventHub>();
69 CHECK_NULL_RETURN(host, nullptr);
70 return hub->GetOrCreateInputEventHub();
71 }
72
OnScrollCallback(float offset,int32_t source)73 bool ScrollablePattern::OnScrollCallback(float offset, int32_t source)
74 {
75 if (source == SCROLL_FROM_START) {
76 return true;
77 }
78 return UpdateCurrentOffset(offset, source);
79 }
80
DraggedDownScrollEndProcess()81 void ScrollablePattern::DraggedDownScrollEndProcess()
82 {
83 CHECK_NULL_VOID_NOLOG(navBarPattern_);
84 if (!navBarPattern_->GetDraggedDown() && isReactInParentMovement_) {
85 isReactInParentMovement_ = false;
86 navBarPattern_->OnCoordScrollEnd();
87 }
88 }
89
ProcessNavBarReactOnStart()90 void ScrollablePattern::ProcessNavBarReactOnStart()
91 {
92 CHECK_NULL_VOID_NOLOG(navBarPattern_);
93 navBarPattern_->OnCoordScrollStart();
94 }
95
ProcessNavBarReactOnUpdate(bool isDraggedDown,float offset)96 bool ScrollablePattern::ProcessNavBarReactOnUpdate(bool isDraggedDown, float offset)
97 {
98 CHECK_NULL_RETURN_NOLOG(navBarPattern_, true);
99 auto minTitle = navBarPattern_ ? navBarPattern_->GetIsMinTitle() : false;
100 navBarPattern_->OnCoordScrollUpdate(offset);
101 DraggedDownScrollEndProcess();
102 if (minTitle) {
103 return scrollEffect_ && scrollEffect_->IsNoneEffect();
104 }
105 return scrollEffect_ && scrollEffect_->IsSpringEffect();
106 }
107
ProcessNavBarReactOnEnd()108 void ScrollablePattern::ProcessNavBarReactOnEnd()
109 {
110 CHECK_NULL_VOID_NOLOG(navBarPattern_);
111 navBarPattern_->OnCoordScrollEnd();
112 }
113
OnScrollPosition(double offset,int32_t source)114 bool ScrollablePattern::OnScrollPosition(double offset, int32_t source)
115 {
116 auto isAtTop = (IsAtTop() && Positive(offset));
117 auto isDraggedDown = navBarPattern_ ? navBarPattern_->GetDraggedDown() : false;
118 auto isFullStatus = navBarPattern_ ? navBarPattern_->GetFullStatus() : false;
119 if (isAtTop && (source == SCROLL_FROM_ANIMATION_SPRING) && !isFullStatus) {
120 SetNavBarVelocity();
121 }
122 if ((isAtTop || isDraggedDown) && (source == SCROLL_FROM_UPDATE) && !isReactInParentMovement_ &&
123 (axis_ == Axis::VERTICAL)) {
124 isReactInParentMovement_ = true;
125 if (coordinationEvent_) {
126 auto onScrollStart = coordinationEvent_->GetOnScrollStartEvent();
127 if (onScrollStart) {
128 onScrollStart();
129 }
130 }
131 ProcessNavBarReactOnStart();
132 }
133 if ((coordinationEvent_ || navBarPattern_) && source != SCROLL_FROM_UPDATE && isReactInParentMovement_) {
134 isReactInParentMovement_ = false;
135 if (coordinationEvent_) {
136 auto onScrollEnd = coordinationEvent_->GetOnScrollEndEvent();
137 if (onScrollEnd) {
138 onScrollEnd();
139 }
140 }
141 ProcessNavBarReactOnEnd();
142 }
143 if (isReactInParentMovement_) {
144 ProcessNavBarReactOnUpdate(isDraggedDown, offset);
145 if (coordinationEvent_) {
146 auto onScroll = coordinationEvent_->GetOnScroll();
147 CHECK_NULL_RETURN(onScroll, false);
148 if (!onScroll(offset)) {
149 isReactInParentMovement_ = false;
150 return true;
151 }
152 return scrollEffect_ && scrollEffect_->IsSpringEffect();
153 }
154 }
155 if (source == SCROLL_FROM_START) {
156 SetParentScrollable();
157 GetParentNavigition();
158 StopScrollBarAnimatorByProxy();
159 AbortScrollAnimator();
160 } else if (!AnimateStoped()) {
161 return false;
162 }
163 return true;
164 }
165
OnScrollEnd()166 void ScrollablePattern::OnScrollEnd()
167 {
168 if (isReactInParentMovement_) {
169 ProcessNavBarReactOnEnd();
170 if (coordinationEvent_) {
171 auto onScrollEnd = coordinationEvent_->GetOnScrollEndEvent();
172 if (onScrollEnd) {
173 onScrollEnd();
174 }
175 isReactInParentMovement_ = false;
176 return;
177 }
178 }
179 }
180
AddScrollEvent()181 void ScrollablePattern::AddScrollEvent()
182 {
183 auto host = GetHost();
184 CHECK_NULL_VOID(host);
185 auto gestureHub = GetGestureHub();
186 CHECK_NULL_VOID(gestureHub);
187 if (scrollableEvent_) {
188 gestureHub->RemoveScrollableEvent(scrollableEvent_);
189 }
190 auto scrollCallback = [weak = WeakClaim(this)](double offset, int32_t source) {
191 auto pattern = weak.Upgrade();
192 CHECK_NULL_RETURN(pattern, false);
193 if (!pattern->OnScrollPosition(offset, source)) {
194 return false;
195 }
196 return pattern->OnScrollCallback(static_cast<float>(offset), source);
197 };
198 auto scrollable = MakeRefPtr<Scrollable>(std::move(scrollCallback), GetAxis());
199 scrollable->SetNodeId(host->GetAccessibilityId());
200 scrollable->Initialize(host->GetContext());
201
202 auto scrollEnd = [weak = WeakClaim(this)]() {
203 auto pattern = weak.Upgrade();
204 CHECK_NULL_VOID(pattern);
205 pattern->OnScrollEnd();
206 pattern->OnScrollEndCallback();
207 };
208 scrollable->SetScrollEndCallback(std::move(scrollEnd));
209 scrollable->SetUnstaticFriction(friction_);
210
211 auto func = [weak = AceType::WeakClaim(this)](double offset) -> OverScrollOffset {
212 auto pattern = weak.Upgrade();
213 if (pattern) {
214 return pattern->GetOverScrollOffset(offset);
215 }
216 return { 0, 0 };
217 };
218 scrollable->SetOverScrollOffsetCallback(std::move(func));
219 scrollable->SetNestedScrollOptions(nestedScroll_);
220
221 auto scrollSnap = [weak = WeakClaim(this)](double targetOffset, double velocity) -> bool {
222 auto pattern = weak.Upgrade();
223 CHECK_NULL_RETURN(pattern, false);
224 return pattern->OnScrollSnapCallback(targetOffset, velocity);
225 };
226 scrollable->SetOnScrollSnapCallback(scrollSnap);
227
228 auto calePredictSnapOffsetCallback = [weak = WeakClaim(this)](float delta) -> std::optional<float> {
229 auto pattern = weak.Upgrade();
230 std::optional<float> predictSnapOffset;
231 CHECK_NULL_RETURN_NOLOG(pattern, predictSnapOffset);
232 return pattern->CalePredictSnapOffset(delta);
233 };
234 scrollable->SetCalePredictSnapOffsetCallback(std::move(calePredictSnapOffsetCallback));
235
236 auto needScrollSnapToSideCallback = [weak = WeakClaim(this)](float delta) -> bool {
237 auto pattern = weak.Upgrade();
238 CHECK_NULL_RETURN_NOLOG(pattern, false);
239 return pattern->NeedScrollSnapToSide(delta);
240 };
241 scrollable->SetNeedScrollSnapToSideCallback(std::move(needScrollSnapToSideCallback));
242
243 scrollableEvent_ = MakeRefPtr<ScrollableEvent>(GetAxis());
244 scrollableEvent_->SetScrollable(scrollable);
245 gestureHub->AddScrollableEvent(scrollableEvent_);
246 }
247
SetEdgeEffect(EdgeEffect edgeEffect)248 void ScrollablePattern::SetEdgeEffect(EdgeEffect edgeEffect)
249 {
250 auto gestureHub = GetGestureHub();
251 CHECK_NULL_VOID(gestureHub);
252 if (scrollEffect_ && (edgeEffect != scrollEffect_->GetEdgeEffect())) {
253 gestureHub->RemoveScrollEdgeEffect(scrollEffect_);
254 scrollEffect_.Reset();
255 }
256 if (edgeEffect == EdgeEffect::SPRING && !scrollEffect_) {
257 auto springEffect = AceType::MakeRefPtr<ScrollSpringEffect>();
258 CHECK_NULL_VOID(springEffect);
259 springEffect->SetOutBoundaryCallback([weak = AceType::WeakClaim(this)]() {
260 auto pattern = weak.Upgrade();
261 CHECK_NULL_RETURN_NOLOG(pattern, false);
262 return pattern->OutBoundaryCallback();
263 });
264 // add callback to springEdgeEffect
265 SetEdgeEffectCallback(springEffect);
266 scrollEffect_ = springEffect;
267 gestureHub->AddScrollEdgeEffect(GetAxis(), scrollEffect_);
268 }
269 if (edgeEffect == EdgeEffect::FADE && !scrollEffect_) {
270 auto fadeEdgeEffect = AceType::MakeRefPtr<ScrollFadeEffect>(Color::GRAY);
271 CHECK_NULL_VOID(fadeEdgeEffect);
272 fadeEdgeEffect->SetHandleOverScrollCallback([weakScroll = AceType::WeakClaim(this)]() -> void {
273 auto list = weakScroll.Upgrade();
274 CHECK_NULL_VOID_NOLOG(list);
275 auto host = list->GetHost();
276 CHECK_NULL_VOID_NOLOG(host);
277 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
278 });
279 SetEdgeEffectCallback(fadeEdgeEffect);
280 fadeEdgeEffect->InitialEdgeEffect();
281 scrollEffect_ = fadeEdgeEffect;
282 gestureHub->AddScrollEdgeEffect(GetAxis(), scrollEffect_);
283 }
284 auto scrollable = scrollableEvent_->GetScrollable();
285 CHECK_NULL_VOID_NOLOG(scrollable);
286 scrollable->SetEdgeEffect(edgeEffect);
287 }
288
HandleEdgeEffect(float offset,int32_t source,const SizeF & size)289 bool ScrollablePattern::HandleEdgeEffect(float offset, int32_t source, const SizeF& size)
290 {
291 bool isAtTop = IsAtTop();
292 bool isAtBottom = IsAtBottom();
293 // check edgeEffect is not springEffect
294 if (scrollEffect_ && scrollEffect_->IsFadeEffect() && (source == SCROLL_FROM_UPDATE ||
295 source == SCROLL_FROM_ANIMATION)) { // handle edge effect
296 if ((isAtTop && Positive(offset)) || (isAtBottom && Negative(offset))) {
297 scrollEffect_->HandleOverScroll(GetAxis(), -offset, size);
298 }
299 }
300 if (!(scrollEffect_ && scrollEffect_->IsSpringEffect() && (source == SCROLL_FROM_UPDATE ||
301 source == SCROLL_FROM_ANIMATION || source == SCROLL_FROM_ANIMATION_SPRING))) {
302 if (isAtTop && Positive(offset)) {
303 animateOverScroll_ = false;
304 return false;
305 }
306 if (isAtBottom && Negative(offset)) {
307 animateOverScroll_ = false;
308 return false;
309 }
310 }
311 animateOverScroll_ = (source == SCROLL_FROM_ANIMATION_CONTROLLER) && (isAtTop || isAtBottom);
312 return true;
313 }
314
RegisterScrollBarEventTask()315 void ScrollablePattern::RegisterScrollBarEventTask()
316 {
317 CHECK_NULL_VOID(scrollBar_);
318 auto host = GetHost();
319 CHECK_NULL_VOID(host);
320 auto gestureHub = GetGestureHub();
321 auto inputHub = GetInputHub();
322 CHECK_NULL_VOID(gestureHub);
323 CHECK_NULL_VOID(inputHub);
324 scrollBar_->SetGestureEvent();
325 scrollBar_->SetMouseEvent();
326 scrollBar_->SetHoverEvent();
327 scrollBar_->SetMarkNeedRenderFunc([weak = AceType::WeakClaim(AceType::RawPtr(host))]() {
328 auto host = weak.Upgrade();
329 CHECK_NULL_VOID(host);
330 host->MarkNeedRenderOnly();
331 });
332 auto scrollCallback = [weak = WeakClaim(this)](double offset, int32_t source) {
333 auto pattern = weak.Upgrade();
334 CHECK_NULL_RETURN(pattern, false);
335 return pattern->OnScrollCallback(static_cast<float>(offset), source);
336 };
337 scrollBar_->SetScrollPositionCallback(std::move(scrollCallback));
338 auto scrollEnd = [weak = WeakClaim(this)]() {
339 auto pattern = weak.Upgrade();
340 CHECK_NULL_VOID(pattern);
341 pattern->OnScrollEnd();
342 pattern->OnScrollEndCallback();
343 };
344 scrollBar_->SetScrollEndCallback(std::move(scrollEnd));
345 auto calePredictSnapOffsetCallback = [weak = WeakClaim(this)](float delta) {
346 auto pattern = weak.Upgrade();
347 CHECK_NULL_RETURN(pattern, std::optional<float>());
348 return pattern->CalePredictSnapOffset(delta);
349 };
350 scrollBar_->SetCalePredictSnapOffsetCallback(std::move(calePredictSnapOffsetCallback));
351 auto startScrollSnapMotionCallback = [weak = WeakClaim(this)](float scrollSnapDelta, float scrollSnapVelocity) {
352 auto pattern = weak.Upgrade();
353 CHECK_NULL_VOID(pattern);
354 pattern->StartScrollSnapMotion(scrollSnapDelta, scrollSnapVelocity);
355 };
356 scrollBar_->SetStartScrollSnapMotionCallback(std::move(startScrollSnapMotionCallback));
357
358 gestureHub->AddTouchEvent(scrollBar_->GetTouchEvent());
359 inputHub->AddOnMouseEvent(scrollBar_->GetMouseEvent());
360 inputHub->AddOnHoverEvent(scrollBar_->GetHoverEvent());
361 CHECK_NULL_VOID(scrollableEvent_);
362 scrollableEvent_->SetInBarRegionCallback(
363 [weak = AceType::WeakClaim(AceType::RawPtr(scrollBar_))](const PointF& point, SourceType source) {
364 auto scrollBar = weak.Upgrade();
365 CHECK_NULL_RETURN_NOLOG(scrollBar, false);
366 if (source == SourceType::MOUSE) {
367 return scrollBar->InBarHoverRegion(Point(point.GetX(), point.GetY()));
368 }
369 return scrollBar->InBarTouchRegion(Point(point.GetX(), point.GetY()));
370 }
371 );
372 scrollableEvent_->SetBarCollectTouchTargetCallback([weak = AceType::WeakClaim(AceType::RawPtr(scrollBar_))]
373 (const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result) {
374 auto scrollBar = weak.Upgrade();
375 CHECK_NULL_VOID_NOLOG(scrollBar);
376 scrollBar->OnCollectTouchTarget(coordinateOffset, getEventTargetImpl, result);
377 }
378 );
379 }
380
SetScrollBar(DisplayMode displayMode)381 void ScrollablePattern::SetScrollBar(DisplayMode displayMode)
382 {
383 auto host = GetHost();
384 CHECK_NULL_VOID_NOLOG(host);
385 if (displayMode == DisplayMode::OFF) {
386 if (scrollBar_) {
387 auto gestureHub = GetGestureHub();
388 if (gestureHub) {
389 gestureHub->RemoveTouchEvent(scrollBar_->GetTouchEvent());
390 }
391 scrollBar_.Reset();
392 if (scrollBarOverlayModifier_) {
393 scrollBarOverlayModifier_->SetOpacity(0);
394 }
395 }
396 return;
397 }
398 DisplayMode oldDisplayMode = DisplayMode::OFF;
399 if (!scrollBar_) {
400 scrollBar_ = AceType::MakeRefPtr<ScrollBar>();
401 // set the scroll bar style
402 if (GetAxis() == Axis::HORIZONTAL) {
403 scrollBar_->SetPositionMode(PositionMode::BOTTOM);
404 }
405 RegisterScrollBarEventTask();
406 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
407 } else {
408 oldDisplayMode = scrollBar_->GetDisplayMode();
409 }
410
411 if (oldDisplayMode != displayMode) {
412 scrollBar_->SetDisplayMode(displayMode);
413 if (scrollBarOverlayModifier_ && scrollBar_->IsScrollable()) {
414 scrollBarOverlayModifier_->SetOpacity(UINT8_MAX);
415 }
416 scrollBar_->ScheduleDisapplearDelayTask();
417 }
418 auto renderContext = host->GetRenderContext();
419 CHECK_NULL_VOID_NOLOG(renderContext);
420 if (renderContext->HasBorderRadius()) {
421 auto borderRadius = renderContext->GetBorderRadius().value();
422 if (!(borderRadius == scrollBar_->GetHostBorderRadius())) {
423 scrollBar_->SetHostBorderRadius(borderRadius);
424 scrollBar_->CalcReservedHeight();
425 }
426 }
427 }
428
SetScrollBar(const std::unique_ptr<ScrollBarProperty> & property)429 void ScrollablePattern::SetScrollBar(const std::unique_ptr<ScrollBarProperty>& property)
430 {
431 if (!property) {
432 SetScrollBar(DisplayMode::AUTO);
433 return;
434 }
435 auto displayMode = property->GetScrollBarMode().value_or(DisplayMode::AUTO);
436 SetScrollBar(displayMode);
437 if (scrollBar_) {
438 auto barColor = property->GetScrollBarColor();
439 if (barColor) {
440 scrollBar_->SetForegroundColor(barColor.value());
441 }
442 auto barWidth = property->GetScrollBarWidth();
443 if (barWidth) {
444 scrollBar_->SetInactiveWidth(barWidth.value());
445 scrollBar_->SetNormalWidth(barWidth.value());
446 scrollBar_->SetActiveWidth(barWidth.value());
447 scrollBar_->SetTouchWidth(barWidth.value());
448 scrollBar_->SetIsUserNormalWidth(true);
449 } else {
450 scrollBar_->SetIsUserNormalWidth(false);
451 }
452 }
453 }
454
UpdateScrollBarRegion(float offset,float estimatedHeight,Size viewPort,Offset viewOffset)455 void ScrollablePattern::UpdateScrollBarRegion(float offset, float estimatedHeight, Size viewPort, Offset viewOffset)
456 {
457 // inner scrollbar, viewOffset is padding offset
458 if (scrollBar_) {
459 auto mainSize = axis_ == Axis::VERTICAL ? viewPort.Height() : viewPort.Width();
460 bool scrollable = GreatNotEqual(estimatedHeight, mainSize) && IsScrollable();
461 if (scrollBar_->IsScrollable() != scrollable) {
462 scrollBar_->SetScrollable(scrollable);
463 if (scrollBarOverlayModifier_) {
464 scrollBarOverlayModifier_->SetOpacity(scrollable ? UINT8_MAX : 0);
465 }
466 if (scrollable) {
467 scrollBar_->ScheduleDisapplearDelayTask();
468 }
469 }
470 Offset scrollOffset = { offset, offset }; // fit for w/h switched.
471 scrollBar_->UpdateScrollBarRegion(viewOffset, viewPort, scrollOffset, estimatedHeight);
472 scrollBar_->MarkNeedRender();
473 }
474
475 // outer scrollbar
476 if (scrollBarProxy_) {
477 estimatedHeight_ = estimatedHeight - (GetAxis() == Axis::VERTICAL ? viewPort.Height() : viewPort.Width());
478 barOffset_ = -offset;
479 scrollBarProxy_->NotifyScrollBar(AceType::WeakClaim(this));
480 }
481 }
482
SetScrollBarProxy(const RefPtr<ScrollBarProxy> & scrollBarProxy)483 void ScrollablePattern::SetScrollBarProxy(const RefPtr<ScrollBarProxy>& scrollBarProxy)
484 {
485 CHECK_NULL_VOID(scrollBarProxy);
486 auto scrollFunction = [weak = WeakClaim(this)](double offset, int32_t source) {
487 if (source != SCROLL_FROM_START) {
488 auto pattern = weak.Upgrade();
489 if (!pattern || pattern->GetAxis() == Axis::NONE) {
490 return false;
491 }
492 return pattern->UpdateCurrentOffset(offset, SCROLL_FROM_BAR);
493 }
494 return true;
495 };
496 auto scrollStartCallback = [weak = WeakClaim(this)](double offset, int32_t source) {
497 auto pattern = weak.Upgrade();
498 CHECK_NULL_RETURN(pattern, false);
499 pattern->OnScrollStartCallback();
500 return pattern->OnScrollCallback(static_cast<float>(offset), source);
501 };
502 auto scrollEndCallback = [weak = WeakClaim(this)]() {
503 auto pattern = weak.Upgrade();
504 CHECK_NULL_VOID(pattern);
505 pattern->OnScrollEnd();
506 pattern->OnScrollEndCallback();
507 };
508 auto calePredictSnapOffsetCallback = [weak = WeakClaim(this)](float delta) {
509 auto pattern = weak.Upgrade();
510 CHECK_NULL_RETURN(pattern, std::optional<float>());
511 return pattern->CalePredictSnapOffset(delta);
512 };
513 auto startScrollSnapMotionCallback = [weak = WeakClaim(this)](float scrollSnapDelta, float scrollSnapVelocity) {
514 auto pattern = weak.Upgrade();
515 CHECK_NULL_VOID(pattern);
516 pattern->StartScrollSnapMotion(scrollSnapDelta, scrollSnapVelocity);
517 };
518 ScrollableNodeInfo nodeInfo = { AceType::WeakClaim(this), std::move(scrollFunction), std::move(scrollStartCallback),
519 std::move(scrollEndCallback), std::move(calePredictSnapOffsetCallback),
520 std::move(startScrollSnapMotionCallback) };
521 scrollBarProxy->RegisterScrollableNode(nodeInfo);
522 scrollBarProxy_ = scrollBarProxy;
523 }
524
CreateScrollBarOverlayModifier()525 void ScrollablePattern::CreateScrollBarOverlayModifier()
526 {
527 CHECK_NULL_VOID(scrollBar_ && scrollBar_->NeedPaint());
528 CHECK_NULL_VOID(!scrollBarOverlayModifier_);
529 scrollBarOverlayModifier_ = AceType::MakeRefPtr<ScrollBarOverlayModifier>();
530 scrollBarOverlayModifier_->SetRect(scrollBar_->GetActiveRect(), scrollBar_->GetBarRect());
531 }
532
HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent)533 void ScrollablePattern::HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent)
534 {
535 scrollBarOutBoundaryExtent_ = scrollBarOutBoundaryExtent;
536 CHECK_NULL_VOID(scrollBar_ && scrollBar_->NeedScrollBar());
537 scrollBar_->SetOutBoundary(std::abs(scrollBarOutBoundaryExtent_));
538 }
539
SetNestedScroll(const NestedScrollOptions & nestedOpt)540 void ScrollablePattern::SetNestedScroll(const NestedScrollOptions& nestedOpt)
541 {
542 nestedScroll_ = nestedOpt;
543 CHECK_NULL_VOID_NOLOG(scrollableEvent_);
544 auto scrollable = scrollableEvent_->GetScrollable();
545 CHECK_NULL_VOID_NOLOG(scrollable);
546 scrollable->SetNestedScrollOptions(nestedScroll_);
547 }
548
SetFriction(double friction)549 void ScrollablePattern::SetFriction(double friction)
550 {
551 if (LessOrEqual(friction, 0.0)) {
552 friction = FRICTION;
553 }
554 friction_ = friction;
555 CHECK_NULL_VOID_NOLOG(scrollableEvent_);
556 auto scrollable = scrollableEvent_->GetScrollable();
557 scrollable->SetUnstaticFriction(friction_);
558 }
559
GetParentScrollable()560 RefPtr<ScrollablePattern> ScrollablePattern::GetParentScrollable()
561 {
562 auto host = GetHost();
563 CHECK_NULL_RETURN(host, nullptr);
564 for (auto parent = host->GetParent(); parent != nullptr; parent = parent->GetParent()) {
565 RefPtr<FrameNode> frameNode = AceType::DynamicCast<FrameNode>(parent);
566 if (!frameNode) {
567 continue;
568 }
569 auto pattern = frameNode->GetPattern<ScrollablePattern>();
570 if (!pattern) {
571 continue;
572 }
573 if (pattern->GetAxis() != GetAxis()) {
574 continue;
575 }
576 return pattern;
577 }
578 return nullptr;
579 }
580
GetParentNavigition()581 void ScrollablePattern::GetParentNavigition()
582 {
583 if (navBarPattern_) {
584 return;
585 }
586 auto host = GetHost();
587 CHECK_NULL_VOID(host);
588 if ((host->GetTag() != V2::LIST_ETS_TAG) && (host->GetTag() != V2::GRID_ETS_TAG) &&
589 (host->GetTag() != V2::SCROLL_ETS_TAG)) {
590 return;
591 }
592 for (auto parent = host->GetParent(); parent != nullptr; parent = parent->GetParent()) {
593 RefPtr<FrameNode> frameNode = AceType::DynamicCast<FrameNode>(parent);
594 if (!frameNode) {
595 continue;
596 }
597 if ((frameNode->GetTag() == V2::LIST_ETS_TAG) || (frameNode->GetTag() == V2::GRID_ETS_TAG) ||
598 (frameNode->GetTag() == V2::SCROLL_ETS_TAG)) {
599 break;
600 }
601 navBarPattern_ = frameNode->GetPattern<NavBarPattern>();
602 if (!navBarPattern_) {
603 continue;
604 }
605 return;
606 }
607 navBarPattern_ = nullptr;
608 return;
609 }
610
SetNavBarVelocity()611 void ScrollablePattern::SetNavBarVelocity()
612 {
613 CHECK_NULL_VOID(scrollableEvent_);
614 auto scrollable = scrollableEvent_->GetScrollable();
615 CHECK_NULL_VOID(scrollable);
616 auto currVelocity = scrollable->GetCurrentVelocity();
617 if (Positive(currVelocity)) {
618 CHECK_NULL_VOID(navBarPattern_);
619 navBarPattern_->NavBarMotion(currVelocity, FRICTION);
620 }
621 }
622
SetParentScrollable()623 void ScrollablePattern::SetParentScrollable()
624 {
625 CHECK_NULL_VOID_NOLOG(scrollableEvent_);
626 CHECK_NULL_VOID_NOLOG(scrollableEvent_->GetScrollable());
627 if (nestedScroll_.NeedParent()) {
628 auto parent = GetParentScrollable();
629 CHECK_NULL_VOID_NOLOG(parent);
630 CHECK_NULL_VOID_NOLOG(parent->scrollableEvent_);
631 auto parentScrollable = parent->scrollableEvent_->GetScrollable();
632 scrollableEvent_->GetScrollable()->SetParent(parentScrollable);
633 } else {
634 scrollableEvent_->GetScrollable()->SetParent(nullptr);
635 }
636 }
637
StopAnimate()638 void ScrollablePattern::StopAnimate()
639 {
640 if (!IsScrollableStopped()) {
641 StopScrollable();
642 }
643 if (animator_ && !animator_->IsStopped()) {
644 animator_->Stop();
645 }
646 }
647
ScrollTo(float position)648 void ScrollablePattern::ScrollTo(float position)
649 {
650 StopAnimate();
651 UpdateCurrentOffset(GetTotalOffset() - position, SCROLL_FROM_JUMP);
652 }
653
AnimateTo(float position,float duration,const RefPtr<Curve> & curve,bool smooth)654 void ScrollablePattern::AnimateTo(float position, float duration, const RefPtr<Curve>& curve, bool smooth)
655 {
656 LOGI("AnimateTo:%{public}f, duration:%{public}f", position, duration);
657 float currVelocity = 0.0f;
658 if (!IsScrollableStopped()) {
659 CHECK_NULL_VOID(scrollableEvent_);
660 auto scrollable = scrollableEvent_->GetScrollable();
661 CHECK_NULL_VOID(scrollable);
662 currVelocity = -scrollable->GetCurrentVelocity();
663 scrollAbort_ = true;
664 StopScrollable();
665 }
666 if (!animator_) {
667 animator_ = CREATE_ANIMATOR(PipelineBase::GetCurrentContext());
668 animator_->AddStopListener([weak = AceType::WeakClaim(this)]() {
669 auto pattern = weak.Upgrade();
670 CHECK_NULL_VOID_NOLOG(pattern);
671 pattern->OnAnimateStop();
672 });
673 } else if (!animator_->IsStopped()) {
674 if (springMotion_) {
675 currVelocity = springMotion_->GetCurrentVelocity();
676 }
677 scrollAbort_ = true;
678 animator_->Stop();
679 }
680 animator_->ClearInterpolators();
681
682 if (smooth) {
683 PlaySpringAnimation(position, DEFAULT_SCROLL_TO_VELOCITY, DEFAULT_SCROLL_TO_MASS,
684 DEFAULT_SCROLL_TO_STIFFNESS, DEFAULT_SCROLL_TO_DAMPING);
685 } else if (AceType::InstanceOf<InterpolatingSpring>(curve)) {
686 auto springCurve = AceType::DynamicCast<InterpolatingSpring>(curve);
687 float velocity = springCurve->GetVelocity();
688 float mass = springCurve->GetMass();
689 float stiffness = springCurve->GetStiffness();
690 float damping = springCurve->GetDamping();
691 PlaySpringAnimation(position, velocity, mass, stiffness, damping);
692 } else if (AceType::InstanceOf<ResponsiveSpringMotion>(curve)) {
693 auto springCurve = AceType::DynamicCast<ResponsiveSpringMotion>(curve);
694 constexpr float PI = 3.1415926f;
695 float tmpStiffness = (2 * PI / springCurve->GetResponse());
696 float stiffness = tmpStiffness * tmpStiffness;
697 float damping = 4 * PI * springCurve->GetDampingRatio() / springCurve->GetResponse();
698 PlaySpringAnimation(position, currVelocity, 1.0f, stiffness, damping);
699 } else {
700 auto animation = AceType::MakeRefPtr<CurveAnimation<float>>(GetTotalOffset(), position, curve);
701 animation->AddListener([weakScroll = AceType::WeakClaim(this), position](float value) {
702 auto pattern = weakScroll.Upgrade();
703 CHECK_NULL_VOID_NOLOG(pattern);
704 if (!pattern->UpdateCurrentOffset(pattern->GetTotalOffset() - value, SCROLL_FROM_ANIMATION_CONTROLLER)) {
705 if ((pattern->IsAtTop() && LessOrEqual(position, pattern->GetTotalOffset())) ||
706 (pattern->IsAtBottom() && GreatOrEqual(position, pattern->GetTotalOffset()))) {
707 pattern->animator_->Stop();
708 }
709 }
710 });
711 animator_->AddInterpolator(animation);
712 animator_->SetDuration(static_cast<int32_t>(duration));
713 animator_->Play();
714 }
715 }
716
PlaySpringAnimation(float position,float velocity,float mass,float stiffness,float damping)717 void ScrollablePattern::PlaySpringAnimation(
718 float position, float velocity, float mass, float stiffness, float damping)
719 {
720 auto start = GetTotalOffset();
721 const RefPtr<SpringProperty> DEFAULT_OVER_SPRING_PROPERTY =
722 AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping);
723 if (!springMotion_) {
724 const RefPtr<SpringProperty> DEFAULT_OVER_SPRING_PROPERTY =
725 AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping);
726 springMotion_ = AceType::MakeRefPtr<SpringMotion>(start, position, velocity, DEFAULT_OVER_SPRING_PROPERTY);
727 CHECK_NULL_VOID(scrollableEvent_);
728 scrollableEvent_->SetAnimateVelocityCallback([weakScroll = AceType::WeakClaim(this)]() -> double {
729 auto pattern = weakScroll.Upgrade();
730 CHECK_NULL_RETURN_NOLOG(pattern, 0.0f);
731 CHECK_NULL_RETURN_NOLOG(pattern->springMotion_, 0.0f);
732 CHECK_NULL_RETURN_NOLOG(pattern->animator_, 0.0f);
733 auto velocity = pattern->animator_->IsStopped() ? 0.0f : pattern->springMotion_->GetCurrentVelocity();
734 return velocity;
735 });
736 } else {
737 springMotion_->Reset(start, position, velocity, DEFAULT_OVER_SPRING_PROPERTY);
738 springMotion_->ClearListeners();
739 }
740 springMotion_->AddListener([weakScroll = AceType::WeakClaim(this)](double position) {
741 auto pattern = weakScroll.Upgrade();
742 CHECK_NULL_VOID(pattern);
743 if (!pattern->UpdateCurrentOffset(pattern->GetTotalOffset() - position, SCROLL_FROM_ANIMATION_CONTROLLER)) {
744 pattern->animator_->Stop();
745 }
746 });
747 animator_->PlayMotion(springMotion_);
748 }
749
OnAttachToFrameNode()750 void ScrollablePattern::OnAttachToFrameNode()
751 {
752 auto host = GetHost();
753 CHECK_NULL_VOID(host);
754 host->GetRenderContext()->SetClipToBounds(true);
755 host->GetRenderContext()->UpdateClipEdge(true);
756 }
757
UninitMouseEvent()758 void ScrollablePattern::UninitMouseEvent()
759 {
760 if (!mouseEvent_) {
761 return;
762 }
763 auto host = GetHost();
764 CHECK_NULL_VOID(host);
765 auto mouseEventHub = host->GetOrCreateInputEventHub();
766 CHECK_NULL_VOID(mouseEventHub);
767 mouseEventHub->RemoveOnMouseEvent(mouseEvent_);
768 ClearMultiSelect();
769 ClearInvisibleItemsSelectedStatus();
770 isMouseEventInit_ = false;
771 }
772
InitMouseEvent()773 void ScrollablePattern::InitMouseEvent()
774 {
775 auto host = GetHost();
776 CHECK_NULL_VOID(host);
777 auto mouseEventHub = host->GetOrCreateInputEventHub();
778 CHECK_NULL_VOID(mouseEventHub);
779 if (!mouseEvent_) {
780 auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
781 auto pattern = weak.Upgrade();
782 if (pattern) {
783 pattern->HandleMouseEventWithoutKeyboard(info);
784 }
785 };
786 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
787 }
788 mouseEventHub->AddOnMouseEvent(mouseEvent_);
789 isMouseEventInit_ = true;
790 auto pipeline = PipelineContext::GetCurrentContext();
791 CHECK_NULL_VOID(pipeline);
792 auto dragDropManager = pipeline->GetDragDropManager();
793 CHECK_NULL_VOID(dragDropManager);
794 dragDropManager->SetNotifyInDraggedCallback([wp = WeakClaim(this)]() {
795 auto pattern = wp.Upgrade();
796 if (pattern && pattern->mousePressed_) {
797 pattern->OnMouseRelease();
798 }
799 });
800 }
801
ClearInvisibleItemsSelectedStatus()802 void ScrollablePattern::ClearInvisibleItemsSelectedStatus()
803 {
804 for (auto& item : itemToBeSelected_) {
805 item.second.FireSelectChangeEvent(false);
806 }
807 itemToBeSelected_.clear();
808 }
809
HandleInvisibleItemsSelectedStatus(const RectF & selectedZone)810 void ScrollablePattern::HandleInvisibleItemsSelectedStatus(const RectF& selectedZone)
811 {
812 auto newRect = selectedZone;
813 auto startMainOffset = mouseStartOffset_.GetMainOffset(axis_);
814 auto endMainOffset = mouseEndOffset_.GetMainOffset(axis_);
815 if (LessNotEqual(startMainOffset, endMainOffset)) {
816 if (axis_ == Axis::VERTICAL) {
817 newRect.SetOffset(OffsetF(selectedZone.Left(), totalOffsetOfMousePressed_));
818 } else {
819 newRect.SetOffset(OffsetF(totalOffsetOfMousePressed_, selectedZone.Top()));
820 }
821 } else {
822 if (axis_ == Axis::VERTICAL) {
823 newRect.SetOffset(
824 OffsetF(selectedZone.Left(), totalOffsetOfMousePressed_ - (startMainOffset - endMainOffset)));
825 } else {
826 newRect.SetOffset(
827 OffsetF(totalOffsetOfMousePressed_ - (startMainOffset - endMainOffset), selectedZone.Top()));
828 }
829 }
830
831 for (auto& item : itemToBeSelected_) {
832 item.second.FireSelectChangeEvent(newRect.IsIntersectWith(item.second.rect));
833 }
834 }
835
HandleMouseEventWithoutKeyboard(const MouseInfo & info)836 void ScrollablePattern::HandleMouseEventWithoutKeyboard(const MouseInfo& info)
837 {
838 if (info.GetButton() != MouseButton::LEFT_BUTTON) {
839 return;
840 }
841
842 auto pipeline = PipelineContext::GetCurrentContext();
843 CHECK_NULL_VOID(pipeline);
844 auto manager = pipeline->GetDragDropManager();
845 CHECK_NULL_VOID(manager);
846 if (manager->IsDragged()) {
847 if (mousePressed_) {
848 OnMouseRelease();
849 }
850 return;
851 }
852
853 auto mouseOffsetX = static_cast<float>(info.GetLocalLocation().GetX());
854 auto mouseOffsetY = static_cast<float>(info.GetLocalLocation().GetY());
855 if (info.GetAction() == MouseAction::PRESS) {
856 if (!IsItemSelected(info)) {
857 ClearMultiSelect();
858 ClearInvisibleItemsSelectedStatus();
859 }
860 mouseStartOffset_ = OffsetF(mouseOffsetX, mouseOffsetY);
861 mouseEndOffset_ = OffsetF(mouseOffsetX, mouseOffsetY);
862 mousePressOffset_ = OffsetF(mouseOffsetX, mouseOffsetY);
863 totalOffsetOfMousePressed_ = mousePressOffset_.GetMainOffset(axis_) + GetTotalOffset();
864 mousePressed_ = true;
865 // do not select when click
866 } else if (info.GetAction() == MouseAction::MOVE) {
867 if (!mousePressed_) {
868 return;
869 }
870 lastMouseMove_ = info;
871 auto delta = OffsetF(mouseOffsetX, mouseOffsetY) - mousePressOffset_;
872 if (Offset(delta.GetX(), delta.GetY()).GetDistance() > DEFAULT_PAN_DISTANCE.ConvertToPx()) {
873 mouseEndOffset_ = OffsetF(mouseOffsetX, mouseOffsetY);
874 auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
875 MultiSelectWithoutKeyboard(selectedZone);
876 HandleInvisibleItemsSelectedStatus(selectedZone);
877 }
878 SelectWithScroll();
879 } else if (info.GetAction() == MouseAction::RELEASE) {
880 OnMouseRelease();
881 }
882 }
883
SelectWithScroll()884 void ScrollablePattern::SelectWithScroll()
885 {
886 if (!IsScrollable()) {
887 return;
888 }
889 auto offset = GetOutOfScrollableOffset();
890 if (NearZero(offset)) {
891 return;
892 }
893
894 if (AnimateRunning()) {
895 return;
896 }
897 if (!animator_) {
898 animator_ = CREATE_ANIMATOR(PipelineBase::GetCurrentContext());
899 animator_->AddStopListener([weak = AceType::WeakClaim(this)]() {
900 auto pattern = weak.Upgrade();
901 CHECK_NULL_VOID_NOLOG(pattern);
902 pattern->OnAnimateStop();
903 });
904 } else if (!animator_->IsStopped()) {
905 scrollAbort_ = true;
906 animator_->Stop();
907 }
908
909 if (!selectMotion_) {
910 selectMotion_ = AceType::MakeRefPtr<SelectMotion>(offset, [weak = WeakClaim(this)]() -> bool {
911 auto pattern = weak.Upgrade();
912 CHECK_NULL_RETURN_NOLOG(pattern, true);
913 return pattern->ShouldSelectScrollBeStopped();
914 });
915 selectMotion_->AddListener([weakScroll = AceType::WeakClaim(this)](double offset) {
916 auto pattern = weakScroll.Upgrade();
917 CHECK_NULL_VOID(pattern);
918 pattern->UpdateCurrentOffset(offset, SCROLL_FROM_AXIS);
919 });
920 } else {
921 selectMotion_->Reset(offset);
922 }
923
924 animator_->PlayMotion(selectMotion_);
925 }
926
OnMouseRelease()927 void ScrollablePattern::OnMouseRelease()
928 {
929 mouseStartOffset_.Reset();
930 mouseEndOffset_.Reset();
931 mousePressed_ = false;
932 ClearSelectedZone();
933 lastMouseMove_.SetLocalLocation(Offset::Zero());
934 }
935
ClearSelectedZone()936 void ScrollablePattern::ClearSelectedZone()
937 {
938 DrawSelectedZone(RectF());
939 }
940
ComputeSelectedZone(const OffsetF & startOffset,const OffsetF & endOffset)941 RectF ScrollablePattern::ComputeSelectedZone(const OffsetF& startOffset, const OffsetF& endOffset)
942 {
943 RectF selectedZone;
944 if (startOffset.GetX() <= endOffset.GetX()) {
945 if (startOffset.GetY() <= endOffset.GetY()) {
946 // bottom right
947 selectedZone = RectF(startOffset.GetX(), startOffset.GetY(), endOffset.GetX() - startOffset.GetX(),
948 endOffset.GetY() - startOffset.GetY());
949 } else {
950 // top right
951 selectedZone = RectF(startOffset.GetX(), endOffset.GetY(), endOffset.GetX() - startOffset.GetX(),
952 startOffset.GetY() - endOffset.GetY());
953 }
954 } else {
955 if (startOffset.GetY() <= endOffset.GetY()) {
956 // bottom left
957 selectedZone = RectF(endOffset.GetX(), startOffset.GetY(), startOffset.GetX() - endOffset.GetX(),
958 endOffset.GetY() - startOffset.GetY());
959 } else {
960 // top left
961 selectedZone = RectF(endOffset.GetX(), endOffset.GetY(), startOffset.GetX() - endOffset.GetX(),
962 startOffset.GetY() - endOffset.GetY());
963 }
964 }
965
966 return selectedZone;
967 }
968
DrawSelectedZone(const RectF & selectedZone)969 void ScrollablePattern::DrawSelectedZone(const RectF& selectedZone)
970 {
971 auto host = GetHost();
972 CHECK_NULL_VOID(host);
973 auto hostContext = host->GetRenderContext();
974 CHECK_NULL_VOID(hostContext);
975 hostContext->UpdateMouseSelectWithRect(selectedZone, SELECT_FILL_COLOR, SELECT_STROKE_COLOR);
976 }
977
MarkSelectedItems()978 void ScrollablePattern::MarkSelectedItems()
979 {
980 if (multiSelectable_ && mousePressed_) {
981 auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
982 if (!selectedZone.IsEmpty()) {
983 MultiSelectWithoutKeyboard(selectedZone);
984 HandleInvisibleItemsSelectedStatus(selectedZone);
985 }
986 }
987 }
988
ShouldSelectScrollBeStopped()989 bool ScrollablePattern::ShouldSelectScrollBeStopped()
990 {
991 if (!mousePressed_) {
992 return true;
993 }
994 auto offset = GetOutOfScrollableOffset();
995 if (NearZero(offset)) {
996 return true;
997 }
998
999 // avoid start position move when offset is bigger then item height
1000 auto currentMainStartOffset = mouseStartOffset_.GetMainOffset(axis_);
1001 if (Positive(offset)) {
1002 if (LessNotEqual(totalOffsetOfMousePressed_, currentMainStartOffset + offset)) {
1003 offset = totalOffsetOfMousePressed_ - currentMainStartOffset;
1004 }
1005 } else {
1006 auto hostSize = GetHostFrameSize();
1007 CHECK_NULL_RETURN_NOLOG(hostSize.has_value(), true);
1008 auto minStartOffset = -(GetTotalHeight() - totalOffsetOfMousePressed_ - hostSize->MainSize(axis_));
1009 if (GreatNotEqual(minStartOffset, currentMainStartOffset + offset)) {
1010 offset = minStartOffset - currentMainStartOffset;
1011 }
1012 }
1013
1014 if (axis_ == Axis::VERTICAL) {
1015 mouseStartOffset_.AddY(offset);
1016 } else {
1017 mouseStartOffset_.AddX(offset);
1018 }
1019 if (selectMotion_) {
1020 selectMotion_->Reset(offset);
1021 }
1022 return false;
1023 };
1024
GetOutOfScrollableOffset() const1025 float ScrollablePattern::GetOutOfScrollableOffset() const
1026 {
1027 auto offset = 0.0f;
1028 auto mouseMainOffset = static_cast<float>(
1029 axis_ == Axis::VERTICAL ? lastMouseMove_.GetLocalLocation().GetY() : lastMouseMove_.GetLocalLocation().GetX());
1030 auto hostSize = GetHostFrameSize();
1031 CHECK_NULL_RETURN_NOLOG(hostSize.has_value(), offset);
1032 auto mainTop = 0.0f;
1033 auto mainBottom = hostSize->MainSize(axis_);
1034 if (GreatOrEqual(mouseMainOffset, mainTop) && LessOrEqual(mouseMainOffset, mainBottom)) {
1035 return offset;
1036 }
1037 if (GreatNotEqual(mouseMainOffset, mainBottom)) {
1038 if (IsAtBottom()) {
1039 return offset;
1040 }
1041 offset = mainBottom - mouseMainOffset;
1042 }
1043 if (LessNotEqual(mouseMainOffset, mainTop)) {
1044 if (IsAtTop()) {
1045 return offset;
1046 }
1047 offset = mainTop - mouseMainOffset;
1048 }
1049 return offset;
1050 }
1051 } // namespace OHOS::Ace::NG
1052