• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/repeat_virtual_scroll_node.h"
17 
18 #include <cstdint>
19 #include <functional>
20 #include <utility>
21 
22 #include "base/log/ace_trace.h"
23 #include "base/log/log_wrapper.h"
24 #include "core/components_ng/base/frame_node.h"
25 #include "core/pipeline/base/element_register.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27 
28 namespace OHOS::Ace::NG {
29 
30 // REPEAT
GetOrCreateRepeatNode(int32_t nodeId,uint32_t totalCount,const std::map<std::string,std::pair<bool,uint32_t>> & templateCachedCountMap,const std::function<void (uint32_t)> & onCreateNode,const std::function<void (const std::string &,uint32_t)> & onUpdateNode,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetKeys4Range,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetTypes4Range,const std::function<void (int32_t,int32_t)> & onSetActiveRange)31 RefPtr<RepeatVirtualScrollNode> RepeatVirtualScrollNode::GetOrCreateRepeatNode(int32_t nodeId, uint32_t totalCount,
32     const std::map<std::string, std::pair<bool, uint32_t>>& templateCachedCountMap,
33     const std::function<void(uint32_t)>& onCreateNode,
34     const std::function<void(const std::string&, uint32_t)>& onUpdateNode,
35     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetKeys4Range,
36     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetTypes4Range,
37     const std::function<void(int32_t, int32_t)>& onSetActiveRange)
38 {
39     auto node = ElementRegister::GetInstance()->GetSpecificItemById<RepeatVirtualScrollNode>(nodeId);
40     if (node) {
41         TAG_LOGD(AceLogTag::ACE_REPEAT, "Found RepeatVirtualScrollNode");
42         node->UpdateTotalCount(totalCount);
43         return node;
44     }
45     node = MakeRefPtr<RepeatVirtualScrollNode>(
46         nodeId, totalCount, templateCachedCountMap, onCreateNode, onUpdateNode, onGetKeys4Range, onGetTypes4Range,
47         onSetActiveRange);
48 
49     ElementRegister::GetInstance()->AddUINode(node);
50     return node;
51 }
52 
RepeatVirtualScrollNode(int32_t nodeId,int32_t totalCount,const std::map<std::string,std::pair<bool,uint32_t>> & templateCachedCountMap,const std::function<void (uint32_t)> & onCreateNode,const std::function<void (const std::string &,uint32_t)> & onUpdateNode,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetKeys4Range,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetTypes4Range,const std::function<void (int32_t,int32_t)> & onSetActiveRange)53 RepeatVirtualScrollNode::RepeatVirtualScrollNode(int32_t nodeId, int32_t totalCount,
54     const std::map<std::string, std::pair<bool, uint32_t>>& templateCachedCountMap,
55     const std::function<void(uint32_t)>& onCreateNode,
56     const std::function<void(const std::string&, uint32_t)>& onUpdateNode,
57     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetKeys4Range,
58     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetTypes4Range,
59     const std::function<void(int32_t, int32_t)>& onSetActiveRange)
60     : ForEachBaseNode(V2::JS_REPEAT_ETS_TAG, nodeId), totalCount_(totalCount),
61       caches_(templateCachedCountMap, onCreateNode, onUpdateNode, onGetKeys4Range, onGetTypes4Range),
62       onSetActiveRange_(onSetActiveRange),
63       postUpdateTaskHasBeenScheduled_(false)
64 {
65 }
66 
UpdateTotalCount(uint32_t totalCount)67 void RepeatVirtualScrollNode::UpdateTotalCount(uint32_t totalCount)
68 {
69     TAG_LOGD(AceLogTag::ACE_REPEAT, "UpdateTotalCount: %{public}d", totalCount);
70     totalCount_ = totalCount;
71 }
72 
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)73 void RepeatVirtualScrollNode::DoSetActiveChildRange(
74     int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
75 {
76     if (showCache) {
77         start -= cacheStart;
78         end += cacheEnd;
79         cacheStart = 0;
80         cacheEnd = 0;
81     }
82     ACE_SCOPED_TRACE("Repeat.DoSetActiveChildRange start[%d] - end[%d]; cacheStart[%d], cacheEnd[%d]",
83         start, end, cacheStart, cacheEnd);
84     CheckActiveRange(start, end, cacheStart, cacheEnd);
85 
86     bool needSync = caches_.RebuildL1([start, end, cacheStart, cacheEnd, this](
87         int32_t index, const RefPtr<UINode>& node) -> bool {
88         if (node == nullptr) {
89             return false;
90         }
91         auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
92         if (!frameNode) {
93             return false;
94         }
95         if (CheckNode4IndexInL1(index, start, end, cacheStart, cacheEnd, frameNode)) {
96             // keep in Repeat L1
97             TAG_LOGD(AceLogTag::ACE_REPEAT, "...in visible, index %{public}d -> nodeId %{public}d: keep in Repeat L1",
98                 static_cast<int32_t>(index), frameNode->GetId());
99             return true;
100         }
101         TAG_LOGD(AceLogTag::ACE_REPEAT, "...out of visible, index %{public}d -> nodeId %{public}d: SetActive(false), "
102             "detach, move to spare items L2", index, frameNode->GetId());
103 
104         // move active node into L2 cached. check transition flag.
105         if (node->OnRemoveFromParent(true)) {
106             // OnRemoveFromParent returns true means the child can be removed from tree immediately.
107             RemoveDisappearingChild(node);
108         } else {
109             AddDisappearingChild(node);
110         }
111         return false;
112     });
113     if (needSync) {
114         UINode::MarkNeedSyncRenderTree(false);
115         children_.clear();
116         PostIdleTask();
117     }
118 }
119 
CheckNode4IndexInL1(int32_t index,int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,RefPtr<FrameNode> & frameNode)120 bool RepeatVirtualScrollNode::CheckNode4IndexInL1(int32_t index, int32_t start, int32_t end,
121     int32_t cacheStart, int32_t cacheEnd, RefPtr<FrameNode>& frameNode)
122 {
123     if (((start <= index) && (index <= end)) || ((end < start) && (index <= end || start <= index))) {
124         TAG_LOGD(AceLogTag::ACE_REPEAT, "...in range: index %{public}d -> nodeId %{public}d: SetActive(true)",
125             index, static_cast<int32_t>(frameNode->GetId()));
126         frameNode->SetActive(true);
127     } else {
128         TAG_LOGD(AceLogTag::ACE_REPEAT, "...out of range: index %{public}d -> nodeId %{public}d: SetActive(false)",
129             index, frameNode->GetId());
130         frameNode->SetActive(false);
131     }
132 
133     auto totalCount = static_cast<int32_t>(totalCount_);
134     if ((start - cacheStart <= index) && (index <= end + cacheEnd)) {
135         return true;
136     }
137     if (isLoop_) {
138         if (((end < start) && (start - cacheStart <= index || index <= end + cacheEnd)) ||
139             ((start - cacheStart < 0) && (index >= start - cacheStart + totalCount)) ||
140             ((end + cacheEnd >= totalCount) && (index <= end + cacheEnd - totalCount))) {
141             return true;
142         }
143     }
144     return false;
145 }
146 
CheckActiveRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd)147 void RepeatVirtualScrollNode::CheckActiveRange(int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd)
148 {
149     // get normalized active range (with positive indices only)
150     const int32_t signed_totalCount = static_cast<int32_t>(totalCount_);
151     int32_t nStart = start - cacheStart;
152     int32_t nEnd = end + cacheEnd;
153     const int32_t divider = 2;
154 
155     if (start > end) { // swiper-loop scenario
156         nStart = std::min(nStart, signed_totalCount);
157         nEnd = std::max(nEnd, 0);
158         if (nStart <= nEnd) { // overlapped
159             nStart = signed_totalCount / divider + 1;
160             nEnd = signed_totalCount / divider;
161         }
162     } else {
163         if (nStart >= signed_totalCount || nEnd < 0) {
164             nStart = 0;
165             nEnd = 0;
166         } else {
167             nStart = std::max(nStart, 0);
168             // start <= end <= totalCount - 1
169             nEnd = std::min(std::max(nEnd, nStart), signed_totalCount - 1);
170         }
171     }
172 
173     TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).DoSetActiveChildRange start: %{public}d - end: %{public}d; "
174         "cacheStart: %{public}d, cacheEnd: %{public}d: ==> keep in L1: %{public}d - %{public}d",
175         static_cast<int32_t>(GetId()), start, end, cacheStart, cacheEnd, nStart, nEnd);
176 
177     // memorize active range
178     caches_.SetLastActiveRange(static_cast<uint32_t>(nStart), static_cast<uint32_t>(nEnd));
179 
180     // notify TS side
181     onSetActiveRange_(nStart, nEnd);
182 }
183 
DropFromL1(const std::string & key)184 void RepeatVirtualScrollNode::DropFromL1(const std::string& key)
185 {
186     RefPtr<UINode> node = caches_.DropFromL1(key);
187     if (node == nullptr) {
188         return;
189     }
190 
191     auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
192     if (!frameNode) {
193         frameNode->SetActive(false);
194     }
195     // move active node into L2 cached.
196     // check transition flag.
197     if (node->OnRemoveFromParent(true)) {
198         // OnRemoveFromParent returns true means the child can be removed from tree immediately.
199         RemoveDisappearingChild(node);
200     } else {
201         // else move child into disappearing children, skip syncing render tree
202         AddDisappearingChild(node);
203     }
204 
205     UINode::MarkNeedSyncRenderTree(false);
206     children_.clear();
207     // re-assemble children_
208     PostIdleTask();
209 }
210 
DoSetActiveChildRange(const std::set<int32_t> & activeItems,const std::set<int32_t> & cachedItems,int32_t baseIndex)211 void RepeatVirtualScrollNode::DoSetActiveChildRange(
212     const std::set<int32_t>& activeItems, const std::set<int32_t>& cachedItems, int32_t baseIndex)
213 {
214     // Notify TS side. Verify line below when DoSetActiveChildRange() will start to be used.
215     // Call onSetActiveRange_ here;
216 
217     bool needSync =
218         caches_.RebuildL1([&activeItems, &cachedItems, baseIndex, this](int32_t index, RefPtr<UINode> node) -> bool {
219             if (node == nullptr) {
220                 return false;
221             }
222             auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
223             if (!frameNode) {
224                 return false;
225             }
226             if (activeItems.find(index + baseIndex) != activeItems.end()) {
227                 frameNode->SetActive(true);
228                 return true;
229             } else {
230                 frameNode->SetActive(false);
231             }
232             if (cachedItems.find(index + baseIndex) != cachedItems.end()) {
233                 return true;
234             }
235             if (node->OnRemoveFromParent(true)) {
236                 RemoveDisappearingChild(node);
237             } else {
238                 AddDisappearingChild(node);
239             }
240             return false;
241         });
242     if (needSync) {
243         UINode::MarkNeedSyncRenderTree(false);
244         children_.clear();
245         PostIdleTask();
246     }
247 }
248 
UpdateRenderState(bool visibleItemsChanged)249 void RepeatVirtualScrollNode::UpdateRenderState(bool visibleItemsChanged)
250 {
251     TAG_LOGD(AceLogTag::ACE_REPEAT,
252         "UpdateRenderState triggered by Repeat rerender: nodeId: %{public}d, visibleItemsChanged: %{public}d",
253         static_cast<int32_t>(GetId()), visibleItemsChanged);
254 
255     if (visibleItemsChanged) {
256         // empty the cache index -> key
257         // C++ will need to ask all new keys from JS side
258         caches_.InvalidateKeyAndTTypeCaches();
259         children_.clear();
260 
261         if (auto frameNode = GetParentFrameNode()) {
262             frameNode->ChildrenUpdatedFrom(0);
263         }
264     } else {
265         auto lastIndexInActiveRange = caches_.GetLastActiveRange().second;
266         TAG_LOGD(AceLogTag::ACE_REPEAT, "lastIndexInActiveRange:%{public}d", lastIndexInActiveRange);
267 
268         if (auto frameNode = GetParentFrameNode()) {
269             frameNode->ChildrenUpdatedFrom(lastIndexInActiveRange + 1);
270         }
271     }
272 
273     MarkNeedSyncRenderTree(true);
274     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT | PROPERTY_UPDATE_BY_CHILD_REQUEST);
275 }
276 
277 // STATE_MGMT_NOTE: added
278 // index N-th item
279 // needBuild: true - if found in cache, then return, if not in cache then return newly build
280 //            false: - if found in cache, then return, if not found in cache then return nullptr
281 // isCache: true indicates prebuild item (only used by List/Grid/Waterflow, this item should go to L2 cache,
282 //          do not add to the tree,
283 //          isCache==false this item is for display or near display area
284 // addToRenderTree: true  - set it to active state, call SetActive
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)285 RefPtr<UINode> RepeatVirtualScrollNode::GetFrameChildByIndex(
286     uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
287 {
288     TAG_LOGD(AceLogTag::ACE_REPEAT, "index:%{public}d", static_cast<int32_t>(index));
289 
290     ACE_SCOPED_TRACE("Repeat.GetFrameChildByIndex index[%d], needBuild[%d] isCache[%d] "
291                      "addToRenderTree[%d]",
292         index, static_cast<int32_t>(needBuild), static_cast<int32_t>(isCache), static_cast<int32_t>(addToRenderTree));
293 
294     // whether child is reused or created
295     bool isChildReused = true;
296 
297     const auto& key = caches_.GetKey4Index(index, true);
298     if (!key) {
299         TAG_LOGE(AceLogTag::ACE_REPEAT, "fail to get key for %{public}d", index);
300         return nullptr;
301     }
302 
303     TAG_LOGD(AceLogTag::ACE_REPEAT,
304         "nodeId: %{public}d: GetFrameChildByIndex(index: %{public}d, "
305         "key %{public}s, needBuild:  %{public}d, isCache: %{public}d, "
306         "addToRenderTree: %{public}d) ...", static_cast<int32_t>(GetId()),
307         static_cast<int32_t>(index), key->c_str(), static_cast<int32_t>(needBuild),
308         static_cast<int32_t>(isCache), static_cast<int32_t>(addToRenderTree));
309 
310     // search if index -> key -> Node exist
311     // will update the same key item if needs.
312     auto node4Index = GetFromCaches(index);
313     if (!node4Index && !needBuild) {
314         TAG_LOGD(AceLogTag::ACE_REPEAT,
315             "index %{public}d -> key '%{public}s' not in caches && needBuild==false, "
316             "GetFrameChildByIndex returns nullptr .",
317             static_cast<int32_t>(index), key->c_str());
318         return nullptr;
319     }
320 
321     // node4Index needs to be created or updated on JS side
322     if (!node4Index) {
323         TAG_LOGD(AceLogTag::ACE_REPEAT,
324             "index %{public}d -> key '%{public}s' not in caches && needBuild==true, calling "
325             "CreateOrUpdateFrameChild4Index ....",
326             static_cast<int32_t>(index), key->c_str());
327 
328         // ask TS to update a Node, if possible
329         // if no suitable node, request to crete a new node
330         node4Index = caches_.UpdateFromL2(index);
331         if (!node4Index) {
332             node4Index = caches_.CreateNewNode(index);
333             isChildReused = false;
334         }
335 
336         if (!node4Index) {
337             TAG_LOGW(AceLogTag::ACE_REPEAT, "index %{public}d -> key '%{public}s' not in caches and failed to build.",
338                 static_cast<int32_t>(index), key->c_str());
339             return nullptr;
340         }
341     }
342 
343     TAG_LOGD(AceLogTag::ACE_REPEAT,
344         "index %{public}d  -> key '%{public}s', needBuild==true, node: %{public}s .",
345         static_cast<int32_t>(index), key->c_str(), caches_.DumpUINode(node4Index).c_str());
346 
347     if (isActive_) {
348         node4Index->SetJSViewActive(true);
349     }
350 
351     if (addToRenderTree && !isCache) {
352         TAG_LOGD(AceLogTag::ACE_REPEAT,
353             "index %{public}d isCache==false setActive and adding to L1 cache",
354             static_cast<int32_t>(index));
355         node4Index->SetActive(true);
356     }
357 
358     if (caches_.IsInL1Cache(key.value())) {
359         return node4Index->GetFrameChildByIndex(0, needBuild);
360     }
361 
362     // refresh the cached ttype and verify it hasn't changed
363     if (caches_.CheckTTypeChanged(index)) {
364         return GetFrameChildByIndex(index, needBuild, isCache, addToRenderTree);
365     }
366 
367     // if the item was in L2 cache, move item to L1 cache.
368     caches_.AddKeyToL1WithNodeUpdate(key.value(), index, isChildReused);
369 
370     if (node4Index->GetDepth() != GetDepth() + 1) {
371         node4Index->SetDepth(GetDepth() + 1);
372     }
373     // attach to repeat node and pass context to it.
374     node4Index->SetParent(WeakClaim(this));
375     if (IsOnMainTree()) {
376         node4Index->AttachToMainTree(false, GetContext());
377     }
378 
379     MarkNeedSyncRenderTree();
380     children_.clear();
381     // re-assemble children_
382     PostIdleTask();
383 
384     auto childNode = node4Index->GetFrameChildByIndex(0, needBuild);
385     if (childNode && onMoveEvent_) {
386         InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
387     }
388 
389     if (childNode) {
390         TAG_LOGD(AceLogTag::ACE_REPEAT, "index %{public}d, its child is %{public}d, returning child.",
391             static_cast<int32_t>(index), static_cast<int32_t>(childNode->GetId()));
392     }
393 
394     return childNode;
395 }
396 
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool)397 int32_t RepeatVirtualScrollNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool /*isExpanded*/)
398 {
399     return caches_.GetFrameNodeIndex(node);
400 }
401 
GetChildren(bool) const402 const std::list<RefPtr<UINode>>& RepeatVirtualScrollNode::GetChildren(bool /*notDetach*/) const
403 {
404     if (!children_.empty()) {
405         TAG_LOGD(AceLogTag::ACE_REPEAT, "GetChildren just returns non-empty children_");
406         return children_;
407     }
408 
409     // can not modify l1_cache while iterating
410     // GetChildren is overloaded, can not change it to non-const
411     // need to order the child.
412     std::map<int32_t, RefPtr<UINode>> children;
413     caches_.ForEachL1IndexUINode(
414         [&children](int32_t index, const RefPtr<UINode>& node) -> void { children.emplace(index, node); });
415     for (const auto& [index, child] : children) {
416         const_cast<RepeatVirtualScrollNode*>(this)->RemoveDisappearingChild(child);
417         children_.emplace_back(child);
418     }
419     return children_;
420 }
421 
OnRecycle()422 void RepeatVirtualScrollNode::OnRecycle()
423 {
424     for (auto& [key, child]: caches_.GetAllNodes()) {
425         if (caches_.IsInL1Cache(key) && child.item) {
426             child.item->OnRecycle();
427         }
428     }
429 }
430 
OnReuse()431 void RepeatVirtualScrollNode::OnReuse()
432 {
433     for (auto& [key, child]: caches_.GetAllNodes()) {
434         if (caches_.IsInL1Cache(key) && child.item) {
435             child.item->OnReuse();
436         }
437     }
438 }
439 
UpdateChildrenFreezeState(bool isFreeze)440 void RepeatVirtualScrollNode::UpdateChildrenFreezeState(bool isFreeze)
441 {
442     const auto& allChildren = caches_.GetAllNodes();
443     for (auto& child : allChildren) {
444         if (child.second.item) {
445             child.second.item->SetFreeze(isFreeze);
446         }
447     }
448 }
449 
RecycleItems(int32_t from,int32_t to)450 void RepeatVirtualScrollNode::RecycleItems(int32_t from, int32_t to)
451 {
452     TAG_LOGD(AceLogTag::ACE_REPEAT,
453         "Repeat(%{public}d: Layout prediction instructs to move Repeat items from index %{public}d up to smaller than "
454         "%{public}d to the reusable items cache",
455         static_cast<int32_t>(GetId()), from - startIndex_, to - startIndex_);
456 
457     offscreenItems_.from = from;
458     offscreenItems_.to = to;
459     for (auto i = from; i < to; i++) {
460         if (i >= startIndex_ && i < startIndex_ + static_cast<int32_t>(totalCount_)) {
461             caches_.RecycleItemsByIndex(i - startIndex_);
462         }
463     }
464 }
465 
SetNodeIndexOffset(int32_t start,int32_t)466 void RepeatVirtualScrollNode::SetNodeIndexOffset(int32_t start, int32_t /*count*/)
467 {
468     startIndex_ = start;
469 }
470 
FrameCount() const471 int32_t RepeatVirtualScrollNode::FrameCount() const
472 {
473     TAG_LOGD(AceLogTag::ACE_REPEAT, "FrameCount returns %{public}d",
474         static_cast<int32_t>(totalCount_));
475     return totalCount_;
476 }
477 
PostIdleTask()478 void RepeatVirtualScrollNode::PostIdleTask()
479 {
480     if (postUpdateTaskHasBeenScheduled_) {
481         return;
482     }
483     TAG_LOGD(AceLogTag::ACE_REPEAT, "Posting idle task");
484     postUpdateTaskHasBeenScheduled_ = true;
485     auto* context = GetContext();
486     CHECK_NULL_VOID(context);
487 
488     context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t /*deadline*/, bool /*canUseLongPredictTask*/) {
489         ACE_SCOPED_TRACE("Repeat.IdleTask");
490         auto node = weak.Upgrade();
491         CHECK_NULL_VOID(node);
492         node->postUpdateTaskHasBeenScheduled_ = false;
493         TAG_LOGD(AceLogTag::ACE_REPEAT, "idle task calls GetChildren");
494         node->GetChildren();
495         node->caches_.Purge();
496         TAG_LOGD(AceLogTag::ACE_REPEAT, " ============ after caches.purge ============= ");
497         TAG_LOGD(AceLogTag::ACE_REPEAT, "%{public}s", node->caches_.DumpL1().c_str());
498         TAG_LOGD(AceLogTag::ACE_REPEAT, "%{public}s", node->caches_.DumpL2().c_str());
499     });
500 }
501 
OnConfigurationUpdate(const ConfigurationChange & configurationChange)502 void RepeatVirtualScrollNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
503 {
504     if ((configurationChange.colorModeUpdate || configurationChange.fontUpdate)) {
505         const auto& children = caches_.GetAllNodes();
506         for (const auto& [key, child] : children) {
507             if (child.item) {
508                 child.item->UpdateConfigurationUpdate(configurationChange);
509             }
510         }
511     }
512 }
513 
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)514 void RepeatVirtualScrollNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
515 {
516     // To do
517 }
518 
519 // FOREAch
MoveData(int32_t from,int32_t to)520 void RepeatVirtualScrollNode::MoveData(int32_t from, int32_t to) {}
521 
GetFrameNode(int32_t index)522 RefPtr<FrameNode> RepeatVirtualScrollNode::GetFrameNode(int32_t index)
523 {
524     return AceType::DynamicCast<FrameNode>(GetFrameChildByIndex(index, false, false));
525 }
526 
InitDragManager(const RefPtr<UINode> & child)527 void RepeatVirtualScrollNode::InitDragManager(const RefPtr<UINode>& child)
528 {
529     // To do
530 }
531 
InitAllChildrenDragManager(bool init)532 void RepeatVirtualScrollNode::InitAllChildrenDragManager(bool init)
533 {
534     // To do
535 }
536 
537 } // namespace OHOS::Ace::NG
538