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
73
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)74 void RepeatVirtualScrollNode::DoSetActiveChildRange(
75 int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
76 {
77 if (showCache) {
78 start -= cacheStart;
79 end += cacheEnd;
80 cacheStart = 0;
81 cacheEnd = 0;
82 }
83 ACE_SCOPED_TRACE("Repeat.DoSetActiveChildRange start [%d] - end [%d]; cacheStart: [%d], cacheEnd: [%d]",
84 start, end, cacheStart, cacheEnd);
85 CheckActiveRange(start, end, cacheStart, cacheEnd);
86
87 bool needSync = caches_.RebuildL1([start, end, cacheStart, cacheEnd, this](
88 int32_t index, const RefPtr<UINode>& node) -> bool {
89 if (node == nullptr) {
90 return false;
91 }
92 auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
93 if (!frameNode) {
94 return false;
95 }
96 if (CheckNode4IndexInL1(index, start, end, cacheStart, cacheEnd, frameNode)) {
97 // keep in Repeat L1
98 TAG_LOGD(AceLogTag::ACE_REPEAT, "...in visible, index %{public}d -> nodeId %{public}d: keep in Repeat L1",
99 static_cast<int32_t>(index), frameNode->GetId());
100 return true;
101 }
102 TAG_LOGD(AceLogTag::ACE_REPEAT, "...out of visible, index %{public}d -> nodeId %{public}d: SetActive(false), "
103 "detach, move to spare items L2", index, frameNode->GetId());
104
105 // move active node into L2 cached. check transition flag.
106 if (node->OnRemoveFromParent(true)) {
107 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
108 RemoveDisappearingChild(node);
109 } else {
110 AddDisappearingChild(node);
111 }
112 return false;
113 });
114 if (needSync) {
115 UINode::MarkNeedSyncRenderTree(false);
116 children_.clear();
117 PostIdleTask();
118 }
119 }
120
CheckNode4IndexInL1(int32_t index,int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,RefPtr<FrameNode> & frameNode)121 bool RepeatVirtualScrollNode::CheckNode4IndexInL1(int32_t index, int32_t start, int32_t end,
122 int32_t cacheStart, int32_t cacheEnd, RefPtr<FrameNode>& frameNode)
123 {
124 if (((start <= index) && (index <= end)) || ((end < start) && (index <= end || start <= index))) {
125 TAG_LOGD(AceLogTag::ACE_REPEAT, "...in range: index %{public}d -> nodeId %{public}d: SetActive(true)",
126 index, static_cast<int32_t>(frameNode->GetId()));
127 frameNode->SetActive(true);
128 } else {
129 TAG_LOGD(AceLogTag::ACE_REPEAT, "...out of range: index %{public}d -> nodeId %{public}d: SetActive(false)",
130 index, frameNode->GetId());
131 frameNode->SetActive(false);
132 }
133
134 auto totalCount = static_cast<int32_t>(totalCount_);
135 if ((start - cacheStart <= index) && (index <= end + cacheEnd)) {
136 return true;
137 }
138 if (isLoop_) {
139 if (((end < start) && (start - cacheStart <= index || index <= end + cacheEnd)) ||
140 ((start - cacheStart < 0) && (index >= start - cacheStart + totalCount)) ||
141 ((end + cacheEnd >= totalCount) && (index <= end + cacheEnd - totalCount))) {
142 return true;
143 }
144 }
145 return false;
146 }
147
CheckActiveRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd)148 void RepeatVirtualScrollNode::CheckActiveRange(int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd)
149 {
150 // get normalized active range (with positive indices only)
151 const int32_t signed_totalCount = static_cast<int32_t>(totalCount_);
152 int32_t nStart = start - cacheStart;
153 int32_t nEnd = end + cacheEnd;
154 const int32_t divider = 2;
155
156 if (start > end) { // swiper-loop scenario
157 nStart = std::min(nStart, signed_totalCount);
158 nEnd = std::max(nEnd, 0);
159 if (nStart <= nEnd) { // overlapped
160 nStart = signed_totalCount / divider + 1;
161 nEnd = signed_totalCount / divider;
162 }
163 } else {
164 if (nStart >= signed_totalCount || nEnd < 0) {
165 nStart = 0;
166 nEnd = 0;
167 } else {
168 nStart = std::max(nStart, 0);
169 // start <= end <= totalCount - 1
170 nEnd = std::min(std::max(nEnd, nStart), signed_totalCount - 1);
171 }
172 }
173
174 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).DoSetActiveChildRange start: %{public}d - end: %{public}d; "
175 "cacheStart: %{public}d, cacheEnd: %{public}d: ==> keep in L1: %{public}d - %{public}d",
176 static_cast<int32_t>(GetId()), start, end, cacheStart, cacheEnd, nStart, nEnd);
177
178 // memorize active range
179 caches_.SetLastActiveRange(static_cast<uint32_t>(nStart), static_cast<uint32_t>(nEnd));
180
181 // notify TS side
182 onSetActiveRange_(nStart, nEnd);
183 }
184
DropFromL1(const std::string & key)185 void RepeatVirtualScrollNode::DropFromL1(const std::string& key)
186 {
187 RefPtr<UINode> node = caches_.DropFromL1(key);
188 if (node == nullptr) {
189 return;
190 }
191
192 auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
193 if (!frameNode) {
194 frameNode->SetActive(false);
195 }
196 // move active node into L2 cached.
197 // check transition flag.
198 if (node->OnRemoveFromParent(true)) {
199 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
200 RemoveDisappearingChild(node);
201 } else {
202 // else move child into disappearing children, skip syncing render tree
203 AddDisappearingChild(node);
204 }
205
206 UINode::MarkNeedSyncRenderTree(false);
207 children_.clear();
208 // re-assemble children_
209 PostIdleTask();
210 }
211
DoSetActiveChildRange(const std::set<int32_t> & activeItems,const std::set<int32_t> & cachedItems,int32_t baseIndex)212 void RepeatVirtualScrollNode::DoSetActiveChildRange(
213 const std::set<int32_t>& activeItems, const std::set<int32_t>& cachedItems, int32_t baseIndex)
214 {
215 // Notify TS side. Verify line below when DoSetActiveChildRange() will start to be used.
216 // Call onSetActiveRange_ here;
217
218 bool needSync =
219 caches_.RebuildL1([&activeItems, &cachedItems, baseIndex, this](int32_t index, RefPtr<UINode> node) -> bool {
220 if (node == nullptr) {
221 return false;
222 }
223 auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
224 if (!frameNode) {
225 return false;
226 }
227 if (activeItems.find(index + baseIndex) != activeItems.end()) {
228 frameNode->SetActive(true);
229 return true;
230 } else {
231 frameNode->SetActive(false);
232 }
233 if (cachedItems.find(index + baseIndex) != cachedItems.end()) {
234 return true;
235 }
236 if (node->OnRemoveFromParent(true)) {
237 RemoveDisappearingChild(node);
238 } else {
239 AddDisappearingChild(node);
240 }
241 return false;
242 });
243 if (needSync) {
244 UINode::MarkNeedSyncRenderTree(false);
245 children_.clear();
246 PostIdleTask();
247 }
248 }
249
UpdateRenderState(bool visibleItemsChanged)250 void RepeatVirtualScrollNode::UpdateRenderState(bool visibleItemsChanged)
251 {
252 TAG_LOGD(AceLogTag::ACE_REPEAT,
253 "UpdateRenderState triggered by Repeat rerender: nodeId: %{public}d, visibleItemsChanged: %{public}d",
254 static_cast<int32_t>(GetId()), visibleItemsChanged);
255
256 if (visibleItemsChanged) {
257 // empty the cache index -> key
258 // C++ will need to ask all new keys from JS side
259 caches_.InvalidateKeyAndTTypeCaches();
260 children_.clear();
261
262 if (auto frameNode = GetParentFrameNode()) {
263 frameNode->ChildrenUpdatedFrom(0);
264 }
265 } else {
266 auto lastIndexInActiveRange = caches_.GetLastActiveRange().second;
267 TAG_LOGD(AceLogTag::ACE_REPEAT, "lastIndexInActiveRange:%{public}d", lastIndexInActiveRange);
268
269 if (auto frameNode = GetParentFrameNode()) {
270 frameNode->ChildrenUpdatedFrom(lastIndexInActiveRange + 1);
271 }
272 }
273
274 MarkNeedSyncRenderTree(true);
275 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT | PROPERTY_UPDATE_BY_CHILD_REQUEST);
276 }
277
278 // STATE_MGMT_NOTE: added
279 // index N-th item
280 // needBuild: true - if found in cache, then return, if not in cache then return newly build
281 // false: - if found in cache, then return, if not found in cache then return nullptr
282 // isCache: true indicates prebuild item (only used by List/Grid/Waterflow, this item should go to L2 cache,
283 // do not add to the tree,
284 // isCache==false this item is for display or near display area
285 // addToRenderTree: true - set it to active state, call SetActive
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)286 RefPtr<UINode> RepeatVirtualScrollNode::GetFrameChildByIndex(
287 uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
288 {
289 TAG_LOGD(AceLogTag::ACE_REPEAT, "index:%{public}d", static_cast<int32_t>(index));
290
291 ACE_SCOPED_TRACE("Repeat.GetFrameChildByIndex index[%d], needBuild[%d] isCache[%d] "
292 "addToRenderTree[%d]",
293 index, static_cast<int32_t>(needBuild), static_cast<int32_t>(isCache), static_cast<int32_t>(addToRenderTree));
294
295 // whether child is reused or created
296 bool isChildReused = true;
297
298 const auto& key = caches_.GetKey4Index(index, true);
299 if (!key) {
300 TAG_LOGE(AceLogTag::ACE_REPEAT, "fail to get key for %{public}d", index);
301 return nullptr;
302 }
303
304 TAG_LOGD(AceLogTag::ACE_REPEAT,
305 "nodeId: %{public}d: GetFrameChildByIndex(index: %{public}d, "
306 "key %{public}s, needBuild: %{public}d, isCache: %{public}d, "
307 "addToRenderTree: %{public}d) ...", static_cast<int32_t>(GetId()),
308 static_cast<int32_t>(index), key->c_str(), static_cast<int32_t>(needBuild),
309 static_cast<int32_t>(isCache), static_cast<int32_t>(addToRenderTree));
310
311 // search if index -> key -> Node exist
312 // will update the same key item if needs.
313 auto node4Index = GetFromCaches(index);
314 if (!node4Index && !needBuild) {
315 TAG_LOGD(AceLogTag::ACE_REPEAT,
316 "index %{public}d -> key '%{public}s' not in caches && needBuild==false, "
317 "GetFrameChildByIndex returns nullptr .",
318 static_cast<int32_t>(index), key->c_str());
319 return nullptr;
320 }
321
322 // node4Index needs to be created or updated on JS side
323 if (!node4Index) {
324 TAG_LOGD(AceLogTag::ACE_REPEAT,
325 "index %{public}d -> key '%{public}s' not in caches && needBuild==true, calling "
326 "CreateOrUpdateFrameChild4Index ....",
327 static_cast<int32_t>(index), key->c_str());
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