美文网首页
Flutter开发上手,WillPopScope 导航返回拦截

Flutter开发上手,WillPopScope 导航返回拦截

作者: 程就人生 | 来源:发表于2021-07-19 21:09 被阅读0次

返回键在页面跳转时经常用,如何控制返回键呢,这就用到了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,可以发现,想控制返回键,必要条件两个:

  1. 通过WillPopScope的onWillPop组件;
  2. 以异步形式调用 onWillPop 方法;

相关文章

网友评论

      本文标题:Flutter开发上手,WillPopScope 导航返回拦截

      本文链接:https://www.haomeiwen.com/subject/eppwpltx.html