美文网首页
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