如何使用Flutter实现类似Talabat应用的餐厅详情页滚动效果

实现方案
该效果核心为头部可折叠+分类栏吸顶+左右列表滚动联动,以下分两种常见开发场景给出可落地实现逻辑:
1. Web/H5 端实现
核心实现步骤
- 页面结构拆分3个模块:
- 顶部餐厅详情模块:包含头图、名称、评分、配送信息等内容,无特殊定位属性,随页面滚动自然收起
- 分类导航栏:添加
position: sticky+top: 0属性,滚动到视口顶部后自动吸顶 - 内容展示区:flex布局分为左右两栏,左侧为分类列表,右侧为对应分类的餐品列表
- 滚动联动逻辑:
- 给右侧餐品滚动容器绑定滚动监听,计算每个餐品分类区块距离容器顶部的偏移量,当偏移量小于当前滚动距离时,同步高亮左侧对应分类选项
- 点击左侧分类时,调用
scrollIntoView方法将右侧对应分类区块滚动到可视区域,可配置behavior: 'smooth'实现平滑滚动效果 - 用节流函数包装滚动监听回调,滚动触发间隔控制在100ms左右,避免性能损耗
- 核心代码片段
/* 分类栏吸顶样式 */ .category-nav { position: sticky; top: 0; z-index: 99; background: #ffffff; } /* 右侧餐品滚动容器 */ .food-wrapper { height: calc(100vh - 48px); /* 48px为分类栏高度 */ overflow-y: auto; }
// 滚动高亮逻辑简化版 const handleScroll = throttle(() => { const scrollTop = document.querySelector('.food-wrapper').scrollTop document.querySelectorAll('.food-group').forEach((group, index) => { if (group.offsetTop <= scrollTop + 10) { // 同步高亮左侧对应分类 document.querySelectorAll('.category-item')[index].classList.add('active') } }) }, 100)
2. Flutter 端实现
核心实现步骤
- 外层用
NestedScrollView实现头部餐厅详情的折叠效果,headerSliverBuilder中放置餐厅详情对应的Sliver组件,设置pinned: false,滚动时可完全收起 - 分类导航栏用
SliverPersistentHeader实现,设置pinned: true,滚动到顶部后固定在视口顶部 - 正文区域用
SliverToBoxAdapter包裹左右联动列表,左侧为分类ListView,右侧为餐品分组ListView - 联动逻辑通过
ScrollController实现:- 给右侧餐品列表绑定滚动控制器,监听滚动偏移,计算每个餐品分组的位置,同步更新左侧分类选中状态
- 点击左侧分类时,计算右侧对应分组的滚动偏移量,调用
animateTo方法滚动到对应位置
- 核心代码片段
// 吸顶分类栏实现示例 SliverPersistentHeader( pinned: true, delegate: _StickyHeaderDelegate( child: const CategoryTabBar(), height: 48, ), ) // 自定义StickyHeaderDelegate class _StickyHeaderDelegate extends SliverPersistentHeaderDelegate { final Widget child; final double height; _StickyHeaderDelegate({required this.child, required this.height}); @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { return SizedBox.expand(child: child); } @override double get maxExtent => height; @override double get minExtent => height; @override bool shouldRebuild(covariant _StickyHeaderDelegate oldDelegate) { return oldDelegate.child != child || oldDelegate.height != height; } }
内容的提问来源于stack exchange,提问作者Owais
相关产品推荐
相关产品推荐

