写点什么

HarmonyOS 实战:Tab 顶部滑动悬停功能实现

作者:IT小码哥
  • 2025-05-27
    北京
  • 本文字数:2379 字

    阅读完需:约 8 分钟

前言

日常开发过程中,遇到这种 Scroll 嵌套 List 列表滑动顶部悬停的场景十分常见,在鸿蒙开发时也正好实现了这个功能,本篇文章将带你一步步实现 Tab 顶部悬停的效果,建议点赞收藏!

实现效果

先看本文的最终实现效果如下:


需求分析

  • 当整体向上滑动时,优先 Scroll 向上滑动。

  • 当整体向下滑动时,优先 Scroll 向下滑动。

技术实现

  1. 首先需要实现基础页面布局,直接使用 Scroll 嵌套 List 布局。将 List 用 Tab 布局嵌套起来。


 Scroll(this.scroller) {          Column() {            Text("内容")              .textAlign(TextAlign.Center)              .fontColor(Color.White)              .backgroundColor(this.themColor.value)              .width('100%')              .height('40%')
Tabs({ barPosition: BarPosition.Start }) { TabContent() { Column() { Refresh({refreshing:false,friction:0,offset:0}){ List({ space: 10, scroller: this.scrollerForList }) { ForEach(this.list, (item: string) => { ListItem() { Text('ListItem' + item) .width('100%') .height('100%') .borderRadius(15) .fontSize(24) .textAlign(TextAlign.Center) .backgroundColor(Color.White) } .width('100%') .height(100) }, (item: string) => item) } .pullToRefresh(true) }
}.tabBar('你好')
TabContent() { Column().width('100%').height('100%').backgroundColor('#007DFF') }.tabBar('好的')
} }
复制代码


这里布局比较简单,使用两个 tab 用来切换布局。外层使用 Scroll 包裹,其中一个 tab 的里面使用 List 布局。相信这对大多人来说没有什么难度。


  1. 搭建好基础布局后,开始处理滑动冲突问题。根据实现效果来看,每次都是让外层的 Scroll 优先滑动,需要给 List 增加拦截处理,让每次滑动优先外层 Scroll 布局滑动,这里使用 nestedScroll 属性的 NestedScrollMode.PARENT_FIRST,即优先父布局滑动。


 .nestedScroll({                      scrollForward: NestedScrollMode.PARENT_FIRST,                      scrollBackward: NestedScrollMode.PARENT_FIRST                    })
复制代码


  1. 这时不管怎么上下滑动,里面的 List 都不会滑动,只让外层的 Scroll 组件滑动。接下来处理 List 的滑动事件。

  2. 首先定义一个枚举类型,用来标记滑动位置。


enum ScrollPosition {  top,  center,  bottom}
复制代码


  1. 接下来分别实现 List 的 onReachStart,onReachEnd,onScrollFrameBegin 三个方法。这个比较容易理解,滑动道顶部时,记录当前位置为顶部,滑动底部时,记录当前位置为底部,onScrollFrameBegin 表示滑动过程中的回调,根据当前滑动位置和滑动偏移量来记录是否继续滑动。


                    .onReachStart(() => {                      this.listPosition = ScrollPosition.top                    })                    .onReachEnd(() => {                      this.listPosition = ScrollPosition.bottom                    })                    .onScrollFrameBegin((offset: number, state: ScrollState) => {                      if ((this.listPosition == ScrollPosition.top && offset <=0)||(this.listPosition == ScrollPosition.bottom && offset>=0)) {                        return {offsetRemain :offset}                      }                      this.listPosition = ScrollPosition.center                      return {offsetRemain:offset}                    })
复制代码


  1. 再看外层 Scroll 的滑动方法监听,同样也是分别实现这三种方法,不过注意 onScrollFrameBegin 里面返回值和 List 的不同,当 Scroll 滑动到底部活着顶部时,Scroll 不再滑动,注意看返回值为 0,否则 Scroll 才滑动。


 .onReachStart(() => {          this.listPosition = ScrollPosition.top        })        .onReachEnd(() => {          this.listPosition = ScrollPosition.bottom        })        .onScrollFrameBegin((offset: number, _: ScrollState) => {          if ((this.listPosition == ScrollPosition.top && offset <= 0) || (            this.listPosition == ScrollPosition.bottom && offset >= 0)          ) {            return { offsetRemain: 0 }          }          //不在底部          this.listPosition = ScrollPosition.center          return { offsetRemain: offset }        })
复制代码


  1. 根据 List 组件和 Scroll 组件的滑动监听,用来判断哪种状态下 Scroll 优先滑动,当 Scroll 滑动到底部活顶部时,通过返回值赋值为 0 ,阻止 Scroll 滑动,将滑动事件交个内部的 List 滑动。注意 List 通过设置 nestedScroll 将滑动事件优先让外层 Scroll 处理。所以一开始是外层的 Scroll 先滑动。

总结

本文主要是根据实际需求实现的滑动效果,每次都优先让 Scroll 滑动,还有更多的滑动场景都可以用这种方式的思路解决,主要通过不同的判断条件即可实现。例如向下滑动时优先让 List 滑动,然后再让 Scroll 滑动。学会的小伙伴赶紧动手试试吧!


用户头像

IT小码哥

关注

还未添加个人签名 2021-04-29 加入

还未添加个人简介

评论

发布
暂无评论
HarmonyOS实战:Tab顶部滑动悬停功能实现_HarmonyOS_IT小码哥_InfoQ写作社区