Flutter自定义Drawer点击已打开页面重复跳转问题求助
问题解决:Flutter Drawer菜单项重复跳转页面
问题描述
自定义Drawer与AppBar后,点击Drawer菜单项时预期效果为:
- 若对应页面未打开:跳转至该页面并关闭Drawer
- 若页面已打开:仅关闭Drawer,不重复跳转
但当前点击已打开页面的Drawer项时,仍会重复打开该页面,自行添加的判断逻辑未生效。
错误原因
你当前的判断逻辑存在核心错误:
if (ModalRoute.of(context)?.settings.arguments is HomePage)
settings.arguments是传递给路由的参数,并非页面组件本身。你没有给HomePage路由传递任何参数,所以这个判断永远为false,导致每次都会执行跳转逻辑。
解决方案
方法一:通过路由名称判断(推荐)
利用你在HomePage中定义的静态路由名homerouter,直接判断当前路由的名称是否匹配:
步骤1:给SettingPage添加静态路由名
在SettingPage类中添加路由标识:
static const String settingRouter = '/settings';
步骤2:修改Drawer菜单项的判断逻辑
修改Home和Settings项的onTap方法:
Home项修改后代码
onTap: () { // 先关闭Drawer Navigator.pop(context); // 判断当前路由是否为HomePage的路由 if (ModalRoute.of(context)?.settings.name != HomePage.homerouter) { // 非Home页面时才执行跳转 Navigator.push( context, MaterialPageRoute( builder: (context) => const HomePage(), // 显式设置路由名称,确保判断生效 settings: const RouteSettings(name: HomePage.homerouter), ), ); } },
Settings项修改后代码
onTap: () { Navigator.pop(context); if (ModalRoute.of(context)?.settings.name != SettingPage.settingRouter) { Navigator.push( context, MaterialPageRoute( builder: (context) => const SettingPage(), settings: const RouteSettings(name: SettingPage.settingRouter), ), ); } },
方法二:通过页面类型判断
如果不使用路由名称,也可以直接判断当前页面的组件类型:
onTap: () { Navigator.pop(context); final currentRoute = ModalRoute.of(context); // 判断当前路由的页面是否为HomePage if (currentRoute is MaterialPageRoute && currentRoute.builder(context) is! HomePage) { Navigator.push( context, MaterialPageRoute(builder: (context) => const HomePage()), ); } },
修改后的完整Drawer代码
import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:lottie/lottie.dart'; import 'package:simplethread/src/auth/auth_service.dart'; import 'package:simplethread/src/screens/home.dart'; import 'package:simplethread/src/screens/setting_page.dart'; class MyDrawer extends StatelessWidget { const MyDrawer({super.key}); final String _animation = 'assets/animation/login_message.json'; void logout() { final _auth = AuthService(); _auth.signOut(); } @override Widget build(BuildContext context) { return Drawer( backgroundColor: Theme.of(context).colorScheme.background, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( children: [ const SizedBox(height: 60), Lottie.asset( _animation, fit: BoxFit.fill, width: 100, height: 100, ), Text( 'Simple Thread', style: GoogleFonts.playfairDisplay( textStyle: const TextStyle( letterSpacing: .5, fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black, ), ), ), const SizedBox(height: 25), // Home Page Item Padding( padding: const EdgeInsets.only(left: 25.0), child: ListTile( title: Text( "H O M E", style: GoogleFonts.playfairDisplay(color: Colors.black), ), leading: const Icon(Icons.home_rounded), onTap: () { Navigator.pop(context); if (ModalRoute.of(context)?.settings.name != HomePage.homerouter) { Navigator.push( context, MaterialPageRoute( builder: (context) => const HomePage(), settings: const RouteSettings(name: HomePage.homerouter), ), ); } }, ), ), // Setting Page Item Padding( padding: const EdgeInsets.only(left: 25.0), child: ListTile( title: Text( "S E T T I N G S", style: GoogleFonts.playfairDisplay(color: Colors.black), ), leading: const Icon(Icons.settings_rounded), onTap: () { Navigator.pop(context); if (ModalRoute.of(context)?.settings.name != SettingPage.settingRouter) { Navigator.push( context, MaterialPageRoute( builder: (context) => const SettingPage(), settings: const RouteSettings(name: SettingPage.settingRouter), ), ); } }, ), ), ], ), Padding( padding: const EdgeInsets.only(left: 25.0, bottom: 25.0), child: ListTile( title: Text( "L O G O U T", style: GoogleFonts.playfairDisplay(color: Colors.black), ), leading: const Icon(Icons.logout_rounded), onTap: logout, ), ), ], ), ); } }
补充说明
- 必须确保
SettingPage类中添加了static const String settingRouter = '/settings'; - 路由名称的方式更灵活,后续修改页面组件时,只要路由名称不变,判断逻辑无需改动
- 先执行
Navigator.pop(context)关闭Drawer,再判断是否跳转,交互体验更流畅
内容的提问来源于stack exchange,提问作者Future Insight
相关产品推荐
相关产品推荐

