1 /*
2 * Copyright (c) 2022-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/list/list_item_pattern.h"
17
18 #include "base/geometry/axis.h"
19 #include "base/geometry/ng/size_t.h"
20 #include "base/log/dump_log.h"
21 #include "base/memory/ace_type.h"
22 #include "base/utils/utils.h"
23 #include "core/components_ng/pattern/list/list_item_group_layout_property.h"
24 #include "core/components/common/properties/color.h"
25 #include "core/components_ng/base/inspector_filter.h"
26 #include "core/components_ng/pattern/list/list_item_layout_algorithm.h"
27 #include "core/components_ng/pattern/list/list_item_layout_property.h"
28 #include "core/components_ng/pattern/list/list_pattern.h"
29 #include "core/components_ng/property/property.h"
30 #include "core/components_v2/inspector/inspector_constants.h"
31 #include "core/common/container.h"
32
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr float SWIPER_TH = 0.25f;
36 constexpr float NEW_SWIPER_TH = 0.5f;
37 constexpr float SWIPER_SPEED_TH = 1500.f;
38 constexpr float SWIPE_RATIO = 0.6f;
39 constexpr float NEW_SWIPE_RATIO = 1.848f;
40 constexpr float SWIPE_SPRING_MASS = 1.f;
41 constexpr float SWIPE_SPRING_STIFFNESS = 228.f;
42 constexpr float SWIPE_SPRING_DAMPING = 30.f;
43 constexpr int32_t DELETE_ANIMATION_DURATION = 400;
44 constexpr Color ITEM_FILL_COLOR = Color(0x1A0A59f7);
45 } // namespace
46
OnAttachToFrameNode()47 void ListItemPattern::OnAttachToFrameNode()
48 {
49 auto host = GetHost();
50 CHECK_NULL_VOID(host);
51 if (listItemStyle_ == V2::ListItemStyle::CARD) {
52 SetListItemDefaultAttributes(host);
53 }
54 }
55
OnColorConfigurationUpdate()56 void ListItemPattern::OnColorConfigurationUpdate()
57 {
58 if (listItemStyle_ != V2::ListItemStyle::CARD) {
59 return;
60 }
61 auto listItemNode = GetHost();
62 CHECK_NULL_VOID(listItemNode);
63 auto renderContext = listItemNode->GetRenderContext();
64 CHECK_NULL_VOID(renderContext);
65 auto pipeline = listItemNode->GetContext();
66 CHECK_NULL_VOID(pipeline);
67 auto listItemTheme = pipeline->GetTheme<ListItemTheme>();
68 CHECK_NULL_VOID(listItemTheme);
69
70 renderContext->UpdateBackgroundColor(listItemTheme->GetItemDefaultColor());
71 }
72
SetListItemDefaultAttributes(const RefPtr<FrameNode> & listItemNode)73 void ListItemPattern::SetListItemDefaultAttributes(const RefPtr<FrameNode>& listItemNode)
74 {
75 auto renderContext = listItemNode->GetRenderContext();
76 CHECK_NULL_VOID(renderContext);
77 auto layoutProperty = listItemNode->GetLayoutProperty<ListItemLayoutProperty>();
78 CHECK_NULL_VOID(layoutProperty);
79 auto pipeline = GetContext();
80 CHECK_NULL_VOID(pipeline);
81 auto listItemTheme = pipeline->GetTheme<ListItemTheme>();
82 CHECK_NULL_VOID(listItemTheme);
83
84 renderContext->UpdateBackgroundColor(listItemTheme->GetItemDefaultColor());
85
86 PaddingProperty itemPadding;
87 itemPadding.left = CalcLength(listItemTheme->GetItemDefaultLeftPadding());
88 itemPadding.right = CalcLength(listItemTheme->GetItemDefaultRightPadding());
89 layoutProperty->UpdatePadding(itemPadding);
90
91 layoutProperty->UpdateUserDefinedIdealSize(
92 CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(listItemTheme->GetItemDefaultHeight())));
93 renderContext->UpdateBorderRadius(listItemTheme->GetItemDefaultBorderRadius());
94 }
95
CreateLayoutAlgorithm()96 RefPtr<LayoutAlgorithm> ListItemPattern::CreateLayoutAlgorithm()
97 {
98 auto host = GetHost();
99 CHECK_NULL_RETURN(host, nullptr);
100 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
101 CHECK_NULL_RETURN(listItemEventHub, nullptr);
102 if (!HasStartNode() && !HasEndNode() && !listItemEventHub->GetStartOnDelete() &&
103 !listItemEventHub->GetEndOnDelete()) {
104 return MakeRefPtr<BoxLayoutAlgorithm>();
105 }
106 auto layoutAlgorithm = MakeRefPtr<ListItemLayoutAlgorithm>(startNodeIndex_, endNodeIndex_, childNodeIndex_);
107 layoutAlgorithm->SetAxis(axis_);
108 layoutAlgorithm->SetStartNodeSize(startNodeSize_);
109 layoutAlgorithm->SetEndNodeSize(endNodeSize_);
110 layoutAlgorithm->SetCurOffset(curOffset_);
111 layoutAlgorithm->SetHasStartDeleteArea(hasStartDeleteArea_);
112 layoutAlgorithm->SetHasEndDeleteArea(hasEndDeleteArea_);
113 return layoutAlgorithm;
114 }
115
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)116 bool ListItemPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
117 {
118 if (config.skipMeasure && config.skipLayout) {
119 return false;
120 }
121 isLayouted_ = true;
122 if (!HasStartNode() && !HasEndNode()) {
123 return false;
124 }
125 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
126 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
127 auto layoutAlgorithm = DynamicCast<ListItemLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
128 CHECK_NULL_RETURN(layoutAlgorithm, false);
129 startNodeSize_ = layoutAlgorithm->GetStartNodeSize();
130 endNodeSize_ = layoutAlgorithm->GetEndNodeSize();
131 if (axis_ != GetAxis()) {
132 ChangeAxis(GetAxis());
133 }
134 return false;
135 }
136
SetStartNode(const RefPtr<NG::UINode> & startNode)137 void ListItemPattern::SetStartNode(const RefPtr<NG::UINode>& startNode)
138 {
139 auto host = GetHost();
140 CHECK_NULL_VOID(host);
141 if (startNode) {
142 if (!HasStartNode()) {
143 host->AddChild(startNode);
144 startNodeIndex_ = host->GetChildIndexById(startNode->GetId());
145 if (childNodeIndex_ >= startNodeIndex_) {
146 childNodeIndex_++;
147 }
148 if (endNodeIndex_ >= startNodeIndex_) {
149 endNodeIndex_++;
150 }
151 } else {
152 host->ReplaceChild(host->GetChildAtIndex(startNodeIndex_), startNode);
153 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
154 }
155 } else if (HasStartNode()) {
156 if (NonNegative(curOffset_)) {
157 curOffset_ = 0.0f;
158 isDragging_ = false;
159 }
160 host->RemoveChildAtIndex(startNodeIndex_);
161 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
162 if (endNodeIndex_ > startNodeIndex_) {
163 endNodeIndex_--;
164 }
165 if (childNodeIndex_ > startNodeIndex_) {
166 childNodeIndex_--;
167 }
168 startNodeIndex_ = -1;
169 }
170 }
171
SetEndNode(const RefPtr<NG::UINode> & endNode)172 void ListItemPattern::SetEndNode(const RefPtr<NG::UINode>& endNode)
173 {
174 auto host = GetHost();
175 CHECK_NULL_VOID(host);
176 if (endNode) {
177 if (!HasEndNode()) {
178 host->AddChild(endNode);
179 endNodeIndex_ = host->GetChildIndexById(endNode->GetId());
180 if (childNodeIndex_ >= endNodeIndex_) {
181 childNodeIndex_++;
182 }
183 if (startNodeIndex_ >= endNodeIndex_) {
184 startNodeIndex_++;
185 }
186 } else {
187 host->ReplaceChild(host->GetChildAtIndex(endNodeIndex_), endNode);
188 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
189 }
190 } else if (HasEndNode()) {
191 if (NonPositive(curOffset_)) {
192 curOffset_ = 0.0f;
193 isDragging_ = false;
194 }
195 host->RemoveChildAtIndex(endNodeIndex_);
196 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
197 if (startNodeIndex_ > endNodeIndex_) {
198 startNodeIndex_--;
199 }
200 if (childNodeIndex_ > endNodeIndex_) {
201 childNodeIndex_--;
202 }
203 endNodeIndex_ = -1;
204 }
205 }
206
OnDidPop()207 void ListItemPattern::OnDidPop()
208 {
209 if (endNodeIndex_ >= 0 && endNodeIndex_ < childNodeIndex_) {
210 auto host = GetHost();
211 CHECK_NULL_VOID(host);
212 auto childNode = host->GetChildAtIndex(childNodeIndex_);
213 CHECK_NULL_VOID(childNode);
214 auto endNode = host->GetChildAtIndex(endNodeIndex_);
215 CHECK_NULL_VOID(endNode);
216 endNode->MovePosition(-1);
217 endNodeIndex_ = host->GetChildIndexById(endNode->GetId());
218 childNodeIndex_--;
219 }
220 }
221
GetContentSize() const222 SizeF ListItemPattern::GetContentSize() const
223 {
224 auto host = GetHost();
225 CHECK_NULL_RETURN(host, {});
226 auto geometryNode = host->GetGeometryNode();
227 CHECK_NULL_RETURN(geometryNode, {});
228 return geometryNode->GetPaddingSize();
229 }
230
GetListFrameNode() const231 RefPtr<FrameNode> ListItemPattern::GetListFrameNode() const
232 {
233 auto host = GetHost();
234 CHECK_NULL_RETURN(host, nullptr);
235 auto parent = host->GetParent();
236 RefPtr<FrameNode> frameNode = AceType::DynamicCast<FrameNode>(parent);
237 while (parent && (!frameNode || (parent->GetTag() == V2::LIST_ITEM_GROUP_ETS_TAG))) {
238 parent = parent->GetParent();
239 frameNode = AceType::DynamicCast<FrameNode>(parent);
240 }
241 return frameNode;
242 }
243
GetParentFrameNode() const244 RefPtr<FrameNode> ListItemPattern::GetParentFrameNode() const
245 {
246 auto host = GetHost();
247 CHECK_NULL_RETURN(host, nullptr);
248 auto parent = host->GetParent();
249 RefPtr<FrameNode> frameNode = AceType::DynamicCast<FrameNode>(parent);
250 while (parent && !frameNode) {
251 parent = parent->GetParent();
252 frameNode = AceType::DynamicCast<FrameNode>(parent);
253 }
254 return frameNode;
255 }
256
GetAxis() const257 Axis ListItemPattern::GetAxis() const
258 {
259 auto frameNode = GetListFrameNode();
260 CHECK_NULL_RETURN(frameNode, Axis::VERTICAL);
261 auto layoutProperty = frameNode->GetLayoutProperty<ListLayoutProperty>();
262 CHECK_NULL_RETURN(layoutProperty, Axis::VERTICAL);
263 return layoutProperty->GetListDirection().value_or(Axis::VERTICAL);
264 }
265
SetSwiperItemForList()266 void ListItemPattern::SetSwiperItemForList()
267 {
268 auto frameNode = GetListFrameNode();
269 CHECK_NULL_VOID(frameNode);
270 auto listPattern = frameNode->GetPattern<ListPattern>();
271 CHECK_NULL_VOID(listPattern);
272 listPattern->SetSwiperItem(AceType::WeakClaim(this));
273 }
274
SetOffsetChangeCallBack(OnOffsetChangeFunc && offsetChangeCallback)275 void ListItemPattern::SetOffsetChangeCallBack(OnOffsetChangeFunc&& offsetChangeCallback)
276 {
277 auto host = GetHost();
278 CHECK_NULL_VOID(host);
279 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
280 CHECK_NULL_VOID(listItemEventHub);
281 listItemEventHub->SetOnOffsetChangeOffset(std::move(offsetChangeCallback));
282 }
283
CloseSwipeAction(OnFinishFunc && onFinishCallback)284 void ListItemPattern::CloseSwipeAction(OnFinishFunc&& onFinishCallback)
285 {
286 onFinishEvent_ = onFinishCallback;
287 ResetSwipeStatus(true);
288 }
289
OnModifyDone()290 void ListItemPattern::OnModifyDone()
291 {
292 auto host = GetHost();
293 CHECK_NULL_VOID(host);
294 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
295 CHECK_NULL_VOID(listItemEventHub);
296 Pattern::OnModifyDone();
297 InitListItemCardStyleForList();
298 if (!listItemEventHub->HasStateStyle(UI_STATE_SELECTED)) {
299 auto context = host->GetRenderContext();
300 CHECK_NULL_VOID(context);
301 context->BlendBgColor(GetBlendGgColor());
302 }
303 if (HasStartNode() || HasEndNode() || listItemEventHub->GetStartOnDelete() || listItemEventHub->GetEndOnDelete()) {
304 auto axis = GetAxis();
305 bool axisChanged = axis_ != axis;
306 axis_ = axis;
307 InitSwiperAction(axisChanged);
308 return;
309 }
310 auto gestureHub = listItemEventHub->GetOrCreateGestureEventHub();
311 CHECK_NULL_VOID(gestureHub);
312 gestureHub->RemovePanEvent(panEvent_);
313 panEvent_.Reset();
314 springController_.Reset();
315 SetAccessibilityAction();
316 }
317
GetEdgeEffect()318 V2::SwipeEdgeEffect ListItemPattern::GetEdgeEffect()
319 {
320 auto layoutProperty = GetLayoutProperty<ListItemLayoutProperty>();
321 CHECK_NULL_RETURN(layoutProperty, V2::SwipeEdgeEffect::Spring);
322 return layoutProperty->GetEdgeEffect().value_or(V2::SwipeEdgeEffect::Spring);
323 }
324
MarkDirtyNode()325 void ListItemPattern::MarkDirtyNode()
326 {
327 auto host = GetHost();
328 CHECK_NULL_VOID(host);
329 if (LessOrEqual(curOffset_, startNodeSize_) && LessOrEqual(-curOffset_, endNodeSize_)) {
330 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
331 return;
332 }
333 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
334 }
335
ChangeAxis(Axis axis)336 void ListItemPattern::ChangeAxis(Axis axis)
337 {
338 auto host = GetHost();
339 CHECK_NULL_VOID(host);
340 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
341 CHECK_NULL_VOID(listItemEventHub);
342 axis_ = axis;
343 if (HasStartNode() || HasEndNode() || listItemEventHub->GetStartOnDelete() || listItemEventHub->GetEndOnDelete()) {
344 InitSwiperAction(true);
345 }
346 }
347
InitSwiperAction(bool axisChanged)348 void ListItemPattern::InitSwiperAction(bool axisChanged)
349 {
350 bool isPanInit = false;
351 if (!panEvent_) {
352 auto weak = AceType::WeakClaim(this);
353 auto actionStartTask = [weak](const GestureEvent& info) {
354 auto pattern = weak.Upgrade();
355 CHECK_NULL_VOID(pattern);
356 auto frameNode = pattern->GetListFrameNode();
357 CHECK_NULL_VOID(frameNode);
358 auto listPattern = frameNode->GetPattern<ListPattern>();
359 CHECK_NULL_VOID(listPattern);
360 if (!listPattern->CanReplaceSwiperItem()) {
361 return;
362 }
363 pattern->HandleDragStart(info);
364 };
365
366 auto actionUpdateTask = [weak](const GestureEvent& info) {
367 auto pattern = weak.Upgrade();
368 CHECK_NULL_VOID(pattern);
369 auto frameNode = pattern->GetListFrameNode();
370 CHECK_NULL_VOID(frameNode);
371 auto listPattern = frameNode->GetPattern<ListPattern>();
372 CHECK_NULL_VOID(listPattern);
373 if (!listPattern->IsCurrentSwiperItem(weak) || !pattern->isDragging_) {
374 return;
375 }
376 pattern->HandleDragUpdate(info);
377 };
378
379 auto actionEndTask = [weak](const GestureEvent& info) {
380 auto pattern = weak.Upgrade();
381 CHECK_NULL_VOID(pattern);
382 auto frameNode = pattern->GetListFrameNode();
383 CHECK_NULL_VOID(frameNode);
384 auto listPattern = frameNode->GetPattern<ListPattern>();
385 CHECK_NULL_VOID(listPattern);
386 if (!listPattern->IsCurrentSwiperItem(weak) || !pattern->isDragging_) {
387 return;
388 }
389 pattern->HandleDragEnd(info);
390 };
391
392 auto actionCancelTask = [weak]() {
393 auto pattern = weak.Upgrade();
394 CHECK_NULL_VOID(pattern);
395 auto frameNode = pattern->GetListFrameNode();
396 CHECK_NULL_VOID(frameNode);
397 auto listPattern = frameNode->GetPattern<ListPattern>();
398 CHECK_NULL_VOID(listPattern);
399 if (!listPattern->IsCurrentSwiperItem(weak) || !pattern->isDragging_) {
400 return;
401 }
402 GestureEvent info;
403 pattern->HandleDragEnd(info);
404 };
405 panEvent_ = MakeRefPtr<PanEvent>(std::move(actionStartTask), std::move(actionUpdateTask),
406 std::move(actionEndTask), std::move(actionCancelTask));
407 isPanInit = true;
408 }
409 if (isPanInit || axisChanged) {
410 auto host = GetHost();
411 CHECK_NULL_VOID(host);
412 auto hub = host->GetEventHub<EventHub>();
413 CHECK_NULL_VOID(hub);
414 auto gestureHub = hub->GetOrCreateGestureEventHub();
415 CHECK_NULL_VOID(gestureHub);
416 PanDirection panDirection = {
417 .type = axis_ == Axis::HORIZONTAL ? PanDirection::VERTICAL : PanDirection::HORIZONTAL,
418 };
419 gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
420
421 startNodeSize_ = 0.0f;
422 endNodeSize_ = 0.0f;
423 float oldOffset = curOffset_;
424 curOffset_ = 0.0f;
425 FireSwipeActionOffsetChange(oldOffset, curOffset_);
426 }
427 if (!springController_) {
428 springController_ = CREATE_ANIMATOR(PipelineBase::GetCurrentContext());
429 } else if (axisChanged) {
430 springController_->Stop();
431 }
432 }
433
HandleDragStart(const GestureEvent & info)434 void ListItemPattern::HandleDragStart(const GestureEvent& info)
435 {
436 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
437 return;
438 }
439 if (springController_ && !springController_->IsStopped()) {
440 // clear stop listener before stop
441 springController_->ClearStopListeners();
442 springController_->Stop();
443 }
444 isDragging_ = true;
445 SetSwiperItemForList();
446 }
447
CalculateFriction(float gamma)448 float ListItemPattern::CalculateFriction(float gamma)
449 {
450 float ratio = SWIPE_RATIO;
451 if (GreatOrEqual(gamma, 1.0)) {
452 gamma = 1.0f;
453 }
454 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
455 ratio = NEW_SWIPE_RATIO;
456 return exp(-ratio * gamma);
457 }
458 float result = ratio * std::pow(1.0 - gamma, SQUARE);
459 if (!std::isnan(result) && LessNotEqual(result, 1.0f)) {
460 return result;
461 }
462 return 1.0f;
463 }
464
GetFriction()465 float ListItemPattern::GetFriction()
466 {
467 if (GreatNotEqual(curOffset_, 0.0f)) {
468 float width = startNodeSize_;
469 float itemWidth = GetContentSize().CrossSize(axis_);
470 if (width < curOffset_) {
471 return CalculateFriction((curOffset_ - width) / (itemWidth - width));
472 }
473 } else if (LessNotEqual(curOffset_, 0.0f)) {
474 float width = endNodeSize_;
475 float itemWidth = GetContentSize().CrossSize(axis_);
476 if (width < -curOffset_) {
477 return CalculateFriction((-curOffset_ - width) / (itemWidth - width));
478 }
479 }
480 return 1.0f;
481 }
482
ChangeDeleteAreaStage()483 void ListItemPattern::ChangeDeleteAreaStage()
484 {
485 auto host = GetHost();
486 CHECK_NULL_VOID(host);
487 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
488 CHECK_NULL_VOID(listItemEventHub);
489 auto enterStartDeleteArea = listItemEventHub->GetOnEnterStartDeleteArea();
490 auto enterEndDeleteArea = listItemEventHub->GetOnEnterEndDeleteArea();
491 auto exitStartDeleteArea = listItemEventHub->GetOnExitStartDeleteArea();
492 auto exitEndDeleteArea = listItemEventHub->GetOnExitEndDeleteArea();
493 if (Positive(curOffset_) && hasStartDeleteArea_) {
494 if (GreatOrEqual(curOffset_, startNodeSize_ + startDeleteAreaDistance_)) {
495 if (!inStartDeleteArea_) {
496 inStartDeleteArea_ = true;
497 if (enterStartDeleteArea) {
498 enterStartDeleteArea();
499 }
500 }
501 } else {
502 if (inStartDeleteArea_) {
503 inStartDeleteArea_ = false;
504 if (exitStartDeleteArea) {
505 exitStartDeleteArea();
506 }
507 }
508 }
509 }
510 if (Negative(curOffset_) && hasEndDeleteArea_) {
511 if (GreatNotEqual(-curOffset_, endNodeSize_ + endDeleteAreaDistance_)) {
512 if (!inEndDeleteArea_) {
513 inEndDeleteArea_ = true;
514 if (enterEndDeleteArea) {
515 enterEndDeleteArea();
516 }
517 }
518 } else {
519 if (inEndDeleteArea_) {
520 inEndDeleteArea_ = false;
521 if (exitEndDeleteArea) {
522 exitEndDeleteArea();
523 }
524 }
525 }
526 }
527 }
528
UpdatePostion(float delta)529 void ListItemPattern::UpdatePostion(float delta)
530 {
531 auto host = GetHost();
532 CHECK_NULL_VOID(host);
533 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
534 CHECK_NULL_VOID(listItemEventHub);
535 auto offset = curOffset_;
536 IsRTLAndVertical() ? curOffset_ -= delta : curOffset_ += delta;
537 ChangeDeleteAreaStage();
538 auto edgeEffect = GetEdgeEffect();
539 if (edgeEffect == V2::SwipeEdgeEffect::None) {
540 if (hasStartDeleteArea_) {
541 if (Positive(startNodeSize_) && GreatNotEqual(curOffset_, startNodeSize_ + startDeleteAreaDistance_)) {
542 curOffset_ = startNodeSize_ + startDeleteAreaDistance_;
543 } else if (startNodeSize_ == 0 && GreatNotEqual(curOffset_, startDeleteAreaDistance_)) {
544 curOffset_ = startDeleteAreaDistance_;
545 }
546 }
547 if (hasEndDeleteArea_) {
548 if (Positive(endNodeSize_) && GreatNotEqual(-curOffset_, endNodeSize_ + endDeleteAreaDistance_)) {
549 curOffset_ = -endNodeSize_ - endDeleteAreaDistance_;
550 } else if (endNodeSize_ == 0 && GreatNotEqual(-curOffset_, endDeleteAreaDistance_)) {
551 curOffset_ = -endDeleteAreaDistance_;
552 }
553 }
554 if (Positive(startNodeSize_) && GreatNotEqual(curOffset_, startNodeSize_) && !hasStartDeleteArea_) {
555 curOffset_ = startNodeSize_;
556 } else if (Positive(endNodeSize_) && GreatNotEqual(-curOffset_, endNodeSize_) && !hasEndDeleteArea_) {
557 curOffset_ = -endNodeSize_;
558 }
559 if ((Negative(curOffset_) && !HasEndNode() && !listItemEventHub->GetEndOnDelete()) ||
560 (Positive(curOffset_) && !HasStartNode() && !listItemEventHub->GetStartOnDelete())) {
561 curOffset_ = 0.0f;
562 }
563 }
564 if (!NearEqual(offset, curOffset_)) {
565 MarkDirtyNode();
566 FireSwipeActionOffsetChange(offset, curOffset_);
567 }
568 }
569
IsRTLAndVertical() const570 bool ListItemPattern::IsRTLAndVertical() const
571 {
572 auto layoutProperty = GetLayoutProperty<ListItemLayoutProperty>();
573 CHECK_NULL_RETURN(layoutProperty, false);
574 auto layoutDirection = layoutProperty->GetNonAutoLayoutDirection();
575 if (layoutDirection == TextDirection::RTL && axis_ == Axis::VERTICAL) {
576 return true;
577 } else {
578 return false;
579 }
580 }
581
HandleDragUpdate(const GestureEvent & info)582 void ListItemPattern::HandleDragUpdate(const GestureEvent& info)
583 {
584 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
585 return;
586 }
587 auto layoutProperty = GetLayoutProperty<ListItemLayoutProperty>();
588 CHECK_NULL_VOID(layoutProperty);
589 hasStartDeleteArea_ = false;
590 hasEndDeleteArea_ = false;
591 float itemWidth = GetContentSize().CrossSize(axis_);
592 float maxDeleteArea = 0.0f;
593
594 if (GreatNotEqual(curOffset_, 0.0)) {
595 maxDeleteArea = itemWidth - startNodeSize_;
596 startDeleteAreaDistance_ = static_cast<float>(
597 layoutProperty->GetStartDeleteAreaDistance().value_or(Dimension(0, DimensionUnit::VP)).ConvertToPx());
598 if (GreatNotEqual(startDeleteAreaDistance_, 0.0) && LessNotEqual(startDeleteAreaDistance_, maxDeleteArea)) {
599 hasStartDeleteArea_ = true;
600 }
601 } else if (LessNotEqual(curOffset_, 0.0)) {
602 maxDeleteArea = itemWidth - endNodeSize_;
603 endDeleteAreaDistance_ = static_cast<float>(
604 layoutProperty->GetEndDeleteAreaDistance().value_or(Dimension(0, DimensionUnit::VP)).ConvertToPx());
605 if (GreatNotEqual(endDeleteAreaDistance_, 0.0) && LessNotEqual(endDeleteAreaDistance_, maxDeleteArea)) {
606 hasEndDeleteArea_ = true;
607 }
608 }
609 float delta = info.GetMainDelta();
610 delta *= GetFriction();
611 UpdatePostion(delta);
612 }
613
StartSpringMotion(float start,float end,float velocity,bool trigOnFinishEvent)614 void ListItemPattern::StartSpringMotion(float start, float end, float velocity, bool trigOnFinishEvent)
615 {
616 if (!springController_) {
617 return;
618 }
619 const RefPtr<SpringProperty> DEFAULT_OVER_SPRING_PROPERTY =
620 AceType::MakeRefPtr<SpringProperty>(SWIPE_SPRING_MASS, SWIPE_SPRING_STIFFNESS, SWIPE_SPRING_DAMPING);
621 if (!springMotion_) {
622 springMotion_ = AceType::MakeRefPtr<SpringMotion>(start, end, velocity, DEFAULT_OVER_SPRING_PROPERTY);
623 } else {
624 springMotion_->Reset(start, end, velocity, DEFAULT_OVER_SPRING_PROPERTY);
625 springMotion_->ClearListeners();
626 }
627 // 10000.0f: use a large value to mask the determination of speed threshold
628 springMotion_->SetVelocityAccuracy(10000.0f);
629 springMotion_->AddListener([weakScroll = AceType::WeakClaim(this), start, end](double position) {
630 auto listItem = weakScroll.Upgrade();
631 CHECK_NULL_VOID(listItem);
632 if (listItem->GetEdgeEffect() == V2::SwipeEdgeEffect::None &&
633 ((GreatNotEqual(end, start) && GreatOrEqual(position, end)) ||
634 (LessNotEqual(end, start) && LessOrEqual(position, end)))) {
635 listItem->springController_->ClearStopListeners();
636 listItem->springController_->Stop();
637 position = end;
638 }
639 if (NearEqual(position, listItem->curOffset_, 1.0) && !listItem->springMotionTraceFlag_) {
640 listItem->springMotionTraceFlag_ = true;
641 AceAsyncTraceBegin(0, TRAILING_ANIMATION);
642 }
643 float delta = listItem->IsRTLAndVertical() ? listItem->curOffset_ - position : position - listItem->curOffset_;
644 listItem->UpdatePostion(delta);
645 });
646 springController_->ClearStopListeners();
647 springController_->PlayMotion(springMotion_);
648 springController_->AddStopListener([weak = AceType::WeakClaim(this), trigOnFinishEvent]() {
649 auto listItem = weak.Upgrade();
650 CHECK_NULL_VOID(listItem);
651 if (NearZero(listItem->curOffset_)) {
652 listItem->FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
653 listItem->ResetNodeSize();
654 listItem->FireSwipeActionOffsetChange(SWIPE_SPRING_MASS, listItem->curOffset_);
655 }
656 if (listItem->springMotionTraceFlag_) {
657 listItem->springMotionTraceFlag_ = false;
658 AceAsyncTraceEnd(0, TRAILING_ANIMATION);
659 }
660 listItem->MarkDirtyNode();
661 if (trigOnFinishEvent) {
662 listItem->FireOnFinshEvent();
663 }
664 });
665 }
666
DoDeleteAnimation(bool isStartDelete)667 void ListItemPattern::DoDeleteAnimation(bool isStartDelete)
668 {
669 auto host = GetHost();
670 CHECK_NULL_VOID(host);
671 auto renderContext = host->GetRenderContext();
672 CHECK_NULL_VOID(renderContext);
673 auto context = GetContext();
674 CHECK_NULL_VOID(context);
675 float itemWidth = GetContentSize().CrossSize(axis_);
676
677 AnimationOption option = AnimationOption();
678 option.SetDuration(DELETE_ANIMATION_DURATION);
679 option.SetCurve(Curves::FRICTION);
680 option.SetFillMode(FillMode::FORWARDS);
681 context->OpenImplicitAnimation(option, option.GetCurve(), nullptr);
682 float oldOffset = curOffset_;
683 curOffset_ = isStartDelete ? itemWidth : -itemWidth;
684 FireSwipeActionOffsetChange(oldOffset, curOffset_);
685 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
686 context->FlushUITasks();
687 context->CloseImplicitAnimation();
688 FireSwipeActionStateChange(ListItemSwipeIndex::SWIPER_ACTION);
689 }
690
FireSwipeActionOffsetChange(float oldOffset,float newOffset)691 void ListItemPattern::FireSwipeActionOffsetChange(float oldOffset, float newOffset)
692 {
693 if (NearEqual(oldOffset, newOffset)) {
694 return;
695 }
696 auto host = GetHost();
697 CHECK_NULL_VOID(host);
698 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
699 CHECK_NULL_VOID(listItemEventHub);
700 listItemEventHub->FireOffsetChangeEvent(Dimension(newOffset).ConvertToVp());
701 }
702
FireSwipeActionStateChange(ListItemSwipeIndex newSwiperIndex)703 void ListItemPattern::FireSwipeActionStateChange(ListItemSwipeIndex newSwiperIndex)
704 {
705 auto host = GetHost();
706 CHECK_NULL_VOID(host);
707 TAG_LOGI(AceLogTag::ACE_LIST, "ListItem:%{public}d swiperIndex origin:%{public}d, new:%{public}d, "
708 "curPos:%{public}f", host->GetId(), swiperIndex_, newSwiperIndex, curOffset_);
709 if (newSwiperIndex == swiperIndex_) {
710 return;
711 }
712 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
713 CHECK_NULL_VOID(listItemEventHub);
714
715 bool trigStart = GreatNotEqual(curOffset_, 0.0f);
716 switch (newSwiperIndex) {
717 case ListItemSwipeIndex::SWIPER_START:
718 case ListItemSwipeIndex::SWIPER_END:
719 swipeActionState_ = SwipeActionState::EXPANDED;
720 break;
721 case ListItemSwipeIndex::SWIPER_ACTION:
722 swipeActionState_ = SwipeActionState::ACTIONING;
723 break;
724 case ListItemSwipeIndex::ITEM_CHILD:
725 default:
726 if (swiperIndex_ == ListItemSwipeIndex::SWIPER_START) {
727 trigStart = true;
728 } else if (swiperIndex_ == ListItemSwipeIndex::SWIPER_END) {
729 trigStart = false;
730 }
731 swipeActionState_ = SwipeActionState::COLLAPSED;
732 }
733 swiperIndex_ = newSwiperIndex;
734 listItemEventHub->FireStateChangeEvent(swipeActionState_, trigStart);
735 UpdateClickJudgeCallback();
736 }
737
UpdateClickJudgeCallback()738 void ListItemPattern::UpdateClickJudgeCallback()
739 {
740 auto frameNode = GetListFrameNode();
741 CHECK_NULL_VOID(frameNode);
742 auto listPattern = frameNode->GetPattern<ListPattern>();
743 CHECK_NULL_VOID(listPattern);
744 auto scrollableEvent = listPattern->GetScrollableEvent();
745 CHECK_NULL_VOID(scrollableEvent);
746 if (swipeActionState_ == SwipeActionState::COLLAPSED) {
747 TAG_LOGI(AceLogTag::ACE_LIST, "List:%{public}d RemoveClickJudgeCallback", frameNode->GetId());
748 scrollableEvent->SetClickJudgeCallback(nullptr);
749 } else if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
750 auto clickJudgeCallback = [weak = WeakClaim(this)](const PointF& localPoint) -> bool {
751 auto item = weak.Upgrade();
752 CHECK_NULL_RETURN(item, false);
753 if (item->swipeActionState_ == SwipeActionState::COLLAPSED) {
754 return false;
755 }
756 return item->ClickJudge(localPoint);
757 };
758 TAG_LOGI(AceLogTag::ACE_LIST, "List:%{public}d AddClickJudgeCallback", frameNode->GetId());
759 scrollableEvent->SetClickJudgeCallback(clickJudgeCallback);
760 }
761 }
762
HandleDragEnd(const GestureEvent & info)763 void ListItemPattern::HandleDragEnd(const GestureEvent& info)
764 {
765 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
766 return;
767 }
768
769 auto listPattern = GetListFrameNode()->GetPattern<ListPattern>();
770 CHECK_NULL_VOID(listPattern);
771 listPattern->SetSwiperItemEnd(AceType::WeakClaim(this));
772
773 auto host = GetHost();
774 CHECK_NULL_VOID(host);
775 auto listItemEventHub = host->GetEventHub<ListItemEventHub>();
776 CHECK_NULL_VOID(listItemEventHub);
777 auto startOnDelete = listItemEventHub->GetStartOnDelete();
778 auto endOnDelete = listItemEventHub->GetEndOnDelete();
779 float end = 0.0f;
780 float friction = GetFriction();
781 float threshold = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE) ? NEW_SWIPER_TH : SWIPER_TH;
782 float velocity = IsRTLAndVertical() ? -info.GetMainVelocity() : info.GetMainVelocity();
783 bool reachRightSpeed = velocity > SWIPER_SPEED_TH;
784 bool reachLeftSpeed = -velocity > SWIPER_SPEED_TH;
785 isDragging_ = false;
786
787 TAG_LOGI(AceLogTag::ACE_LIST, "ListItem:%{public}d HandleDragEnd, velocity:%{public}f, curPos:%{public}f",
788 host->GetId(), velocity, curOffset_);
789 if (swiperIndex_ != ListItemSwipeIndex::SWIPER_ACTION && hasStartDeleteArea_ && !HasStartNode() && startOnDelete &&
790 GreatOrEqual(curOffset_, startDeleteAreaDistance_) && swiperIndex_ != ListItemSwipeIndex::SWIPER_END) {
791 DoDeleteAnimation(true);
792 startOnDelete();
793 return;
794 } else if (hasStartDeleteArea_ && !HasStartNode()) {
795 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
796 }
797
798 if (swiperIndex_ != ListItemSwipeIndex::SWIPER_ACTION && hasEndDeleteArea_ && !HasEndNode() && endOnDelete &&
799 GreatOrEqual(-curOffset_, endDeleteAreaDistance_) && swiperIndex_ != ListItemSwipeIndex::SWIPER_START) {
800 DoDeleteAnimation(false);
801 endOnDelete();
802 return;
803 } else if (hasEndDeleteArea_ && !HasEndNode()) {
804 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
805 }
806
807 if (GreatNotEqual(curOffset_, 0.0) && HasStartNode()) {
808 float width = startNodeSize_;
809 if (swiperIndex_ == ListItemSwipeIndex::ITEM_CHILD && reachLeftSpeed) {
810 StartSpringMotion(curOffset_, 0, velocity * friction);
811 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
812 return;
813 }
814 if (swiperIndex_ != ListItemSwipeIndex::SWIPER_ACTION && swiperIndex_ != ListItemSwipeIndex::SWIPER_END &&
815 GreatOrEqual(curOffset_, width + startDeleteAreaDistance_) && hasStartDeleteArea_ && startOnDelete) {
816 DoDeleteAnimation(true);
817 startOnDelete();
818 return;
819 }
820 if (swiperIndex_ == ListItemSwipeIndex::ITEM_CHILD && width > 0 &&
821 (curOffset_ > width * threshold || reachRightSpeed)) {
822 FireSwipeActionStateChange(ListItemSwipeIndex::SWIPER_START);
823 } else if (swiperIndex_ == ListItemSwipeIndex::SWIPER_START && (curOffset_ < width *
824 (1 - threshold) || (reachLeftSpeed && curOffset_ < width))) {
825 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
826 } else if (swiperIndex_ == ListItemSwipeIndex::SWIPER_END ||
827 swiperIndex_ == ListItemSwipeIndex::SWIPER_ACTION) {
828 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
829 }
830 end = width * static_cast<int32_t>(swiperIndex_);
831 } else if (LessNotEqual(curOffset_, 0.0) && HasEndNode()) {
832 float width = endNodeSize_;
833 if (swiperIndex_ == ListItemSwipeIndex::ITEM_CHILD && reachRightSpeed) {
834 StartSpringMotion(curOffset_, 0, velocity * friction);
835 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
836 return;
837 }
838 if (swiperIndex_ != ListItemSwipeIndex::SWIPER_ACTION && swiperIndex_ != ListItemSwipeIndex::SWIPER_START &&
839 GreatOrEqual(-curOffset_, width + endDeleteAreaDistance_) && hasEndDeleteArea_ && endOnDelete) {
840 DoDeleteAnimation(false);
841 endOnDelete();
842 return;
843 }
844 if (swiperIndex_ == ListItemSwipeIndex::ITEM_CHILD && width > 0 &&
845 (width * threshold < -curOffset_ || reachLeftSpeed)) {
846 FireSwipeActionStateChange(ListItemSwipeIndex::SWIPER_END);
847 } else if (swiperIndex_ == ListItemSwipeIndex::SWIPER_END && (-curOffset_ < width *
848 (1 - threshold) || (reachRightSpeed && -curOffset_ < width))) {
849 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
850 } else if (swiperIndex_ == ListItemSwipeIndex::SWIPER_START ||
851 swiperIndex_ == ListItemSwipeIndex::SWIPER_ACTION) {
852 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
853 }
854 end = width * static_cast<int32_t>(swiperIndex_);
855 }
856 StartSpringMotion(curOffset_, end, velocity * friction);
857 }
858
ResetSwipeStatus(bool calledByUser)859 void ListItemPattern::ResetSwipeStatus(bool calledByUser)
860 {
861 if (swiperIndex_ == ListItemSwipeIndex::ITEM_CHILD) {
862 return;
863 }
864 FireSwipeActionStateChange(ListItemSwipeIndex::ITEM_CHILD);
865 float velocity = 0.0f;
866 if (springMotion_) {
867 velocity = springMotion_->GetCurrentVelocity();
868 }
869 if (springController_ && !springController_->IsStopped()) {
870 // clear stop listener before stop
871 springController_->ClearStopListeners();
872 springController_->Stop();
873 }
874 StartSpringMotion(curOffset_, 0.0f, velocity, calledByUser);
875 }
876
MarkIsSelected(bool isSelected)877 void ListItemPattern::MarkIsSelected(bool isSelected)
878 {
879 if (isSelected_ != isSelected) {
880 isSelected_ = isSelected;
881 auto eventHub = GetEventHub<ListItemEventHub>();
882 eventHub->FireSelectChangeEvent(isSelected);
883 auto host = GetHost();
884 CHECK_NULL_VOID(host);
885 if (isSelected) {
886 eventHub->UpdateCurrentUIState(UI_STATE_SELECTED);
887 host->OnAccessibilityEvent(AccessibilityEventType::SELECTED);
888 } else {
889 eventHub->ResetCurrentUIState(UI_STATE_SELECTED);
890 host->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
891 }
892 if (!eventHub->HasStateStyle(UI_STATE_SELECTED)) {
893 auto context = host->GetRenderContext();
894 CHECK_NULL_VOID(context);
895 context->BlendBgColor(GetBlendGgColor());
896 }
897 }
898 }
899
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const900 void ListItemPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
901 {
902 json->PutFixedAttr("selectable", selectable_, filter, FIXED_ATTR_SELECTABLE);
903 json->PutExtAttr("selected", isSelected_, filter);
904 }
905
SetAccessibilityAction()906 void ListItemPattern::SetAccessibilityAction()
907 {
908 auto host = GetHost();
909 CHECK_NULL_VOID(host);
910 auto listItemAccessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
911 CHECK_NULL_VOID(listItemAccessibilityProperty);
912 listItemAccessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
913 const auto& pattern = weakPtr.Upgrade();
914 CHECK_NULL_VOID(pattern);
915 if (!pattern->Selectable()) {
916 return;
917 }
918 auto host = pattern->GetHost();
919 CHECK_NULL_VOID(host);
920 auto context = host->GetRenderContext();
921 CHECK_NULL_VOID(context);
922 context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
923 pattern->MarkIsSelected(true);
924 context->OnMouseSelectUpdate(true, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
925 });
926
927 listItemAccessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
928 const auto& pattern = weakPtr.Upgrade();
929 CHECK_NULL_VOID(pattern);
930 if (!pattern->Selectable()) {
931 return;
932 }
933 auto host = pattern->GetHost();
934 CHECK_NULL_VOID(host);
935 auto context = host->GetRenderContext();
936 CHECK_NULL_VOID(context);
937 pattern->MarkIsSelected(false);
938 context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
939 });
940 }
941
InitListItemCardStyleForList()942 void ListItemPattern::InitListItemCardStyleForList()
943 {
944 if (listItemStyle_ == V2::ListItemStyle::CARD) {
945 UpdateListItemAlignToCenter();
946 InitHoverEvent();
947 InitPressEvent();
948 InitDisableEvent();
949 }
950 }
951
UpdateListItemAlignToCenter()952 void ListItemPattern::UpdateListItemAlignToCenter()
953 {
954 auto frameNode = GetListFrameNode();
955 CHECK_NULL_VOID(frameNode);
956 auto layoutProperty = frameNode->GetLayoutProperty<ListLayoutProperty>();
957 CHECK_NULL_VOID(layoutProperty);
958 if (!layoutProperty->HasListItemAlign()) {
959 layoutProperty->UpdateListItemAlign(V2::ListItemAlign::CENTER);
960 }
961 }
962
GetBlendGgColor()963 Color ListItemPattern::GetBlendGgColor()
964 {
965 Color color = Color::TRANSPARENT;
966 auto pipeline = PipelineContext::GetCurrentContext();
967 CHECK_NULL_RETURN(pipeline, color);
968 auto theme = pipeline->GetTheme<ListItemTheme>();
969 CHECK_NULL_RETURN(theme, color);
970 if (isSelected_) {
971 auto eventHub = GetEventHub<ListItemEventHub>();
972 CHECK_NULL_RETURN(eventHub, color);
973 if (!eventHub->HasStateStyle(UI_STATE_SELECTED)) {
974 color = theme->GetItemSelectedColor();
975 }
976 }
977 if (isPressed_) {
978 color = color.BlendColor(theme->GetItemPressColor());
979 } else if (isHover_) {
980 color = color.BlendColor(theme->GetItemHoverColor());
981 }
982 return color;
983 }
984
InitHoverEvent()985 void ListItemPattern::InitHoverEvent()
986 {
987 if (hoverEvent_) {
988 return;
989 }
990 auto host = GetHost();
991 CHECK_NULL_VOID(host);
992 auto eventHub = host->GetEventHub<EventHub>();
993 CHECK_NULL_VOID(eventHub);
994 auto inputHub = eventHub->GetOrCreateInputEventHub();
995 CHECK_NULL_VOID(inputHub);
996 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
997 auto pattern = weak.Upgrade();
998 if (pattern) {
999 pattern->HandleHoverEvent(isHover, pattern->GetHost());
1000 }
1001 };
1002 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
1003 inputHub->AddOnHoverEvent(hoverEvent_);
1004 }
1005
HandleHoverEvent(bool isHover,const RefPtr<NG::FrameNode> & itemNode)1006 void ListItemPattern::HandleHoverEvent(bool isHover, const RefPtr<NG::FrameNode>& itemNode)
1007 {
1008 auto renderContext = itemNode->GetRenderContext();
1009 CHECK_NULL_VOID(renderContext);
1010 auto pipeline = GetContext();
1011 CHECK_NULL_VOID(pipeline);
1012 auto theme = pipeline->GetTheme<ListItemTheme>();
1013 CHECK_NULL_VOID(theme);
1014
1015 isHover_ = isHover;
1016 auto hoverColor = GetBlendGgColor();
1017 AnimationUtils::BlendBgColorAnimation(
1018 renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
1019 }
1020
InitPressEvent()1021 void ListItemPattern::InitPressEvent()
1022 {
1023 if (touchListener_) {
1024 return;
1025 }
1026 auto host = GetHost();
1027 CHECK_NULL_VOID(host);
1028 auto gesture = host->GetOrCreateGestureEventHub();
1029 CHECK_NULL_VOID(gesture);
1030 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
1031 auto pattern = weak.Upgrade();
1032 CHECK_NULL_VOID(pattern);
1033 auto touchType = info.GetTouches().front().GetTouchType();
1034 if (touchType == TouchType::DOWN || touchType == TouchType::UP || touchType == TouchType::CANCEL) {
1035 pattern->HandlePressEvent(touchType == TouchType::DOWN, pattern->GetHost());
1036 }
1037 };
1038 auto touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
1039 gesture->AddTouchEvent(touchListener_);
1040 }
1041
HandlePressEvent(bool isPressed,const RefPtr<NG::FrameNode> & itemNode)1042 void ListItemPattern::HandlePressEvent(bool isPressed, const RefPtr<NG::FrameNode>& itemNode)
1043 {
1044 auto renderContext = itemNode->GetRenderContext();
1045 CHECK_NULL_VOID(renderContext);
1046 auto pipeline = GetContext();
1047 CHECK_NULL_VOID(pipeline);
1048 auto theme = pipeline->GetTheme<ListItemTheme>();
1049 CHECK_NULL_VOID(theme);
1050 auto duration = isHover_ ? theme->GetHoverToPressAnimationDuration() : theme->GetHoverAnimationDuration();
1051 isPressed_ = isPressed;
1052 Color color = GetBlendGgColor();
1053 AnimationUtils::BlendBgColorAnimation(renderContext, color, duration, Curves::SHARP);
1054 }
1055
InitDisableEvent()1056 void ListItemPattern::InitDisableEvent()
1057 {
1058 auto host = GetHost();
1059 CHECK_NULL_VOID(host);
1060 auto eventHub = host->GetEventHub<ListItemEventHub>();
1061 CHECK_NULL_VOID(eventHub);
1062 auto renderContext = host->GetRenderContext();
1063 CHECK_NULL_VOID(renderContext);
1064 auto pipeline = PipelineBase::GetCurrentContext();
1065 CHECK_NULL_VOID(pipeline);
1066 auto theme = pipeline->GetTheme<ListItemTheme>();
1067 CHECK_NULL_VOID(theme);
1068 auto userDefineOpacity = renderContext->GetOpacityValue(1.0);
1069
1070 if (!eventHub->IsDeveloperEnabled()) {
1071 if (selectable_) {
1072 selectable_ = false;
1073 }
1074 enableOpacity_ = renderContext->GetOpacityValue(1.0);
1075 renderContext->UpdateOpacity(theme->GetItemDisabledAlpha());
1076 } else {
1077 if (enableOpacity_.has_value()) {
1078 renderContext->UpdateOpacity(enableOpacity_.value());
1079 } else {
1080 renderContext->UpdateOpacity(userDefineOpacity);
1081 }
1082 }
1083 }
1084
GetLayouted() const1085 bool ListItemPattern::GetLayouted() const
1086 {
1087 return isLayouted_;
1088 }
1089
DumpAdvanceInfo()1090 void ListItemPattern::DumpAdvanceInfo()
1091 {
1092 DumpLog::GetInstance().AddDesc("indexInList:" + std::to_string(indexInList_));
1093 DumpLog::GetInstance().AddDesc("indexInListItemGroup:" + std::to_string(indexInListItemGroup_));
1094 DumpLog::GetInstance().AddDesc("swiperAction.startNodeIndex:" + std::to_string(startNodeIndex_));
1095 DumpLog::GetInstance().AddDesc("swiperAction.endNodeIndex:" + std::to_string(endNodeIndex_));
1096 DumpLog::GetInstance().AddDesc("swiperAction.childNodeIndex:" + std::to_string(childNodeIndex_));
1097 DumpLog::GetInstance().AddDesc("curOffset:" + std::to_string(curOffset_));
1098 DumpLog::GetInstance().AddDesc("startNodeSize:" + std::to_string(startNodeSize_));
1099 DumpLog::GetInstance().AddDesc("endNodeSize:" + std::to_string(endNodeSize_));
1100 DumpLog::GetInstance().AddDesc("startDeleteAreaDistance:" + std::to_string(startDeleteAreaDistance_));
1101 DumpLog::GetInstance().AddDesc("endDeleteAreaDistance:" + std::to_string(endDeleteAreaDistance_));
1102 switch (swipeActionState_) {
1103 case SwipeActionState::COLLAPSED:
1104 DumpLog::GetInstance().AddDesc("SwipeActionState::COLLAPSED");
1105 break;
1106 case SwipeActionState::EXPANDED:
1107 DumpLog::GetInstance().AddDesc("SwipeActionState::EXPANDED");
1108 break;
1109 case SwipeActionState::ACTIONING:
1110 DumpLog::GetInstance().AddDesc("SwipeActionState::ACTIONING");
1111 break;
1112 }
1113 hasStartDeleteArea_ ? DumpLog::GetInstance().AddDesc("hasStartDeleteArea:true")
1114 : DumpLog::GetInstance().AddDesc("hasStartDeleteArea:false");
1115 hasEndDeleteArea_ ? DumpLog::GetInstance().AddDesc("hasEndDeleteArea:true")
1116 : DumpLog::GetInstance().AddDesc("hasEndDeleteArea:false");
1117 inStartDeleteArea_ ? DumpLog::GetInstance().AddDesc("inStartDeleteArea:true")
1118 : DumpLog::GetInstance().AddDesc("inStartDeleteArea:false");
1119 inEndDeleteArea_ ? DumpLog::GetInstance().AddDesc("inEndDeleteArea:true")
1120 : DumpLog::GetInstance().AddDesc("inEndDeleteArea:false");
1121 selectable_ ? DumpLog::GetInstance().AddDesc("selectable:true")
1122 : DumpLog::GetInstance().AddDesc("selectable:false");
1123 isSelected_ ? DumpLog::GetInstance().AddDesc("isSelected:true")
1124 : DumpLog::GetInstance().AddDesc("isSelected:false");
1125 isHover_ ? DumpLog::GetInstance().AddDesc("isHover:true")
1126 : DumpLog::GetInstance().AddDesc("isHover:false");
1127 isPressed_ ? DumpLog::GetInstance().AddDesc("isPressed:true")
1128 : DumpLog::GetInstance().AddDesc("isPressed:false");
1129 isLayouted_ ? DumpLog::GetInstance().AddDesc("isLayouted:true")
1130 : DumpLog::GetInstance().AddDesc("isLayouted:false");
1131 if (enableOpacity_.has_value()) {
1132 enableOpacity_.value() ? DumpLog::GetInstance().AddDesc("enableOpacity:true")
1133 : DumpLog::GetInstance().AddDesc("enableOpacity:false");
1134 } else {
1135 DumpLog::GetInstance().AddDesc("enableOpacity:null");
1136 }
1137 }
1138
GetEstimateHeight(float estimateHeight,Axis axis) const1139 float ListItemPattern::GetEstimateHeight(float estimateHeight, Axis axis) const
1140 {
1141 auto layoutProperty = GetLayoutProperty<ListItemLayoutProperty>();
1142 CHECK_NULL_RETURN(layoutProperty, 0.0f);
1143 auto visible = layoutProperty->GetVisibility().value_or(VisibleType::VISIBLE);
1144 if (visible == VisibleType::GONE) {
1145 return 0.0f;
1146 }
1147 if (!isLayouted_) {
1148 return estimateHeight;
1149 }
1150 auto host = GetHost();
1151 CHECK_NULL_RETURN(host, estimateHeight);
1152 auto geometryNode = host->GetGeometryNode();
1153 CHECK_NULL_RETURN(geometryNode, estimateHeight);
1154 return GetMainAxisSize(geometryNode->GetMarginFrameSize(), axis);
1155 }
1156
ClickJudgeVertical(const SizeF & size,double xOffset,double yOffset)1157 bool ListItemPattern::ClickJudgeVertical(const SizeF& size, double xOffset, double yOffset)
1158 {
1159 if (yOffset < 0 || yOffset > size.Height()) {
1160 return true;
1161 }
1162 if (!IsRTLAndVertical()) {
1163 if (startNodeSize_ && xOffset > 0 && xOffset < startNodeSize_) {
1164 return false;
1165 } else if (endNodeSize_ && xOffset > size.Width() - endNodeSize_ && xOffset < size.Width()) {
1166 return false;
1167 }
1168 } else {
1169 if (endNodeSize_ && xOffset > 0 && xOffset < endNodeSize_) {
1170 return false;
1171 } else if (startNodeSize_ && xOffset > size.Width() - startNodeSize_ && xOffset < size.Width()) {
1172 return false;
1173 }
1174 }
1175 return true;
1176 }
1177
ClickJudge(const PointF & localPoint)1178 bool ListItemPattern::ClickJudge(const PointF& localPoint)
1179 {
1180 auto host = GetHost();
1181 CHECK_NULL_RETURN(host, false);
1182 auto geometryNode = host->GetGeometryNode();
1183 CHECK_NULL_RETURN(geometryNode, false);
1184 auto offset = geometryNode->GetFrameOffset();
1185 if (indexInListItemGroup_ != -1) {
1186 auto parentFrameNode = GetParentFrameNode();
1187 CHECK_NULL_RETURN(parentFrameNode, false);
1188 auto parentGeometryNode = parentFrameNode->GetGeometryNode();
1189 CHECK_NULL_RETURN(parentGeometryNode, false);
1190 auto parentOffset = parentGeometryNode->GetFrameOffset();
1191 offset = offset + parentOffset;
1192 }
1193 auto size = geometryNode->GetFrameSize();
1194 auto xOffset = localPoint.GetX() - offset.GetX();
1195 auto yOffset = localPoint.GetY() - offset.GetY();
1196 if (GetAxis() == Axis::VERTICAL) {
1197 return ClickJudgeVertical(size, xOffset, yOffset);
1198 } else {
1199 if (xOffset > 0 && xOffset < size.Width()) {
1200 if (startNodeSize_ && yOffset > 0 && yOffset < startNodeSize_) {
1201 return false;
1202 } else if (endNodeSize_ && yOffset > size.Height() - endNodeSize_ && yOffset < size.Height()) {
1203 return false;
1204 }
1205 }
1206 }
1207 return true;
1208 }
1209
OnDetachFromMainTree()1210 void ListItemPattern::OnDetachFromMainTree()
1211 {
1212 auto frameNode = GetListFrameNode();
1213 CHECK_NULL_VOID(frameNode);
1214 auto listPattern = frameNode->GetPattern<ListPattern>();
1215 CHECK_NULL_VOID(listPattern);
1216 listPattern->SetSwiperItemEnd(AceType::WeakClaim(this));
1217 swipeActionState_ = SwipeActionState::COLLAPSED;
1218 }
1219
RenderCustomChild(int64_t deadline)1220 bool ListItemPattern::RenderCustomChild(int64_t deadline)
1221 {
1222 if (shallowBuilder_ && !shallowBuilder_->IsExecuteDeepRenderDone()) {
1223 if (GetSysTimestamp() > deadline) {
1224 return false;
1225 }
1226 shallowBuilder_->ExecuteDeepRender();
1227 shallowBuilder_.Reset();
1228 }
1229 return true;
1230 }
1231 } // namespace OHOS::Ace::NG
1232
1233