如何在SlidingUpPanel下滑时逐步隐藏BottomNavigationBar?
针对你遇到的onPanelSlide回调卡顿问题,核心原因是频繁调用setState导致整个页面频繁重建。以下是两种高效且专业的实现方案,能达到类似Airbnb的流畅效果:
方案一:使用AnimatedBuilder联动PanelController
利用SlidingUpPanel的PanelController内置动画驱动,通过AnimatedBuilder仅更新BottomNavigationBar组件,避免全局刷新:
import 'package:flutter/material.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final PanelController _panelController = PanelController(); @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: AnimatedBuilder( animation: _panelController, builder: (context, child) { // 获取面板当前位置:0=完全收起,1=完全展开 final panelPosition = _panelController.isAttached ? _panelController.position : 0.0; // 设置触发隐藏的阈值,面板滑动超过20%时开始隐藏导航栏 final threshold = 0.2; final hideProgress = (panelPosition / threshold).clamp(0.0, 1.0); return Transform.translate( offset: Offset(0, hideProgress * kBottomNavigationBarHeight), child: Opacity( opacity: 1.0 - hideProgress, child: child, ), ); }, child: BottomNavigationBar( items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'), BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'), BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'), ], ), ), body: SlidingUpPanel( controller: _panelController, minHeight: 80, panel: const Center(child: Text('滑动面板内容')), body: const Center(child: Text('主页面内容')), ), ); } }
方案二:使用ValueListenableBuilder监听面板位置
PanelController的position属性是ValueNotifier<double>,通过ValueListenableBuilder精准监听位置变化,仅更新导航栏的动画状态:
import 'package:flutter/material.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final PanelController _panelController = PanelController(); @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: ValueListenableBuilder<double>( valueListenable: _panelController.position, builder: (context, position, child) { final threshold = 0.2; final hideProgress = (position / threshold).clamp(0.0, 1.0); return AnimatedSlide( offset: Offset(0, hideProgress), duration: const Duration(milliseconds: 150), curve: Curves.easeInOut, child: AnimatedOpacity( opacity: 1.0 - hideProgress, duration: const Duration(milliseconds: 150), curve: Curves.easeInOut, child: child, ), ); }, child: BottomNavigationBar( items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'), BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'), BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'), ], ), ), body: SlidingUpPanel( controller: _panelController, minHeight: 80, panel: const Center(child: Text('滑动面板内容')), body: const Center(child: Text('主页面内容')), ), ); } }
核心优化点
- 避免全局刷新:两种方案都只针对BottomNavigationBar组件进行局部更新,不会触发整个页面的
setState - 平滑动画过渡:通过计算面板滑动进度,结合透明度和位移动画,实现和Airbnb一致的自然隐藏效果
- 性能高效:利用Flutter内置的动画组件,避免手动计算和频繁回调导致的性能损耗
内容的提问来源于stack exchange,提问作者Mickael Roignant
相关产品推荐
相关产品推荐

