为了避免用户误触返回按钮而导致 App 退出,在很多 App 中都拦截了用户点击返回键的按钮,然后进行一些防误触判断,比如当用户在某一个时间段内点击两次时,才会认为用户是要退出(而非误触)。Flutter中可以通过WillPopScope
来实现返回按钮拦截,我们看看WillPopScope
的默认构造函数:
const WillPopScope({
...
required WillPopCallback onWillPop,
required Widget child
})
onWillPop
是一个回调函数,当用户点击返回按钮时被调用(包括导航返回按钮及Android物理返回按钮)。该回调需要返回一个Future
对象,如果返回的Future
最终值为false
时,则当前路由不出栈(不会返回);最终值为true
时,当前路由出栈退出。我们需要提供这个回调来决定是否退出。
为了防止用户误触返回键退出,我们拦截返回事件。当用户在1秒内点击两次返回按钮时,则退出;如果间隔超过1秒则不退出,并重新记时。代码如下:
WillPopScope(
child: Container(
alignment: Alignment.center,
child: Text("1秒内连续按两次返回键退出"),
),
onWillPop: () async {
if (_lastPressedAt != null ||
DateTime.now().difference(_lastPressedAt!) >
Duration(seconds: 1)) {
//两次点击间隔超过1秒则重新计时
_lastPressedAt = DateTime.now();
print('false');
return false;
}
print('true');
return true;
});
App中有多个Navigator
我们的App通常是在MaterialApp和CupertinoApp下,MaterialApp和CupertinoApp本身有一个Navigator,所以默认情况下调用Navigator.pop或者Navigator.push就是在操作此Navigator。不过在一些情况下,我们希望有自己定义的Navigator,比如如下场景:
-
在页面底部有一个常驻bar,其上展示内容,这个常驻bar就需要一个自己的Navigator。
-
在使用TabView、BottomNavigationBar、CupertinoTabView这些组件时,希望有多个Tab,但每个Tab中有自己的导航行为,这时需要给每一个Tab加一个Navigator。
首页:
class MyHomePage1 extends StatefulWidget {
MyHomePage1({required Key key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePage1State createState() => _MyHomePage1State();
}
class _MyHomePage1State extends State<MyHomePage1> {
GlobalKey<NavigatorState> _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: getAppBar('Navigator'),
body: WillPopScope(
onWillPop: () async {
if (_key.currentState!.canPop()) {
_key.currentState!.pop();
return false;
}
return true;
},
child: Column(
children: <Widget>[
Expanded(
child: Navigator(
key: _key,
onGenerateRoute: (RouteSettings settings) =>
MaterialPageRoute(builder: (context) {
return OnePage();
}),
),
),
Container(
height: 64,
color: Colors.blue,
alignment: Alignment.center,
child: Text('底部Bar'),
)
],
)),
);
}
}
class OnePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: ElevatedButton(
child: Text('去下一个页面'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return TwoPage();
}));
},
),
),
),
);
}
}
class TwoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Text('这是第二个页面'),
),
),
);
}
}