Flutter多Drawer实现:点击不同ListTile展示对应数据
问题解决:Flutter中点击ListTile打开对应Drawer展示数据
原代码问题分析
- Drawer嵌套Scaffold不合理:Drawer本身是独立组件,无需嵌套Scaffold,会导致上下文混乱和结构冗余。
- SizedBox占满屏幕高度:导致第二个ListTile被挤出屏幕,无法交互。
- Drawer打开逻辑错误:嵌套结构下的
Scaffold.of(context)无法正确获取到目标Scaffold上下文,导致无法打开子Drawer。
修正后的实现方案
方式一:直接通过Navigator打开独立Drawer(推荐,无需依赖主页面Scaffold配置)
List filterType = ['Asset Code', 'Name', 'Description', 'Location']; class FilterTerms extends StatefulWidget { const FilterTerms({Key? key}) : super(key: key); @override State<FilterTerms> createState() => _FilterTermsState(); } class _FilterTermsState extends State<FilterTerms> { @override Widget build(BuildContext context) { return Drawer( child: ListView( padding: EdgeInsets.zero, children: [ DrawerHeader( decoration: BoxDecoration(color: Colors.blue[900]), padding: const EdgeInsets.all(8.0), child: const Center( child: Text( 'Filter Options', style: TextStyle( color: Colors.white, fontSize: 40, fontWeight: FontWeight.bold, ), ), ), ), // 直接添加可点击的ListTile ListTile( title: Text(filterType[0]), onTap: () { // 先关闭当前FilterTerms Drawer Navigator.of(context).pop(); // 打开对应数据的Drawer Navigator.push( context, MaterialPageRoute( builder: (context) => const Drawer(child: Center(child: Text('Code Data'))), fullscreenDialog: false, // 保持Drawer侧边栏样式 ), ); }, ), ListTile( title: Text(filterType[1]), onTap: () { Navigator.of(context).pop(); Navigator.push( context, MaterialPageRoute( builder: (context) => const Drawer(child: Center(child: Text('Name Data'))), ), ); }, ), ListTile( title: Text(filterType[2]), onTap: () { Navigator.of(context).pop(); Navigator.push( context, MaterialPageRoute( builder: (context) => const Drawer(child: Center(child: Text('Description Data'))), ), ); }, ), ListTile( title: Text(filterType[3]), onTap: () { Navigator.of(context).pop(); Navigator.push( context, MaterialPageRoute( builder: (context) => const Drawer(child: Center(child: Text('Location Data'))), ), ); }, ), ], ), ); } }
方式二:通过主页面Scaffold的endDrawer动态切换内容
如果需要统一使用主页面的侧边栏容器,可以通过回调通知主页面切换endDrawer内容:
- 修改FilterTerms组件
class FilterTerms extends StatefulWidget { final Function(Widget) onFilterSelected; const FilterTerms({Key? key, required this.onFilterSelected}) : super(key: key); @override State<FilterTerms> createState() => _FilterTermsState(); } class _FilterTermsState extends State<FilterTerms> { @override Widget build(BuildContext context) { return Drawer( child: ListView( padding: EdgeInsets.zero, children: [ // ... 保留原DrawerHeader ... ListTile( title: Text(filterType[0]), onTap: () { Navigator.of(context).pop(); widget.onFilterSelected(const Drawer(child: Center(child: Text('Code Data')))); }, ), // ... 其他ListTile逻辑类似 ... ], ), ); } }
- 主页面配置
class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { Widget? _currentEndDrawer; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), drawer: FilterTerms( onFilterSelected: (drawer) { setState(() { _currentEndDrawer = drawer; }); Scaffold.of(context).openEndDrawer(); }, ), endDrawer: _currentEndDrawer ?? const Drawer(child: SizedBox()), body: const Center(child: Text('Main Content')), ); } }
核心优化点
- 移除Drawer内部嵌套的Scaffold,直接用ListView承载内容,符合Flutter组件结构规范。
- 取消占满屏幕的SizedBox,让ListView自动管理子组件排列,确保所有ListTile可见。
- 点击ListTile时先关闭当前Drawer,再打开目标Drawer,避免多层Drawer叠加导致的交互混乱。
内容的提问来源于stack exchange,提问作者Vectorr
相关产品推荐
相关产品推荐

