一、报错信息
Flutter 界面跳转时 , 报如下错误 :
======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
When the exception was thrown, this was the stack:
#0 Navigator.of.<anonymous closure> (package:flutter/src/widgets/navigator.dart:2711:9)
#1 Navigator.of (package:flutter/src/widgets/navigator.dart:2718:6)
#2 HeroAnimation.build.<anonymous closure> (package:flutter_animation/main.dart:57:25)
#3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:994:20)
#4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#68181
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(216.4, 420.6)
finalLocalPosition: Offset(160.7, 193.9)
button: 1
sent tap down
====================================================================================================
错误代码 :
void main() {
runApp(
HeroAnimation()
);
}
class HeroAnimation extends StatelessWidget{
@override
Widget build(BuildContext context) {
// 时间膨胀系数 , 用于降低动画运行速度
timeDilation = 10.0;
return MaterialApp(
home: Scaffold(
body: Container(
child: HeroWidget(
imageUrl: "https://img-blog.csdnimg.cn/20210329101628636.jpg",
width: 300,
// 点击事件 , 这里点击该组件后 , 跳转到新页面
onTap: (){
print("点击事件触发");
Navigator.of(context).push(
MaterialPageRoute(
builder: (context){
/// 跳转到的新界面再此处定义
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
padding: EdgeInsets.all(20),
alignment: Alignment.topLeft,
child: HeroWidget(
imageUrl: "https://img-blog.csdnimg.cn/20210329101628636.jpg",
width: 100,
onTap: (){
/// 退出当前界面
Navigator.of(context).pop();
},
),
),
),
);
}
)
);
},
),
),
),
);
}
}
二、问题分析
Navigator operation requested with a context that does not include a Navigator.
该错误与跳转的目标界面无关 , 只与当前的界面有关 ;
The [MaterialApp] configures the top-level [Navigator] to search for routes
in the following order:
1. For the `/` route, the [home] property, if non-null, is used.
2. Otherwise, the [routes] table is used, if it has an entry for the route.
3. Otherwise, [onGenerateRoute] is called, if provided. It should return a
non-null value for any _valid_ route not handled by [home] and [routes].
4. Finally if all else fails [onUnknownRoute] is called.
If a [Navigator] is created, at least one of these options must handle the
`/` route, since it is used when an invalid [initialRoute] is specified on
startup (e.g. by another application launching this one with an intent on
Android; see [dart:ui.PlatformDispatcher.defaultRouteName]).
This widget also configures the observer of the top-level [Navigator] (if
any) to perform [Hero] animations.
If [home], [routes], [onGenerateRoute], and [onUnknownRoute] are all null,
and [builder] is not null, then no [Navigator] is created.
上面是 MaterialApp 的注释 , MaterialApp 中会自动创建一个 Navigator , 此处使用了 MaterialApp 仍然报上述错误 ;
Navigator 查找机制 : 这是由于调用了 Navigator.of(context)
代码获取 Navigator , 注意这里的 context 上下文关联的是 StatelessWidget 组件 , 也就是数从该 StatelessWidget 组件开始 , 向上查找 Navigator ;
但是实际的层级是这样的 , StatelessWidget 包裹 MaterialApp 包裹 Scaffold 包裹 Container , 查找 Navigator 时 , 越过了 MaterialApp , 直接从最顶层的 StatelessWidget 组件开始向上查找 , 肯定找不到 Navigator , 这里直接报错了 ;
这是由于 Navigator 的查找机制导致的错误 , 解决这个问题也很简单 , 在 StatelessWidget 的外层再包裹一个 MaterialApp , 这样就可以解决问题了 ;
三、解决方案
在 main.dart 中的 main() 函数中 , 使用 MaterialApp 包裹界面跳转的组件 ;
这样在 StatelessWidget 组件的外层又包裹了一层 MaterialApp , 这样从 StatelessWidget 组件开始向上查找 Navigator , 就可以找到 Navigator , 问题解决 ;
void main() {
runApp(
MaterialApp(
title: "Hero 动画",
home: HeroAnimation(),
)
);
}