HarmonyOS tabs滑动出现延迟显示?

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  @State mis: string[] = ["1", "2", "3", "4", "5"];
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController();
  @State misTabsIndex: number = 0;
  @State fontColor: string = '#182431'
  @State selectedFontColor: string = '#007DFF'

  @Builder tabBuilder(index: number, name: string) {
    Column() {
      Text(name)
        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
        .fontSize(16)
        .fontWeight(this.currentIndex === index ? 500 : 400)
        .lineHeight(22)
        .margin({ top: 17, bottom: 7 })
      Divider()
        .strokeWidth(2)
        .color('#007DFF')
        .opacity(this.currentIndex === index ? 1 : 0)
    }.width('100%')
  }

  build() {
    RelativeContainer() {
      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
        ForEach(this.mis, (str: string, inx) => {
          TabContent() {
            if (this.currentIndex == inx) {
              Column(){
                Text(str)
              }
              .width("100%")
              .height("100%")
              .backgroundColor(Color.White)
            }
          }
          .tabBar(this.tabBuilder(inx, 'green'))
          .onWillShow(() => {
            console.info("1234")
          })
        }, (str: string) => JSON.stringify(str))
      }
      .onChange((index)=>{
        this.currentIndex = index
      })
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#f4f4f4")
  }
}

TabContent进行循环显示,滑动导致出现短暂的空白,头部和TabContent中的内容延迟显示,请问怎么解决

阅读 460
1 个回答

这边有个demo,您可以尝试下

新增的onAnimationStart、onAnimationEnd和onGestureSwipe事件,本地测试不会感知到明显的延迟,

demo如下:

import ComponentUtils from '@ohos.arkui.UIContext';

@Entry
@Component
export default struct Index {
  message: string = '通讯录'
  @State selectedFontColor: string = '#007DFF'
  @State fontColor: string = '#182431'
  @State currentPosition: number = 0
  // @Prop @Watch ('onRefresh') currentIndex: number
  private tabsController: TabsController = new TabsController()
  @State animationDuration: number = 300
  @State indicatorLeftMargin: number = 0
  @State indicatorWidth: number = 0
  @State currentIndex: number = 0
  private tabsWidth: number = 0
  private componentUtils: ComponentUtils.ComponentUtils = this.getUIContext().getComponentUtils()

  @Builder
  TabBuilder(index: number, name: ESObject) {
    Column() {
      Row() {
        Text(name)
          .fontColor(this.currentPosition === index ? this.selectedFontColor : this.fontColor)
          .fontSize(16)
          .fontWeight(this.currentPosition === index ? 600 : 400)
          .lineHeight(22)
          .margin({ top: 5, bottom: 5, left: 2 })
      }.width('95%').backgroundColor(this.currentPosition === index ? '#ffffff' : null).borderRadius(15)
    }.height('50%')
  }

  build() {
    Column() {

      Column() {
        Tabs({ barPosition: BarPosition.Start, index: this.currentPosition, controller: this.tabsController }) {
          TabContent() {
            Text('1111').fontSize(14)
          }.tabBar(this.TabBuilder(0, '最近联系人'))

          TabContent() {
            Text('2222').fontSize(14)
          }.tabBar(this.TabBuilder(1, '关注联系人'))

          TabContent() {
            Text('3333').fontSize(14)
          }.tabBar(this.TabBuilder(2, '我的群组'))

        }
        .vertical(false)
        .barMode(BarMode.Fixed)
        // .barWidth(360)
        .barHeight(65)
        .padding({ bottom: 15 })
        .onChange((index: number) => {
          this.currentPosition = index
        })
        .width('100%')
        .animationDuration(this.animationDuration)
        .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
          // 切换动画开始时触发该回调。下划线跟着页面一起滑动,同时宽度渐变。
          this.currentPosition = targetIndex
          let targetIndexInfo = this.getTextInfo(targetIndex)
          this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width)
        })
        .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
          // 切换动画结束时触发该回调。下划线动画停止。
          let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
          this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width)
        })
        .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
          // 在页面跟手滑动过程中,逐帧触发该回调。
          let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
          this.currentIndex = currentIndicatorInfo.index
          this.indicatorLeftMargin = currentIndicatorInfo.left
          this.indicatorWidth = currentIndicatorInfo.width
        })
      }
      .width('100%')
      .height('100%')
      .align(Alignment.TopStart)

      // .padding({top:20})
    }.width('100%').height('100%')
    .backgroundImageSize(ImageSize.Cover)
  }

  private getTextInfo(index: number): Record<string, number> {
    let rectangle = this.componentUtils.getRectangleById(index.toString())
    return { 'left': px2vp(rectangle.windowOffset.x), 'width': px2vp(rectangle.size.width) }
  }

  private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
    let nextIndex = index
    if (index > 0 && event.currentOffset > 0) {
      nextIndex--
    } else if (index < 3 && event.currentOffset < 0) {
      nextIndex++
    }
    let indexInfo = this.getTextInfo(index)
    let nextIndexInfo = this.getTextInfo(nextIndex)
    let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth)
    let currentIndex = swipeRatio > 0.5 ? nextIndex : index // 页面滑动超过一半,tabBar切换到下一页。
    let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio
    let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio
    return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth }
  }

  private startAnimateTo(duration: number, leftMargin: number, width: number) {
    animateTo({
      duration: duration, // 动画时长
      curve: Curve.Linear, // 动画曲线
      iterations: 1, // 播放次数
      playMode: PlayMode.Normal, // 动画模式
      onFinish: () => {
        console.info('play end')
      }
    }, () => {
      this.indicatorLeftMargin = leftMargin
      this.indicatorWidth = width
    })
  }
}

文档链接:

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-tabs-V5\#事件

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进