本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(HarmonyOS)开发中,实现 Tabs吸顶效果(即滚动到顶部时固定)需要结合 Tabs 组件、Scroll 容器和动态布局控制。
一、实现原理
- 布局结构
- 使用
Scroll包裹整个页面内容,监听滚动事件。 - 将
Tabs分为两部分:- 吸顶的Tabs:固定在顶部(
position: fixed)。 - 占位Tabs:隐藏但保持高度,避免页面跳动。
- 吸顶的Tabs:固定在顶部(
- 使用
- 滚动逻辑
- 当页面滚动到
占位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%')
}
}
四、关键逻辑解析
-
双Tabs设计
- 吸顶Tabs:通过
position: fixed固定,默认隐藏(Visibility.None)。 - 占位Tabs:隐藏但保留高度,用于计算滚动阈值。
- 吸顶Tabs:通过
-
滚动监听
- 通过
Scroll.onScroll获取滚动位置scrollY。 - 当
scrollY >= tabsTop(占位Tabs的顶部位置),切换吸顶状态。
- 通过
-
性能优化
- 使用
onAreaChange动态获取占位Tabs的位置,避免硬编码。 - 吸顶Tabs的
zIndex设为较高值,防止被其他组件覆盖。
- 使用
五、注意事项
-
兼容性问题
- 鸿蒙API版本需 ≥ 7(支持
Position.Fixed)。 - 在折叠屏设备上需额外处理分屏布局。
- 鸿蒙API版本需 ≥ 7(支持
-
交互细节
- 吸顶时添加阴影或边框,增强视觉层次感:
.border({ width: 1, color: '#DDDDDD' })
.shadow({ radius: 5, color: '#20000000' })
- 动态内容高度
- 如果Tab内容高度动态变化,需在
aboutToAppear中重新计算占位高度:
- 如果Tab内容高度动态变化,需在
aboutToAppear() {
this.tabsTop = /* 重新计算位置 */;
}
六、最终效果
- 滚动前:Tabs 随页面正常滚动。
- 滚动到顶部:Tabs 固定,内容继续滚动。
- 切换Tab:吸顶Tabs同步更新选中状态。
1575

被折叠的 条评论
为什么被折叠?



