HarmonyOS 鸿蒙Next 两个list使用scrolltoindex失效

发布于 1周前 作者 itying888 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 两个list使用scrolltoindex失效

两个list滑动,形成父子关系,共用一个二维数组,父list点击事件,触发两个scrollertoindex, 子组件更新,但是不会滑动,偶尔会划过去,有什么解决方案吗?

9 回复

参考一下这个:

[@Entry](/user/Entry)
[@Component](/user/Component)
struct Page2 {
 [@State](/user/State) messageArr: string[] = ['1', '2', '3', '4', '5', '6', '7']
 scroller: Scroller = new Scroller()
 [@State](/user/State) currentIndex: number = 1
 scroller2: Scroller = new Scroller()

 build() {
   Column() {
     List({ initialIndex: 1, scroller: this.scroller }) {
       ListItem() {
         Column() {
           Text('second floor')
           Button('to index 1').onClick(() => {
             this.scroller.scrollToIndex(1, true, ScrollAlign.CENTER)
           })
         }
       }
       .height('100%')
       .width('100%')
       .backgroundColor(Color.Grey)

       ListItem() {
         Column() {
           Row() {
             Text('点击操作').onClick(() => {
               this.scroller.scrollToIndex(0, true, ScrollAlign.CENTER)
               this.scroller2.scrollToIndex(0, true, ScrollAlign.CENTER)
             })
           }
           .height(100)
           .width('100%')
           .backgroundColor(Color.Pink)

           List({ scroller: this.scroller2 }) {
             ForEach(this.messageArr, (item: string) => {
               ListItem() {
                 Row() {
                   Text(`message ${item}`)
                 }
                 .width('100%')
                 .height('200vp')
               }
             })
           }
           .divider({ strokeWidth: 2 })
           .backgroundColor('#eee')
           .nestedScroll({
             scrollBackward: NestedScrollMode.SELF_FIRST,
             scrollForward: NestedScrollMode.PARENT_FIRST,
           })
           .padding({
             bottom: 100
           })
           .edgeEffect(EdgeEffect.None)
         }

       }
       .width('100%')
       .height('100%')

     }
     .friction(2)
     .edgeEffect(EdgeEffect.None)
     .scrollSnapAlign(ScrollSnapAlign.CENTER)
     .onScrollFrameBegin((offset, state) => {
       if (state === ScrollState.Fling) {
         return { offsetRemain: 0 }
       }
       return { offsetRemain: offset }
     })
     .onScrollIndex((start, end, center) => {
       this.currentIndex = center
     })
     .onTouch((event: TouchEvent) => {
       let touchObject: TouchObject = event.touches[0]
       if (touchObject.type === TouchType.Up) {
         this.scroller.scrollToIndex(this.currentIndex, true, ScrollAlign.CENTER)
       }
     })

   }
   .height('100%')
   .width('100%')
 }
}

你看一下我给1楼发的代码,demo测试的时候是没问题的,但是实际上相同操作在工程代码上出现了问题,猜测是跳转发生在Ui更新完成前,导致无法跳转,想找一下解决方案,我试用settimeout100 可以解决,但是项目好像不支持这个时间

给第二个控制器跳转加了定时器晚5毫秒触发,明显问题解决了,但是想寻求一个更稳妥的解决方案

期待HarmonyOS能在未来带来更多创新的技术和理念。

提供个能复现的demo代码哈

import { promptAction } from ‘@kit.ArkUI’;

export class parent { title: string = ‘’ child: child[] = [] selectId: number = 0 }

export class child { title: string = ‘’ image: ResourceStr = ‘’ }

@Entry @Component struct TabsOpaque { @State tabArray: parent[] = [{ title: ‘父0’, child: [{ title: ‘子0’, image: $r(‘app.media.app_icon’) }], selectId: 0 }, { title: ‘父1’, child: [{ title: ‘子0’, image: $r(‘app.media.app_icon’) }, { title: ‘子1’, image: $r(‘app.media.app_icon’) }, { title: ‘子2’, image: $r(‘app.media.app_icon’) }, { title: ‘子3’, image: $r(‘app.media.app_icon’) }, { title: ‘子4’, image: $r(‘app.media.app_icon’) }], selectId: 3 }, { title: ‘父2’, child: [{ title: ‘子0’, image: $r(‘app.media.app_icon’) }, { title: ‘子0’, image: $r(‘app.media.app_icon’) }], selectId: 0

}, { title: ‘父3’, child: [{ title: ‘子0’, image: $r(‘app.media.app_icon’) }, { title: ‘子0’, image: $r(‘app.media.app_icon’) }], selectId: 0 }] @State contCurrentIndex: number = 0; //记录当前内容导航索引 @State subCurrentIndex: number = 0; //记录当前下部导航索引 selectedFontColor: Color = Color.Black fontColor: Color = Color.Blue //滑动X轴 @State offsetX: number = 0 private subController: Scroller = new Scroller() private subListController: Scroller = new Scroller() private contScroller: Scroller = new Scroller() private contListScroller: Scroller = new Scroller()

build() { Column() { //用于窗口晃动操作 Column() { Text(‘用于滑动驱动变化’) .onClick(() => { this.contCurrentIndex++ this.contListScroller.scrollToIndex(this.contCurrentIndex, true, ScrollAlign.CENTER) }) } .justifyContent(FlexAlign.Center) .align(Alignment.Center) .height(“50%”) .width(“100%”) .gesture( PanGesture() .onActionUpdate((event: GestureEvent) => { if (event) { this.offsetX = this.offsetX + event.offsetX } }) .onActionEnd((event: GestureEvent) => { //极端return if (this.contCurrentIndex == 0 && this.subCurrentIndex == 0 && this.offsetX > 0) { this.offsetX = 0 return } if (this.contCurrentIndex == this.tabArray[this.subCurrentIndex].child.length - 1 && this.subCurrentIndex == this.tabArray.length - 1 && this.offsetX < 0) { this.offsetX = 0 return } //右滑 if (this.offsetX > 0) { if (this.contCurrentIndex == 0) { this.subCurrentIndex– this.subListController.scrollToIndex(this.subCurrentIndex, true, ScrollAlign.CENTER) } else { this.contCurrentIndex– this.contListScroller.scrollToIndex(this.contCurrentIndex, true, ScrollAlign.CENTER) } } //左滑 if (this.offsetX < 0) { if (this.contCurrentIndex == this.tabArray[this.subCurrentIndex].child.length - 1) { this.subCurrentIndex++ this.subListController.scrollToIndex(this.subCurrentIndex, true, ScrollAlign.CENTER) } else { this.contCurrentIndex++ this.contListScroller.scrollToIndex(this.contCurrentIndex, true, ScrollAlign.CENTER) } } this.offsetX = 0 //更新为0 }) )

  //子Tab
  Scroll(this.contScroller) {
    List({ scroller: this.contListScroller }) {
      ForEach(this.tabArray[this.subCurrentIndex].child, (contTab: child, contIndex: number) =&gt; {
        ListItem() {
          Column() {
            Image($r('app.media.app_icon'))
              .width(20)
            Text(contTab.title)
              .fontSize(20)
              .fontColor(this.contCurrentIndex == contIndex ? Color.Red : Color.Black)
              .onClick(() =&gt; {
                this.contListScroller.scrollToIndex(contIndex, true, ScrollAlign.CENTER)
                this.contCurrentIndex = contIndex
              })
          }
          .margin({
            left: 10,
            right: 10
          })
        }
      })
    }
    .gesture(
      PanGesture()
        .onActionStart((event: GestureEvent) =&gt; {
          if (event) {
            //极限返回
            if ((this.contCurrentIndex == 0 &amp;&amp; event.offsetX &gt; 0) ||
              (this.contCurrentIndex == this.tabArray[this.subCurrentIndex].child.length - 1 &amp;&amp;
                event.offsetX &lt; 0)) {
              return
            }
            //触发滑动
            if (event.offsetX &lt; 0) {
              this.contCurrentIndex++
            } else {
              this.contCurrentIndex--
            }
            this.contListScroller.scrollToIndex(this.contCurrentIndex, true, ScrollAlign.CENTER)
          }
        })
    )
    .enableScrollInteraction(false) //关闭自带滑动
    .scrollSnapAlign(ScrollSnapAlign.CENTER)
    .width("100%")
    .height("100%")
    .listDirection(Axis.Horizontal)
    .scrollBar(BarState.Off)
  }
  .width("100%")
  .height(50)
  .border({
    width: 1
  })
  .scrollBar(BarState.Off)
  .scrollable(ScrollDirection.Horizontal)

  //父
  Scroll(this.subController) {
    List({ scroller: this.subListController }) {
      ForEach(this.tabArray, (subTab: parent, subIndex: number) =&gt; {
        ListItem() {
          Text(subTab.title)
            .fontSize(30)
            .fontColor(this.subCurrentIndex == subIndex ? Color.Red : Color.Black)
            .onClick(async () =&gt; {
              //TODO 未更新二级滑动 使用scrollToIndex 出现index&gt;子组件最大索引 取消跳转
              if (this.subCurrentIndex == subIndex) {
                return
              }

              await this.subListController.scrollToIndex(subIndex, true, ScrollAlign.CENTER)
              this.subCurrentIndex = subIndex
              // 更新子导航索引 视图更新
              this.contCurrentIndex = this.tabArray[subIndex].selectId

              await this.contListScroller.scrollToIndex(this.contCurrentIndex, true, ScrollAlign.CENTER)


            })
            .margin({
              left: 10,
              right: 10
            })
        }
      })
    }
    .gesture(
      PanGesture()
        .onActionStart((event: GestureEvent) =&gt; {
          if (event) {
            //极限返回
            if ((this.subCurrentIndex == 0 &amp;&amp; event.offsetX &gt; 0) ||
              (this.subCurrentIndex == this.tabArray.length - 1 &amp;&amp; event.offsetX &lt; 0)) {
              return
            }
            //触发滑动
            if (event.offsetX &lt; 0) {
              this.subCurrentIndex++
            } else {
              this.subCurrentIndex--
            }
            this.subListController.scrollToIndex(this.subCurrentIndex, true, ScrollAlign.CENTER)
          }
          // Event.offsetX&gt;0
        })
    )
    .enableScrollInteraction(false) //关闭自带滑动
    .scrollSnapAlign(ScrollSnapAlign.CENTER)
    .scrollBar(BarState.Off)
    .listDirection(Axis.Horizontal)
    .width("100%")
    .height(30)
  }

  .scrollBar(BarState.Off)
  .scrollable(ScrollDirection.Horizontal)

}

} }

demo 和代码有一些出入,不知道是数组嵌套原因,还是哪里出现问题,我在第二个控制器跳转前加了settimeout 100 就避免了这个问题发生,我猜测是UI更新,父改变索引,趋势子视图发生变化,而第二个控制器跳转应该是发生在完全更新之前,形成了【未更新二级滑动 使用scrollToIndex 出现index>子组件最大索引 取消跳转】,且监听ScrollStart 未发生, 有没有什么办法监听子组件更新成功后在进行后续操作的方案?

demo没问题,和延迟有关。可以从几个方面入手 【1】数据更新过程尽量不要删减组件,只改变组件内容的情况下通常没有问题。 【2】尝试使用@Watch装饰器监听,在监听回调里处理你的操作方法 【3】我看到你用了async ,建议这里使用EventHub发送到主线程去执行更新UI操作 【4】现在你这种数据更新方式落后了,建议使用@ObservedV2+@Trace 参考:https://blog.csdn.net/zhongcongxu01/article/details/142677808

针对HarmonyOS 鸿蒙Next中两个list使用scrollToIndex失效的问题,可能的原因及解决方案如下:

  1. 高度设置不当

    • List组件未设置高度或高度设置不合理,会导致无法正常渲染和计算布局,从而影响scrollToIndex功能。
    • 解决方案:确保每个List组件都有合理且固定的高度设置。
  2. 嵌套Scroll容器

    • 如果List组件嵌套在Scroll容器中,且Scroll容器未设置固定高度,会导致滚动事件处理异常。
    • 解决方案:为嵌套的Scroll容器设置固定高度,确保滚动事件正常触发。
  3. 数据加载与渲染问题

    • 动态加载数据时,若数据加载未完成或渲染逻辑存在性能瓶颈,也可能影响scrollToIndex的效果。
    • 解决方案:确保数据加载完成后再调用scrollToIndex,并优化数据渲染逻辑。
  4. 版本或系统问题

    • 某些HarmonyOS版本可能存在特定bug,影响scrollToIndex功能。
    • 解决方案:尝试更新HarmonyOS版本到最新,看问题是否得到解决。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部