鸿蒙开发:使用nestedScroll解决滑动冲突

前言

本文基于Api13

在实际的开发中,滑动冲突在所难免,常见于可滚动的容器组件嵌套使用,比如Scroll组件嵌套List组件,List组件嵌套了Grid组件等等,只要是滚动容器组件嵌套,令人厌烦的滑动冲突就会扑面而来,十分让人抓狂;如何处理滑动冲突,成了开发中的必修之课,然而,鸿蒙当中的处理方式,相对与Android端而言,似乎更加的直观和简单,使用一个属性便可以搞定,那就是nestedScroll。

简单案例

案例很是简单,外层是一个Scroll滚动容器,内部也有一个List组件滚动组件,在List上面有一个普通的组件。

@Entry
@Component
struct Index {
  build() {
    Scroll() {
      Column() {
        Text("我是顶部的组件")
          .width("100%")
          .height(200)
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Pink)
          .fontColor(Color.White)

        List() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number) => {
            ListItem() {
              Text(item.toString())
                .width("100%")
                .height(80)
                .textAlign(TextAlign.Center)
            }
          })
        }
        .width("100%")
        .height("100%")
        .scrollBar(BarState.Off)
        .divider({ color: Color.Gray, strokeWidth: 1 })
        .edgeEffect(EdgeEffect.None)

      }
    }.width("100%")
    .height("100%")
    .scrollBar(BarState.Off)
  }
}

效果如下所示:

image.png

我们想要的效果是,先让顶部的组件滚动上去,然后再滚动下面的List组件,我们运行看下效果:

91001.gif

显然未达到我们的效果,这就是滑动冲突导致的,这种情况下,做为子组件的List组件,一定是先把滑动事件交给Scroll组件,等Scroll组件滚动到边缘后,再把滑动事件交给自己,这样的流程也是正确的,如何做到呢,前边已经说过了,那就是nestedScroll属性。

每个滚动容器组件都有一个nestedScroll属性,主要解决嵌套滚动模式下的的滑动冲突,我们给List组件设置一下,代码如下:

.nestedScroll({
          scrollForward: NestedScrollMode.PARENT_FIRST,
          scrollBackward: NestedScrollMode.SELF_FIRST
        })

设置完后,再看下效果:

91002.gif

可以看到,已经完美的解决了滑动冲突,达到了我们想要的效果。

了解nestedScroll

通过前言中的案例,我们基本上已经知道了nestedScroll属性的作用,主要是,用于设置嵌套滚动选项,设置前后两个方向的嵌套滚动模式,实现与父组件的滚动联动。

image.png

我们重点关注一下NestedScrollOptions这个参数,其中有两个值,分别是scrollForward和scrollBackward,一个代表往末尾端滚动,一个代表往起始端滚动。

image.png

两个参数都有一个共同的值类型NestedScrollMode,可供选择的有以下几个值:

名称 说明
SELF_ONLY 只自身滚动,不与父组件联动。
SELF_FIRST 自身先滚动,自身滚动到边缘以后父组件滚动。父组件滚动到边缘以后,如果父组件有边缘效果,则父组件触发边缘效果,否则子组件触发边缘效果。
PARENT_FIRST 父组件先滚动,父组件滚动到边缘以后自身滚动。自身滚动到边缘后,如果有边缘效果,会触发自身的边缘效果,否则触发父组件的边缘效果。
PARALLEL 自身和父组件同时滚动,自身和父组件都到达边缘以后,如果自身有边缘效果,则自身触发边缘效果,否则父组件触发边缘效果。

举例使用

前言中,我们简单使用Scroll组件嵌套List组件举了一个例子,我们再来看一个Scroll组件嵌套Web组件的案例。

import webview from **********'

@Entry
@Component
struct Index {
  private controller: webview.WebviewController = new webview.WebviewController()

  build() {

    Scroll() {
      Column() {
        Text("我是顶部的组件")
          .width("100%")
          .height(200)
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Pink)
          .fontColor(Color.White)

        Web({
          src: "https://juejin.cn/user/1398234520239095/columns",
          controller: this.controller
        })
          .nestedScroll({
            scrollForward: NestedScrollMode.PARENT_FIRST,
            scrollBackward: NestedScrollMode.SELF_FIRST
          })

      }
    }.width("100%")
    .height("100%")
    .scrollBar(BarState.Off)

  }
}

以上的效果和前言中基本一致,不在贴效果了,其实再多的案例,基本上都是一样的,只是nestedScroll中的值不一样而已。

相关总结

在实际的开发中,远远要比前边的案例复杂,比如我之前封装的刷新库,滚动组件上面有刷新头,下面也有加载尾,还有更复杂的,列表吸顶操作等等,一个nestedScroll属性是远远不够的,往往还要和滑动监听,是否滚动到了顶部和尾部等相结合,才能实现我们实际的效果。

比如,还是以上的案例,我们在List组件下面再增加一个底部的组件,我们运行看下效果:

显然之前配置的nestedScroll属性只满足了顶部的组件,而底部的组件在滑动的过程中明显有滑动冲突,并没有达到我们的预期,其实对于底部,上滑是先滚动自己后滚动父组件,下滑是要先滚动父组件,然后再去滚动自身组件的。

91003.gif

针对以上的问题,其实处理有多种方式,最简单的莫过于,底部组件在最后一个组件下面,当做List组件的部分,当然了顶部组件也可以这么去做,这样就不存在滑动冲突。

if (index == this.dataArray.length - 1) {
                Column() {
                  Text(item.toString())
                    .width("100%")
                    .height(80)
                    .textAlign(TextAlign.Center)
                  
                  Text("我是底部的组件")
                    .width("100%")
                    .height(200)
                    .textAlign(TextAlign.Center)
                    .backgroundColor(Color.Pink)
                    .fontColor(Color.White)
                }

  }

我们看下效果:

91004.gif

把组件加到首尾数据的位置,这种方式会存在一个问题,比如说,如果没有数据呢?顶部组件和底部组件那么就无法显示,再比如如果加载的不是List组件,而是一个Grid组件或者其他的滚动组件呢?显然处理上有很大的问题。

这个作业留给友友们,你们知道如何解决吗?

#鸿蒙开发#
鸿蒙点石成金 文章被收录于专栏

简单的也好,复杂的也罢,关于HarmonyOS,总要深入浅出,总要步步为赢。

全部评论

相关推荐

07-02 13:29
已编辑
北京化工大学 Java
简历发邮箱:**********地点:上海虹桥公司:汽车行业-智驾方向岗位:JAVA开发工程师(数仓方向)工作职业1. 参与数仓指标体系建设- 基于业务需求,使用 SQL 和 UDF 开发数据指标计算任务,构建企业级数据仓库。- 优化数仓模型,提升数据质量和查询性能,支持业务决策分析。2. 数据集成与 ETL 开发- 使用 Seatunnel 开发数据同步任务,实现跨源数据(如 MongoDB、业务库)的抽取、清洗和转换。- 基于 DolphinScheduler 设计和调度数据处理工作流,确保任务稳定运行。3. 业务埋点体系开发- 参与设计业务埋点方案,跟踪用户行为数据,支持产品优化和运营分析。- 开发埋点数据采集、清洗和入库的全流程处理逻辑。4. 技术协作与问题排查- 与后端团队协作,基于 Spring 框架开发数据服务接口。- 使用 Doris 等 OLAP 引擎优化指标查询性能,解决数据处理中的疑难问题。岗位要求:1. Java 编程基础扎实,- 熟练掌握面向对象编程(OOP),包括类、继承、多态、接口等概念- 深入理解 Java 容器类(如 List、Map、Set 的实现原理)- 熟悉多线程编程和常用设计模式2. 数据库与 SQL- 精通 SQL,包括复杂查询、索引优化、窗口函数等- 熟悉 MySQL 数据库设计和调优,了解事务隔离级别3. 后端开发框架熟练使用 Spring/Spring Boot 框架,理解依赖注入(DI)和 AOP 原理掌握 MyBatis 或其他 ORM 框架的使用4. 有大数据基础- 了解大数据组件 Hadoop 生态(HDFS、YARN、MapReduce)- 熟悉 Flink 或 Spark 的基本原理和使用场景- 掌握 SeaTunnel(或类似 ETL 工具)的数据同步开发5. 数据仓库知识- 理解数仓分层架构(ODS/DWD/DWS/ADS)- 掌握维度建模方法(星型 / 雪花模型)- 了解 OLAP 数据库(如 Doris、ClickHouse)的特点和适用场景
Java求职圈
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务