Flutter笔记--popUntilWithResult

在Flutter开发中,popUntilWithResult经常会用到,它是Flutter框架中用于简化页面导航和结果传递的API,它允许使用者从嵌套的页面栈中直接返回到目标页面,并携带结果数据。简单总结如下:

API:

popUntilWithResult:结合了popUntil和结果传递的能力。它会从当前页面开始,逐级检查页面栈,直到找到匹配的目标页面,然后直接返回到该页面,并携带结果数据。
场景:

1 表单提交后返回上级页面

2 筛选页面返回主列表并更新数据

3 多级设置页面返回并保存配置

栗子:

Dart 复制代码
import 'package:flutter/material.dart';

void main() => runApp(const MyPopTest());
class MyPopTest extends StatelessWidget {
  const MyPopTest({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const HomePage(),
      theme: ThemeData(primarySwatch: Colors.blue),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String _result = "暂无数据";
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Home 首页")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              _result,
              style: const TextStyle(fontSize: 22, color: Colors.blue),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (_) => const Page1()),
                ).then((value) {
                  if (value != null) {
                    setState(() {
                      _result = "收到:$value";
                    });
                  }
                });
              },
              child: const Text("跳转到 Page1"),
            ),
          ],
        ),
      ),
    );
  }
}

// Page1
class Page1 extends StatelessWidget {
  const Page1({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Page1")),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Navigator.push(
            context,
            MaterialPageRoute(builder: (_) => const Page2()),
          ),
          child: const Text("跳转到 Page2"),
        ),
      ),
    );
  }
}

// Page2
class Page2 extends StatelessWidget {
  const Page2({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Page2")),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Navigator.push(
            context,
            MaterialPageRoute(builder: (_) => const Page3()),
          ),
          child: const Text("跳转到 Page3"),
        ),
      ),
    );
  }
}

class Page3 extends StatelessWidget {
  const Page3({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Page3")),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.popUntilWithResult(
              context,
                  (route) => route.isFirst, 
              "来自Page3的数据",
            );
          },
          child: const Text(
            "返回首页并传值",
            style: TextStyle(fontSize: 18),
          ),
        ),
      ),
    );
  }
}
Dart 复制代码
import 'package:flutter/material.dart';

void main() => runApp(const MyPopTest01());

class MyPopTest01 extends StatelessWidget {
  const MyPopTest01({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (ctx) => const HomePage(),
        '/list': (ctx) => const ListPage(),
        '/edit': (ctx) => const EditPage(),
      },
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("首页")),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Navigator.pushNamed(context, '/list'),
          child: const Text("进入列表页"),
        ),
      ),
    );
  }
}

class ListPage extends StatefulWidget {
  const ListPage({super.key});
  @override
  State<ListPage> createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
  String info = "等待编辑结果...";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("列表页")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(info, style: const TextStyle(fontSize: 18, color: Colors.green)),
            ElevatedButton(
              onPressed: () {
                Navigator.pushNamed(context, '/edit').then((value) {
                  if (value != null) {
                    setState(() {
                      info = "更新:${value.toString()}";
                    });
                  }
                });
              },
              child: const Text("去编辑页"),
            ),
          ],
        ),
      ),
    );
  }
}

class EditPage extends StatelessWidget {
  const EditPage({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("编辑页")),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.popUntilWithResult(
              context,
                  (route) => route.settings.name == '/list',
              {
                "id": 1001,
                "title": "已完成编辑",
                "time": DateTime.now().toString(),
              },
            );
          },
          child: const Text("保存并返回列表页"),
        ),
      ),
    );
  }
}

注意:

1 版本兼容性:确保使用 Flutter 3.41 或更高版本。

2 目标页面唯一性:确保页面栈中只有一个匹配的目标页面,否则可能返回错误的页面。

3 结果类型安全:传递结果时建议使用 Map<String, dynamic> 或自定义模型类,并在目标页面进行类型检查。

4 异步处理:如果目标页面需要异步处理结果,尽量在initState或didChangeDependencies中处理。

源码:

Dart 复制代码
@optionalTypeArgs
  void popUntilWithResult<T extends Object?>(RoutePredicate predicate, T? result) {
    _RouteEntry? candidate = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate);

    while (candidate != null) {
      if (predicate(candidate.route)) {
        return;
      }
      // Check what would be next if we pop this route.
      final _RouteEntry? next = _lastRouteEntryWhereOrNull(
        (_RouteEntry e) => _RouteEntry.isPresentPredicate(e) && e != candidate,
      );

      if (next != null && !next.route.willHandlePopInternally && predicate(next.route)) {
        pop<T>(result);
      } else {
        pop();
      }

      candidate = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate);
    }
  }

分析:

Dart 复制代码
<T extends Object?>:泛型类型 T,表示返回结果的类型;
RoutePredicate predicate:一个回调函数,用于判断当前路由是否为目标路由
T? result:需要传递到目标路由的结果数据

流程:

1 初始化候选路由;

2 循环检查路由栈;

3 查找下一个候选路由;

4 决定是否带结果返回;

5 更新候选路由;

相关推荐
iiiiii114 分钟前
【论文阅读笔记】Reparameterization Proximal Policy Optimization (RPO):将PPO的稳定性引入可微分强化学习
论文阅读·人工智能·笔记·深度学习·机器学习·机器人·具身智能
布鲁飞丝27 分钟前
从零实现富文本编辑器#-浏览器选区与编辑器选区模型同步
java·前端·编辑器
写不来代码的草莓熊36 分钟前
Cesium 地图交互绘制圆形、多边形
前端·javascript·地图
weixin_427771611 小时前
前端版本检测
前端
鱼子星_1 小时前
【C++】深入剖析list:list及其双向迭代器实现
开发语言·数据结构·c++·笔记·stl·list
禅思院1 小时前
流式 Markdown 渲染完全指南【引子】
前端·架构·前端框架
起司喵喵1 小时前
Flutter-MacOS桌面OS系统|flutter.+window_manager客户端OS模板
flutter·macos·策略模式
JackSparrow4141 小时前
前端安全之JS混淆+请求加密+请求签名以提升爬虫难度
前端·javascript·后端·爬虫·python·安全
IMPYLH2 小时前
HTML 的 <em> 元素
java·前端·html
看昭奚恤哭2 小时前
基于 RuoYi-Vue-Pro 定制了一个后台管理系统 magic-admin , 开源出来!
前端·vue.js·开源