You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Flutter中从新页面返回数据?Navigator 2.0实现方法咨询

在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)

如果你的项目已经完全基于RouterRouterDelegateRouteInformationParser这套声明式路由体系,那返回数据需要结合共享状态管理来实现(比如用ChangeNotifierProvider或者Riverpod)。

举个用ChangeNotifier的例子:

  1. 先定义一个共享状态类,用来存返回数据:
class RouteResultNotifier extends ChangeNotifier {
  dynamic _result;
  dynamic get result => _result;

  void setResult(dynamic data) {
    _result = data;
    notifyListeners(); // 通知监听者更新
  }

  void clearResult() {
    _result = null;
    notifyListeners();
  }
}
  1. 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等)...
}
  1. 新页面通过回调传递返回数据:
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('返回'),
        ),
      ),
    );
  }
}
  1. 基础页面监听状态变化获取返回值:
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('跳转到新页面'),
            ),
          ],
        ),
      ),
    );
  }
}

方案三:弹窗类页面(和旧版完全一致)

如果是showModalBottomSheetshowDialog这类弹窗式页面,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

火山引擎 最新活动