back_button.dart 5.84 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7 8
import 'package:flutter/widgets.dart';

9
import 'debug.dart';
10
import 'icon_button.dart';
11
import 'icons.dart';
12
import 'material_localizations.dart';
13
import 'theme.dart';
14

15 16
/// A "back" icon that's appropriate for the current [TargetPlatform].
///
17 18
/// The current platform is determined by querying for the ambient [Theme].
///
19 20 21 22 23 24 25
/// See also:
///
///  * [BackButton], an [IconButton] with a [BackButtonIcon] that calls
///    [Navigator.maybePop] to return to the previous route.
///  * [IconButton], which is a more general widget for creating buttons
///    with icons.
///  * [Icon], a material design icon.
26
///  * [ThemeData.platform], which specifies the current platform.
27
class BackButtonIcon extends StatelessWidget {
28 29
  /// Creates an icon that shows the appropriate "back" image for
  /// the current platform (as obtained from the [Theme]).
30 31
  const BackButtonIcon({ Key key }) : super(key: key);

32
  /// Returns the appropriate "back" icon for the given `platform`.
33 34 35 36
  static IconData _getIconData(TargetPlatform platform) {
    switch (platform) {
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
37 38
      case TargetPlatform.linux:
      case TargetPlatform.windows:
39 40
        return Icons.arrow_back;
      case TargetPlatform.iOS:
41
      case TargetPlatform.macOS:
42 43 44 45 46 47 48
        return Icons.arrow_back_ios;
    }
    assert(false);
    return null;
  }

  @override
49
  Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context).platform));
50 51
}

52 53 54 55
/// A material design back button.
///
/// A [BackButton] is an [IconButton] with a "back" icon appropriate for the
/// current [TargetPlatform]. When pressed, the back button calls
56 57
/// [Navigator.maybePop] to return to the previous route unless a custom
/// [onPressed] callback is provided.
58 59 60 61 62 63 64 65 66 67 68 69
///
/// When deciding to display a [BackButton], consider using
/// `ModalRoute.of(context)?.canPop` to check whether the current route can be
/// popped. If that value is false (e.g., because the current route is the
/// initial route), the [BackButton] will not have any effect when pressed,
/// which could frustrate the user.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// See also:
///
///  * [AppBar], which automatically uses a [BackButton] in its
70 71
///    [AppBar.leading] slot when the [Scaffold] has no [Drawer] and the
///    current [Route] is not the [Navigator]'s first route.
72 73
///  * [BackButtonIcon], which is useful if you need to create a back button
///    that responds differently to being pressed.
74 75
///  * [IconButton], which is a more general widget for creating buttons with
///    icons.
76 77
///  * [CloseButton], an alternative which may be more appropriate for leaf
///    node pages in the navigation tree.
78 79 80
class BackButton extends StatelessWidget {
  /// Creates an [IconButton] with the appropriate "back" icon for the current
  /// target platform.
81
  const BackButton({ Key key, this.color, this.onPressed }) : super(key: key);
82 83 84 85 86 87

  /// The color to use for the icon.
  ///
  /// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
  /// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
  final Color color;
88

89 90 91 92
  /// An override callback to perform instead of the default behavior which is
  /// to pop the [Navigator].
  ///
  /// It can, for instance, be used to pop the platform's navigation stack
93
  /// via [SystemNavigator] instead of Flutter's [Navigator] in add-to-app
94 95 96 97 98
  /// situations.
  ///
  /// Defaults to null.
  final VoidCallback onPressed;

99 100
  @override
  Widget build(BuildContext context) {
101
    assert(debugCheckHasMaterialLocalizations(context));
102
    return IconButton(
103
      icon: const BackButtonIcon(),
104
      color: color,
105
      tooltip: MaterialLocalizations.of(context).backButtonTooltip,
106
      onPressed: () {
107 108 109 110 111
        if (onPressed != null) {
          onPressed();
        } else {
          Navigator.maybePop(context);
        }
112
      },
113 114 115
    );
  }
}
116

117
/// A material design close button.
118 119 120 121 122 123 124 125 126 127 128
///
/// A [CloseButton] is an [IconButton] with a "close" icon. When pressed, the
/// close button calls [Navigator.maybePop] to return to the previous route.
///
/// Use a [CloseButton] instead of a [BackButton] on fullscreen dialogs or
/// pages that may solicit additional actions to close.
///
/// See also:
///
///  * [AppBar], which automatically uses a [CloseButton] in its
///    [AppBar.leading] slot when appropriate.
129
///  * [BackButton], which is more appropriate for middle nodes in the
130 131
///    navigation tree or where pages can be popped instantaneously with
///    no user data consequence.
132
///  * [IconButton], to create other material design icon buttons.
133
class CloseButton extends StatelessWidget {
134
  /// Creates a Material Design close button.
135
  const CloseButton({ Key key, this.color, this.onPressed }) : super(key: key);
136 137 138 139 140 141

  /// The color to use for the icon.
  ///
  /// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
  /// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
  final Color color;
142

143 144 145 146
  /// An override callback to perform instead of the default behavior which is
  /// to pop the [Navigator].
  ///
  /// It can, for instance, be used to pop the platform's navigation stack
147
  /// via [SystemNavigator] instead of Flutter's [Navigator] in add-to-app
148 149 150 151 152
  /// situations.
  ///
  /// Defaults to null.
  final VoidCallback onPressed;

153 154
  @override
  Widget build(BuildContext context) {
155
    assert(debugCheckHasMaterialLocalizations(context));
156
    return IconButton(
157
      icon: const Icon(Icons.close),
158
      color: color,
159
      tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
160
      onPressed: () {
161 162 163 164 165
        if (onPressed != null) {
          onPressed();
        } else {
          Navigator.maybePop(context);
        }
166 167 168 169
      },
    );
  }
}