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