• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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/list/render_list_item.h"
17 
18 #include "base/log/dump_log.h"
19 #include "core/common/vibrator/vibrator_proxy.h"
20 #include "core/components/flex/render_flex.h"
21 #include "core/components/list/render_list_item_group.h"
22 #include "core/components/list/tv_interactive_effect.h"
23 #ifdef WEARABLE_PRODUCT
24 #include "core/components/list/watch_interactive_effect.h"
25 #endif
26 
27 namespace OHOS::Ace {
28 namespace {
29 
30 const double HALF_SIZE = 0.5;
31 const double ITEM_DISTANCE_BASE = 76.0;
32 const double ITEM_DEFAULT_SCALE = 1.0;
33 const double ITEM_ZERO = 0.0;
34 const double ITEM_SCALE_BASE = 1.12;
35 const double ITEM_OPACITY_BASE = 1.0;
36 const double ITEM_RATIO = -0.34; // 0.78 - 1.12  // 0.66 - 1.0
37 const double DISTANCE_EPSILON = 1.0;
38 constexpr int32_t MIN_COMPATITABLE_VERSION = 5;
39 const double WATCH_SIZE = 466.0;
40 
41 #ifdef WEARABLE_PRODUCT
42 const std::string& VIBRATOR_TYPE_WATCH_CROWN_STRENGTH1 = "watchhaptic.crown.strength1";
43 #endif
44 
45 } // namespace
46 
RenderListItem()47 RenderListItem::RenderListItem()
48 {
49     Initialize();
50 }
51 
Initialize()52 void RenderListItem::Initialize()
53 {
54     clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
55     clickRecognizer_->SetOnClick([weakItem = AceType::WeakClaim(this)](const ClickInfo&) {
56         auto item = weakItem.Upgrade();
57         if (item) {
58             item->HandleClicked();
59         }
60     });
61     touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
62     touchRecognizer_->SetOnTouchDown([weakItem = AceType::WeakClaim(this)](const TouchEventInfo&) {
63         auto item = weakItem.Upgrade();
64         if (item && item->GetSupportClick()) {
65             item->PlayPressDownAnimation();
66         }
67     });
68     touchRecognizer_->SetOnTouchUp([weakItem = AceType::WeakClaim(this)](const TouchEventInfo&) {
69         auto item = weakItem.Upgrade();
70         if (item && item->GetSupportClick()) {
71             item->PlayPressUpAnimation();
72         }
73     });
74     touchRecognizer_->SetOnTouchCancel([weakItem = AceType::WeakClaim(this)](const TouchEventInfo&) {
75         auto item = weakItem.Upgrade();
76         if (item && item->GetSupportClick()) {
77             item->PlayPressUpAnimation();
78         }
79     });
80 }
81 
PerformLayout()82 void RenderListItem::PerformLayout()
83 {
84     if (!GetChildren().empty()) {
85         auto child = GetChildren().front();
86         auto context = context_.Upgrade();
87         if (NeedDivider() && context && context->GetIsDeclarative()) {
88             auto layoutParam = GetLayoutParam();
89             auto maxSize = layoutParam.GetMaxSize();
90             auto dividerSize = IsListVertical() ? Size(0.0, NormalizeToPx(dividerHeight_))
91                                                 : Size(NormalizeToPx(dividerHeight_), 0.0);
92             maxSize = maxSize - dividerSize;
93             layoutParam.SetMaxSize(maxSize);
94             child->Layout(layoutParam);
95         } else {
96             child->Layout(GetLayoutParam());
97         }
98         child->SetPosition(Offset::Zero());
99         if (NeedDivider()) {
100             auto dividerSize = IsListVertical() ? Size(0.0, NormalizeToPx(dividerHeight_))
101                 : Size(NormalizeToPx(dividerHeight_), 0.0);
102             SetLayoutSize(dividerSize + child->GetLayoutSize());
103         } else {
104             SetLayoutSize(child->GetLayoutSize());
105         }
106         // update focus animation size
107         focusAnimationRRect_.SetRect(Rect(Offset(0, 0), GetPaintSize() * TV_ITEM_SCALE));
108 
109         if (SystemProperties::GetDeviceType() == DeviceType::WATCH ||
110             SystemProperties::GetDeviceType() == DeviceType::WEARABLE) {
111             CalculateScaleFactorOnWatch();
112         }
113     }
114 }
115 
CalculateScaleFactorOnWatch()116 void RenderListItem::CalculateScaleFactorOnWatch()
117 {
118     if (isTitle_) {
119         return;
120     }
121 
122     auto context = GetContext().Upgrade();
123     const static int32_t PLATFORM_VERSION_FIVE = 5;
124     if (context && context->GetMinPlatformVersion() <= PLATFORM_VERSION_FIVE) {
125         Offset itemCenter = GetGlobalOffset() + GetLayoutSize() * HALF_SIZE;
126         double scale = ITEM_DEFAULT_SCALE;
127         double viewScale = ITEM_DEFAULT_SCALE;
128         auto pipelineContext = context_.Upgrade();
129         if (pipelineContext) {
130             scale = pipelineContext->GetDipScale();
131             viewScale = pipelineContext->GetViewScale();
132         }
133         if (NearZero(scale) || NearZero(viewScale)) {
134             LOGE("pipeline parameter is invalid");
135             return;
136         }
137         auto distance = std::abs(itemCenter.GetY() - WATCH_SIZE / viewScale * HALF_SIZE);
138         auto ratio = std::pow(distance, SQUARE) * ITEM_RATIO / std::pow(ITEM_DISTANCE_BASE * scale, SQUARE);
139         scaleFactor_ = std::max(ITEM_ZERO, ratio + ITEM_SCALE_BASE);
140         opacityFactor_ = std::max(ITEM_ZERO, ratio + ITEM_OPACITY_BASE);
141     } else {
142         auto renderList = GetRenderList();
143         if (!renderList) {
144             LOGE("Can not find parent render list");
145             return;
146         }
147 
148         double itemSize = renderList->IsVertical() ? GetLayoutSize().Height() : GetLayoutSize().Width();
149         double itemCenter = GetPositionInList() + renderList->GetListPosition() + itemSize * HALF_SIZE;
150         double scale = ITEM_DEFAULT_SCALE;
151         auto pipelineContext = context_.Upgrade();
152         if (pipelineContext) {
153             scale = pipelineContext->GetDipScale();
154         }
155         if (NearZero(scale)) {
156             LOGE("Pipeline parameter is invalid");
157             return;
158         }
159         double viewPort = renderList->IsVertical() ? viewPort_.Height() : viewPort_.Width();
160         auto distance = std::abs(itemCenter - viewPort * HALF_SIZE);
161         if (NearZero(distance, DISTANCE_EPSILON)) {
162             distance = 0.0;
163         }
164         auto ratio = std::pow(distance, SQUARE) * ITEM_RATIO / std::pow(ITEM_DISTANCE_BASE * scale, SQUARE);
165         scaleFactor_ = std::max(ITEM_ZERO, ratio + ITEM_SCALE_BASE);
166         opacityFactor_ = std::max(ITEM_ZERO, ratio + ITEM_OPACITY_BASE);
167     }
168 }
169 
Update(const RefPtr<Component> & component)170 void RenderListItem::Update(const RefPtr<Component>& component)
171 {
172     itemComponent_ = component;
173     auto item = AceType::DynamicCast<ListItemComponent>(component);
174     if (item) {
175         type_ = item->GetType();
176         index_ = item->GetIndex();
177         columnSpan_ = item->GetColumnSpan();
178         op_ = item->GetOperation();
179         flags_ = item->GetFlags();
180         // update focus animation color
181         focusAnimationColor_ = item->GetFocusAnimationColor();
182         // update focus animation corner radius
183         focusAnimationRRect_.SetCorner({ item->GetTopLeftRadius(), item->GetTopRightRadius(),
184             item->GetBottomRightRadius(), item->GetBottomLeftRadius() });
185 
186         needVibrate_ = item->NeedVibrate();
187         auto context = context_.Upgrade();
188         if (needVibrate_ && !vibrator_ && context) {
189             vibrator_ = VibratorProxy::GetInstance().GetVibrator(context->GetTaskExecutor());
190         }
191 
192         rotationVibrate_ = item->IsRotationVibrate();
193         if (rotationVibrate_ && !vibrator_ && context) {
194             vibrator_ = VibratorProxy::GetInstance().GetVibrator(context->GetTaskExecutor());
195         }
196 
197         supportScale_ = item->GetSupportScale();
198         supportOpacity_ = item->GetSupportOpacity();
199         supportClick_ = item->GetSupportClick();
200         isTitle_ = item->IsTitle();
201         sticky_ = item->GetSticky();
202         stickyMode_ = item->GetStickyMode();
203         clickColor_ = item->GetClickColor();
204         selfAlign_ = item->GetAlignSelf();
205         Dimension radius = item->GetStickyRadius();
206         if (radius.IsValid()) {
207             stickyRadius_ = context ? context->NormalizeToPx(radius) : stickyRadius_;
208         }
209 
210         if (!primary_ && item->GetPrimary()) {
211             NotifyGroupPrimaryChange();
212         }
213         SetPrimary(item->GetPrimary());
214 
215         // list divider
216         needDivider_ = item->NeedDivider();
217         isActive_ = item->IsActive();
218         dividerLength_ = item->GetDividerLength();
219         dividerHeight_ = item->GetDividerHeight();
220         dividerOrigin_ = item->GetDividerOrigin();
221         dividerColor_ = item->GetDividerColor();
222         auto onClickId = item->GetClickEventId();
223         clickEvent_ = AceAsyncEvent<void()>::Create(onClickId, GetContext());
224         clickRecognizer_->SetUseCatchMode(true);
225         if (!onClickId.GetCatchMode()) {
226             static const int32_t bubbleModeVersion = 6;
227             auto pipeline = context_.Upgrade();
228             if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
229                 clickRecognizer_->SetUseCatchMode(false);
230                 return;
231             }
232         }
233         stickyEvent_ = AceAsyncEvent<void(const std::string&)>::Create(item->GetStickyEventId(), GetContext());
234         transitionEffect_ = item->GetTransitionEffect();
235         UpdateAccessibilityAttr();
236         MarkNeedLayout();
237     }
238 }
239 
NotifyGroupPrimaryChange()240 void RenderListItem::NotifyGroupPrimaryChange()
241 {
242     auto parent = GetParent().Upgrade();
243     while (parent) {
244         auto group = AceType::DynamicCast<RenderListItemGroup>(parent);
245         if (group) {
246             group->ItemPrimaryChange(GetIndex());
247             break;
248         }
249         parent = parent->GetParent().Upgrade();
250     }
251 }
252 
GetPositionInList() const253 double RenderListItem::GetPositionInList() const
254 {
255     RefPtr<RenderNode> parentNode = GetParent().Upgrade();
256     while (parentNode) {
257         RefPtr<RenderList> listNode = AceType::DynamicCast<RenderList>(parentNode);
258         if (listNode) {
259             return listNode->GetItemPosition(index_);
260         }
261         parentNode = parentNode->GetParent().Upgrade();
262     }
263     return 0.0;
264 }
265 
IsItemCenter(bool isVertical,Size viewport)266 bool RenderListItem::IsItemCenter(bool isVertical, Size viewport)
267 {
268     auto parent = GetParent().Upgrade();
269     if (!parent) {
270         return false;
271     }
272     Size itemSize = GetLayoutSize();
273     Offset itemPosition = parent->GetPosition();
274     double size = isVertical ? itemSize.Height() : itemSize.Width();
275     double position = isVertical ? itemPosition.GetY() : itemPosition.GetX();
276     double center = (isVertical ? viewport.Height() : viewport.Width()) / 2.0;
277     return center > position && center < (position + size);
278 }
279 
ResetFocusEffect()280 void RenderListItem::ResetFocusEffect()
281 {
282 #ifdef WEARABLE_PRODUCT
283     if (SystemProperties::GetDeviceType() == DeviceType::WATCH ||
284         SystemProperties::GetDeviceType() == DeviceType::WEARABLE) {
285         focusController_ = AceType::MakeRefPtr<WatchInteractiveEffect>(GetContext());
286 #else
287     if (SystemProperties::GetDeviceType() == DeviceType::TV) {
288         focusController_ = AceType::MakeRefPtr<TVInteractiveEffect>(GetContext());
289 #endif
290     } else {
291         focusController_ = AceType::MakeRefPtr<InteractiveEffect>(GetContext());
292     }
293     focusController_->Initialize(GetThemeManager());
294     focusController_->SetItemNode(AceType::WeakClaim(this));
295     auto listNode = GetRenderList();
296     if (listNode) {
297         auto weakList = WeakPtr<RenderList>(listNode);
298         focusController_->SetListNode(weakList);
299     }
300 }
301 
302 void RenderListItem::HandleItemEffect(bool isFromRotate)
303 {
304     if (!focusController_) {
305         ResetFocusEffect();
306     }
307 
308     if (currentState_ != lastState_) {
309 #ifdef WEARABLE_PRODUCT
310         if (needVibrate_ && lastState_ == ItemState::NEARBY && currentState_ == ItemState::FOCUS && vibrator_) {
311             vibrator_->Vibrate(VIBRATOR_TYPE_WATCH_CROWN_STRENGTH1);
312         }
313         if (rotationVibrate_ && isFromRotate && vibrator_) {
314             vibrator_->Vibrate(VIBRATOR_TYPE_WATCH_CROWN_STRENGTH1);
315         }
316 #endif
317         lastState_ = currentState_;
318         if (currentState_ != ItemState::NONE && currentState_ != ItemState::CLICK) {
319             focusController_->ShowAnimation(currentState_);
320         } else {
321             // invalid focus
322         }
323     }
324     MarkNeedRender();
325 }
326 
327 void RenderListItem::HandleClicked()
328 {
329     if (clickEvent_) {
330         clickEvent_();
331     }
332 
333     if (primary_ && clicked_) {
334         clicked_();
335     }
336 }
337 
338 void RenderListItem::PlayPressDownAnimation()
339 {
340     if (!focusController_) {
341         ResetFocusEffect();
342     }
343     pressAnimation_ = true;
344     focusController_->TouchDownAnimation();
345 }
346 
347 void RenderListItem::PlayPressUpAnimation()
348 {
349     if (!focusController_) {
350         ResetFocusEffect();
351     }
352     pressAnimation_ = false;
353     focusController_->TouchUpAnimation();
354 }
355 
356 void RenderListItem::OnCancelPressAnimation()
357 {
358     if (!pressAnimation_) {
359         return;
360     }
361     if (!focusController_) {
362         ResetFocusEffect();
363     }
364     focusController_->CancelTouchAnimation();
365 }
366 
367 void RenderListItem::HandleStickyEvent(bool sticky)
368 {
369     std::string state = sticky ? "true" : "false";
370     std::string param = std::string(R"("sticky",{"state":)").append(state).append("},null");
371     if (stickyEvent_) {
372         stickyEvent_(param);
373     }
374 }
375 
376 void RenderListItem::OnTouchTestHit(
377     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
378 {
379     if (!GetVisible() && !GetClonedBySticky()) {
380         return;
381     }
382     // supportClick means show click effect
383     bool supportClick = supportClick_;
384     auto pipeline = context_.Upgrade();
385     if (pipeline && pipeline->GetMinPlatformVersion() > MIN_COMPATITABLE_VERSION) {
386         supportClick = true;
387     }
388     if ((!touchRecognizer_) || (!clickRecognizer_) || (!supportClick)) {
389         return;
390     }
391     touchRecognizer_->SetCoordinateOffset(coordinateOffset);
392     clickRecognizer_->SetCoordinateOffset(coordinateOffset);
393     result.emplace_back(touchRecognizer_);
394     result.emplace_back(clickRecognizer_);
395 }
396 
397 void RenderListItem::UpdateItemFocusRect(double scale)
398 {
399     focusAnimationRRect_.SetRect(Rect(Offset(0.0, 0.0), GetPaintSize() * scale));
400 }
401 
402 void RenderListItem::HandleFocusEvent(bool focus, bool isInGroup)
403 {
404     if (SystemProperties::GetDeviceType() == DeviceType::WATCH ||
405         SystemProperties::GetDeviceType() == DeviceType::WEARABLE) {
406         return;
407     }
408     focused_ = focus;
409 
410     ShowFocusAnimation(focus, Rect(0.0, 0.0, 0.0, 0.0));
411 
412     if (focus) {
413         ChangeStatus(RenderStatus::FOCUS);
414         currentState_ = ItemState::FOCUS;
415         if (isInGroup) {
416             HandleItemEffect();
417             return;
418         }
419         RefPtr<RenderNode> parentNode = GetParent().Upgrade();
420         while (parentNode) {
421             RefPtr<RenderList> listNode = AceType::DynamicCast<RenderList>(parentNode);
422             if (listNode) {
423                 listNode->ListItemFocused(index_);
424                 break;
425             }
426             parentNode = parentNode->GetParent().Upgrade();
427         }
428     } else {
429         ChangeStatus(RenderStatus::BLUR);
430         currentState_ = ItemState::BLUR;
431     }
432     HandleItemEffect();
433 }
434 
435 Offset RenderListItem::GetPaintOffset() const
436 {
437     auto globalOffset = GetGlobalOffset();
438     auto layoutSize = GetLayoutSize(); // size include margin
439     auto paintSize = GetPaintSize();   // size exclude margin
440     auto margin = GetMarginInPx();
441     if (layoutSize > paintSize) {
442         globalOffset.SetX(globalOffset.GetX() + margin.LeftPx());
443         globalOffset.SetY(globalOffset.GetY() + margin.TopPx());
444     }
445     return globalOffset;
446 }
447 
448 EdgePx RenderListItem::GetMarginInPx() const
449 {
450     EdgePx marginInPx;
451     auto children = GetChildren();
452     if (children.empty()) {
453         return marginInPx;
454     }
455 
456     auto child = children.front();
457     while (child) {
458         auto box = AceType::DynamicCast<RenderBoxBase>(child);
459         if (box) {
460             auto boxChildren = box->GetChildren();
461             if (boxChildren.empty()) {
462                 break;
463             }
464             auto boxChild = boxChildren.front();
465             if (boxChild && AceType::DynamicCast<RenderFlex>(boxChild)) {
466                 marginInPx = box->GetMargin();
467                 break;
468             }
469         }
470         children = child->GetChildren();
471         if (children.empty()) {
472             break;
473         }
474         child = children.front();
475     }
476     return marginInPx;
477 }
478 
479 Size RenderListItem::GetPaintSize() const
480 {
481     Size size = GetLayoutSize();
482     auto margin = GetMarginInPx();
483     return size - margin.GetLayoutSize();
484 }
485 
486 Border RenderListItem::GetFocusBorder() const
487 {
488     Border border;
489     border.SetTopRightRadius(focusAnimationRRect_.GetCorner().topRightRadius);
490     border.SetTopLeftRadius(focusAnimationRRect_.GetCorner().topLeftRadius);
491     border.SetBottomLeftRadius(focusAnimationRRect_.GetCorner().bottomLeftRadius);
492     border.SetBottomRightRadius(focusAnimationRRect_.GetCorner().bottomRightRadius);
493     return border;
494 }
495 
496 void RenderListItem::ShowFocusAnimation(bool focus, const Rect& listRect, double scale)
497 {
498     // paint focus animation
499     auto context = context_.Upgrade();
500     if (!context) {
501         LOGE("[Focus]Pipeline context is nullptr");
502         return;
503     }
504 
505     if (focus) {
506         Size size = GetPaintSize();
507         auto globalOffset = GetPaintOffset() + (size * (DEFAULT_SCALE - scale) * HALF_SIZE);
508         if (listRect.IsValid()) {
509             context->ShowFocusAnimation(focusAnimationRRect_, focusAnimationColor_, globalOffset, listRect);
510             context->ShowShadow(focusAnimationRRect_, globalOffset);
511         } else {
512             context->ShowFocusAnimation(focusAnimationRRect_, focusAnimationColor_, globalOffset);
513             context->ShowShadow(focusAnimationRRect_, globalOffset);
514         }
515     } else {
516         context->CancelFocusAnimation();
517         context->CancelShadow();
518     }
519 }
520 
521 void RenderListItem::UpdateAccessibilityAttr()
522 {
523     auto refPtr = accessibilityNode_.Upgrade();
524     if (!refPtr) {
525         return;
526     }
527 
528     refPtr->SetClickableState(true);
529     refPtr->SetActionClickImpl([weakItem = AceType::WeakClaim(this)]() {
530         auto item = weakItem.Upgrade();
531         if (item) {
532             LOGI("Trigger ActionClick by Accessibility(%{public}d).", item->index_);
533             item->HandleClicked();
534             item->OnGroupClicked();
535         }
536     });
537 
538     refPtr->SetFocusableState(true);
539     refPtr->SetActionFocusImpl([weakItem = AceType::WeakClaim(this)]() {
540         auto item = weakItem.Upgrade();
541         if (item) {
542             LOGI("Trigger ActionFocus by Accessibility(%{public}d).", item->index_);
543             item->MoveToViewPort();
544         }
545     });
546     refPtr->AddSupportAction(AceAction::ACTION_ACCESSIBILITY_FOCUS);
547 }
548 
549 void RenderListItem::OnGroupClicked()
550 {
551     if (!primary_ || !curPrimary_) {
552         return; // Only trigger group click when current item is primary.
553     }
554     RefPtr<RenderNode> parent = GetParent().Upgrade();
555     while (parent) {
556         RefPtr<RenderListItemGroup> group = AceType::DynamicCast<RenderListItemGroup>(parent);
557         if (group) {
558             return group->HandleClicked();
559         }
560         parent = parent->GetParent().Upgrade();
561     }
562 }
563 
564 void RenderListItem::MoveToViewPort()
565 {
566     RefPtr<RenderNode> parentNode = GetParent().Upgrade();
567     while (parentNode) {
568         RefPtr<RenderList> listNode = AceType::DynamicCast<RenderList>(parentNode);
569         if (listNode) {
570             return listNode->MoveItemToViewPort(GetPositionInList());
571         }
572         parentNode = parentNode->GetParent().Upgrade();
573     }
574 }
575 
576 RefPtr<RenderList> RenderListItem::GetRenderList() const
577 {
578     auto parent = GetParent().Upgrade();
579     while (parent) {
580         auto parentNode = AceType::DynamicCast<RenderList>(parent);
581         if (parentNode) {
582             return parentNode;
583         }
584         parent = parent->GetParent().Upgrade();
585     }
586     return nullptr;
587 }
588 
589 bool RenderListItem::NeedDivider()
590 {
591     return needDivider_ && !IsLastItem();
592 }
593 
594 bool RenderListItem::IsLastItem()
595 {
596     auto renderList = GetRenderList();
597     if (renderList) {
598         int32_t maxCount = renderList->GetMaxCount();
599         if (GetIndex() == maxCount - 1) {
600             return true;
601         }
602     }
603     return false;
604 }
605 
606 bool RenderListItem::IsListVertical()
607 {
608     auto renderList = GetRenderList();
609     if (renderList) {
610         FlexDirection listDirection = renderList->GetDirection();
611         return listDirection == FlexDirection::COLUMN || listDirection == FlexDirection::COLUMN_REVERSE;
612     }
613     return true;
614 }
615 
616 void RenderListItem::Dump()
617 {
618     DumpLog::GetInstance().AddDesc(std::string("index: ").append(std::to_string(GetIndex())));
619 }
620 
621 void RenderListItem::RunCardTransitionAnimation(double shiftHeight)
622 {
623     auto renderList = GetRenderList();
624     if (!renderList) {
625         LOGE("list render is null");
626         return;
627     }
628     makeCardTransition_ = true;
629     renderList->SetMakeCardTransition(makeCardTransition_);
630     if (transitionEffect_ == TransitionEffect::UNFOLD) {
631         renderList->SetShiftHeight(shiftHeight);
632     } else {
633         renderList->SetShiftHeight(0.0);
634     }
635     renderList->MarkNeedRender();
636 }
637 
638 void RenderListItem::StopCardTransitionAnimation()
639 {
640     makeCardTransition_ = false;
641     auto renderList = GetRenderList();
642     if (renderList) {
643         renderList->SetMakeCardTransition(makeCardTransition_);
644         renderList->SetShiftHeight(0.0);
645         renderList->MarkNeedRender();
646     }
647 }
648 
649 RRect RenderListItem::GetRRect() const
650 {
651     auto child = GetFirstChild();
652     while (child) {
653         auto childNode = AceType::DynamicCast<RenderBox>(child);
654         if (childNode) {
655             auto margin = childNode->GetMargin();
656             auto rrect = RRect(Rect(childNode->GetGlobalOffset() + margin.GetOffset(),
657                 childNode->GetLayoutSize() - margin.GetLayoutSize()));
658             if (childNode->GetBackDecoration()) {
659                 auto border = childNode->GetBackDecoration()->GetBorder();
660                 rrect.SetCorner({ border.TopLeftRadius(), border.TopRightRadius(),
661                     border.BottomLeftRadius(), border.BottomRightRadius() });
662             }
663             return rrect;
664         }
665         child = child->GetFirstChild();
666     }
667     return RRect();
668 }
669 
670 } // namespace OHOS::Ace
671