will_pop_scope.dart 2.29 KB
Newer Older
1 2 3 4 5
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'framework.dart';
6
import 'navigator.dart';
7 8 9 10 11 12 13
import 'routes.dart';

/// Registers a callback to veto attempts by the user to dismiss the enclosing
/// [ModalRoute].
///
/// See also:
///
14
///  * [ModalRoute.addScopedWillPopCallback] and [ModalRoute.removeScopedWillPopCallback],
15 16 17 18 19 20
///    which this widget uses to register and unregister [onWillPop].
class WillPopScope extends StatefulWidget {
  /// Creates a widget that registers a callback to veto attempts by the user to
  /// dismiss the enclosing [ModalRoute].
  ///
  /// The [child] argument must not be null.
21
  const WillPopScope({
22 23 24
    Key key,
    @required this.child,
    @required this.onWillPop,
25 26
  }) : assert(child != null),
       super(key: key);
27 28

  /// The widget below this widget in the tree.
29 30
  ///
  /// {@macro flutter.widgets.child}
31 32 33 34 35 36
  final Widget child;

  /// Called to veto attempts by the user to dismiss the enclosing [ModalRoute].
  ///
  /// If the callback returns a Future that resolves to false, the enclosing
  /// route will not be popped.
37
  final WillPopCallback onWillPop;
38 39

  @override
40
  _WillPopScopeState createState() => _WillPopScopeState();
41 42 43 44 45 46
}

class _WillPopScopeState extends State<WillPopScope> {
  ModalRoute<dynamic> _route;

  @override
47 48
  void didChangeDependencies() {
    super.didChangeDependencies();
49 50
    if (widget.onWillPop != null)
      _route?.removeScopedWillPopCallback(widget.onWillPop);
51
    _route = ModalRoute.of(context);
52 53
    if (widget.onWillPop != null)
      _route?.addScopedWillPopCallback(widget.onWillPop);
54 55 56
  }

  @override
57
  void didUpdateWidget(WillPopScope oldWidget) {
58
    super.didUpdateWidget(oldWidget);
59
    assert(_route == ModalRoute.of(context));
60 61 62 63 64
    if (widget.onWillPop != oldWidget.onWillPop && _route != null) {
      if (oldWidget.onWillPop != null)
        _route.removeScopedWillPopCallback(oldWidget.onWillPop);
      if (widget.onWillPop != null)
        _route.addScopedWillPopCallback(widget.onWillPop);
65 66 67 68 69
    }
  }

  @override
  void dispose() {
70 71
    if (widget.onWillPop != null)
      _route?.removeScopedWillPopCallback(widget.onWillPop);
72 73 74 75
    super.dispose();
  }

  @override
76
  Widget build(BuildContext context) => widget.child;
77
}