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 更新候选路由;

相关推荐
圣光SG3 小时前
Maven 学习笔记(基础入门版)
笔记·maven
树獭非懒3 小时前
Google A2UI:让 AI 智能体「开口说界面」
前端·人工智能·后端
Wect3 小时前
LeetCode 4. 寻找两个正序数组的中位数:二分优化思路详解
前端·算法·typescript
李剑一3 小时前
纯干货,前端字体极致优化!谷歌、阿里、字节、腾讯都在用的终极解决方案,Vue3 + Vite 直接抄,页面提速不妥协!
前端·vue.js·面试
memeflyfly3 小时前
Vercel 自动部署完全指南:从配置到问题排查
前端·前端工程化
智者知已应修善业4 小时前
【C++非递归剪枝问题凑钱方案数】2024-7-18
c语言·c++·经验分享·笔记·算法·剪枝
身如柳絮随风扬4 小时前
Git 超详细学习笔记
笔记·git
星辰徐哥4 小时前
C语言Web开发:CGI、FastCGI、Nginx深度解析
c语言·前端·nginx
云潮汐表4 小时前
浒浦潮汐表查询2026-03-28
笔记