如何在Flutter中从新页面返回数据?Navigator 2.0实现方法咨询
嘿,这个问题我之前踩过坑!Navigator 2.0换成了声明式路由管理,和旧版的命令式玩法确实不一样,下面给你几个实用的实现方案,覆盖不同场景:
方案一:兼容旧版写法(最省心)
如果你还在混合使用旧版的Navigator.push跳转页面(别担心,2.0完全兼容这个API),那返回数据的逻辑几乎和旧版一模一样:
在基础页面用await Navigator.push(...)等待返回值,新页面用Navigator.pop(context, result)传值就行:
// 基础页面:跳转并接收返回值 ElevatedButton( onPressed: () async { final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => NewScreen()), ); // 处理返回数据 if (result != null) { debugPrint('收到新页面返回的数据:$result'); } }, child: const Text('跳转到新页面'), ) // 新页面:返回并传值 ElevatedButton( onPressed: () { Navigator.pop(context, "这是新页面返回的内容"); }, child: const Text('返回'), )
这个方案适合不想重构现有路由逻辑的场景,零学习成本。
方案二:纯声明式路由场景(完全适配2.0)
如果你的项目已经完全基于Router、RouterDelegate、RouteInformationParser这套声明式路由体系,那返回数据需要结合共享状态管理来实现(比如用ChangeNotifier、Provider或者Riverpod)。
举个用ChangeNotifier的例子:
- 先定义一个共享状态类,用来存返回数据:
class RouteResultNotifier extends ChangeNotifier { dynamic _result; dynamic get result => _result; void setResult(dynamic data) { _result = data; notifyListeners(); // 通知监听者更新 } void clearResult() { _result = null; notifyListeners(); } }
- 在
RouterDelegate里管理路由栈,同时关联这个状态类:
class AppRouterDelegate extends RouterDelegate<RouteConfig> with ChangeNotifier, PopNavigatorRouterDelegateMixin<RouteConfig> { final RouteResultNotifier resultNotifier; final GlobalKey<NavigatorState> navigatorKey = GlobalKey(); final List<RouteConfig> _routeStack = []; AppRouterDelegate(this.resultNotifier) { resultNotifier.addListener(notifyListeners); } @override Widget build(BuildContext context) { return Navigator( key: navigatorKey, pages: [ const MaterialPage(child: HomePage()), // 根据路由栈渲染新页面 if (_routeStack.any((config) => config is NewScreenConfig)) MaterialPage( child: NewScreen( onReturn: (data) { // 把返回数据存入状态类 resultNotifier.setResult(data); // 从路由栈移除新页面 _routeStack.removeWhere((config) => config is NewScreenConfig); notifyListeners(); }, ), ), ], onPopPage: (route, result) { if (!route.didPop(result)) return false; if (_routeStack.isNotEmpty) { _routeStack.removeLast(); notifyListeners(); } return true; }, ); } // 其他RouterDelegate必需的实现方法(比如setNewRoutePath等)... }
- 新页面通过回调传递返回数据:
class NewScreen extends StatelessWidget { final Function(dynamic) onReturn; const NewScreen({required this.onReturn, super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('新页面')), body: Center( child: ElevatedButton( onPressed: () { onReturn("通过声明式路由返回的数据"); }, child: const Text('返回'), ), ), ); } }
- 基础页面监听状态变化获取返回值:
class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { final resultNotifier = Provider.of<RouteResultNotifier>(context); return Scaffold( appBar: AppBar(title: const Text('首页')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(resultNotifier.result ?? "暂无返回数据"), ElevatedButton( onPressed: () { // 跳转到新页面:往路由栈加配置 Provider.of<AppRouterDelegate>(context, listen: false) ._routeStack.add(NewScreenConfig()); Provider.of<AppRouterDelegate>(context, listen: false).notifyListeners(); }, child: const Text('跳转到新页面'), ), ], ), ), ); } }
方案三:弹窗类页面(和旧版完全一致)
如果是showModalBottomSheet、showDialog这类弹窗式页面,2.0里的返回逻辑和旧版没有区别,直接用await接收返回值就行:
// 基础页面打开弹窗 ElevatedButton( onPressed: () async { final result = await showModalBottomSheet( context: context, builder: (context) => const BottomSheetPage(), ); debugPrint('弹窗返回的数据:$result'); }, child: const Text('打开底部弹窗'), ) // 弹窗页面返回数据 ElevatedButton( onPressed: () { Navigator.pop(context, "弹窗返回的内容"); }, child: const Text('关闭弹窗'), )
总结
- 兼容旧版跳转:直接用
push+pop+await,最省事; - 纯声明式路由:结合状态管理传递数据,适配2.0的设计理念;
- 弹窗类页面:和旧版逻辑完全一致,无需改动。
内容的提问来源于stack exchange,提问作者atdima




