HarmonyOS鸿蒙Next中IDatasource和List、LazyForeach的使用
HarmonyOS鸿蒙Next中IDatasource和List、LazyForeach的使用
基本信息
// BasicDataSource实现了IDataSource接口,用于管理listener监听,以及通知LazyForEach数据更新
class BasicDataSource<T> implements IDataSource {
private listeners: DataChangeListener[] = [];
public totalCount(): number {
return 0
}
public getData(index: number): T | undefined {
return undefined
}
// 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener);
}
}
// 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1);
}
}
// 通知LazyForEach组件需要重载所有子组件
notifyDataReload(): void {
this.listeners.forEach(listener => {
// listener.onDataReloaded();
// 写法2:listener.onDatasetChange([{ type: DataOperationType.RELOAD }])
listener.onDatasetChange([{ type: DataOperationType.RELOAD }])
});
}
// 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
// listener.onDataChange(index);
// 写法2:listener.onDatasetChange([{type: DataOperationType.CHANGE, index: index}]);
listener.onDatasetChange([{ type: DataOperationType.CHANGE, index: index }]);
});
}
// 通知LazyForEach组件需要在index对应索引处添加子组件
notifyDataAdd(index: number, count: number): void {
this.listeners.forEach(listener => {
// listener.onDataAdd(index);
// 写法2:listener.onDatasetChange([{type: DataOperationType.ADD, index: index}]);
listener.onDatasetChange([{ type: DataOperationType.ADD, index: index, count: count }]);
});
}
// 通知LazyForEach组件需要在index对应索引处删除该子组件
notifyDataDelete(index: number, count: number): void {
this.listeners.forEach(listener => {
// listener.onDataDelete(index);
// 写法2:listener.onDatasetChange([{type: DataOperationType.DELETE, index: index}]);
listener.onDatasetChange([{ type: DataOperationType.DELETE, index: index, count: count }]);
});
}
// 通知LazyForEach组件将from索引和to索引处的子组件进行交换
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
// listener.onDataMove(from, to);
// 写法2:listener.onDatasetChange([{type: DataOperationType.EXCHANGE, index: {start: from, end: to}}]);
listener.onDatasetChange([{ type: DataOperationType.EXCHANGE, index: { start: from, end: to } }]);
});
}
}
@ObservedV2
export default class LazyDataSource<T> extends BasicDataSource<T> {
dataArray: T[] = []
// 列表数量
public totalCount(): number {
return this.dataArray.length;
}
// 获取某一项
public getData(index: number): T {
return this.dataArray[index];
}
//获取列表数据
public getDataList(): T[] {
return this.dataArray;
}
// 修改数据
public setData(index: number, data: T): void {
this.dataArray[index] = data
this.notifyDataChange(index)
}
//列表尾部添加数据
public pushData(data: T): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1, 1);
}
// 根据索引添加数据
public addData(index: number, data: T): void {
this.dataArray.splice(index, 0, data);
this.notifyDataAdd(index, 1)
}
// 根据索引添加数据
public addBatch(index: number, data: T[]): void {
this.dataArray.splice(index, 0, ...data);
this.notifyDataAdd(index, data.length);
}
// 添加
public pushAll(newData: T[]): void {
this.dataArray.push(...newData)
this.notifyDataAdd(this.dataArray.length - 1, newData.length)
}
// 删除
public deleteData(index: number): void {
this.dataArray.splice(index, 1);
this.notifyDataDelete(index, 1)
}
// 批量删除
public deleteBatch(index: number, count: number): void {
this.dataArray.splice(index, count);
this.notifyDataDelete(index, count);
}
// 刷新数据
public refreshData(newData: T[]): void {
this.dataArray = newData;
this.notifyDataReload();
}
}
@ObservedV2
export default class Item {
@Trace id: string = "";
@Trace name: string = "";
}
List({ scroller: this.elementsScroller }) {
LazyForEach(this.datasource, (item: Item, index) => {
ListItem() {
Flex() {
Flex({
direction: FlexDirection.Row,
justifyContent: FlexAlign.SpaceBetween,
alignItems: ItemAlign.Center
}) {
Text(item.id)
.height(50)
.fontColor('#7082a7')
.fontSize(20)
.width('30%')
.textAlign(TextAlign.Start)
.padding({ left: 5 })
.borderWidth({ right: 1 })
.borderColor('#b2b9d1')
Text(item.name)
.height(50)
.fontColor('#7082a7')
.fontSize(20)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.padding({ left: 5 })
.layoutWeight(1)
}
}
}
}, (item: Item, index) => item.id)
}
.height(FULL_PERCENT)
问题1:在中间某个位置插入、删除后,LazyForeach第二个参数中的index没有变化。LazyForeach第三个参数key为元素的唯一id。
问题2:refreshData方法,会让Scroller处于底部,会出现list组件滑动不了的情况
更多关于HarmonyOS鸿蒙Next中IDatasource和List、LazyForeach的使用的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS鸿蒙Next中IDatasource和List、LazyForeach的使用的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
- 名称: 示例名称
- 描述: 这是一个示例描述,用于展示如何将HTML转换为Markdown格式。
- 类型: 示例类型
- 状态: 活动
- 创建日期: 2023-10-01
- 更新日期: 2023-10-02
(item: Item) => item.id)
这里也去掉index
// 刷新数据
public refreshData(newData: T[]): void {
this.dataArray.length = 1; //先清空
this.dataArray = newData;
this.notifyDataReload();
}
在HarmonyOS Next中,IDataSource是数据源接口,用于为LazyForEach提供数据。List是数据容器,存储要展示的项目集合。LazyForEach是懒加载组件,仅在项目可见时构建对应组件,提升列表性能。
使用步骤:
- 实现IDataSource接口,重写totalCount()和getData()方法
- 创建包含数据的List对象
- 在UI中使用LazyForEach,绑定数据源和项构建函数
示例代码片段:
class MyDataSource implements IDataSource {
private dataList: string[] = ['a', 'b', 'c']
totalCount(): number { return this.dataList.length }
getData(index: number): string { return this.dataList[index] }
}
@Entry
@Component
struct MyComponent {
private data = new MyDataSource()
build() {
LazyForEach(this.data, (item: string) => {
Text(item)
})
}
}
关于问题1:LazyForEach的index参数在数据源变更时不会自动更新,这是预期行为。index仅表示当前渲染时的位置索引,当数据源中间插入/删除数据时,后续项的index不会自动调整。正确的做法是始终使用数据项的唯一id(key)来标识组件,而不是依赖index参数。
关于问题2:refreshData后Scroller位置异常的问题,这是已知的性能优化场景。建议在调用refreshData前记录当前滚动位置,刷新后通过scroller.scrollToIndex恢复位置。示例代码:
// 刷新前记录位置
let firstVisibleIndex = this.elementsScroller.currentOffset().y / itemHeight;
this.datasource.refreshData(newData);
// 刷新后恢复位置
this.elementsScroller.scrollToIndex(firstVisibleIndex);
对于数据源实现,注意到示例中使用了onDatasetChange的统一通知方式,这是推荐的写法。但需要注意在批量操作时(如addBatch)要正确传递count参数,否则可能导致渲染异常。