You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter多Drawer实现:点击不同ListTile展示对应数据

问题解决:Flutter中点击ListTile打开对应Drawer展示数据

原代码问题分析

  1. Drawer嵌套Scaffold不合理:Drawer本身是独立组件,无需嵌套Scaffold,会导致上下文混乱和结构冗余。
  2. SizedBox占满屏幕高度:导致第二个ListTile被挤出屏幕,无法交互。
  3. 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内容:

  1. 修改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逻辑类似 ...
        ],
      ),
    );
  }
}
  1. 主页面配置
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:05:38