HarmonyOS鸿蒙Next中List的父/祖父组件是Scroll组件,List的maintainVisibleContentPosition(true)属性失效?
HarmonyOS鸿蒙Next中List的父/祖父组件是Scroll组件,List的maintainVisibleContentPosition(true)属性失效?
const PAGE_SIZE = 20;
@Component
struct ListPage {
readonly listData: BaseDataSource<ItemData> = new BaseDataSource()
page = 10
aboutToAppear(): void {
const firstData = getData(this.page * PAGE_SIZE, PAGE_SIZE)
this.listData.array.push(...firstData)
}
build() {
Column() {
Button('添加上一页的数据').onClick(() => {
if (this.page >= 0) {
const list = getData((--this.page) * PAGE_SIZE, PAGE_SIZE)
this.listData.array.splice(0, 0, ...list)
this.listData.notifyDatasetChange([{
type: DataOperationType.ADD,
index: 0,
count: list.length,
key: list.map(item => item.name)
}])
}
})
//Scroll () {
Column() {
List() {
LazyForEach(this.listData, (item: ItemData) => {
ListItem() {
this.listItem(item)
}
}, (item: ItemData) => item.name)
}.width('100%').padding(15)
.maintainVisibleContentPosition(true)
}
//}
}.width('100%')
.height('100%')
}
}
export function getData(start: number, count: number): Array<ItemData> {
const arr: Array<ItemData> = []
for (let i = 0; i < count; i++) {
arr.push(new ItemData(`id = ${i + start}`))
}
return arr
}
把父组件Scroll去掉,然后点击按钮添加上一页的数据,可见内容位置是不变的, 然后把父组件Scroll加上,点击按钮钮添加上一页的数据,List就自动滑动到顶部。这个是bug吗?
更多关于HarmonyOS鸿蒙Next中List的父/祖父组件是Scroll组件,List的maintainVisibleContentPosition(true)属性失效?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【背景知识】
-
maintainVisibleContentPosition
:设置显示区域上方插入或删除数据时是否要保持可见内容位置不变。只有使用LazyForEach在显示区域外插入或删除数据时,才能保持可见内容位置不变。设置为true后,在显示区域上方插入或删除数据,会触发onDidScroll
、onScrollIndex
事件。详见接口说明。 -
Scroll嵌套List导致按需加载失效
:当Scroll容器嵌套List组件加载长列表时,若不指定List的宽高尺寸,则默认加载全部ListItem,导致按需加载失效,甚至会导致应用卡顿、崩溃,详细案例可参考布局优化指导。
【问题定位】
-
样例代码中Scroll内的List组件仅指定了宽度,并未指定高度,而根据背景知识第二条可知,如果不指定List宽高尺寸,则会默认加载全部ListItem,因此怀疑是未指定高度使得List重新加载,导致可视区域数据变化。
-
指定内层List组件高度为500,验证点击按钮加载新数据后,可视区域数据未发生变化。
【分析结论】
Scroll内层的List组件未明确指定宽高,导致新数据加载后触发了ListItem的重新加载,使得现象与maintainVisibleContentPosition(true)
失效一致。
【修改建议】 给内层List组件显式指定明确宽高,示例代码如下:
Scroll() {
Column() {
List() {
LazyForEach(this.listData, (item: ItemData) => {
ListItem() {
Text(item.name).width('100%').height(20)
}
}, (item: ItemData) => item.name)
}
.width('100%')
.height(500)
.padding(15)
.maintainVisibleContentPosition(true)
}
}
【常见FAQ】
Q:maintainVisibleContentPosition
这个属性不支持Repeat吗?
A:Repeat
的功能是基于数组类型数据来进行循环渲染,一般与容器组件配合使用。而maintainVisibleContentPosition
是UI组件的属性,其使用方法与说明可参考maintainVisibleContentPosition。
更多关于HarmonyOS鸿蒙Next中List的父/祖父组件是Scroll组件,List的maintainVisibleContentPosition(true)属性失效?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
maintainVisibleContentPosition 这个属性不支持Repeat吗?
Button('添加上一页的数据').onClick(() => {
if (this.page >= 0) {
const list = getData((--this.page) * PAGE_SIZE, PAGE_SIZE)
this.array.splice(0, 0, ...list)
}
})
List() {
Repeat(this.array)
.each((riItemData) => {
this.listItemV2(riItemData)
})
.key((item) => item.name)
}.width('100%').padding(15)
.maintainVisibleContentPosition(true)
我换成Repeat,list外面也没Scroll,点击按钮内容还是自动向上滑动。
只有使用LazyForEach在显示区域外插入或删除数据时,才能保持可见内容位置不变
貌似不支持Repeat🤣,
在HarmonyOS Next中,当List的父/祖父组件是Scroll时,maintainVisibleContentPosition(true)会失效。这是因为Scroll和List的滚动机制存在冲突,两者都试图控制滚动位置保持逻辑。该属性仅在List作为唯一滚动容器时生效。解决方案是将List作为顶级滚动容器,避免嵌套Scroll组件。华为官方文档已确认该限制。
在HarmonyOS Next中,当List组件被嵌套在Scroll组件内时,maintainVisibleContentPosition
属性确实可能会失效。这是因为Scroll组件本身也是一个可滚动容器,它会接管滚动位置的维护逻辑,导致List组件内部的这个属性无法正常工作。
这不是一个bug,而是预期的行为设计。当存在多层滚动容器嵌套时,系统会优先处理最外层滚动容器的行为。要解决这个问题,可以考虑以下方案:
-
移除外层的Scroll组件,因为List本身已经是一个可滚动容器
-
如果需要保留Scroll容器,可以尝试通过编程方式记录和恢复滚动位置:
let scrollOffset = 0;
Scroll() {
Column() {
List() {
// ...
}
.onScroll((offset: number) => {
scrollOffset = offset;
})
}
}
// 在添加数据后恢复位置
this.listData.notifyDatasetChange([...]);
this.scroller.scrollTo({offset: scrollOffset});
- 或者考虑重新设计布局,避免不必要的滚动容器嵌套
这种设计是为了确保滚动行为的一致性,特别是在复杂嵌套布局中。开发者需要根据实际场景选择合适的解决方案。