目录

左右滑动图片切换时文字没有跟随图片同步更新

问题现象

左右滑动图片列表切换时,图片跟随手指移动距离进行切换,但图片上方的文字直到页面切换完成后才更新,有延迟。

背景知识

问题定位

  1. 使用ArkUI Inspector抓取应用布局组件树,查看图片列表和上方文字相应的组件,发现图片列表是采用Swiper组件实现,而上方的文字则是Text组件,两者均为Stack组件的子组件,Text组件覆盖在Swiper组件上。
  2. 使用DevEco Profiler Frame分析工具抓取该过程的Trace信息,搜索H:APP_SWIPER_SCROLL和H:APP_SWIPER_FLING确定图片滑动切换阶段如下所示。

    在上方搜索框中搜索文本组件渲染任务执行的Trace点H:FrameNode[Text][id:3147]::RenderTask,发现是在图片滑动切换完成之后,可知是在图片切换完成后才更新文字,导致文字更新有延迟。

分析结论

在图片切换完成之后更新文字,导致在图片切换过程时文字没有变化,更新不同步,有延迟。

修改建议

可将图片和文字作为整体,当左右滑动切换图片时,文字可随图片同步切换。

import { image } from '@kit.ImageKit';

class SwiperItemData {
  content: string = ''; // 文本内容

  image: image.PixelMap | ResourceStr | DrawableDescriptor = ''; // 图片

  constructor(content: string, image: image.PixelMap | ResourceStr | DrawableDescriptor) {
    this.content = content;
    this.image = image;
  }
}

class SwiperItemDataSource implements IDataSource {
  private dataArray: SwiperItemData[] = [];

  private listeners: DataChangeListener[] = [];

  totalCount(): number {
    return this.dataArray.length;
  }

  getData(index: number): SwiperItemData {
    return this.dataArray[index];
  }

  addData(data: SwiperItemData): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    this.listeners.push(listener);
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    let index = this.listeners.indexOf(listener);
    if (index >= 0) {
      this.listeners.splice(index, 1);
    }
  }

  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    });
  }
}

@Entry
@Component
struct ImageTextDemoPage {
  private swiperController: SwiperController = new SwiperController();

  private swiperItemDataSource: SwiperItemDataSource = new SwiperItemDataSource();

  initPageData(): void {
    // 测试需要替换成可引用到的资源
    let data1 = new SwiperItemData('页面1', $r('app.media.picture1'));
    let data2 = new SwiperItemData('页面2', $r('app.media.picture2'));
    let data3 = new SwiperItemData('页面3', $r('app.media.picture3'));
    let data4 = new SwiperItemData('页面4', $r('app.media.picture4'));
    let data5 = new SwiperItemData('页面5', $r('app.media.picture5'));
    let data6 = new SwiperItemData('页面6', $r('app.media.picture6'));
    this.swiperItemDataSource.addData(data1);
    this.swiperItemDataSource.addData(data2);
    this.swiperItemDataSource.addData(data3);
    this.swiperItemDataSource.addData(data4);
    this.swiperItemDataSource.addData(data5);
    this.swiperItemDataSource.addData(data6);
  }

  aboutToAppear(): void {
    this.initPageData();
  }

  @Builder
  itemBuilder(data: SwiperItemData) {
    Stack() {
      Image(data.image) // 图片
        .width('100%')
        .height('100%')
      Text(data.content) // 文本内容
        .fontSize(25)
        .fontColor(Color.White)
    }
  }

  build() {
    Swiper(this.swiperController) {
      LazyForEach(this.swiperItemDataSource, (item: SwiperItemData) => {
        this.itemBuilder(item);
      })
    }
    .autoPlay(false)
    .cachedCount(2)
    .loop(false)
    .indicator(false)
    .height('100%')
    .width('100%')
  }
}