Flutter 的页面跳转,我一直觉得有点像“叠盘子”:打开新页面就是把盘子放上去,返回就是把最上面那只拿走。
理解了这个“栈”的模型,很多看起来绕的 API 就突然变得顺眼了。
这篇文章我按自己的使用习惯来写:先把最常用的 Navigator.push/pop 讲清楚,再聊命名路由、传参/返回值,最后补几个我踩过的坑。
1)最常用:push / pop(MaterialPageRoute)
从 A 跳到 B
1 | Navigator.of(context).push( |
这句干的事很朴素:把 DetailPage 压到导航栈顶。
从 B 返回到 A
1 | Navigator.of(context).pop(); |
通常我会把“返回”放在 AppBar 的 back 上(Flutter 默认就帮你处理了),或者在按钮里手动 pop()。
2)传参:把数据带过去(最省心的方式)
我习惯直接在页面构造函数里收参数:
1 | // A 页面 |
这类传参最大的好处是:类型安全,重构起来也舒服。
3)拿返回值:pop 的时候顺手带回去
有些交互很常见:去编辑页改个昵称,回到上一页刷新一下。
我一般用 push 的返回 Future 来接结果:
1 | // A 页面 |
这一套写下来很直观:去哪里拿结果、从哪里把结果带回,都在代码里摆得明明白白。
4)命名路由:适合“入口多、页面多”的项目
当页面数量上来、跳转入口变多(比如通知、深链、多个模块复用同一页),命名路由会更好管理一点。
最简单的 routes 表
1 | MaterialApp( |
带参数:我更常用 onGenerateRoute
routes 表在“无参页面”很好用;一旦要传参,我更倾向 onGenerateRoute 统一处理:
1 | MaterialApp( |
这写法谈不上多优雅,但它的优点是:路由入口集中,出了问题很好排查。
5)我常遇到的两个“导航小坑”
坑 A:context 用错了,push 找不到 Navigator
最典型的情况:你在 showDialog、Builder、或者某个局部组件的 context 里 push,结果报错说找不到 Navigator。
我的经验是:用离 Scaffold 更近的 context(比如页面的 context),或者干脆 Navigator.of(context, rootNavigator: true)。
坑 B:列表快速点击导致重复 push
如果 item 点击会请求接口 + 进入详情页,连点两下很容易 push 两次。
我一般会做一个简单的“防抖/锁”,或者在进入详情页前先禁用按钮一小段时间。
结尾:什么时候该上路由库?
只用 Flutter 自带的 Navigator,其实能搞定大多数业务。
如果你要做 Web(URL 同步、深链)、或者复杂的嵌套路由,我会建议看看 go_router 这类库——但那已经是另一篇文章了。