icon_button.dart 5.84 KB
Newer Older
1 2 3 4
// Copyright 2015 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.

5 6
import 'dart:math' as math;

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

10
import 'debug.dart';
11
import 'icon.dart';
Ian Hickson's avatar
Ian Hickson committed
12 13
import 'icon_theme.dart';
import 'icon_theme_data.dart';
14
import 'icons.dart';
15
import 'ink_well.dart';
16
import 'material.dart';
17
import 'theme.dart';
Hixie's avatar
Hixie committed
18
import 'tooltip.dart';
19

20
// Minimum logical pixel size of the IconButton.
21
const double _kMinButtonSize = 48.0;
22

23
/// A material design icon button.
24 25 26 27
///
/// An icon button is a picture printed on a [Material] widget that reacts to
/// touches by filling with color.
///
28 29
/// Icon buttons are commonly used in the [AppBar.actions] field, but they can
/// be used in many other places as well.
30
///
31 32
/// If the [onPressed] callback is null, then the button will be disabled and
/// will not react to touch.
33
///
34 35
/// Requires one of its ancestors to be a [Material] widget.
///
36 37
/// Will be automatically sized up to the recommended 48 logical pixels if smaller.
///
38 39 40 41
/// See also:
///
///  * [Icons]
///  * [AppBar]
42
class IconButton extends StatelessWidget {
43 44 45 46 47 48
  /// Creates an icon button.
  ///
  /// Icon buttons are commonly used in the [AppBar.actions] field, but they can
  /// be used in many other places as well.
  ///
  /// Requires one of its ancestors to be a [Material] widget.
49
  ///
50
  /// The [iconSize], [padding], and [alignment] arguments must not be null (though
51 52
  /// they each have default values).
  ///
Ian Hickson's avatar
Ian Hickson committed
53 54
  /// The [icon] argument must be specified, and is typically either an [Icon]
  /// or an [ImageIcon].
55 56
  const IconButton({
    Key key,
57
    this.iconSize: 24.0,
58 59
    this.padding: const EdgeInsets.all(8.0),
    this.alignment: FractionalOffset.center,
60
    @required this.icon,
61
    this.color,
62
    this.disabledColor,
63
    @required this.onPressed,
Hixie's avatar
Hixie committed
64
    this.tooltip
65
  }) : super(key: key);
66

Adam Barth's avatar
Adam Barth committed
67
  /// The size of the icon inside the button.
68 69
  ///
  /// This property must not be null. It defaults to 24.0.
70 71 72 73 74 75 76
  ///
  /// The size given here is passed down to the widget in the [icon] property
  /// via an [IconTheme]. Setting the size here instead of in, for example, the
  /// [Icon.size] property allows the [IconButton] to size the splash area to
  /// fit the [Icon]. If you were to set the size of the [Icon] using
  /// [Icon.size] instead, then the [IconButton] would default to 24.0 and then
  /// the [Icon] itself would likely get clipped.
77
  final double iconSize;
Adam Barth's avatar
Adam Barth committed
78

79 80
  /// The padding around the button's icon. The entire padded icon will react
  /// to input gestures.
81 82
  ///
  /// This property must not be null. It defaults to 8.0 padding on all sides.
83 84 85
  final EdgeInsets padding;

  /// Defines how the icon is positioned within the IconButton.
86 87
  ///
  /// This property must not be null. It defaults to [FractionalOffset.center].
88 89
  final FractionalOffset alignment;

Ian Hickson's avatar
Ian Hickson committed
90 91
  /// The icon to display inside the button.
  ///
92 93 94
  /// The [size] and [color] of the icon is configured automatically based on
  /// the properties of _this_ widget using an [IconTheme] and therefore should
  /// not be explicitly given in the icon widget.
95 96
  ///
  /// This property must not be null.
Ian Hickson's avatar
Ian Hickson committed
97 98 99
  ///
  /// See [Icon], [ImageIcon].
  final Widget icon;
Adam Barth's avatar
Adam Barth committed
100

101
  /// The color to use for the icon inside the button, if the icon is enabled.
Ian Hickson's avatar
Ian Hickson committed
102
  /// Defaults to leaving this up to the [icon] widget.
103 104 105 106
  ///
  /// The icon is enabled if [onPressed] is not null.
  ///
  /// See also [disabledColor].
107 108 109
  ///
  /// ```dart
  ///  new IconButton(
110
  ///    color: Colors.blue,
111 112 113 114
  ///    onPressed: _handleTap,
  ///    icon: Icons.widgets,
  ///  ),
  /// ```
Adam Barth's avatar
Adam Barth committed
115
  final Color color;
116

117 118 119 120 121 122 123 124
  /// The color to use for the icon inside the button, if the icon is disabled.
  /// Defaults to the [ThemeData.disabledColor] of the current [Theme].
  ///
  /// The icon is disabled if [onPressed] is null.
  ///
  /// See also [color].
  final Color disabledColor;

125
  /// The callback that is called when the button is tapped or otherwise activated.
126 127
  ///
  /// If this is set to null, the button will be disabled.
128
  final VoidCallback onPressed;
Adam Barth's avatar
Adam Barth committed
129 130 131 132 133

  /// Text that describes the action that will occur when the button is pressed.
  ///
  /// This text is displayed when the user long-presses on the button and is
  /// used for accessibility.
Hixie's avatar
Hixie committed
134
  final String tooltip;
135

136
  @override
137
  Widget build(BuildContext context) {
138
    assert(debugCheckHasMaterial(context));
139 140 141 142 143
    Color currentColor;
    if (onPressed != null)
      currentColor = color;
    else
      currentColor = disabledColor ?? Theme.of(context).disabledColor;
144 145

    Widget result = new ConstrainedBox(
146
      constraints: const BoxConstraints(minWidth: _kMinButtonSize, minHeight: _kMinButtonSize),
147 148 149 150 151
      child: new Padding(
        padding: padding,
        child: new SizedBox(
          height: iconSize,
          width: iconSize,
152 153 154 155 156
          child: new Align(
            alignment: alignment,
            child: new IconTheme.merge(
              context: context,
              data: new IconThemeData(
157
                size: iconSize,
158 159 160
                color: currentColor
              ),
              child: icon
161 162 163 164
            ),
          ),
        ),
      ),
165
    );
166

Hixie's avatar
Hixie committed
167 168 169 170 171 172
    if (tooltip != null) {
      result = new Tooltip(
        message: tooltip,
        child: result
      );
    }
Hixie's avatar
Hixie committed
173 174
    return new InkResponse(
      onTap: onPressed,
175
      child: result,
176 177 178 179 180
      radius: math.max(
        Material.defaultSplashRadius,
        (iconSize + math.min(padding.horizontal, padding.vertical)) * 0.7,
        // x 0.5 for diameter -> radius and + 40% overflow derived from other Material apps.
      ),
Hixie's avatar
Hixie committed
181
    );
182
  }
Hixie's avatar
Hixie committed
183

184
  @override
Hixie's avatar
Hixie committed
185 186 187
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    description.add('$icon');
Hixie's avatar
Hixie committed
188 189 190 191
    if (onPressed == null)
      description.add('disabled');
    if (tooltip != null)
      description.add('tooltip: "$tooltip"');
Hixie's avatar
Hixie committed
192
  }
193
}