鸿蒙中 Tabs吸顶效果实现

该文章已生成可运行项目,

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

鸿蒙(HarmonyOS)开发中,实现 Tabs吸顶效果(即滚动到顶部时固定)需要结合 Tabs 组件、Scroll 容器和动态布局控制。

一、实现原理

  1. 布局结构
    • 使用 Scroll 包裹整个页面内容,监听滚动事件。
    • 将 Tabs 分为两部分:
      • 吸顶的Tabs:固定在顶部(position: fixed)。
      • 占位Tabs:隐藏但保持高度,避免页面跳动。
  2. 滚动逻辑
    • 当页面滚动到 占位Tabs 的顶部时,显示吸顶Tabs,反之隐藏。

二、核心API与组件

API/组件作用关键属性/方法
Tabs选项卡组件barPosition(选项卡栏位置)
Scroll可滚动容器onScroll(滚动事件监听)
position定位方式Position.Fixed(固定定位)
visibility控制显隐Visibility.None(隐藏占位)

三、完整代码实现

1. 页面结构定义
@Entry
@Component
struct StickyTabsExample {
  @State currentTab: number = 0; // 当前选中Tab
  @State isSticky: boolean = false; // 是否吸顶
  @State scrollY: number = 0; // 滚动位置

  // Tab数据
  private tabs: string[] = ['首页', '分类', '发现', '我的'];

  build() {
    Column() {
      // 1. 吸顶的Tabs(动态显示)
      Tabs({ barPosition: BarPosition.Start }) {
        ForEach(this.tabs, (tab, index) => {
          TabContent() {
            this.buildTabContent(index)
          }.tabBar(tab)
        })
      }
      .barWidth('100%')
      .barHeight(50)
      .visibility(this.isSticky ? Visibility.Visible : Visibility.None)
      .position({ top: 0 })
      .zIndex(2) // 确保在最上层
      .width('100%')
      .height(50)

      // 2. 主滚动区域
      Scroll() {
        Column() {
          // 占位Tabs(高度与吸顶Tabs一致)
          Tabs({ barPosition: BarPosition.Start }) {
            ForEach(this.tabs, (tab) => {
              TabContent() { /* 空内容 */ }.tabBar(tab)
            })
          }
          .visibility(Visibility.None)
          .width('100%')
          .height(50)
          .onAreaChange((oldVal, newVal) => {
            this.tabsTop = newVal.globalPosition.y; // 获取占位Tabs的顶部位置
          })

          // 页面内容(模拟长列表)
          Column() {
            ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item) => {
              Text(`列表项 ${item}`)
                .fontSize(20)
                .width('100%')
                .height(100)
                .backgroundColor('#F5F5F5')
                .margin({ bottom: 10 })
            })
          }
          .width('100%')
        }
      }
      .onScroll((xOffset: number, yOffset: number) => {
        this.scrollY = yOffset;
        // 当滚动超过占位Tabs顶部时,显示吸顶Tabs
        this.isSticky = this.scrollY >= this.tabsTop;
      })
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
  }

  // 构建Tab内容
  @Builder
  buildTabContent(index: number) {
    Column() {
      Text(`这是${this.tabs[index]}页的内容`)
        .fontSize(18)
        .margin(20)
    }
    .width('100%')
    .height('100%')
  }
}

四、关键逻辑解析

  1. 双Tabs设计

    • 吸顶Tabs:通过 position: fixed 固定,默认隐藏(Visibility.None)。
    • 占位Tabs:隐藏但保留高度,用于计算滚动阈值。
  2. 滚动监听

    • 通过 Scroll.onScroll 获取滚动位置 scrollY
    • 当 scrollY >= tabsTop(占位Tabs的顶部位置),切换吸顶状态。
  3. 性能优化

    • 使用 onAreaChange 动态获取占位Tabs的位置,避免硬编码。
    • 吸顶Tabs的 zIndex 设为较高值,防止被其他组件覆盖。

五、注意事项

  1. 兼容性问题

    • 鸿蒙API版本需 ≥ 7(支持 Position.Fixed)。
    • 在折叠屏设备上需额外处理分屏布局。
  2. 交互细节

    • 吸顶时添加阴影或边框,增强视觉层次感:
     .border({ width: 1, color: '#DDDDDD' })
     .shadow({ radius: 5, color: '#20000000' })
  1. 动态内容高度
    • 如果Tab内容高度动态变化,需在 aboutToAppear 中重新计算占位高度:
     aboutToAppear() {
       this.tabsTop = /* 重新计算位置 */;
     }

六、最终效果

  • 滚动前:Tabs 随页面正常滚动。
  • 滚动到顶部:Tabs 固定,内容继续滚动。
  • 切换Tab:吸顶Tabs同步更新选中状态。
本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值