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