返回键在页面跳转时经常用,如何控制返回键呢,这就用到了WillPopScope组件。有时为了防止用户误点,我们就需要通过WillPopScope组件控制是否真的需要返回。
先看看WillPopScope的源码;
// WillPopScope 继承 StatefulWidget,是一个有状态的组件
class WillPopScope extends StatefulWidget {
const WillPopScope({
Key? key,
required this.child, // 必须包含一个子组件
required this.onWillPop, // 必须实现onWillPop回调方法
}) : assert(child != null),
super(key: key);
// 只包含一个子组件
final Widget child;
// 为true时,执行该回调方法,路由返回
final WillPopCallback? onWillPop;
@override
_WillPopScopeState createState() => _WillPopScopeState();
}
// WillPopScope的状态类
class _WillPopScopeState extends State<WillPopScope> {
ModalRoute<dynamic>? _route;
// 依赖改变的时候,做了什么
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 从当前路由中移除回调方法
if (widget.onWillPop != null)
_route?.removeScopedWillPopCallback(widget.onWillPop!);
_route = ModalRoute.of(context);
// 从当前路由添加回调方法
if (widget.onWillPop != null)
_route?.addScopedWillPopCallback(widget.onWillPop!);
}
// 组件改变的时候,做了什么
@override
void didUpdateWidget(WillPopScope oldWidget) {
super.didUpdateWidget(oldWidget);
assert(_route == ModalRoute.of(context));
if (widget.onWillPop != oldWidget.onWillPop && _route != null) {
// 移除旧的回到方法
if (oldWidget.onWillPop != null)
_route!.removeScopedWillPopCallback(oldWidget.onWillPop!);
// 添加新的回到方法
if (widget.onWillPop != null)
_route!.addScopedWillPopCallback(widget.onWillPop!);
}
}
// 销毁方法
@override
void dispose() {
if (widget.onWillPop != null)
_route?.removeScopedWillPopCallback(widget.onWillPop!);
super.dispose();
}
@override
Widget build(BuildContext context) => widget.child;
}
通过源码可以发现,WillPopScope 是一个有状态的组件,通过依赖和组件的改变,来控制路由是否跳转。
接下来看一个小示例;
import 'package:flutter/material.dart';
class WillPopScopeTestRoute extends StatefulWidget {
@override
WillPopScopeTestRouteState createState() {
return new WillPopScopeTestRouteState();
}
}
class WillPopScopeTestRouteState extends State<WillPopScopeTestRoute> {
late DateTime _lastPressedAt; //上次点击时间
@override
void initState() {
super.initState();
_lastPressedAt = DateTime.now().subtract(const Duration(minutes: 1));
}
@override
Widget build(BuildContext context) {
return WillPopScope(
// 返回true时,执行返回操作;
onWillPop: () async {
if (DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
//两次点击间隔超过1秒则重新计时
_lastPressedAt = DateTime.now();
return false;
}
return true;
},
child: Container(
alignment: Alignment.center,
child: TextButton(onPressed: () {
},
child: Text("1秒内连续按两次返回键退出"),),
)
);
}
}
从一个页面跳往另一个页面,当点击返回按钮时,通过执行WillPopScope组件的onWillPop方法,还必须是异步的,当返回值为true,才执行返回操作;返回false,依旧停留在原页面。
通过这个Demo,可以发现,想控制返回键,必要条件两个:
- 通过WillPopScope的onWillPop组件;
- 以异步形式调用 onWillPop 方法;
网友评论