首先检查一下BackButton所在页面是不是被MaterialApp组件包裹了呢,被MaterialApp包裹的页面是无法通过BackButton组件返回到上一页的,将外层的MaterialApp去掉即可:
@override
Widget build(BuildContext context) {
return MaterialApp(
...
home: Scaffold(
appBar: AppBar(
title: Text('BackButton点击没反应'),
leading: BackButton(),
),
...
}
//改成
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BackButton点击没反应'),
leading: BackButton()//外层不能有MaterialApp,
),
...
}BackButton被点击的时候会调用maybePop进行返回:
@optionalTypeArgs
Future<bool> maybePop<T extends Object>([ T result ]) async {
final Route<T> route = _history.last;
assert(route._navigator == this);
final RoutePopDisposition disposition = await route.willPop();
if (disposition != RoutePopDisposition.bubble && mounted) {
if (disposition == RoutePopDisposition.pop)
pop(result);
return true;
}
return false;
}接下来说下一原理:
在上述代码中:
final RoutePopDisposition disposition = await route.willPop();
当BackButton被点击时,会通过route.willPop()决定是否可以返回到上一页,这里我们先看一下willPop()到底做了什么:
Future<RoutePopDisposition> willPop() async {
return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop;
}willPop会判断当前页面是不是处于栈顶(当前MaterialApp中的第一个页面),如果是则返回RoutePopDisposition.bubble,所以说只有当前页面不是MaterialApp中的第一个页面时才能通过maybePop返回到上一页,在上述案例中,BackButton被放在了MaterialApp下的第一个页面中所以会出现BackButton点击无效的问题。
接下来在扩充下maybePop与pop的区别,它们的不同之处在于maybePop会多了一步向系统询问是否处理当前返回操作,当Route.willPop返回值为RoutePopDisposition.bubble时即交给系统处理,这里也简单介绍RoutePopDisposition三个枚举值:
简单来讲,pop()要比maybePop()的功能更强大些,pop()不管当前页面是不是处于栈顶都会使当前页面关闭,也可以返回到上一个MaterialApp中的页面,而maybePop()只能返回当前MaterialApp中的上一个页面。
注意:pop()这么强大但它有个副作用,如果当前页面已经处于栈顶并且前面没有其他MaterialApp的时候,调用pop()你会看到黑屏,这是因为在这种情况下pop()将应用中的唯一的一个页面关闭导致的,所以为了防止这个问题可以在调用pop()之前通过Navigator.canPop(context)判断下是不是还可以返回。