// Copyright 2014 The Flutter 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 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'color_scheme.dart'; import 'colors.dart'; import 'constants.dart'; import 'flat_button.dart'; import 'material_button.dart'; import 'material_state.dart'; import 'outline_button.dart'; import 'raised_button.dart'; import 'theme.dart'; import 'theme_data.dart' show MaterialTapTargetSize; /// Used with [ButtonTheme] and [ButtonThemeData] to define a button's base /// colors, and the defaults for the button's minimum size, internal padding, /// and shape. /// /// See also: /// /// * [RaisedButton], [FlatButton], [OutlineButton], which are configured /// based on the ambient [ButtonTheme]. enum ButtonTextTheme { /// Button text is black or white depending on [ThemeData.brightness]. normal, /// Button text is [ThemeData.accentColor]. accent, /// Button text is based on [ThemeData.primaryColor]. primary, } /// Used with [ButtonTheme] and [ButtonThemeData] to define how the button bar /// should size itself with either constraints or internal padding. enum ButtonBarLayoutBehavior { /// Button bars will be constrained to a minimum height of 52. /// /// This setting is require to create button bars which conform to the /// material specification. constrained, /// Button bars will calculate their padding from the button theme padding. padded, } /// Used with [ButtonThemeData] to configure the color and geometry of buttons. /// /// A button theme can be specified as part of the overall Material theme /// using [ThemeData.buttonTheme]. The Material theme's button theme data /// can be overridden with [ButtonTheme]. /// /// The actual appearance of buttons depends on the button theme, the /// button's enabled state, its elevation (if any), and the overall [Theme]. /// /// See also: /// /// * [FlatButton] [RaisedButton], and [OutlineButton], which are styled /// based on the ambient button theme. /// * [RawMaterialButton], which can be used to configure a button that doesn't /// depend on any inherited themes. class ButtonTheme extends InheritedTheme { /// Creates a button theme. /// /// The [textTheme], [minWidth], [height], and [colorScheme] arguments /// must not be null. ButtonTheme({ Key key, ButtonTextTheme textTheme = ButtonTextTheme.normal, ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded, double minWidth = 88.0, double height = 36.0, EdgeInsetsGeometry padding, ShapeBorder shape, bool alignedDropdown = false, Color buttonColor, Color disabledColor, Color focusColor, Color hoverColor, Color highlightColor, Color splashColor, ColorScheme colorScheme, MaterialTapTargetSize materialTapTargetSize, Widget child, }) : assert(textTheme != null), assert(minWidth != null && minWidth >= 0.0), assert(height != null && height >= 0.0), assert(alignedDropdown != null), assert(layoutBehavior != null), data = ButtonThemeData( textTheme: textTheme, minWidth: minWidth, height: height, padding: padding, shape: shape, alignedDropdown: alignedDropdown, layoutBehavior: layoutBehavior, buttonColor: buttonColor, disabledColor: disabledColor, focusColor: focusColor, hoverColor: hoverColor, highlightColor: highlightColor, splashColor: splashColor, colorScheme: colorScheme, materialTapTargetSize: materialTapTargetSize, ), super(key: key, child: child); /// Creates a button theme from [data]. /// /// The [data] argument must not be null. const ButtonTheme.fromButtonThemeData({ Key key, @required this.data, Widget child, }) : assert(data != null), super(key: key, child: child); // TODO(darrenaustin): remove after this deprecation warning has been on // stable for a couple of releases. // See https://github.com/flutter/flutter/issues/37333 // /// Creates a button theme that is appropriate for button bars, as used in /// dialog footers and in the headers of data tables. /// /// Deprecated. Please use [ButtonBarTheme] instead which offers more /// flexibility to configure [ButtonBar] widgets. /// /// To migrate instances of code that were just wrapping a [ButtonBar]: /// /// ```dart /// ButtonTheme.bar( /// child: ButtonBar(...) /// ); /// ``` /// /// you can just remove the `ButtonTheme.bar` as the defaults are now handled /// by [ButtonBar] directly. /// /// If you have more complicated usages of `ButtonTheme.bar` like: /// /// ```dart /// ButtonTheme.bar( /// padding: EdgeInsets.symmetric(horizontal: 10.0), /// textTheme: ButtonTextTheme.accent, /// child: ButtonBar(...), /// ); /// ``` /// /// you can remove the `ButtonTheme.bar` and move the parameters to the /// [ButtonBar] instance directly: /// /// ```dart /// ButtonBar( /// padding: EdgeInsets.symmetric(horizontal: 10.0), /// textTheme: ButtonTextTheme.accent, /// ... /// ); /// ``` /// /// You can also replace the defaults for all [ButtonBar] widgets by updating /// [ThemeData.buttonBarTheme] for your app. @Deprecated( 'Use ButtonBarTheme instead. ' 'This feature was deprecated after v1.9.1.' ) ButtonTheme.bar({ Key key, ButtonTextTheme textTheme = ButtonTextTheme.accent, double minWidth = 64.0, double height = 36.0, EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 8.0), ShapeBorder shape, bool alignedDropdown = false, Color buttonColor, Color disabledColor, Color focusColor, Color hoverColor, Color highlightColor, Color splashColor, ColorScheme colorScheme, Widget child, ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded, }) : assert(textTheme != null), assert(minWidth != null && minWidth >= 0.0), assert(height != null && height >= 0.0), assert(alignedDropdown != null), data = ButtonThemeData( textTheme: textTheme, minWidth: minWidth, height: height, padding: padding, shape: shape, alignedDropdown: alignedDropdown, layoutBehavior: layoutBehavior, buttonColor: buttonColor, disabledColor: disabledColor, focusColor: focusColor, hoverColor: hoverColor, highlightColor: highlightColor, splashColor: splashColor, colorScheme: colorScheme, ), super(key: key, child: child); /// Specifies the color and geometry of buttons. final ButtonThemeData data; /// The closest instance of this class that encloses the given context. /// /// Typical usage is as follows: /// /// ```dart /// ButtonThemeData theme = ButtonTheme.of(context); /// ``` static ButtonThemeData of(BuildContext context) { final ButtonTheme inheritedButtonTheme = context.dependOnInheritedWidgetOfExactType<ButtonTheme>(); ButtonThemeData buttonTheme = inheritedButtonTheme?.data; if (buttonTheme?.colorScheme == null) { // if buttonTheme or buttonTheme.colorScheme is null final ThemeData theme = Theme.of(context); buttonTheme ??= theme.buttonTheme; if (buttonTheme.colorScheme == null) { buttonTheme = buttonTheme.copyWith( colorScheme: theme.buttonTheme.colorScheme ?? theme.colorScheme, ); assert(buttonTheme.colorScheme != null); } } return buttonTheme; } @override Widget wrap(BuildContext context, Widget child) { final ButtonTheme ancestorTheme = context.findAncestorWidgetOfExactType<ButtonTheme>(); return identical(this, ancestorTheme) ? child : ButtonTheme.fromButtonThemeData(data: data, child: child); } @override bool updateShouldNotify(ButtonTheme oldWidget) => data != oldWidget.data; } /// Used with [ButtonTheme] to configure the color and geometry of buttons. /// /// A button theme can be specified as part of the overall Material theme /// using [ThemeData.buttonTheme]. The Material theme's button theme data /// can be overridden with [ButtonTheme]. class ButtonThemeData extends Diagnosticable { /// Create a button theme object that can be used with [ButtonTheme] /// or [ThemeData]. /// /// The [textTheme], [minWidth], [height], [alignedDropDown], and /// [layoutBehavior] parameters must not be null. The [minWidth] and /// [height] parameters must greater than or equal to zero. /// /// The ButtonTheme's methods that have a [MaterialButton] parameter and /// have a name with a `get` prefix are used by [RaisedButton], /// [OutlineButton], and [FlatButton] to configure a [RawMaterialButton]. const ButtonThemeData({ this.textTheme = ButtonTextTheme.normal, this.minWidth = 88.0, this.height = 36.0, EdgeInsetsGeometry padding, ShapeBorder shape, this.layoutBehavior = ButtonBarLayoutBehavior.padded, this.alignedDropdown = false, Color buttonColor, Color disabledColor, Color focusColor, Color hoverColor, Color highlightColor, Color splashColor, this.colorScheme, MaterialTapTargetSize materialTapTargetSize, }) : assert(textTheme != null), assert(minWidth != null && minWidth >= 0.0), assert(height != null && height >= 0.0), assert(alignedDropdown != null), assert(layoutBehavior != null), _buttonColor = buttonColor, _disabledColor = disabledColor, _focusColor = focusColor, _hoverColor = hoverColor, _highlightColor = highlightColor, _splashColor = splashColor, _padding = padding, _shape = shape, _materialTapTargetSize = materialTapTargetSize; /// The minimum width for buttons. /// /// The actual horizontal space allocated for a button's child is /// at least this value less the theme's horizontal [padding]. /// /// Defaults to 88.0 logical pixels. final double minWidth; /// The minimum height for buttons. /// /// Defaults to 36.0 logical pixels. final double height; /// Defines a button's base colors, and the defaults for the button's minimum /// size, internal padding, and shape. /// /// Despite the name, this property is not a [TextTheme], its value is not a /// collection of [TextStyle]s. final ButtonTextTheme textTheme; /// Defines whether a [ButtonBar] should size itself with a minimum size /// constraint or with padding. /// /// Defaults to [ButtonBarLayoutBehavior.padded]. final ButtonBarLayoutBehavior layoutBehavior; /// Simply a convenience that returns [minWidth] and [height] as a /// [BoxConstraints] object: /// /// ```dart /// return BoxConstraints( /// minWidth: minWidth, /// minHeight: height, /// ); /// ``` BoxConstraints get constraints { return BoxConstraints( minWidth: minWidth, minHeight: height, ); } /// Padding for a button's child (typically the button's label). /// /// Defaults to 24.0 on the left and right if [textTheme] is /// [ButtonTextTheme.primary], 16.0 on the left and right otherwise. /// /// See also: /// /// * [getPadding], which is used by [RaisedButton], [OutlineButton] /// and [FlatButton]. EdgeInsetsGeometry get padding { if (_padding != null) return _padding; switch (textTheme) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: return const EdgeInsets.symmetric(horizontal: 16.0); case ButtonTextTheme.primary: return const EdgeInsets.symmetric(horizontal: 24.0); } assert(false); return EdgeInsets.zero; } final EdgeInsetsGeometry _padding; /// The shape of a button's material. /// /// The button's highlight and splash are clipped to this shape. If the /// button has an elevation, then its drop shadow is defined by this /// shape as well. /// /// Defaults to a rounded rectangle with circular corner radii of 4.0 if /// [textTheme] is [ButtonTextTheme.primary], a rounded rectangle with /// circular corner radii of 2.0 otherwise. /// /// See also: /// /// * [getShape], which is used by [RaisedButton], [OutlineButton] /// and [FlatButton]. ShapeBorder get shape { if (_shape != null) return _shape; switch (textTheme) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: return const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(2.0)), ); case ButtonTextTheme.primary: return const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4.0)), ); } return const RoundedRectangleBorder(); } final ShapeBorder _shape; /// If true, then a [DropdownButton] menu's width will match the button's /// width. /// /// If false (the default), then the dropdown's menu will be wider than /// its button. In either case the dropdown button will line up the leading /// edge of the menu's value with the leading edge of the values /// displayed by the menu items. /// /// This property only affects [DropdownButton] and its menu. final bool alignedDropdown; /// The background fill color for [RaisedButton]s. /// /// This property is null by default. /// /// If the button is in the focused, hovering, or highlighted state, then the /// [focusColor], [hoverColor], or [highlightColor] will take precedence over /// the [focusColor]. /// /// See also: /// /// * [getFillColor], which is used by [RaisedButton] to compute its /// background fill color. final Color _buttonColor; /// The background fill color for disabled [RaisedButton]s. /// /// This property is null by default. /// /// See also: /// /// * [getDisabledFillColor], which is used by [RaisedButton] to compute its /// background fill color. final Color _disabledColor; /// The fill color of the button when it has the input focus. /// /// This property is null by default. /// /// If the button is in the hovering or highlighted state, then the [hoverColor] /// or [highlightColor] will take precedence over the [focusColor]. /// /// See also: /// /// * [getFocusColor], which is used by [RaisedButton], [OutlineButton] /// and [FlatButton]. final Color _focusColor; /// The fill color of the button when a pointer is hovering over it. /// /// This property is null by default. /// /// If the button is in the highlighted state, then the [highlightColor] will /// take precedence over the [hoverColor]. /// /// See also: /// /// * [getHoverColor], which is used by [RaisedButton], [OutlineButton] /// and [FlatButton]. final Color _hoverColor; /// The color of the overlay that appears when a button is pressed. /// /// This property is null by default. /// /// See also: /// /// * [getHighlightColor], which is used by [RaisedButton], [OutlineButton] /// and [FlatButton]. final Color _highlightColor; /// The color of the ink "splash" overlay that appears when a button is tapped. /// /// This property is null by default. /// /// See also: /// /// * [getSplashColor], which is used by [RaisedButton], [OutlineButton] /// and [FlatButton]. final Color _splashColor; /// A set of thirteen colors that can be used to derive the button theme's /// colors. /// /// This property was added much later than the theme's set of highly /// specific colors, like [ThemeData.buttonColor], [ThemeData.highlightColor], /// [ThemeData.splashColor] etc. /// /// The colors for new button classes can be defined exclusively in terms /// of [colorScheme]. When it's possible, the existing buttons will /// (continue to) gradually migrate to it. final ColorScheme colorScheme; // The minimum size of a button's tap target. // // This property is null by default. // // See also: // // * [getMaterialTargetTapSize], which is used by [RaisedButton], // [OutlineButton] and [FlatButton]. final MaterialTapTargetSize _materialTapTargetSize; /// The [button]'s overall brightness. /// /// Returns the button's [MaterialButton.colorBrightness] if it is non-null, /// otherwise the color scheme's [ColorScheme.brightness] is returned. Brightness getBrightness(MaterialButton button) { return button.colorBrightness ?? colorScheme.brightness; } /// Defines the [button]'s base colors, and the defaults for the button's /// minimum size, internal padding, and shape. /// /// Despite the name, this property is not the [TextTheme] whose /// [TextTheme.button] is used as the button text's [TextStyle]. ButtonTextTheme getTextTheme(MaterialButton button) { return button.textTheme ?? textTheme; } /// The foreground color of the [button]'s text and icon when /// [MaterialButton.onPressed] is null (when MaterialButton.enabled is false). /// /// Returns the button's [MaterialButton.disabledColor] if it is non-null. /// Otherwise the color scheme's [ColorScheme.onSurface] color is returned /// with its opacity set to 0.38. /// /// If [MaterialButton.textColor] is a [MaterialStateProperty<Color>], it will be /// used as the `disabledTextColor`. It will be resolved in the [MaterialState.disabled] state. Color getDisabledTextColor(MaterialButton button) { if (button.textColor is MaterialStateProperty<Color>) return button.textColor; if (button.disabledTextColor != null) return button.disabledTextColor; return colorScheme.onSurface.withOpacity(0.38); } /// The [button]'s background color when [MaterialButton.onPressed] is null /// (when [MaterialButton.enabled] is false). /// /// Returns the button's [MaterialButton.disabledColor] if it is non-null. /// /// Otherwise the value of the `disabledColor` constructor parameter /// is returned, if it is non-null. /// /// Otherwise the color scheme's [ColorScheme.onSurface] color is returned /// with its opacity set to 0.38. Color getDisabledFillColor(MaterialButton button) { if (button.disabledColor != null) return button.disabledColor; if (_disabledColor != null) return _disabledColor; return colorScheme.onSurface.withOpacity(0.38); } /// The button's background fill color or null for buttons that don't have /// a background color. /// /// Returns [MaterialButton.color] if it is non-null and the button /// is enabled. /// /// Otherwise, returns [MaterialButton.disabledColor] if it is non-null and /// the button is disabled. /// /// Otherwise, if button is a [FlatButton] or an [OutlineButton] then null is /// returned. /// /// Otherwise, if button is a [RaisedButton], returns the `buttonColor` /// constructor parameter if it was non-null and the button is enabled. /// /// Otherwise the fill color depends on the value of [getTextTheme]. /// /// * [ButtonTextTheme.normal] or [ButtonTextTheme.accent], the /// color scheme's [ColorScheme.primary] color if the [button] is enabled /// the value of [getDisabledFillColor] otherwise. /// * [ButtonTextTheme.primary], if the [button] is enabled then the value /// of the `buttonColor` constructor parameter if it is non-null, /// otherwise the color scheme's ColorScheme.primary color. If the button /// is not enabled then the colorScheme's [ColorScheme.onSurface] color /// with opacity 0.12. Color getFillColor(MaterialButton button) { final Color fillColor = button.enabled ? button.color : button.disabledColor; if (fillColor != null) return fillColor; if (button is FlatButton || button is OutlineButton || button.runtimeType == MaterialButton) return null; if (button.enabled && button is RaisedButton && _buttonColor != null) return _buttonColor; switch (getTextTheme(button)) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: return button.enabled ? colorScheme.primary : getDisabledFillColor(button); case ButtonTextTheme.primary: return button.enabled ? _buttonColor ?? colorScheme.primary : colorScheme.onSurface.withOpacity(0.12); } assert(false); return null; } /// The foreground color of the [button]'s text and icon. /// /// If [button] is not [MaterialButton.enabled], the value of /// [getDisabledTextColor] is returned. If the button is enabled and /// [buttonTextColor] is non-null, then [buttonTextColor] is returned. /// /// Otherwise the text color depends on the value of [getTextTheme] /// and [getBrightness]. /// /// * [ButtonTextTheme.normal]: [Colors.white] is used if [getBrightness] /// resolves to [Brightness.dark]. [Colors.black87] is used if /// [getBrightness] resolves to [Brightness.light]. /// * [ButtonTextTheme.accent]: [colorScheme.secondary]. /// * [ButtonTextTheme.primary]: If [getFillColor] is dark then [Colors.white], /// otherwise if [button] is a [FlatButton] or an [OutlineButton] then /// [colorScheme.primary], otherwise [Colors.black]. Color getTextColor(MaterialButton button) { if (!button.enabled) return getDisabledTextColor(button); if (button.textColor != null) return button.textColor; switch (getTextTheme(button)) { case ButtonTextTheme.normal: return getBrightness(button) == Brightness.dark ? Colors.white : Colors.black87; case ButtonTextTheme.accent: return colorScheme.secondary; case ButtonTextTheme.primary: final Color fillColor = getFillColor(button); final bool fillIsDark = fillColor != null ? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark : getBrightness(button) == Brightness.dark; if (fillIsDark) return Colors.white; if (button is FlatButton || button is OutlineButton) return colorScheme.primary; return Colors.black; } assert(false); return null; } /// The color of the ink "splash" overlay that appears when the (enabled) /// [button] is tapped. /// /// Returns the button's [MaterialButton.splashColor] if it is non-null. /// /// Otherwise, returns the value of the `splashColor` constructor parameter /// it is non-null and [button] is a [RaisedButton] or an [OutlineButton]. /// /// Otherwise, returns the value of the `splashColor` constructor parameter /// if it is non-null and [button] is a [FlatButton] and /// [getTextTheme] is not [ButtonTextTheme.primary] /// /// Otherwise, returns [getTextColor] with an opacity of 0.12. Color getSplashColor(MaterialButton button) { if (button.splashColor != null) return button.splashColor; if (_splashColor != null && (button is RaisedButton || button is OutlineButton)) return _splashColor; if (_splashColor != null && button is FlatButton) { switch (getTextTheme(button)) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: return _splashColor; case ButtonTextTheme.primary: break; } } return getTextColor(button).withOpacity(0.12); } /// The fill color of the button when it has input focus. /// /// Returns the button's [MaterialButton.focusColor] if it is non-null. /// Otherwise the focus color depends on [getTextTheme]: /// /// * [ButtonTextTheme.normal], [ButtonTextTheme.accent]: returns the /// value of the `focusColor` constructor parameter if it is non-null, /// otherwise the value of [getTextColor] with opacity 0.12. /// * [ButtonTextTheme.primary], returns [Colors.transparent]. Color getFocusColor(MaterialButton button) { return button.focusColor ?? _focusColor ?? getTextColor(button).withOpacity(0.12); } /// The fill color of the button when it has input focus. /// /// Returns the button's [MaterialButton.focusColor] if it is non-null. /// Otherwise the focus color depends on [getTextTheme]: /// /// * [ButtonTextTheme.normal], [ButtonTextTheme.accent], /// [ButtonTextTheme.primary]: returns the value of the `focusColor` /// constructor parameter if it is non-null, otherwise the value of /// [getTextColor] with opacity 0.04. Color getHoverColor(MaterialButton button) { return button.hoverColor ?? _hoverColor ?? getTextColor(button).withOpacity(0.04); } /// The color of the overlay that appears when the [button] is pressed. /// /// Returns the button's [MaterialButton.highlightColor] if it is non-null. /// Otherwise the highlight color depends on [getTextTheme]: /// /// * [ButtonTextTheme.normal], [ButtonTextTheme.accent]: returns the /// value of the `highlightColor` constructor parameter if it is non-null, /// otherwise the value of [getTextColor] with opacity 0.16. /// * [ButtonTextTheme.primary], returns [Colors.transparent]. Color getHighlightColor(MaterialButton button) { if (button.highlightColor != null) return button.highlightColor; switch (getTextTheme(button)) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: return _highlightColor ?? getTextColor(button).withOpacity(0.16); case ButtonTextTheme.primary: return Colors.transparent; } assert(false); return Colors.transparent; } /// The [button]'s elevation when it is enabled and has not been pressed. /// /// Returns the button's [MaterialButton.elevation] if it is non-null. /// /// If button is a [FlatButton] then elevation is 0.0, otherwise it is 2.0. double getElevation(MaterialButton button) { if (button.elevation != null) return button.elevation; if (button is FlatButton) return 0.0; return 2.0; } /// The [button]'s elevation when it is enabled and has focus. /// /// Returns the button's [MaterialButton.focusElevation] if it is non-null. /// /// If button is a [FlatButton] or an [OutlineButton] then the focus /// elevation is 0.0, otherwise the highlight elevation is 4.0. double getFocusElevation(MaterialButton button) { if (button.focusElevation != null) return button.focusElevation; if (button is FlatButton) return 0.0; if (button is OutlineButton) return 0.0; return 4.0; } /// The [button]'s elevation when it is enabled and has focus. /// /// Returns the button's [MaterialButton.hoverElevation] if it is non-null. /// /// If button is a [FlatButton] or an [OutlineButton] then the hover /// elevation is 0.0, otherwise the highlight elevation is 4.0. double getHoverElevation(MaterialButton button) { if (button.hoverElevation != null) return button.hoverElevation; if (button is FlatButton) return 0.0; if (button is OutlineButton) return 0.0; return 4.0; } /// The [button]'s elevation when it is enabled and has been pressed. /// /// Returns the button's [MaterialButton.highlightElevation] if it is non-null. /// /// If button is a [FlatButton] or an [OutlineButton] then the highlight /// elevation is 0.0, otherwise the highlight elevation is 8.0. double getHighlightElevation(MaterialButton button) { if (button.highlightElevation != null) return button.highlightElevation; if (button is FlatButton) return 0.0; if (button is OutlineButton) return 0.0; return 8.0; } /// The [button]'s elevation when [MaterialButton.onPressed] is null (when /// MaterialButton.enabled is false). /// /// Returns the button's [MaterialButton.elevation] if it is non-null. /// /// Otherwise the disabled elevation is 0.0. double getDisabledElevation(MaterialButton button) { if (button.disabledElevation != null) return button.disabledElevation; return 0.0; } /// Padding for the [button]'s child (typically the button's label). /// /// Returns the button's [MaterialButton.padding] if it is non-null. /// /// If this is a button constructed with [RaisedButton.icon] or /// [FlatButton.icon] or [OutlineButton.icon] then the padding is: /// `EdgeInsetsDirectional.only(start: 12.0, end: 16.0)`. /// /// Otherwise, returns [padding] if it is non-null. /// /// Otherwise, returns horizontal padding of 24.0 on the left and right if /// [getTextTheme] is [ButtonTextTheme.primary], 16.0 on the left and right /// otherwise. EdgeInsetsGeometry getPadding(MaterialButton button) { if (button.padding != null) return button.padding; if (button is MaterialButtonWithIconMixin) return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0); if (_padding != null) return _padding; switch (getTextTheme(button)) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: return const EdgeInsets.symmetric(horizontal: 16.0); case ButtonTextTheme.primary: return const EdgeInsets.symmetric(horizontal: 24.0); } assert(false); return EdgeInsets.zero; } /// The shape of the [button]'s [Material]. /// /// Returns the button's [MaterialButton.shape] if it is non-null, otherwise /// [shape] is returned. ShapeBorder getShape(MaterialButton button) { return button.shape ?? shape; } /// The duration of the [button]'s highlight animation. /// /// Returns the button's [MaterialButton.animationDuration] it if is non-null, /// otherwise 200ms. Duration getAnimationDuration(MaterialButton button) { return button.animationDuration ?? kThemeChangeDuration; } /// The [BoxConstraints] that the define the [button]'s size. /// /// By default this method just returns [constraints]. Subclasses /// could override this method to return a value that was, /// for example, based on the button's type. BoxConstraints getConstraints(MaterialButton button) => constraints; /// The minimum size of the [button]'s tap target. /// /// Returns the button's [MaterialButton.tapTargetSize] if it is non-null. /// /// Otherwise the value of the [materialTapTargetSize] constructor /// parameter is returned if that's non-null. /// /// Otherwise [MaterialTapTargetSize.padded] is returned. MaterialTapTargetSize getMaterialTapTargetSize(MaterialButton button) { return button.materialTapTargetSize ?? _materialTapTargetSize ?? MaterialTapTargetSize.padded; } /// Creates a copy of this button theme data object with the matching fields /// replaced with the non-null parameter values. ButtonThemeData copyWith({ ButtonTextTheme textTheme, ButtonBarLayoutBehavior layoutBehavior, double minWidth, double height, EdgeInsetsGeometry padding, ShapeBorder shape, bool alignedDropdown, Color buttonColor, Color disabledColor, Color focusColor, Color hoverColor, Color highlightColor, Color splashColor, ColorScheme colorScheme, MaterialTapTargetSize materialTapTargetSize, }) { return ButtonThemeData( textTheme: textTheme ?? this.textTheme, layoutBehavior: layoutBehavior ?? this.layoutBehavior, minWidth: minWidth ?? this.minWidth, height: height ?? this.height, padding: padding ?? this.padding, shape: shape ?? this.shape, alignedDropdown: alignedDropdown ?? this.alignedDropdown, buttonColor: buttonColor ?? _buttonColor, disabledColor: disabledColor ?? _disabledColor, focusColor: focusColor ?? _focusColor, hoverColor: hoverColor ?? _hoverColor, highlightColor: highlightColor ?? _highlightColor, splashColor: splashColor ?? _splashColor, colorScheme: colorScheme ?? this.colorScheme, materialTapTargetSize: materialTapTargetSize ?? _materialTapTargetSize, ); } @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; return other is ButtonThemeData && other.textTheme == textTheme && other.minWidth == minWidth && other.height == height && other.padding == padding && other.shape == shape && other.alignedDropdown == alignedDropdown && other._buttonColor == _buttonColor && other._disabledColor == _disabledColor && other._focusColor == _focusColor && other._hoverColor == _hoverColor && other._highlightColor == _highlightColor && other._splashColor == _splashColor && other.colorScheme == colorScheme && other._materialTapTargetSize == _materialTapTargetSize; } @override int get hashCode { return hashValues( textTheme, minWidth, height, padding, shape, alignedDropdown, _buttonColor, _disabledColor, _focusColor, _hoverColor, _highlightColor, _splashColor, colorScheme, _materialTapTargetSize, ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); const ButtonThemeData defaultTheme = ButtonThemeData(); properties.add(EnumProperty<ButtonTextTheme>('textTheme', textTheme, defaultValue: defaultTheme.textTheme)); properties.add(DoubleProperty('minWidth', minWidth, defaultValue: defaultTheme.minWidth)); properties.add(DoubleProperty('height', height, defaultValue: defaultTheme.height)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: defaultTheme.padding)); properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultTheme.shape)); properties.add(FlagProperty('alignedDropdown', value: alignedDropdown, defaultValue: defaultTheme.alignedDropdown, ifTrue: 'dropdown width matches button', )); properties.add(ColorProperty('buttonColor', _buttonColor, defaultValue: null)); properties.add(ColorProperty('disabledColor', _disabledColor, defaultValue: null)); properties.add(ColorProperty('focusColor', _focusColor, defaultValue: null)); properties.add(ColorProperty('hoverColor', _hoverColor, defaultValue: null)); properties.add(ColorProperty('highlightColor', _highlightColor, defaultValue: null)); properties.add(ColorProperty('splashColor', _splashColor, defaultValue: null)); properties.add(DiagnosticsProperty<ColorScheme>('colorScheme', colorScheme, defaultValue: defaultTheme.colorScheme)); properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', _materialTapTargetSize, defaultValue: null)); } }