【HarmonyOS NEXT】解决Repeat复用导致Image加载图片展示的是上一张图片的问题

1. 背景

在使用Repeat+virtualScroll+image 的时候,滑动列表到第二屏的时候会发现Image 的alt 失效,先展示的是上一屏的图片,然后才会展示最新的图片,效果如下

代码如下

typescript 复制代码
@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重复上下树

下面是解决后的效果

下面是解决代码

typescript 复制代码
@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
}
相关推荐
Tom4i16 分钟前
Android 系统的进程模型
android
介一安全18 分钟前
【Frida Android】基础篇9:Java层Hook基础——Hook构造函数
android·网络安全·逆向·安全性测试·frida
杨筱毅21 分钟前
【Android】Compose绘制系统 VS 传统View绘制系统
android
介一安全21 分钟前
【Frida Android】基础篇10:Native层Hook基础--普通 Hook
android·网络安全·逆向·安全性测试·frida
飞翔的佩奇22 分钟前
【完整源码+数据集+部署教程】【天线&水】舰船战舰检测与分类图像分割系统源码&数据集全套:改进yolo11-repvit
前端·python·yolo·计算机视觉·数据集·yolo11·舰船战舰检测与分类图像分割系统
哆啦A梦15881 小时前
点击Top切换数据
前端·javascript·vue.js
位步2 小时前
在linux系统中使用通用包安装 Mysql
android·linux·mysql
程序猿追2 小时前
Vue组件化开发
前端·html
艾德金的溪2 小时前
redis-7.4.6部署安装
前端·数据库·redis·缓存
小光学长2 小时前
基于Vue的2025年哈尔滨亚冬会志愿者管理系统5zqg6m36(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js