button.dart 4.37 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
import 'package:flutter/widgets.dart';
6

7
import 'colors.dart';
8
import 'debug.dart';
9 10 11
import 'ink_well.dart';
import 'material.dart';
import 'theme.dart';
12

13 14 15 16 17 18 19 20 21 22 23 24 25
enum ButtonColor { normal, accent }

class ButtonTheme extends InheritedWidget {
  ButtonTheme({
    Key key,
    this.color,
    Widget child
  }) : super(key: key, child: child) {
    assert(child != null);
  }

  final ButtonColor color;

26 27 28
  /// The color from the closest instance of this class that encloses the given context.
  ///
  /// Defaults to [ButtonColor.normal] if none exists.
29
  static ButtonColor of(BuildContext context) {
Ian Hickson's avatar
Ian Hickson committed
30
    ButtonTheme result = context.inheritFromWidgetOfExactType(ButtonTheme);
31 32 33 34 35 36 37
    return result?.color ?? ButtonColor.normal;
  }

  bool updateShouldNotify(ButtonTheme old) => color != old.color;
}

/// Base class for buttons in the Material theme.
38 39 40 41
/// Rather than using this class directly, please use [FlatButton] or [RaisedButton].
///
/// MaterialButtons whose [onPressed] handler is null will be disabled. To have
/// an enabled button, make sure to pass a non-null value for onPressed.
42
abstract class MaterialButton extends StatefulComponent {
43
  MaterialButton({
44
    Key key,
45
    this.child,
46
    this.textTheme,
47
    this.textColor,
48
    this.disabledTextColor,
49
    this.onPressed
50
  }) : super(key: key);
51

52
  final Widget child;
53 54 55
  final ButtonColor textTheme;
  final Color textColor;
  final Color disabledTextColor;
56 57 58 59

  /// The callback that is invoked when the button is tapped or otherwise activated.
  ///
  /// If this is set to null, the button will be disabled.
60
  final VoidCallback onPressed;
Hixie's avatar
Hixie committed
61

62 63
  /// Whether the button is enabled or disabled. Buttons are disabled by default. To
  /// enable a button, set its [onPressed] property to a non-null value.
64 65
  bool get enabled => onPressed != null;

Hixie's avatar
Hixie committed
66 67 68 69 70
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    if (!enabled)
      description.add('disabled');
  }
71 72
}

73 74 75
abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
  bool highlight = false;

Hans Muller's avatar
Hans Muller committed
76
  int get elevation;
77
  Color getColor(BuildContext context);
78 79 80 81
  ThemeBrightness getColorBrightness(BuildContext context);

  Color getTextColor(BuildContext context) {
    if (config.enabled) {
82 83 84
      if (config.textColor != null)
        return config.textColor;
      switch (config.textTheme ?? ButtonTheme.of(context)) {
85 86 87 88 89 90 91 92 93 94 95
        case ButtonColor.accent:
          return Theme.of(context).accentColor;
        case ButtonColor.normal:
          switch (getColorBrightness(context)) {
            case ThemeBrightness.light:
              return Colors.black87;
            case ThemeBrightness.dark:
              return Colors.white;
          }
      }
    }
96 97
    if (config.disabledTextColor != null)
      return config.disabledTextColor;
98 99 100 101 102 103 104 105
    switch (getColorBrightness(context)) {
      case ThemeBrightness.light:
        return Colors.black26;
      case ThemeBrightness.dark:
        return Colors.white30;
    }
  }

106 107
  void _handleHighlightChanged(bool value) {
    setState(() {
108
      // mostly just used by the RaisedButton subclass to change the elevation
109 110 111 112 113
      highlight = value;
    });
  }

  Widget build(BuildContext context) {
114
    assert(debugCheckHasMaterial(context));
115 116 117 118 119 120 121 122 123
    Widget contents = new InkWell(
      onTap: config.onPressed,
      onHighlightChanged: _handleHighlightChanged,
      child: new Container(
        padding: new EdgeDims.symmetric(horizontal: 8.0),
        child: new Center(
          widthFactor: 1.0,
          child: config.child
        )
124
      )
125
    );
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    TextStyle style = Theme.of(context).text.button.copyWith(color: getTextColor(context));
    int elevation = this.elevation;
    Color color = getColor(context);
    if (elevation > 0 || color != null) {
      contents = new Material(
        type: MaterialType.button,
        color: getColor(context),
        elevation: elevation,
        textStyle: style,
        child: contents
      );
    } else {
      contents = new DefaultTextStyle(
        style: style,
        child: contents
      );
    }
143 144 145
    return new Container(
      height: 36.0,
      constraints: new BoxConstraints(minWidth: 88.0),
146 147
      padding: const EdgeDims.symmetric(horizontal: 8.0),
      margin: const EdgeDims.all(8.0),
148
      child: contents
149 150 151
    );
  }
}