1. 背景
在使用Repeat+virtualScroll+image 的时候,滑动列表到第二屏的时候会发现Image 的alt 失效,先展示的是上一屏的图片,然后才会展示最新的图片,效果如下
代码如下
@Entry
@ComponentV2
struct Index {
@Local dataSource: Array<string> = []
aboutToAppear(): void {
for (let i = 0; i < 1000; i++) {
this.dataSource.push(`https://placehold.co/400x300/orange/white/png?text=testimage_${i}`)
}
}
build() {
Column() {
WaterFlow() {
Repeat(this.dataSource)
.virtualScroll()
.each(() => {
})
.key((item) => {
return item
})
.templateId((item) => {
return 'templateImage'
})
.template("templateImage", (ri) => {
Image(ri.item)
.width('100%')
.alt($r('app.media.ic_placeholder_400x300'))
.aspectRatio(4 / 3)
}, { cachedCount: 10 })
}
.width('100%')
.height('100%')
.cachedCount(0)
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(3)
.rowsGap(3)
}
}
}
1.1 问题原因
和行业内的大佬沟通,发现这个问题其实在2024年11月左右就已经存在了,原因是image的问题,没有适配好repeat,导致alt 在Repeat virtualScroll image 复用的情况下无效,加载新的图片时,展示的还是上一次src的图片。
1.2 解决办法
既然是复用,那么可以在封装一个自定义image组件,内部监听src的变化,如果变化,则重新生成一个新的image 让image重复上下树
下面是解决后的效果
下面是解决代码
@Entry
@ComponentV2
struct Index {
@Local dataSource: Array<string> = []
aboutToAppear(): void {
for (let i = 0; i < 1000; i++) {
this.dataSource.push(`https://placehold.co/400x300/orange/white/png?text=testimage_${i}`)
}
}
build() {
Column() {
WaterFlow() {
Repeat(this.dataSource)
.virtualScroll()
.each(() => {
})
.key((item) => {
return item
})
.templateId((item) => {
return 'templateImage'
})
.template("templateImage", (ri) => {
RepeatImageV2({
src: ri.item,
attribute: {
alt: $r('app.media.ic_placeholder_400x300')
}
})
.width('100%')
.aspectRatio(4 / 3)
}, { cachedCount: 10 })
}
.width('100%')
.height('100%')
.cachedCount(0)
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(3)
.rowsGap(3)
}
}
}
@ComponentV2
export struct RepeatImageV2 {
@Param @Require src: PixelMap | ResourceStr | DrawableDescriptor
@Param attribute: ZZImageModifier = {};
@Local isAppear: boolean = false
build() {
if (this.isAppear) {
this.imageContent()
} else {
this.imageContent()
}
}
@Builder
imageContent() {
Image(this.src)
.draggable(false)
.alt(this.attribute?.alt)
.objectFit(this.attribute?.objectFit)
.borderRadius(this.attribute?.borderRadius)
.borderColor(this.attribute?.borderColor)
.width('100%')
.height('100%')
}
@Monitor("src")
updateImageSrc() {
this.isAppear = !this.isAppear;
}
}
export interface ZZImageModifier {
objectFit?: ImageFit
alt?: string | Resource | PixelMap
borderRadius?: Length | BorderRadiuses | LocalizedBorderRadiuses
borderColor?: ResourceColor | EdgeColors | LocalizedEdgeColors
}