• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_ng/syntax/lazy_for_each_node.h"
17 
18 #include <utility>
19 
20 #include "base/log/ace_trace.h"
21 #include "base/log/dump_log.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/time_util.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/list/list_item_pattern.h"
27 #include "core/components_ng/property/property.h"
28 #include "core/components_ng/syntax/lazy_layout_wrapper_builder.h"
29 #include "core/components_v2/inspector/inspector_constants.h"
30 #include "core/pipeline/base/element_register.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32 
33 namespace OHOS::Ace::NG {
34 
GetOrCreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)35 RefPtr<LazyForEachNode> LazyForEachNode::GetOrCreateLazyForEachNode(
36     int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
37 {
38     auto node = ElementRegister::GetInstance()->GetSpecificItemById<LazyForEachNode>(nodeId);
39     if (node) {
40         if (node->builder_ != forEachBuilder) {
41             TAG_LOGI(AceLogTag::ACE_LAZY_FOREACH, "replace old lazy for each builder");
42             node->builder_ = forEachBuilder;
43         }
44         return node;
45     }
46     node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
47     ElementRegister::GetInstance()->AddUINode(node);
48     node->RegisterBuilderListener();
49     return node;
50 }
51 
CreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)52 RefPtr<LazyForEachNode> LazyForEachNode::CreateLazyForEachNode(
53     int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
54 {
55     auto node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
56     ElementRegister::GetInstance()->AddUINode(node);
57     return node;
58 }
59 
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)60 void LazyForEachNode::AdjustLayoutWrapperTree(
61     const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
62 {
63     CHECK_NULL_VOID(builder_);
64     auto lazyLayoutWrapperBuilder = MakeRefPtr<LazyLayoutWrapperBuilder>(builder_, WeakClaim(this));
65     if (parent->GetHostTag() == V2::SWIPER_ETS_TAG) {
66         lazyLayoutWrapperBuilder->SetLazySwiper();
67     }
68     lazyLayoutWrapperBuilder->UpdateForceFlag(forceMeasure, forceLayout);
69     parent->SetLayoutWrapperBuilder(lazyLayoutWrapperBuilder);
70 }
71 
BuildAllChildren()72 void LazyForEachNode::BuildAllChildren()
73 {
74     for (int i = 0; i < FrameCount(); i++) {
75         GetFrameChildByIndex(i, true);
76     }
77     tempChildren_.clear();
78     tempChildren_.swap(children_);
79     auto items = builder_->GetAllChildren();
80     for (auto& [index, item] : items) {
81         if (item.second) {
82             RemoveDisappearingChild(item.second);
83             children_.push_back(item.second);
84         }
85     }
86 }
87 
PostIdleTask()88 void LazyForEachNode::PostIdleTask()
89 {
90     if (needPredict_) {
91         return;
92     }
93     needPredict_ = true;
94     auto context = GetContext();
95     CHECK_NULL_VOID(context);
96     context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t deadline, bool canUseLongPredictTask) {
97         ACE_SCOPED_TRACE("LazyForEach predict");
98         auto node = weak.Upgrade();
99         CHECK_NULL_VOID(node);
100         node->needPredict_ = false;
101         auto canRunLongPredictTask = node->requestLongPredict_ && canUseLongPredictTask;
102         if (node->builder_) {
103             node->GetChildren();
104             auto preBuildResult = node->builder_->PreBuild(deadline, node->itemConstraint_, canRunLongPredictTask);
105             if (!preBuildResult) {
106                 node->PostIdleTask();
107             } else {
108                 node->requestLongPredict_ = true;
109                 node->itemConstraint_.reset();
110             }
111         }
112     });
113 }
114 
OnDataReloaded()115 void LazyForEachNode::OnDataReloaded()
116 {
117     ACE_SCOPED_TRACE("LazyForEach OnDataReloaded");
118     tempChildren_.clear();
119     tempChildren_.swap(children_);
120     if (builder_) {
121         builder_->SetUseNewInterface(false);
122         builder_->OnDataReloaded();
123         if (FrameCount() == 0) {
124             PostIdleTask();
125         }
126     }
127     NotifyChangeWithCount(0, 0, NotificationType::START_CHANGE_POSITION);
128     if (builder_) {
129         int32_t endChangePos = std::max(builder_->GetHistoryTotalCount(), FrameCount());
130         NotifyChangeWithCount(endChangePos, 0, NotificationType::END_CHANGE_POSITION);
131     }
132     MarkNeedSyncRenderTree(true);
133     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
134 }
135 
OnDataAdded(size_t index)136 void LazyForEachNode::OnDataAdded(size_t index)
137 {
138     ACE_SCOPED_TRACE("LazyForEach OnDataAdded");
139     auto insertIndex = static_cast<int32_t>(index);
140     if (builder_) {
141         builder_->SetUseNewInterface(false);
142         builder_->OnDataAdded(index);
143     }
144     tempChildren_.clear();
145     tempChildren_.swap(children_);
146     NotifyChangeWithCount(insertIndex, 1, NotificationType::START_AND_END_CHANGE_POSITION);
147     MarkNeedSyncRenderTree(true);
148     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
149 }
150 
OnDataBulkAdded(size_t index,size_t count)151 void LazyForEachNode::OnDataBulkAdded(size_t index, size_t count)
152 {
153     ACE_SCOPED_TRACE("LazyForEach OnDataBulkAdded");
154     auto insertIndex = static_cast<int32_t>(index);
155     if (builder_) {
156         builder_->SetUseNewInterface(false);
157         builder_->OnDataBulkAdded(index, count);
158     }
159     tempChildren_.clear();
160     tempChildren_.swap(children_);
161     NotifyChangeWithCount(insertIndex, static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
162     MarkNeedSyncRenderTree(true);
163     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
164 }
165 
OnDataDeleted(size_t index)166 void LazyForEachNode::OnDataDeleted(size_t index)
167 {
168     ACE_SCOPED_TRACE("LazyForEach OnDataDeleted");
169     auto deletedIndex = static_cast<int32_t>(index);
170     if (builder_) {
171         builder_->SetUseNewInterface(false);
172         auto node = builder_->OnDataDeleted(index);
173 
174         if (node) {
175             if (!node->OnRemoveFromParent(true)) {
176                 AddDisappearingChild(node);
177             } else {
178                 node->DetachFromMainTree();
179             }
180             builder_->ProcessOffscreenNode(node, true);
181         }
182     }
183     tempChildren_.clear();
184     tempChildren_.swap(children_);
185     NotifyChangeWithCount(deletedIndex, -1, NotificationType::START_AND_END_CHANGE_POSITION);
186     MarkNeedSyncRenderTree(true);
187     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
188 }
189 
OnDataBulkDeleted(size_t index,size_t count)190 void LazyForEachNode::OnDataBulkDeleted(size_t index, size_t count)
191 {
192     ACE_SCOPED_TRACE("LazyForEach OnDataBulkDeleted");
193     auto deletedIndex = static_cast<int32_t>(index);
194     if (builder_) {
195         builder_->SetUseNewInterface(false);
196         const auto& nodeList = builder_->OnDataBulkDeleted(index, count);
197         for (const auto& node : nodeList) {
198             if (node.second == nullptr) {
199                 continue;
200             }
201             if (!node.second->OnRemoveFromParent(true)) {
202                 AddDisappearingChild(node.second);
203             } else {
204                 node.second->DetachFromMainTree();
205             }
206             builder_->ProcessOffscreenNode(node.second, true);
207             builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
208         }
209         builder_->clearDeletedNodes();
210     }
211     tempChildren_.clear();
212     tempChildren_.swap(children_);
213     NotifyChangeWithCount(deletedIndex, -static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
214     MarkNeedSyncRenderTree(true);
215     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
216 }
217 
OnDataChanged(size_t index)218 void LazyForEachNode::OnDataChanged(size_t index)
219 {
220     auto changedIndex = static_cast<int32_t>(index);
221     if (builder_) {
222         builder_->SetUseNewInterface(false);
223         builder_->OnDataChanged(index);
224     }
225     tempChildren_.clear();
226     tempChildren_.swap(children_);
227     NotifyChangeWithCount(changedIndex, 0, NotificationType::START_AND_END_CHANGE_POSITION);
228     MarkNeedSyncRenderTree(true);
229     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
230 }
231 
OnDataBulkChanged(size_t index,size_t count)232 void LazyForEachNode::OnDataBulkChanged(size_t index, size_t count)
233 {
234     ACE_SCOPED_TRACE("LazyForEach OnDataBulkChanged");
235     auto changedIndex = static_cast<int32_t>(index);
236     if (builder_) {
237         builder_->SetUseNewInterface(false);
238         const auto& nodeList = builder_->OnDataBulkChanged(index, count);
239         for (const auto& node : nodeList) {
240             if (node.second == nullptr) {
241                 continue;
242             }
243             if (!node.second->OnRemoveFromParent(true)) {
244                 AddDisappearingChild(node.second);
245             } else {
246                 node.second->DetachFromMainTree();
247             }
248             builder_->ProcessOffscreenNode(node.second, true);
249             builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
250         }
251         builder_->clearDeletedNodes();
252     }
253     tempChildren_.clear();
254     tempChildren_.swap(children_);
255     NotifyChangeWithCount(changedIndex, 0, NotificationType::START_CHANGE_POSITION);
256     NotifyChangeWithCount(changedIndex + static_cast<int32_t>(count) - 1, 0, NotificationType::END_CHANGE_POSITION);
257     MarkNeedSyncRenderTree(true);
258     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
259 }
260 
OnDataMoveToNewPlace(size_t from,size_t to)261 void LazyForEachNode::OnDataMoveToNewPlace(size_t from, size_t to)
262 {
263     if (builder_) {
264         builder_->SetUseNewInterface(false);
265         builder_->OnDataMoveToNewPlace(from, to);
266     }
267     tempChildren_.clear();
268     tempChildren_.swap(children_);
269     NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
270     NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
271     MarkNeedSyncRenderTree(true);
272     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
273 }
274 
OnDataMoved(size_t from,size_t to)275 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
276 {
277     if (builder_) {
278         builder_->SetUseNewInterface(false);
279         builder_->OnDataMoved(from, to);
280     }
281     tempChildren_.clear();
282     tempChildren_.swap(children_);
283     NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
284     NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
285     MarkNeedSyncRenderTree(true);
286     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
287 }
288 
OnDatasetChange(const std::list<V2::Operation> & DataOperations)289 void LazyForEachNode::OnDatasetChange(const std::list<V2::Operation>& DataOperations)
290 {
291     ACE_SCOPED_TRACE("LazyForEach OnDatasetChange");
292     int32_t initialChangedIndex = 0;
293     if (builder_) {
294         builder_->SetUseNewInterface(true);
295         std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> pair =
296             builder_->OnDatasetChange(DataOperations);
297         initialChangedIndex = pair.first;
298         std::list<std::pair<std::string, RefPtr<UINode>>> nodeList = pair.second;
299         for (const auto& node : nodeList) {
300             if (node.second == nullptr) {
301                 continue;
302             }
303             if (!node.second->OnRemoveFromParent(true)) {
304                 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
305             } else {
306                 node.second->DetachFromMainTree();
307             }
308             builder_->ProcessOffscreenNode(node.second, true);
309             builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
310         }
311         builder_->clearDeletedNodes();
312     }
313     tempChildren_.clear();
314     tempChildren_.swap(children_);
315     NotifyChangeWithCount(initialChangedIndex, 0, NotificationType::START_CHANGE_POSITION);
316     ParseOperations(DataOperations);
317     MarkNeedSyncRenderTree(true);
318     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
319 }
320 
MarkNeedSyncRenderTree(bool needRebuild)321 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
322 {
323     if (needMarkParent_) {
324         UINode::MarkNeedSyncRenderTree(needRebuild);
325     }
326 }
327 
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)328 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
329 {
330     if (index >= static_cast<uint32_t>(FrameCount())) {
331         return nullptr;
332     }
333     auto child = builder_->GetChildByIndex(index, needBuild, isCache);
334     if (!child.second) {
335         return nullptr;
336     }
337     if (isCache) {
338         child.second->SetParent(WeakClaim(this));
339         child.second->SetJSViewActive(false, true);
340         return child.second->GetFrameChildByIndex(0, needBuild);
341     }
342     if (isActive_) {
343         child.second->SetJSViewActive(true, true);
344     }
345     if (addToRenderTree) {
346         child.second->SetActive(true);
347     }
348     if (child.second->GetDepth() != GetDepth() + 1) {
349         child.second->SetDepth(GetDepth() + 1);
350     }
351     MarkNeedSyncRenderTree();
352     tempChildren_.clear();
353     tempChildren_.swap(children_);
354     child.second->SetParent(WeakClaim(this));
355     if (IsOnMainTree()) {
356         child.second->AttachToMainTree(false, GetContext());
357     }
358     PostIdleTask();
359     auto childNode = child.second->GetFrameChildByIndex(0, needBuild);
360     if (onMoveEvent_) {
361         InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
362     }
363     return childNode;
364 }
365 
GetIndexByUINode(const RefPtr<UINode> & uiNode) const366 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
367 {
368     if (!builder_) {
369         return -1;
370     }
371     auto items = builder_->GetAllChildren();
372     for (auto& [index, item] : items) {
373         if (item.second == uiNode) {
374             return index;
375         }
376     }
377     return -1;
378 }
379 
RecycleItems(int32_t from,int32_t to)380 void LazyForEachNode::RecycleItems(int32_t from, int32_t to)
381 {
382     if (!builder_) {
383         return;
384     }
385     tempChildren_.clear();
386     tempChildren_.swap(children_);
387     for (auto index = from; index < to; index++) {
388         if (index >= startIndex_ && index < startIndex_ + count_) {
389             builder_->RecordOutOfBoundaryNodes(index - startIndex_);
390         }
391     }
392     PostIdleTask();
393 }
394 
DoRemoveChildInRenderTree(uint32_t index,bool isAll)395 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
396 {
397     if (!builder_) {
398         return;
399     }
400     tempChildren_.clear();
401     tempChildren_.swap(children_);
402     if (isAll) {
403         builder_->RemoveAllChild();
404         MarkNeedSyncRenderTree();
405         PostIdleTask();
406     }
407 }
408 
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)409 void LazyForEachNode::DoSetActiveChildRange(
410     int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
411 {
412     if (!builder_) {
413         return;
414     }
415     if (showCache) {
416         start -= cacheStart;
417         end += cacheEnd;
418         builder_->SetShowCached(cacheStart, cacheEnd);
419     }
420     if (builder_->SetActiveChildRange(start, end)) {
421         tempChildren_.clear();
422         tempChildren_.swap(children_);
423         MarkNeedSyncRenderTree();
424         PostIdleTask();
425     }
426 }
427 
GetChildren(bool notDetach) const428 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren(bool notDetach) const
429 {
430     if (children_.empty()) {
431         LoadChildren(notDetach);
432 
433         // if measure not done, return previous children
434         if (notDetach && children_.empty()) {
435             return tempChildren_;
436         }
437 
438         tempChildren_.clear();
439     }
440     return children_;
441 }
442 
UpdateChildrenFreezeState(bool isFreeze)443 void LazyForEachNode::UpdateChildrenFreezeState(bool isFreeze)
444 {
445     if (!builder_) {
446         return;
447     }
448     std::vector<UINode*> children;
449     builder_->GetAllItems(children);
450     for (const auto& child : children) {
451         if (child) {
452             child->SetFreeze(isFreeze);
453         }
454     }
455 }
456 
LoadChildren(bool notDetach) const457 void LazyForEachNode::LoadChildren(bool notDetach) const
458 {
459     std::list<std::pair<std::string, RefPtr<UINode>>> childList;
460     const auto& items = builder_->GetItems(childList);
461 
462     if (!notDetach) {
463         for (auto& node : childList) {
464             if (!node.second->OnRemoveFromParent(true)) {
465                 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
466             } else {
467                 node.second->DetachFromMainTree();
468             }
469         }
470     }
471 
472     for (const auto& [index, item] : items) {
473         if (item.second) {
474             const_cast<LazyForEachNode*>(this)->RemoveDisappearingChild(item.second);
475             children_.push_back(item.second);
476         }
477     }
478 }
479 
OnConfigurationUpdate(const ConfigurationChange & configurationChange)480 void LazyForEachNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
481 {
482     if (configurationChange.IsNeedUpdate() && builder_) {
483         auto map = builder_->GetCachedUINodeMap();
484         for (auto& it : map) {
485             auto node = DynamicCast<UINode>(it.second.second);
486             if (node) {
487                 node->UpdateConfigurationUpdate(configurationChange);
488             }
489         }
490     }
491 }
492 
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)493 void LazyForEachNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
494 {
495     if (onMove && !onMoveEvent_) {
496         InitAllChilrenDragManager(true);
497     } else if (!onMove && onMoveEvent_) {
498         InitAllChilrenDragManager(false);
499     }
500     onMoveEvent_ = onMove;
501 }
502 
MoveData(int32_t from,int32_t to)503 void LazyForEachNode::MoveData(int32_t from, int32_t to)
504 {
505     if (builder_) {
506         builder_->OnDataMoveToNewPlace(from, to);
507         builder_->UpdateMoveFromTo(from, to);
508     }
509     tempChildren_.clear();
510     tempChildren_.swap(children_);
511     MarkNeedSyncRenderTree(true);
512     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
513 }
514 
FireOnMove(int32_t from,int32_t to)515 void LazyForEachNode::FireOnMove(int32_t from, int32_t to)
516 {
517     if (builder_) {
518         builder_->ResetMoveFromTo();
519     }
520     ForEachBaseNode::FireOnMove(from, to);
521 }
522 
GetFrameNode(int32_t index)523 RefPtr<FrameNode> LazyForEachNode::GetFrameNode(int32_t index)
524 {
525     CHECK_NULL_RETURN(builder_, nullptr);
526     auto child = builder_->GetChildByIndex(index, false, false);
527     CHECK_NULL_RETURN(child.second, nullptr);
528     return AceType::DynamicCast<FrameNode>(child.second->GetFrameChildByIndex(0, true));
529 }
530 
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)531 int32_t LazyForEachNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
532 {
533     if (!isExpanded) {
534         return UINode::GetFrameNodeIndex(node, false);
535     }
536     CHECK_NULL_RETURN(builder_, -1);
537     return builder_->GetChildIndex(node);
538 }
539 
InitDragManager(const RefPtr<FrameNode> & childNode)540 void LazyForEachNode::InitDragManager(const RefPtr<FrameNode>& childNode)
541 {
542     CHECK_NULL_VOID(childNode);
543     auto parentNode = GetParentFrameNode();
544     CHECK_NULL_VOID(parentNode);
545     if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
546         return;
547     }
548     auto pattern = childNode->GetPattern<ListItemPattern>();
549     CHECK_NULL_VOID(pattern);
550     pattern->InitDragManager(AceType::Claim(this));
551 }
552 
InitAllChilrenDragManager(bool init)553 void LazyForEachNode::InitAllChilrenDragManager(bool init)
554 {
555     auto parentNode = GetParentFrameNode();
556     CHECK_NULL_VOID(parentNode);
557     if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
558         return;
559     }
560     const auto& children = GetChildren();
561     for (const auto& child : children) {
562         if (!child) {
563             continue;
564         }
565         auto childNode = child->GetFrameChildByIndex(0, false);
566         auto listItem = AceType::DynamicCast<FrameNode>(childNode);
567         if (!listItem) {
568             continue;
569         }
570 
571         auto pattern = listItem->GetPattern<ListItemPattern>();
572         if (!pattern) {
573             continue;
574         }
575         if (init) {
576             pattern->InitDragManager(AceType::Claim(this));
577         } else {
578             pattern->DeInitDragManager();
579         }
580     }
581 }
582 
NotifyChangeWithCount(int32_t index,int32_t count,NotificationType notificationType) const583 void LazyForEachNode::NotifyChangeWithCount(int32_t index, int32_t count, NotificationType notificationType) const
584 {
585     auto parent = GetParent();
586     int64_t accessibilityId = GetAccessibilityId();
587     if (parent) {
588         parent->NotifyChange(index, count, accessibilityId, notificationType);
589     }
590 }
591 
ParseOperations(const std::list<V2::Operation> & dataOperations)592 void LazyForEachNode::ParseOperations(const std::list<V2::Operation>& dataOperations)
593 {
594     std::map<std::string, int32_t> operationTypeMap = { { "add", 1 }, { "delete", 2 }, { "change", 3 }, { "move", 4 },
595         { "exchange", 5 }, { "reload", 6 } };
596     constexpr int ADDOP = 1;
597     constexpr int DELETEOP = 2;
598     constexpr int CHANGEOP = 3;
599     constexpr int MOVEOP = 4;
600     constexpr int EXCHANGEOP = 5;
601     constexpr int RELOADOP = 6;
602     for (const auto& operation : dataOperations) {
603         switch (operationTypeMap[operation.type]) {
604             case ADDOP:
605                 NotifyChangeWithCount(operation.index, operation.count, NotificationType::END_CHANGE_POSITION);
606                 break;
607             case DELETEOP:
608                 NotifyChangeWithCount(operation.index, -operation.count, NotificationType::END_CHANGE_POSITION);
609                 break;
610             case CHANGEOP:
611                 NotifyChangeWithCount(operation.index + operation.count - 1, 0, NotificationType::END_CHANGE_POSITION);
612                 break;
613             case MOVEOP:
614                 NotifyChangeWithCount(std::max(operation.coupleIndex.first, operation.coupleIndex.second), 0,
615                     NotificationType::END_CHANGE_POSITION);
616                 break;
617             case EXCHANGEOP:
618                 NotifyChangeWithCount(operation.coupleIndex.second, 0, NotificationType::END_CHANGE_POSITION);
619                 break;
620             case RELOADOP:
621                 if (builder_) {
622                     int32_t endChangePos = std::max(builder_->GetHistoryTotalCount(), FrameCount());
623                     NotifyChangeWithCount(endChangePos, 0, NotificationType::END_CHANGE_POSITION);
624                 }
625                 break;
626         }
627     }
628 }
629 } // namespace OHOS::Ace::NG
630