diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/repeat.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/repeat.ts index ac443e515fd7fd71613ffb69be7b6b6c355d2bd3..5be8e11068ef93cd1d4e3d66c9feb484467e79a1 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/repeat.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/repeat.ts @@ -33,7 +33,9 @@ export type TemplateTypedFunc = (item: T, index: number) => string; export interface VirtualScrollOptions { totalCount?: number; reusable?: boolean; + onLazyLoading?: (index: number) => void; onTotalCount?: () => number; + disableVirtualScroll?: boolean; } export interface TemplateOptions { diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/RepeatImpl.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/RepeatImpl.ts index 2d2775314496abf5c74da76cdd97eacec68802f8..c442f5a52a3228b4b184e8197aef83d07074329d 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/RepeatImpl.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/RepeatImpl.ts @@ -38,15 +38,15 @@ export function RepeatImpl( if (!repeat.itemGenFuncs_.get(RepeatEachFuncType)) { throw new Error('Repeat item builder function unspecified. Usage error!'); } - if (repeat.isVirtualScroll_) { + if (repeat.disableVirtualScroll_) { + nonVirtualRender(arr, repeat.itemGenFuncs_.get(RepeatEachFuncType)!, repeat.keyGenFunc_); + } else { const repeatId = __id(); const node = contextNode(); scheduleCallback(() => // postpone until node is attached repeat.templateCacheSize_.forEach((size: number, template: string) => node.setReusePoolSize(size, template + repeatId)) ); virtualRender(arr, repeat, repeatId); - } else { - nonVirtualRender(arr, repeat.itemGenFuncs_.get(RepeatEachFuncType)!, repeat.keyGenFunc_); } } @@ -80,6 +80,7 @@ class RepeatDataSource implements IDataSource { private arr_: RepeatArray; private listener_?: InternalListener; private total_: number; + private onLazyLoading_?: (index: number) => void; constructor(arr: RepeatArray) { this.arr_ = arr; @@ -112,12 +113,23 @@ class RepeatDataSource implements IDataSource { } getData(index: number): T { - if (index < 0 || index >= this.arr_.length) { + if (index < 0 || index >= this.total_) { throw new Error('index out of range. Application error!'); } + if (index >= this.arr_.length && index < this.total_) { + try { + this.onLazyLoading_?.(index); + } catch (error) { + console.error(`onLazyLoading function execute error: ${error}`); + } + } return this.arr_[index]; } + setOnLazyLoading(onLazyLoading?: (index: number) => void): void { + this.onLazyLoading_ = onLazyLoading; + } + registerDataChangeListener(listener: DataChangeListener): void { if (listener instanceof InternalListener) this.listener_ = listener as InternalListener; @@ -137,11 +149,14 @@ const RepeatEachFuncType: string = ''; export class RepeatAttributeImpl implements RepeatAttribute { itemGenFuncs_: Map> = new Map>(); keyGenFunc_?: (item: T, index: number) => string; - userDefinedTotal_?: number; - templateCacheSize_: Map = new Map(); + templateCacheSize_: Map = new Map(); // size of spare nodes for each template ttypeGenFunc_: TemplateTypedFunc = () => RepeatEachFuncType; + + userDefinedTotal_?: number; // if totalCount is specified + onLazyLoading_?: (index: number) => void; + reusable_: boolean = false; - isVirtualScroll_: boolean = false; + disableVirtualScroll_: boolean = false; each(itemGenerator: RepeatItemBuilder): RepeatAttributeImpl { if (itemGenerator === undefined || typeof itemGenerator !== 'function') { @@ -160,8 +175,9 @@ export class RepeatAttributeImpl implements RepeatAttribute { virtualScroll(options?: VirtualScrollOptions): RepeatAttributeImpl { this.userDefinedTotal_ = options?.onTotalCount?.() ?? options?.totalCount; this.reusable_ = options?.reusable !== false; + this.onLazyLoading_ = options?.onLazyLoading; - this.isVirtualScroll_ = true; + this.disableVirtualScroll_ = options?.disableVirtualScroll ?? false; return this; } @@ -192,6 +208,11 @@ function virtualRender( ): void { let dataSource = remember(() => new RepeatDataSource(arr)); dataSource.updateData(arr, attributes.userDefinedTotal_ ?? arr.length); + if (!attributes.onLazyLoading_ && dataSource.totalCount() > arr.length) { + console.error(`(${repeatId}) totalCount must not exceed the array length without onLazyLoading callback.`); + } + dataSource.setOnLazyLoading(attributes.onLazyLoading_); + /** @memo */ const itemGen = (item: T, index: number): void => { const ri = new RepeatItemImpl(item, index); diff --git a/frameworks/core/components_ng/base/lazy_compose_adapter.cpp b/frameworks/core/components_ng/base/lazy_compose_adapter.cpp index be4fffff796b1a8c95837e11c5aaa8513bef31be..83a78c9494c767348aea68ef56ca34d60896c477 100644 --- a/frameworks/core/components_ng/base/lazy_compose_adapter.cpp +++ b/frameworks/core/components_ng/base/lazy_compose_adapter.cpp @@ -36,9 +36,14 @@ RefPtr LazyComposeAdapter::GetChild(uint32_t index) void LazyComposeAdapter::SetActiveRange(int32_t start, int32_t end) { + if (start == activeStart_ && end == activeEnd_) { + return; + } if (updateRange_) { updateRange_(start, end); } + activeStart_ = start; + activeEnd_ = end; items_.RemoveIf([start, end](const uint32_t& k, const auto& _) { const auto idx = static_cast(k); diff --git a/frameworks/core/components_ng/base/lazy_compose_adapter.h b/frameworks/core/components_ng/base/lazy_compose_adapter.h index b2f453342458c92c4ddcd713fc63ea6117615872..fb4a3f5add0672de23fa5fc8063f27b0578b44be 100644 --- a/frameworks/core/components_ng/base/lazy_compose_adapter.h +++ b/frameworks/core/components_ng/base/lazy_compose_adapter.h @@ -59,6 +59,8 @@ private: CreateItemCb createItem_; UpdateRangeCb updateRange_; int32_t totalCount_ = 0; + int32_t activeStart_ = -1; + int32_t activeEnd_ = -1; }; } // namespace OHOS::Ace::NG #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_LAZY_COMPOSE_ADAPTER_H