Flutter如何实现带TabBar与TabBarView的带动画Bottom Sheet
实现思路
你当前的写法逻辑和要实现的效果方向不一致:你现在把TabBarView放在了Scaffold的body区域,切换Tab会直接替换整个页面内容,而参考效果里的Tab是固定在底部,点击后弹出对应高度的Bottom Sheet,不会替换页面主体内容。具体实现逻辑可以参考这几点:
- 先把Scaffold的body替换为你的App主业务内容,移除原来body里的TabBarView结构
- 不要直接使用Scaffold自带的bottomSheet属性,这个属性默认没有动态高度动画能力,你可以选择自定义可持久化Bottom Sheet,或者用模态Bottom Sheet组件承载Tab结构
- 把TabBar和TabBarView都放到Bottom Sheet的内容容器里,用
AnimatedSize或者AnimatedContainer包裹TabBarView,开启动画属性 - 给每个Tab对应的页面组件绑定GlobalKey,Tab切换时获取当前页面的渲染高度,传给动画控制器,驱动Bottom Sheet的高度平滑过渡,动画时长和曲线可以自己调整匹配参考效果
可用的第三方包
不用完全手搓动画逻辑,有成熟的第三方包可以直接适配这个场景:
- 优先选
sliding_up_panel:本身就是专门做可滑动底部面板的组件,支持自定义内部结构,自带高度变化动画,你只需要把TabBar+TabBarView放到面板内容里,开启动态尺寸动画的参数,就能实现Tab切换时的高度自动过渡效果,不需要自己手动计算每个页面的高度,适配成本很低。 - 也可以用
custom_bottom_sheet:对原生Bottom Sheet做了扩展,支持动态修改内容高度、自定义动画参数,对Tab场景的适配性也很好。
简化实现示例
这里给你一个基于sliding_up_panel的核心代码参考:
class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateMixin { late TabController _tabController; final PanelController _panelController = PanelController(); @override void initState() { super.initState(); _tabController = TabController(length: 4, vsync: this, initialIndex: 2); } @override void dispose() { _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // 这里放你的APP主页面内容 body: const SafeArea(child: Center(child: Text("APP主内容"))), body: SlidingUpPanel( controller: _panelController, minHeight: 60, // 最小高度设置为TabBar的高度 maxHeight: MediaQuery.of(context).size.height * 0.8, // 最大高度可根据需求调整 animatePanelSize: true, // 开启动态高度动画 panel: Column( children: [ // 固定的TabBar TabBar( controller: _tabController, labelColor: Colors.blue, indicatorColor: Colors.black, unselectedLabelColor: Colors.black, tabs: const [ Tab(icon: Icon(Icons.home_outlined)), Tab(icon: Icon(Icons.shopping_cart_outlined)), Tab(icon: Icon(Icons.favorite_border)), Tab(icon: Icon(Icons.send)), ], ), // 动态高度的Tab内容区域 Expanded( child: TabBarView( controller: _tabController, children: const [ HomePage(), PersonalData(), LoginPage(), RegistrationPage() ], ), ) ], ), ), ); } }
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

