4

目录

  • 前言
  • 关于Scroll组件
  • 常见问题:Scroll不滚动
  • 番外篇:Scroll组件的scrollToIndex无效
  • 结束语

前言

在移动开发过程中,滚动视图是用户交互界面中常用的组件之一,主要是用于展示超出视图范围的内容,它允许用户在有限的屏幕空间内浏览大量的内容,这也是移动开发者经常遇到问题的地方。而在HarmonyOS开发中也是如此,Scroll组件的使用,是HarmonyOS开发中实现页面滚动功能的重要组件之一。但是在实际开发中,开发者们很可能会遇到Scroll组件使用的问题,比如不滚动的问题,这会严重影响应用的开发效果和用户体验。那么本文就来详细分享 Scroll组件的使用,以及解析HarmonyOS 开发中 Scroll 不滚动问题的原因,并提供详细的解决方案,帮助大家更好地理解和解决这一问题。

关于Scroll组件

在HarmonyOS中,先来分享关于Scroll组件的基本使用,Scroll是一个可滚动的容器组件,它可以包含其他组件,并提供滚动功能。Scroll组件允许用户通过滑动操作查看更多的内容,且支持水平和垂直两种滚动模式,也可以同时在两个方向上滚动。当 Scroll 中的内容超出其可视区域时,用户可以通过滑动手势来浏览超出部分的内容,也就是说当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。

1、子组件

Scroll组件是支持单个子组件的。

2、接口

在实际开发中,使用Scroll组件,是通过接口:Scroll(scroller?: Scroller) 来实现的。

3、属性

Scroll组件有11个常用属性,这里只做简单的罗列介绍,具体如下:scrollable(设置滚动方向)、scrollBar(设置滚动条状态。如果容器组件无法滚动,则滚动条不显示;如果容器组件的子组件大小为无穷大,则滚动条不支持拖动和伴随滚动)、scrollBarColor(设置滚动条的颜色)、scrollBarWidth(设置滚动条的宽度,不支持百分比设置。宽度设置后,滚动条正常状态和按压状态宽度均为滚动条的宽度值;如果滚动条的宽度超过Scroll组件主轴方向的高度,则滚动条的宽度会变为默认值)、scrollSnap(设置Scroll组件的限位滚动模式)、edgeEffect(设置边缘滑动效果)、enableScrollInteraction(设置是否支持滚动手势,当设置为false时,无法通过手指或者鼠标滚动,但不影响控制器的滚动接口)、nestedScroll(设置向前向后两个方向上的嵌套滚动模式,实现与父组件的滚动联动)、friction(设置摩擦系数,手动划动滚动区域时生效,只对惯性滚动过程有影响,对惯性滚动过程中的链式效果有间接影响。设置为小于等于0的值时,按默认值处理)、enablePaging(设置是否支持划动翻页。如果同时设置了划动翻页enablePaging和限位滚动scrollSnap,则scrollSnap优先生效,enablePaging不生效)、initialOffset(设置初始滚动偏移量。只在首次布局时生效,后续动态修改该属性值不生效)。

4、ScrollDirection枚举

关于Scroll组件的ScrollDirection枚举,主要涉及4个属性值,如下所示:
image.png

5、关于点击事件

关于Scroll组件的点击事件,主要涉及8个点击事件:onScrollFrameBegin()、onScroll()、onWillScroll()、onDidScroll()、onScrollEdge()、onScrollEnd()、onScrollStart()、onScrollStop()。

(1)onScrollFrameBegin()

onScrollFrameBegin()是在每帧开始滚动时触发,事件参数传入即将发生的滚动量,事件处理函数中可根据应用场景计算实际需要的滚动量并作为事件处理函数的返回值返回,Scroll将按照返回值的实际滚动量进行滚动。(注:支持offsetRemain为负值)

(2)onScroll()

onScroll()是在滚动事件回调,返回滚动时水平、竖直方向偏移量,单位vp。

(3)onWillScroll()

onWillScroll()是在滚动事件回调,Scroll滚动前触发。

(4)onDidScroll()

onDidScroll()是在滚动事件回调,Scroll滚动时触发。返回当前帧滚动的偏移量和当前滚动状态。

(5)onScrollEdge()

onScrollEdge()是在滚动到边缘事件回调。

(6)onScrollEnd()

onScrollEnd()是在滚动停止事件回调。

(7)onScrollStart()

onScrollStart()是在滚动开始时触发。手指拖动Scroll或拖动Scroll的滚动条触发的滚动开始时,会触发该事件。使用Scroller滚动控制器触发的带动画的滚动,动画开始时会触发该事件。

(8)onScrollStop()

onScrollStop()是在滚动停止时触发。手拖动Scroll或拖动Scroll的滚动条触发的滚动,手离开屏幕并且滚动停止时会触发该事件。使用Scroller滚动控制器触发的带动画的滚动,动画停止时会触发该事件。

6、使用示例

这里先分享一个关于Scroll组件使用的示例,这个示例是可以正常滑动的,具体代码如下所示:

@Entry
@Component
//滚动控制器新增按给定速度执行惯性滚动的函数fling
struct ListExample {
  private arr: number[] = [1, 2, 3, 4, 5, 6]
  scrollerList: Scroller = new Scroller()
  build() {
    Column() {
      Button('titlebar')
        .height('5%')
        .onClick(() => {

        })
      List({ space: 20, initialIndex: 0, scroller: this.scrollerList }) {
        ForEach(this.arr, (item: number) => {
          ListItem() {
            Text('' + item)
              .width('100%').height(100).fontSize(16)
              .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
          }
        }, (item: string) => item)
      }
      .listDirection(Axis.Vertical) // 排列方向
      .scrollBar(BarState.Off)
      .friction(0.9)
      .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
      .edgeEffect(EdgeEffect.Spring) // 边缘效果
      .width('90%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor(0xDCDCDC)
    .padding({ top: 5 })
  }
}

常见问题:Scroll不滚动

接下来分享一个在实际开发中使用Scroll组件时候比较常见的问题,即Scroll组件无法滚动的问题,这也是刚使用Scroll组件的开发者容易遇到的问题,那么接下来就来详细的分享一下解决方法。

1、Scroll组件不滚动的原因分析

当遇到Scroll组件不滚动的问题,一般情况下是由于Scroll内部的容器组件设定了width或height属性,也就是设置了固定的宽度(width)或高度(height)引起的,所以当容器组件的尺寸被固定时,Scroll组件无法根据内容的大小自动调整其滚动区域,从而导致无法滚动。解决方法就是移除这些限制,确保Scroll能够根据内容自由扩展。
如果滚动方向设置不当也会引起Scroll组件不滚动的问题。尤其是在嵌套滚动场景中,如果外层Scroll组件的滚动方向设置不当,也可能导致滚动冲突,进而影响内层组件的滚动,比如外层Scroll设置为同时支持水平和垂直滚动(direction="both"),但是内层List仅需要垂直滚动,这可能会导致滚动冲突,会使得Scroll组件无法正确滚动。
还有布局方式影响也会引起Scroll组件不滚动的问题,比如在某些情况下Scroll组件的布局方式(如Flex布局)也会影响其滚动性能,如果布局方式设置不当,可能会导致Scroll组件无法正确计算其滚动区域,进而造成Scroll组件无法滚动。

2、经典问题答疑:为啥Column设定了100%的高度,页面中Scroll组件就不滚动了?

答案:因为Scroll组件是根据其直接子组件的高度是否超出其高度判断是否开启滚动,如果设定100%后Column就与Scroll同高了,不会出现超出情况,也就不会开启滚动,只是Column内部UI超出Column高度只是画出屏幕外,不能影响Scroll的判断,若有屏幕延伸可看到超出的部分画出Column外,但Scoll不知道,所以不会滚动。

3、Scroll组件不滚动的示例分享

在使用Scroll组件时设置了滚动的方向,内容也超出了页面的大小,但是就是不能滚动,原因是因为Scroll组件包裹下的容器组件Row或者Column设置了width或者height属性,如果是横向Row不要设置width,如果是竖向Column不要设置height。这里分享一个对比示例,方便大家对比了解。
(1)Scroll组件不滚动的代码

Scroll() {
  // Column
  Column() {
        
  }.height('100%') //包裹下的容器组件设置了高度
}.height('100%')

(2)Scroll组件可以滚动的代码

Scroll() {
  Column() {
        
  }
}.height('100%')

4、解决方案

针对上面列举的Scroll不滚动问题的汇总,这里也分享一下上述情况的解决方法。

  • 移除容器组件的尺寸限制:对于因容器组件尺寸限制导致的Scroll不滚动问题,最简单的解决方案是移除这些尺寸限制,需要确保Scroll组件内部的容器组件(如Row或Column)能够根据其内容自由扩展,对于竖向滚动的Scroll组件,其内部的Column组件不应设置固定的高度。
  • 合理设置滚动方向:在嵌套滚动场景中,应合理设置外层Scroll组件的滚动方向。如果内层组件仅需要单一方向的滚动(如垂直滚动),则外层Scroll组件的滚动方向也应相应设置为该方向。如果确实需要同时支持多个方向的滚动,可以考虑使用NestedScroll组件来替代普通的Scroll组件,以支持更复杂的滚动嵌套处理。
  • 调整布局方式:对于因布局方式导致的Scroll不滚动问题,可以尝试调整布局方式,比如将Flex布局的方向设置为与滚动方向一致,并确保Flex容器能够根据其内容自动调整大小,而且还可以考虑使用弹性布局(Flex)或网格布局(Grid)等现代布局方式,以更好地支持滚动和响应式设计。
  • 监听滚动事件并动态调整:在某些复杂场景下,可以通过监听外层Scroll组件的滚动事件,并根据滚动的位置和状态来动态调整内层组件的布局或显示状态。例如,在外层Scroll开始滚动时禁用内层List的滚动,滚动停止后再启用。这种方法需要编写额外的逻辑来处理滚动事件和布局调整,但可以有效地解决滚动冲突问题。

    番外篇:Scroll组件的scrollToIndex无效

    关于Scroll组件的scrollToIndex无效的问题,其实示例代码如下,点击按钮Scroll不会发生滚动:

@Entry
@Component
struct Index {
  private scrollerForScroll: Scroller = new Scroller()

  build() {

    Column() {
      Scroll(this.scrollerForScroll) {
        Row({ space: '20lpx' }) {
          ForEach(['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',], (item: string, index: number) => {
            Row() {
              Text(`${index}`)
            }
            .width('50lpx')
            .height('50lpx')
            .backgroundColor(Color.Red)
          })

        }
        .height('100%')
      }
      .width('100%')
      .height('100lpx')
      .scrollable(ScrollDirection.Horizontal)
      .borderWidth('4lpx')
      .borderColor('#ffffff')

      Button('滚动').onClick(() => {
        this.scrollerForScroll.scrollToIndex(5)
      })
    }

  }
}

解决方法及原因分析:造成上面的Scroll组件的scrollToIndex无效的原因就是Scroll组件不支持scrollToIndex(),但是Scroll滚动可以通过以下方式滚动,具体如下所示:

Button('滚动').onClick(() => {
  this.scrollerForScroll.scrollTo({xOffset:'750lpx',yOffset:0,animation:true}
})

另外,具体的官方详细API说明,请参考链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-refere...\#ZH-CN\_TOPIC\_0000001821000913\_\_scrolltoindex

结束语

通过本文的详细介绍,想必各位对Scroll组件的工作原理和常见问题都有了更深入的了解。也可以发现滚动问题在HarmonyOS开发中是一个常见且复杂的问题,涉及多个方面,我们通过理解Scroll组件的工作原理和常见问题,就可以更有效地诊断和解决这些问题。在实际开发过程中,Scroll组件不滚动是HarmonyOS开发中常见的问题之一,我们可以通过移除容器组件的尺寸限制、合理设置滚动方向、调整布局方式以及监听滚动事件并动态调整等方法,有效地解决这一问题。如果你还没有遇到这些问题,建议你在开发过程中应注意避免这些常见问题,以确保Scroll组件能够正常使用,同时也建议大家多使用调试工具,仔细检查布局和事件处理逻辑,从而确保应用的正常使用和提高用户体验。随着HarmonyOS生态的不断成熟,社区和文档资源也在不断丰富,我们可以利用这些资源来提高开发效率和应用质量,希望本文能够帮助大家解决Scroll不滚动的问题!


三掌柜
20.6k 声望6.7k 粉丝

一分耕耘,不一定有一分收获,但十分耕耘,一定会有一分收获!