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

Flutter Drawer记住选中项问题:条件样式不生效

解决Flutter Drawer复用与菜单项高亮不生效的问题

我来帮你分析一下问题所在,然后给出两种可行的解决方案:

问题根源

你当前的代码里有两个核心问题导致条件样式不生效:

  1. 执行顺序错误:你在onTap里先调用了Navigator.pop(ctxt)关闭Drawer,之后才调用setState更新选中状态。这时候Drawer已经被移除出Widget树了,setState触发的UI更新根本不会被渲染出来。
  2. 状态与页面不绑定:全局的sameDrawerOnly实例会保留之前的选中状态,当你从新页面回到首页时,Drawer还是会显示之前选中的菜单项,不符合“当前页面对应菜单项高亮”的预期。

方案一:调整执行顺序(快速修复)

只需要把setState移到Navigator.pop之前,这样在关闭Drawer前就能完成状态更新并渲染高亮样式:

// 修改DrawerOnly中的ListTile onTap逻辑
ListTile(
  title: Text("Item => A", style: itemClicked==1 ? TextStyle(
    fontWeight: FontWeight.bold,
    color: Colors.red.withOpacity(0.6)
  ) : null),
  onTap: () {
    // 先更新状态,再关闭Drawer
    setState(() {
      itemClicked=1;
    });
    Navigator.pop(ctxt);
    Navigator.push(ctxt, MaterialPageRoute(builder: (ctxt) => FirstPage()));
  },
),

同时,如果你希望回到首页时恢复默认选中状态,可以把MyHomePage改成StatefulWidget,在initState里重置状态:

class MyHomePage extends StatefulWidget {
  final String title;
  MyHomePage({Key key, this.title}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    // 重置Drawer的选中状态
    sameDrawerOnly.setState(() {
      sameDrawerOnly.state.itemClicked = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(child: Text('My Page!')),
      drawer: sameDrawerOnly,
    );
  }
}

方案二:根据路由自动高亮(推荐)

这种方法不需要维护额外的状态变量,而是通过当前路由自动判断应该高亮哪个菜单项,更可靠也更符合页面与菜单的对应关系:

步骤1:配置命名路由

修改MyApp,使用命名路由管理页面跳转:

class MyApp extends StatelessWidget {
  final appTitle = 'Drawer Demo';
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: appTitle,
      initialRoute: '/', // 首页路由
      routes: {
        '/': (context) => MyHomePage(title: appTitle),
        '/first': (context) => FirstPage(),
        '/second': (context) => SecondPage(),
      },
    );
  }
}

步骤2:修改DrawerOnly,根据路由判断高亮

去掉itemClicked变量,在build方法中获取当前路由名称,动态设置样式:

class DrawerOnly extends StatefulWidget {
  const DrawerOnly ({ Key key, }) : super(key: key);
  @override
  _DrawerOnlyState createState() => _DrawerOnlyState();
}

class _DrawerOnlyState extends State<DrawerOnly > {
  @override
  Widget build(BuildContext ctxt) {
    // 获取当前页面的路由名称
    final currentRoute = ModalRoute.of(ctxt)?.settings?.name;

    return Drawer(
      child: ListView(
        children: <Widget>[
          DrawerHeader(
            child: Text("DRAWER HEADER.."),
            decoration: BoxDecoration(color: Colors.orange),
          ),
          ListTile(
            title: Text("Item => A", style: currentRoute == '/first' ? TextStyle(
              fontWeight: FontWeight.bold,
              color: Colors.red.withOpacity(0.6)
            ) : null),
            onTap: () {
              Navigator.pop(ctxt);
              Navigator.pushNamed(ctxt, '/first'); // 使用命名路由跳转
            },
          ),
          ListTile(
            title: Text("Item => 2", style: currentRoute == '/second' ? TextStyle(
              fontWeight: FontWeight.bold , color: Colors.green.withOpacity(0.6)
            ) : null),
            onTap: () {
              Navigator.pop(ctxt);
              Navigator.pushNamed(ctxt, '/second'); // 使用命名路由跳转
            },
          ),
        ]
      )
    );
  }
}

步骤3:每个页面直接使用DrawerOnly实例

不需要再使用全局的sameDrawerOnly,每个页面的drawer直接创建DrawerOnly()即可:

class MyHomePage extends StatelessWidget {
  final String title;
  MyHomePage({Key key, this.title}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(child: Text('My Page!')),
      drawer: DrawerOnly(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext ctxt) {
    return Scaffold(
      drawer: DrawerOnly(),
      appBar: AppBar(title: Text("First Page")),
      body: Text("I belongs to First Page"),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext ctxt) {
    return Scaffold(
      drawer: DrawerOnly(),
      appBar: AppBar(title: Text("Second Page")),
      body: Text("I belongs to Second Page"),
    );
  }
}

这种方法的优势在于:

  • 不需要维护额外的状态变量,避免状态不同步的问题
  • 自动适配当前页面,打开Drawer时自动高亮对应菜单项
  • 不需要全局实例,代码更简洁可维护

内容的提问来源于stack exchange,提问作者user12021836

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 11:22:32