diff --git a/dev/integration_tests/ios_host_app/flutterapp/lib/main b/dev/integration_tests/ios_host_app/flutterapp/lib/main index d770b1cad1..c00de68108 100644 --- a/dev/integration_tests/ios_host_app/flutterapp/lib/main +++ b/dev/integration_tests/ios_host_app/flutterapp/lib/main @@ -166,7 +166,7 @@ class _MyHomePageState extends State { style: const TextStyle(fontSize: 17.0), ), ), - const FlatButton( + const TextButton( child: Text('POP'), onPressed: SystemNavigator.pop, ), diff --git a/dev/integration_tests/ios_host_app/flutterapp/lib/marquee b/dev/integration_tests/ios_host_app/flutterapp/lib/marquee index 71375e4ad0..ff33e9f152 100644 --- a/dev/integration_tests/ios_host_app/flutterapp/lib/marquee +++ b/dev/integration_tests/ios_host_app/flutterapp/lib/marquee @@ -65,7 +65,7 @@ class MarqueeState extends State with SingleTickerProviderStateMixin { child: _MarqueeText(animation: animation), alignment: Alignment.centerLeft, ), - const FlatButton(child: Text('POP'), onPressed: SystemNavigator.pop), + const TextButton(child: Text('POP'), onPressed: SystemNavigator.pop), ], ), ), diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart index 9d1638fcd5..38bee62a28 100644 --- a/packages/flutter/lib/material.dart +++ b/packages/flutter/lib/material.dart @@ -74,7 +74,6 @@ export 'src/material/expansion_panel.dart'; export 'src/material/expansion_tile.dart'; export 'src/material/expansion_tile_theme.dart'; export 'src/material/feedback.dart'; -export 'src/material/flat_button.dart'; export 'src/material/flexible_space_bar.dart'; export 'src/material/floating_action_button.dart'; export 'src/material/floating_action_button_location.dart'; diff --git a/packages/flutter/lib/src/material/button.dart b/packages/flutter/lib/src/material/button.dart index cd94960cd4..9ad2aab04e 100644 --- a/packages/flutter/lib/src/material/button.dart +++ b/packages/flutter/lib/src/material/button.dart @@ -20,22 +20,20 @@ import 'theme_data.dart'; /// Creates a button based on [Semantics], [Material], and [InkWell] /// widgets. /// -/// ### This class is obsolete. -/// -/// Custom button classes can be created by configuring the -/// [ButtonStyle] of a [TextButton], [ElevatedButton] or an -/// [OutlinedButton]. -/// -/// FlatButton has been replaced by TextButton and ButtonTheme has been -/// replaced by TextButtonTheme. Please migrate code that uses them. -/// There's a detailed migration guide for the new button and button -/// theme classes in -/// [flutter.dev/go/material-button-migration-guide](https://flutter.dev/go/material-button-migration-guide). -/// /// This class does not use the current [Theme] or [ButtonTheme] to /// compute default values for unspecified parameters. It's intended to /// be used for custom Material buttons that optionally incorporate defaults /// from the themes or from app-specific sources. +/// +/// This class is planned to be deprecated in a future release, see +/// [ButtonStyleButton], the base class of [TextButton], [ElevatedButton], and +/// [OutlinedButton]. +/// +/// See also: +/// +/// * [TextButton], a simple flat button without a shadow. +/// * [ElevatedButton], a filled button whose material elevates when pressed. +/// * [OutlinedButton], a [TextButton] with a border outline. @Category(['Material', 'Button']) class RawMaterialButton extends StatefulWidget { /// Create a button based on [Semantics], [Material], and [InkWell] widgets. diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart index 600ed533e3..593f041ab8 100644 --- a/packages/flutter/lib/src/material/button_theme.dart +++ b/packages/flutter/lib/src/material/button_theme.dart @@ -8,7 +8,6 @@ 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 'theme.dart'; @@ -17,10 +16,6 @@ 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: -/// -/// * [FlatButton] which is configured based on the ambient [ButtonTheme]. enum ButtonTextTheme { /// Button text is black or white depending on [ThemeData.brightness]. normal, @@ -47,15 +42,12 @@ enum ButtonBarLayoutBehavior { /// Used with [ButtonThemeData] to configure the color and geometry of buttons. /// -/// ### This class is obsolete. +/// This class is planned to be deprecated in a future release. +/// Please use one or more of these buttons and associated themes instead: /// -/// Please use one or more of the new buttons and their themes -/// instead: [TextButton] and [TextButtonTheme], [ElevatedButton] and -/// [ElevatedButtonTheme], [OutlinedButton] and -/// [OutlinedButtonTheme]. The original classes have been deprecated, -/// please migrate code that uses them. There's a detailed -/// migration guide for the new button and button theme classes in -/// [flutter.dev/go/material-button-migration-guide](https://flutter.dev/go/material-button-migration-guide). +/// * [TextButton], [TextButtonTheme], [TextButtonThemeData], +/// * [ElevatedButton], [ElevatedButtonTheme], [ElevatedButtonThemeData], +/// * [OutlinedButton], [OutlinedButtonTheme], [OutlinedButtonThemeData] /// /// A button theme can be specified as part of the overall Material theme /// using [ThemeData.buttonTheme]. The Material theme's button theme data @@ -66,7 +58,6 @@ enum ButtonBarLayoutBehavior { /// /// See also: /// -/// * [FlatButton] which is 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 { @@ -163,21 +154,13 @@ class ButtonTheme extends InheritedTheme { /// Used with [ButtonTheme] to configure the color and geometry of buttons. /// -/// ### This class is obsolete. -/// -/// Please use one or more of the new buttons and their themes instead: +/// This class is planned to be deprecated in a future release. +/// Please use one or more of these buttons and associated themes instead: /// /// * [TextButton], [TextButtonTheme], [TextButtonThemeData], /// * [ElevatedButton], [ElevatedButtonTheme], [ElevatedButtonThemeData], /// * [OutlinedButton], [OutlinedButtonTheme], [OutlinedButtonThemeData] /// -/// FlatButton has been replaced by TextButton and ButtonTheme has been replaced -/// by TextButtonTheme. Please migrate code that uses them. -/// -/// There's a detailed migration guide for the new button and button -/// theme classes in -/// [flutter.dev/go/material-button-migration-guide](https://flutter.dev/go/material-button-migration-guide). -/// /// 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]. @@ -191,7 +174,7 @@ class ButtonThemeData with Diagnosticable { /// [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 [FlatButton] to configure a + /// have a name with a `get` prefix are used to configure a /// [RawMaterialButton]. const ButtonThemeData({ this.textTheme = ButtonTextTheme.normal, @@ -273,7 +256,8 @@ class ButtonThemeData with Diagnosticable { /// /// See also: /// - /// * [getPadding], which is used by [FlatButton]. + /// * [getPadding], which is used to calculate padding for the [button]'s + /// child (typically the button's label). EdgeInsetsGeometry get padding { if (_padding != null) return _padding!; @@ -299,7 +283,8 @@ class ButtonThemeData with Diagnosticable { /// /// See also: /// - /// * [getShape], which is used by [FlatButton]. + /// * [getShape], which is used to calculate the shape of the [button]'s + /// [Material]. ShapeBorder get shape { if (_shape != null) return _shape!; @@ -360,7 +345,8 @@ class ButtonThemeData with Diagnosticable { /// /// See also: /// - /// * [getFocusColor], which is used by [FlatButton]. + /// * [getFocusColor], which is used to compute the fill color of the button + /// when it has input focus. final Color? _focusColor; /// The fill color of the button when a pointer is hovering over it. @@ -372,7 +358,8 @@ class ButtonThemeData with Diagnosticable { /// /// See also: /// - /// * [getHoverColor], which is used by [FlatButton]. + /// * [getHoverColor], which is used to compute the fill color of the button + /// when it has input focus. final Color? _hoverColor; /// The color of the overlay that appears when a button is pressed. @@ -381,7 +368,8 @@ class ButtonThemeData with Diagnosticable { /// /// See also: /// - /// * [getHighlightColor], which is used by [FlatButton]. + /// * [getHighlightColor], which is used to compute the color of the overlay + /// that appears when the [button] is pressed. final Color? _highlightColor; /// The color of the ink "splash" overlay that appears when a button is tapped. @@ -390,7 +378,8 @@ class ButtonThemeData with Diagnosticable { /// /// See also: /// - /// * [getSplashColor], which is used by [FlatButton]. + /// * [getSplashColor], which is used to compute the color of the ink + /// "splash" overlay that appears when the (enabled) [button] is tapped. final Color? _splashColor; /// A set of thirteen colors that can be used to derive the button theme's @@ -408,10 +397,6 @@ class ButtonThemeData with Diagnosticable { // The minimum size of a button's tap target. // // This property is null by default. - // - // See also: - // - // * [getMaterialTargetTapSize], which is used by [FlatButton]. final MaterialTapTargetSize? _materialTapTargetSize; /// The [button]'s overall brightness. @@ -427,9 +412,7 @@ class ButtonThemeData with Diagnosticable { /// /// 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; - } + ButtonTextTheme getTextTheme(MaterialButton button) => button.textTheme ?? textTheme; /// The foreground color of the [button]'s text and icon when /// [MaterialButton.onPressed] is null (when MaterialButton.enabled is false). @@ -441,11 +424,7 @@ class ButtonThemeData with Diagnosticable { /// If [MaterialButton.textColor] is a [MaterialStateProperty], 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) - return button.textColor!; - if (button.disabledTextColor != null) - return button.disabledTextColor!; - return colorScheme!.onSurface.withOpacity(0.38); + return button.textColor ?? button.disabledTextColor ?? colorScheme!.onSurface.withOpacity(0.38); } /// The [button]'s background color when [MaterialButton.onPressed] is null @@ -459,11 +438,7 @@ class ButtonThemeData with Diagnosticable { /// 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); + return button.disabledColor ?? _disabledColor ?? colorScheme!.onSurface.withOpacity(0.38); } /// The button's background fill color or null for buttons that don't have @@ -475,9 +450,6 @@ class ButtonThemeData with Diagnosticable { /// Otherwise, returns [MaterialButton.disabledColor] if it is non-null and /// the button is disabled. /// - /// Otherwise, if button is a [FlatButton] then null is - /// returned. - /// /// Otherwise the fill color depends on the value of [getTextTheme]. /// /// * [ButtonTextTheme.normal] or [ButtonTextTheme.accent], the @@ -493,7 +465,7 @@ class ButtonThemeData with Diagnosticable { if (fillColor != null) return fillColor; - if (button is FlatButton || button.runtimeType == MaterialButton) + if (button.runtimeType == MaterialButton) return null; if (button.enabled && _buttonColor != null) @@ -525,8 +497,7 @@ class ButtonThemeData with Diagnosticable { /// [getBrightness] resolves to [Brightness.light]. /// * [ButtonTextTheme.accent]: [ColorScheme.secondary] of [colorScheme]. /// * [ButtonTextTheme.primary]: If [getFillColor] is dark then [Colors.white], - /// otherwise if [button] is a [FlatButton] then - /// [ColorScheme.primary] of [colorScheme], otherwise [Colors.black]. + /// otherwise [Colors.black]. Color getTextColor(MaterialButton button) { if (!button.enabled) return getDisabledTextColor(button); @@ -546,11 +517,7 @@ class ButtonThemeData with Diagnosticable { final bool fillIsDark = fillColor != null ? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark : getBrightness(button) == Brightness.dark; - if (fillIsDark) - return Colors.white; - if (button is FlatButton) - return colorScheme!.primary; - return Colors.black; + return fillIsDark ? Colors.white : Colors.black; } } @@ -563,18 +530,14 @@ class ButtonThemeData with Diagnosticable { /// it is non-null. /// /// 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] + /// if it is non-null 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) - return _splashColor!; - - if (_splashColor != null && button is FlatButton) { + if (_splashColor != null) { switch (getTextTheme(button)) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: @@ -637,58 +600,27 @@ class ButtonThemeData with Diagnosticable { /// 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; - } + /// Returns the button's [MaterialButton.elevation] if it is non-null, + /// otherwise it is 2.0. + double getElevation(MaterialButton button) => button.elevation ?? 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] 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; - return 4.0; - } + /// Returns the button's [MaterialButton.focusElevation] if it is non-null, + /// otherwise the highlight elevation is 4.0. + double getFocusElevation(MaterialButton button) => button.focusElevation ?? 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] 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; - return 4.0; - } + /// Returns the button's [MaterialButton.hoverElevation] if it is non-null, + /// otherwise the highlight elevation is 4.0. + double getHoverElevation(MaterialButton button) => button.hoverElevation ?? 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] 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; - return 8.0; - } + /// Returns the button's [MaterialButton.highlightElevation] if it is non-null, + /// otherwise the highlight elevation is 8.0. + double getHighlightElevation(MaterialButton button) => button.highlightElevation ?? 8.0; /// The [button]'s elevation when [MaterialButton.onPressed] is null (when /// MaterialButton.enabled is false). @@ -696,21 +628,13 @@ class ButtonThemeData with Diagnosticable { /// 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; - } + double getDisabledElevation(MaterialButton button) => button.disabledElevation ?? 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 [FlatButton.icon] then the padding - /// is: - /// `EdgeInsetsDirectional.only(start: 12.0, end: 16.0)`. - /// - /// Otherwise, returns [padding] if it is non-null. + /// Returns the button's [MaterialButton.padding] if it is non-null, + /// otherwise, returns the `padding` of the constructor parameter 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 @@ -738,9 +662,7 @@ class ButtonThemeData with Diagnosticable { /// /// Returns the button's [MaterialButton.shape] if it is non-null, otherwise /// [shape] is returned. - ShapeBorder getShape(MaterialButton button) { - return button.shape ?? shape; - } + ShapeBorder getShape(MaterialButton button) => button.shape ?? shape; /// The duration of the [button]'s highlight animation. /// diff --git a/packages/flutter/lib/src/material/flat_button.dart b/packages/flutter/lib/src/material/flat_button.dart deleted file mode 100644 index 28a9edcf7b..0000000000 --- a/packages/flutter/lib/src/material/flat_button.dart +++ /dev/null @@ -1,235 +0,0 @@ -// 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/widgets.dart'; - -import 'button.dart'; -import 'button_theme.dart'; -import 'material_button.dart'; -import 'theme.dart'; -import 'theme_data.dart'; - -/// A Material Design "flat button". -/// -/// ### This class is deprecated, please use [TextButton] instead. -/// -/// FlatButton have been replaced by [TextButton] and ButtonTheme has been -/// replaced by [TextButtonTheme]. Please migrate code that uses them. -/// There's a detailed migration guide for the new button and button -/// theme classes in -/// [flutter.dev/go/material-button-migration-guide](https://flutter.dev/go/material-button-migration-guide). -@Deprecated( - 'Use TextButton instead. See the migration guide in flutter.dev/go/material-button-migration-guide). ' - 'This feature was deprecated after v1.26.0-18.0.pre.', -) -class FlatButton extends MaterialButton { - /// Create a simple text button. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. - @Deprecated( - 'Use TextButton instead. See the migration guide in flutter.dev/go/material-button-migration-guide). ' - 'This feature was deprecated after v1.26.0-18.0.pre.', - ) - const FlatButton({ - Key? key, - required VoidCallback? onPressed, - VoidCallback? onLongPress, - ValueChanged? onHighlightChanged, - MouseCursor? mouseCursor, - ButtonTextTheme? textTheme, - Color? textColor, - Color? disabledTextColor, - Color? color, - Color? disabledColor, - Color? focusColor, - Color? hoverColor, - Color? highlightColor, - Color? splashColor, - Brightness? colorBrightness, - EdgeInsetsGeometry? padding, - VisualDensity? visualDensity, - ShapeBorder? shape, - Clip clipBehavior = Clip.none, - FocusNode? focusNode, - bool autofocus = false, - MaterialTapTargetSize? materialTapTargetSize, - required Widget child, - double? height, - double? minWidth, - }) : assert(clipBehavior != null), - assert(autofocus != null), - super( - key: key, - height: height, - minWidth: minWidth, - onPressed: onPressed, - onLongPress: onLongPress, - onHighlightChanged: onHighlightChanged, - mouseCursor: mouseCursor, - textTheme: textTheme, - textColor: textColor, - disabledTextColor: disabledTextColor, - color: color, - disabledColor: disabledColor, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - colorBrightness: colorBrightness, - padding: padding, - visualDensity: visualDensity, - shape: shape, - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: materialTapTargetSize, - child: child, - ); - - /// Create a text button from a pair of widgets that serve as the button's - /// [icon] and [label]. - /// - /// The icon and label are arranged in a row and padded by 12 logical pixels - /// at the start, and 16 at the end, with an 8 pixel gap in between. - /// - /// The [icon], [label], and [clipBehavior] arguments must not be null. - @Deprecated( - 'Use TextButton instead. See the migration guide in flutter.dev/go/material-button-migration-guide). ' - 'This feature was deprecated after v1.26.0-18.0.pre.', - ) - factory FlatButton.icon({ - Key? key, - required VoidCallback? onPressed, - VoidCallback? onLongPress, - ValueChanged? onHighlightChanged, - MouseCursor? mouseCursor, - ButtonTextTheme? textTheme, - Color? textColor, - Color? disabledTextColor, - Color? color, - Color? disabledColor, - Color? focusColor, - Color? hoverColor, - Color? highlightColor, - Color? splashColor, - Brightness? colorBrightness, - EdgeInsetsGeometry? padding, - ShapeBorder? shape, - Clip clipBehavior, - FocusNode? focusNode, - bool autofocus, - MaterialTapTargetSize? materialTapTargetSize, - required Widget icon, - required Widget label, - double? minWidth, - double? height, - }) = _FlatButtonWithIcon; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final ButtonThemeData buttonTheme = ButtonTheme.of(context); - return RawMaterialButton( - onPressed: onPressed, - onLongPress: onLongPress, - onHighlightChanged: onHighlightChanged, - mouseCursor: mouseCursor, - fillColor: buttonTheme.getFillColor(this), - textStyle: theme.textTheme.button!.copyWith(color: buttonTheme.getTextColor(this)), - focusColor: buttonTheme.getFocusColor(this), - hoverColor: buttonTheme.getHoverColor(this), - highlightColor: buttonTheme.getHighlightColor(this), - splashColor: buttonTheme.getSplashColor(this), - elevation: buttonTheme.getElevation(this), - focusElevation: buttonTheme.getFocusElevation(this), - hoverElevation: buttonTheme.getHoverElevation(this), - highlightElevation: buttonTheme.getHighlightElevation(this), - disabledElevation: buttonTheme.getDisabledElevation(this), - padding: buttonTheme.getPadding(this), - visualDensity: visualDensity ?? theme.visualDensity, - constraints: buttonTheme.getConstraints(this).copyWith( - minWidth: minWidth, - minHeight: height, - ), - shape: buttonTheme.getShape(this), - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this), - animationDuration: buttonTheme.getAnimationDuration(this), - child: child, - ); - } -} - -/// The type of FlatButtons created with [FlatButton.icon]. -/// -/// This class only exists to give FlatButtons created with [FlatButton.icon] -/// a distinct class for the sake of [ButtonTheme]. It can not be instantiated. -class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin { - _FlatButtonWithIcon({ - Key? key, - required VoidCallback? onPressed, - VoidCallback? onLongPress, - ValueChanged? onHighlightChanged, - MouseCursor? mouseCursor, - ButtonTextTheme? textTheme, - Color? textColor, - Color? disabledTextColor, - Color? color, - Color? disabledColor, - Color? focusColor, - Color? hoverColor, - Color? highlightColor, - Color? splashColor, - Brightness? colorBrightness, - EdgeInsetsGeometry? padding, - ShapeBorder? shape, - Clip clipBehavior = Clip.none, - FocusNode? focusNode, - bool autofocus = false, - MaterialTapTargetSize? materialTapTargetSize, - required Widget icon, - required Widget label, - double? minWidth, - double? height, - }) : assert(icon != null), - assert(label != null), - assert(clipBehavior != null), - assert(autofocus != null), - super( - key: key, - onPressed: onPressed, - onLongPress: onLongPress, - onHighlightChanged: onHighlightChanged, - mouseCursor: mouseCursor, - textTheme: textTheme, - textColor: textColor, - disabledTextColor: disabledTextColor, - color: color, - disabledColor: disabledColor, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - colorBrightness: colorBrightness, - padding: padding, - shape: shape, - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: materialTapTargetSize, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - icon, - const SizedBox(width: 8.0), - label, - ], - ), - minWidth: minWidth, - height: height, - ); - -} diff --git a/packages/flutter/lib/src/material/material_button.dart b/packages/flutter/lib/src/material/material_button.dart index a3cbb2b0bc..f083d89d66 100644 --- a/packages/flutter/lib/src/material/material_button.dart +++ b/packages/flutter/lib/src/material/material_button.dart @@ -19,27 +19,18 @@ import 'theme_data.dart'; /// A utility class for building Material buttons that depend on the /// ambient [ButtonTheme] and [Theme]. /// -/// ### This class is obsolete. +/// This class is planned to be deprecated in a future release. +/// Please use one or more of these buttons and associated themes instead: /// -/// FlatButton has been replaced by TextButton and ButtonTheme has been replaced -/// by TextButtonTheme. The appearance of the -/// new widgets can be customized by specifying a [ButtonStyle] -/// or by creating a one-off style using a `styleFrom` method like -/// [TextButton.styleFrom]. The original button classes -/// have been deprecated, please migrate code that uses them. -/// There's a detailed migration guide for the new button and button -/// theme classes in -/// [flutter.dev/go/material-button-migration-guide](https://flutter.dev/go/material-button-migration-guide). +/// * [TextButton], [TextButtonTheme], [TextButtonThemeData], +/// * [ElevatedButton], [ElevatedButtonTheme], [ElevatedButtonThemeData], +/// * [OutlinedButton], [OutlinedButtonTheme], [OutlinedButtonThemeData] /// /// The button's size will expand to fit the child widget, if necessary. /// /// MaterialButtons whose [onPressed] and [onLongPress] callbacks are null will be disabled. To have /// an enabled button, make sure to pass a non-null value for [onPressed] or [onLongPress]. /// -/// Rather than using this class directly, consider using [FlatButton], which -/// configure this class with appropriate defaults that match the material -/// design specification. -/// /// To create a button directly, without inheriting theme defaults, use /// [RawMaterialButton]. /// @@ -52,9 +43,8 @@ import 'theme_data.dart'; class MaterialButton extends StatelessWidget { /// Creates a material button. /// - /// Rather than creating a material button directly, consider using - /// [FlatButton]. To create a custom Material button - /// consider using [RawMaterialButton]. + /// To create a custom Material button consider using [TextButton], + /// [ElevatedButton], or [OutlinedButton]. /// /// The [autofocus] and [clipBehavior] arguments must not be null. /// Additionally, [elevation], [hoverElevation], [focusElevation], @@ -238,7 +228,7 @@ class MaterialButton extends StatelessWidget { /// /// See also: /// - /// * [FlatButton], a button with no elevation or fill color. + /// * [TextButton], a button with no elevation or fill color. /// * [focusElevation], the elevation when the button is focused. /// * [hoverElevation], the elevation when a pointer is hovering over the /// button. @@ -455,7 +445,9 @@ class MaterialButton extends StatelessWidget { } } -/// The type of [MaterialButton]s created with FlatButton.icon. +/// The distinguished type of [MaterialButton]. +/// +/// This class is deprecated and will be removed in a future release. /// /// This mixin only exists to give the "label and icon" button widgets a distinct /// type for the sake of [ButtonTheme]. diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 5870bb0cc7..977bf5bb2b 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -114,7 +114,6 @@ const Color _kDarkThemeSplashColor = Color(0x40CCCCCC); /// * [OutlinedButton] /// * [TextButton] /// * [ElevatedButton] -/// * [FlatButton] /// * The time picker widget ([showTimePicker]) /// * [SnackBar] /// * [Chip] @@ -1376,7 +1375,8 @@ class ThemeData with Diagnosticable { /// A theme for customizing the appearance and layout of [ButtonBar] widgets. final ButtonBarThemeData buttonBarTheme; - /// Defines the default configuration of button widgets, like [FlatButton]. + /// Defines the default configuration of button widgets, like [DropdownButton] + /// and [ButtonBar]. final ButtonThemeData buttonTheme; /// The colors and styles used to render [Card]. @@ -2486,7 +2486,6 @@ class _FifoCache { /// * [Checkbox] /// * [Chip] /// * [ElevatedButton] -/// * [FlatButton] /// * [IconButton] /// * [InputDecorator] (which gives density support to [TextField], etc.) /// * [ListTile] diff --git a/packages/flutter/test/material/button_theme_test.dart b/packages/flutter/test/material/button_theme_test.dart index 9dbc49de7a..d33dbc71d5 100644 --- a/packages/flutter/test/material/button_theme_test.dart +++ b/packages/flutter/test/material/button_theme_test.dart @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -36,55 +34,6 @@ void main() { expect(theme.alignedDropdown, true); }); - testWidgets('ButtonTheme defaults', (WidgetTester tester) async { - late ButtonTextTheme textTheme; - late ButtonBarLayoutBehavior layoutBehavior; - late BoxConstraints constraints; - late EdgeInsets padding; - late ShapeBorder shape; - late bool alignedDropdown; - late ColorScheme colorScheme; - - await tester.pumpWidget( - ButtonTheme( - child: Builder( - builder: (BuildContext context) { - final ButtonThemeData theme = ButtonTheme.of(context); - textTheme = theme.textTheme; - constraints = theme.constraints; - padding = theme.padding as EdgeInsets; - shape = theme.shape; - layoutBehavior = theme.layoutBehavior; - colorScheme = theme.colorScheme!; - alignedDropdown = theme.alignedDropdown; - return Container( - alignment: Alignment.topLeft, - child: Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - onPressed: () { }, - child: const Text('b'), // intrinsic width < minimum width - ), - ), - ); - }, - ), - ), - ); - - expect(textTheme, ButtonTextTheme.normal); - expect(layoutBehavior, ButtonBarLayoutBehavior.padded); - expect(constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0)); - expect(padding, const EdgeInsets.symmetric(horizontal: 16.0)); - expect(shape, const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(2.0)), - )); - expect(alignedDropdown, false); - expect(colorScheme, ThemeData.light().colorScheme); - expect(tester.widget(find.byType(Material)).shape, shape); - expect(tester.getSize(find.byType(Material)), const Size(88.0, 36.0)); - }); - test('ButtonThemeData.copyWith', () { ButtonThemeData theme = const ButtonThemeData().copyWith(); expect(theme.textTheme, ButtonTextTheme.normal); @@ -221,78 +170,4 @@ void main() { expect(fooText, findsNWidgets(2)); expect(tester.getRect(fooText.at(0)), tester.getRect(fooText.at(1))); }); - - testWidgets('button theme with stateful color changes color in states', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - - const Color pressedColor = Color(0x00000001); - const Color hoverColor = Color(0x00000002); - const Color focusedColor = Color(0x00000003); - const Color defaultColor = Color(0x00000004); - - Color getTextColor(Set states) { - if (states.contains(MaterialState.pressed)) { - return pressedColor; - } - if (states.contains(MaterialState.hovered)) { - return hoverColor; - } - if (states.contains(MaterialState.focused)) { - return focusedColor; - } - return defaultColor; - } - - const ColorScheme colorScheme = ColorScheme.light(); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: ButtonTheme( - colorScheme: colorScheme.copyWith( - primary: MaterialStateColor.resolveWith(getTextColor), - ), - textTheme: ButtonTextTheme.primary, - child: FlatButton( - onPressed: () {}, - focusNode: focusNode, - child: const Text('FlatButton'), - ), - ), - ), - ), - ), - ); - - Color textColor() { - return tester.renderObject(find.text('FlatButton')).text.style!.color!; - } - - // Default, not disabled. - expect(textColor(), equals(defaultColor)); - - // Focused. - focusNode.requestFocus(); - await tester.pumpAndSettle(); - expect(textColor(), focusedColor); - - // Hovered. - final Offset center = tester.getCenter(find.byType(FlatButton)); - final TestGesture gesture = await tester.createGesture( - kind: PointerDeviceKind.mouse, - ); - await gesture.addPointer(location: Offset.zero); - addTearDown(gesture.removePointer); - await gesture.moveTo(center); - await tester.pumpAndSettle(); - expect(textColor(), hoverColor); - - // Highlighted (pressed). - await gesture.down(center); - await tester.pump(); // Start the splash and highlight animations. - await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - expect(textColor(), pressedColor); - }, - ); } diff --git a/packages/flutter/test/material/flat_button_test.dart b/packages/flutter/test/material/flat_button_test.dart deleted file mode 100644 index 8b381ec49b..0000000000 --- a/packages/flutter/test/material/flat_button_test.dart +++ /dev/null @@ -1,876 +0,0 @@ -// 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/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../rendering/mock_canvas.dart'; -import '../widgets/semantics_tester.dart'; - -void main() { - testWidgets('FlatButton defaults', (WidgetTester tester) async { - final Finder rawButtonMaterial = find.descendant( - of: find.byType(FlatButton), - matching: find.byType(Material), - ); - - // Enabled FlatButton - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - onPressed: () { }, - child: const Text('button'), - ), - ), - ); - Material material = tester.widget(rawButtonMaterial); - expect(material.animationDuration, const Duration(milliseconds: 200)); - expect(material.borderOnForeground, true); - expect(material.borderRadius, null); - expect(material.clipBehavior, Clip.none); - expect(material.color, null); - expect(material.elevation, 0.0); - expect(material.shadowColor, null); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)))); - expect(material.textStyle!.color, const Color(0xdd000000)); - expect(material.textStyle!.fontFamily, 'Roboto'); - expect(material.textStyle!.fontSize, 14); - expect(material.textStyle!.fontWeight, FontWeight.w500); - expect(material.type, MaterialType.transparency); - - final Offset center = tester.getCenter(find.byType(FlatButton)); - await tester.startGesture(center); - await tester.pumpAndSettle(); - - material = tester.widget(rawButtonMaterial); - // No change vs enabled and not pressed. - expect(material.animationDuration, const Duration(milliseconds: 200)); - expect(material.borderOnForeground, true); - expect(material.borderRadius, null); - expect(material.clipBehavior, Clip.none); - expect(material.color, null); - expect(material.elevation, 0.0); - expect(material.shadowColor, null); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)))); - expect(material.textStyle!.color, const Color(0xdd000000)); - expect(material.textStyle!.fontFamily, 'Roboto'); - expect(material.textStyle!.fontSize, 14); - expect(material.textStyle!.fontWeight, FontWeight.w500); - expect(material.type, MaterialType.transparency); - - // Disabled FlatButton - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - onPressed: null, - child: Text('button'), - ), - ), - ); - material = tester.widget(rawButtonMaterial); - expect(material.animationDuration, const Duration(milliseconds: 200)); - expect(material.borderOnForeground, true); - expect(material.borderRadius, null); - expect(material.clipBehavior, Clip.none); - expect(material.color, null); - expect(material.elevation, 0.0); - expect(material.shadowColor, null); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)))); - expect(material.textStyle!.color, const Color(0x61000000)); - expect(material.textStyle!.fontFamily, 'Roboto'); - expect(material.textStyle!.fontSize, 14); - expect(material.textStyle!.fontWeight, FontWeight.w500); - expect(material.type, MaterialType.transparency); - }); - - testWidgets('FlatButton implements debugFillProperties', (WidgetTester tester) async { - final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - FlatButton( - onPressed: () { }, - textColor: const Color(0xFF00FF00), - disabledTextColor: const Color(0xFFFF0000), - color: const Color(0xFF000000), - highlightColor: const Color(0xFF1565C0), - splashColor: const Color(0xFF9E9E9E), - child: const Text('Hello'), - ).debugFillProperties(builder); - final List description = builder.properties - .where((DiagnosticsNode n) => !n.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode n) => n.toString()).toList(); - expect(description, [ - 'textColor: Color(0xff00ff00)', - 'disabledTextColor: Color(0xffff0000)', - 'color: Color(0xff000000)', - 'highlightColor: Color(0xff1565c0)', - 'splashColor: Color(0xff9e9e9e)', - ]); - }); - - testWidgets('Default FlatButton meets a11y contrast guidelines', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: FlatButton( - onPressed: () { }, - focusNode: focusNode, - child: const Text('FlatButton'), - ), - ), - ), - ), - ); - - // Default, not disabled. - await expectLater(tester, meetsGuideline(textContrastGuideline)); - - // Focused. - focusNode.requestFocus(); - await tester.pumpAndSettle(); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - - // Hovered. - final Offset center = tester.getCenter(find.byType(FlatButton)); - final TestGesture gesture = await tester.createGesture( - kind: PointerDeviceKind.mouse, - ); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(center); - await tester.pumpAndSettle(); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - - // Highlighted (pressed). - await gesture.down(center); - await tester.pump(); // Start the splash and highlight animations. - await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - await expectLater(tester, meetsGuideline(textContrastGuideline)); - }, - skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 - ); - - testWidgets('FlatButton with colored theme meets a11y contrast guidelines', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - - final ColorScheme colorScheme = ColorScheme.fromSwatch(); - - Color getTextColor(Set states) { - final Set interactiveStates = { - MaterialState.pressed, - MaterialState.hovered, - MaterialState.focused, - }; - if (states.any(interactiveStates.contains)) { - return Colors.blue[900]!; - } - return Colors.blue[800]!; - } - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: ButtonTheme( - colorScheme: colorScheme, - textTheme: ButtonTextTheme.primary, - child: FlatButton( - onPressed: () {}, - focusNode: focusNode, - textColor: MaterialStateColor.resolveWith(getTextColor), - child: const Text('FlatButton'), - ), - ), - ), - ), - ), - ); - - // Default, not disabled. - await expectLater(tester, meetsGuideline(textContrastGuideline)); - - // Focused. - focusNode.requestFocus(); - await tester.pumpAndSettle(); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - - // Hovered. - final Offset center = tester.getCenter(find.byType(FlatButton)); - final TestGesture gesture = await tester.createGesture( - kind: PointerDeviceKind.mouse, - ); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(center); - await tester.pumpAndSettle(); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - - // Highlighted (pressed). - await gesture.down(center); - await tester.pump(); // Start the splash and highlight animations. - await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - await expectLater(tester, meetsGuideline(textContrastGuideline)); - }, - skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 - ); - - testWidgets('FlatButton uses stateful color for text color in different states', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - - const Color pressedColor = Color(0x00000001); - const Color hoverColor = Color(0x00000002); - const Color focusedColor = Color(0x00000003); - const Color defaultColor = Color(0x00000004); - - Color getTextColor(Set states) { - if (states.contains(MaterialState.pressed)) { - return pressedColor; - } - if (states.contains(MaterialState.hovered)) { - return hoverColor; - } - if (states.contains(MaterialState.focused)) { - return focusedColor; - } - return defaultColor; - } - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: FlatButton( - onPressed: () {}, - focusNode: focusNode, - textColor: MaterialStateColor.resolveWith(getTextColor), - child: const Text('FlatButton'), - ), - ), - ), - ), - ); - - Color? textColor() { - return tester.renderObject(find.text('FlatButton')).text.style?.color; - } - - // Default, not disabled. - expect(textColor(), equals(defaultColor)); - - // Focused. - focusNode.requestFocus(); - await tester.pumpAndSettle(); - expect(textColor(), focusedColor); - - // Hovered. - final Offset center = tester.getCenter(find.byType(FlatButton)); - final TestGesture gesture = await tester.createGesture( - kind: PointerDeviceKind.mouse, - ); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(center); - await tester.pumpAndSettle(); - expect(textColor(), hoverColor); - - // Highlighted (pressed). - await gesture.down(center); - await tester.pump(); // Start the splash and highlight animations. - await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - expect(textColor(), pressedColor); - }); - - testWidgets('FlatButton uses stateful color for icon color in different states', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final Key buttonKey = UniqueKey(); - - const Color pressedColor = Color(0x00000001); - const Color hoverColor = Color(0x00000002); - const Color focusedColor = Color(0x00000003); - const Color defaultColor = Color(0x00000004); - - Color getTextColor(Set states) { - if (states.contains(MaterialState.pressed)) { - return pressedColor; - } - if (states.contains(MaterialState.hovered)) { - return hoverColor; - } - if (states.contains(MaterialState.focused)) { - return focusedColor; - } - return defaultColor; - } - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: FlatButton.icon( - key: buttonKey, - icon: const Icon(Icons.add), - label: const Text('FlatButton'), - onPressed: () {}, - focusNode: focusNode, - textColor: MaterialStateColor.resolveWith(getTextColor), - ), - ), - ), - ), - ); - - Color? iconColor() => _iconStyle(tester, Icons.add)?.color; - // Default, not disabled. - expect(iconColor(), equals(defaultColor)); - - // Focused. - focusNode.requestFocus(); - await tester.pumpAndSettle(); - expect(iconColor(), focusedColor); - - // Hovered. - final Offset center = tester.getCenter(find.byKey(buttonKey)); - final TestGesture gesture = await tester.createGesture( - kind: PointerDeviceKind.mouse, - ); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(center); - await tester.pumpAndSettle(); - expect(iconColor(), hoverColor); - - // Highlighted (pressed). - await gesture.down(center); - await tester.pump(); // Start the splash and highlight animations. - await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - expect(iconColor(), pressedColor); - }); - - testWidgets('FlatButton ignores disabled text color if text color is stateful', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - - const Color disabledColor = Color(0x00000001); - const Color defaultColor = Color(0x00000002); - const Color unusedDisabledTextColor = Color(0x00000003); - - Color getTextColor(Set states) { - if (states.contains(MaterialState.disabled)) { - return disabledColor; - } - return defaultColor; - } - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: FlatButton( - onPressed: null, - focusNode: focusNode, - textColor: MaterialStateColor.resolveWith(getTextColor), - disabledTextColor: unusedDisabledTextColor, - child: const Text('FlatButton'), - ), - ), - ), - ), - ); - - Color? textColor() { - return tester.renderObject(find.text('FlatButton')).text.style?.color; - } - - // Disabled. - expect(textColor(), equals(disabledColor)); - expect(textColor(), isNot(unusedDisabledTextColor)); - }); - - testWidgets('FlatButton has no clip by default', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - child: Container(), - onPressed: () { /* to make sure the button is enabled */ }, - ), - ), - ); - - expect( - tester.renderObject(find.byType(FlatButton)), - paintsExactlyCountTimes(#clipPath, 0), - ); - }); - - testWidgets('Does FlatButton work with hover', (WidgetTester tester) async { - const Color hoverColor = Color(0xff001122); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - hoverColor: hoverColor, - onPressed: () { }, - child: const Text('button'), - ), - ), - ); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); - await gesture.addPointer(); - await gesture.moveTo(tester.getCenter(find.byType(FlatButton))); - await tester.pumpAndSettle(); - - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paints..rect(color: hoverColor)); - - await gesture.removePointer(); - }); - - testWidgets('FlatButton changes mouse cursor when hovered', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: FlatButton.icon( - icon: const Icon(Icons.add), - label: const Text('Hello'), - onPressed: () {}, - mouseCursor: SystemMouseCursors.text, - ), - ), - ), - ); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); - await gesture.addPointer(location: const Offset(1, 1)); - addTearDown(gesture.removePointer); - - await tester.pump(); - expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: FlatButton( - onPressed: () {}, - mouseCursor: SystemMouseCursors.text, - child: const Text('Hello'), - ), - ), - ), - ); - - expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); - - // Test default cursor - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: FlatButton( - onPressed: () {}, - child: const Text('Hello'), - ), - ), - ), - ); - - expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); - - // Test default cursor when disabled - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: FlatButton( - onPressed: null, - child: Text('Hello'), - ), - ), - ), - ); - - expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); - }); - - testWidgets('Does FlatButton work with focus', (WidgetTester tester) async { - const Color focusColor = Color(0xff001122); - - final FocusNode focusNode = FocusNode(debugLabel: 'FlatButton Node'); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - focusColor: focusColor, - focusNode: focusNode, - onPressed: () { }, - child: const Text('button'), - ), - ), - ); - - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; - focusNode.requestFocus(); - await tester.pumpAndSettle(); - - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paints..rect(color: focusColor)); - }); - - testWidgets('Does FlatButton contribute semantics', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: FlatButton( - onPressed: () { }, - child: const Text('ABC'), - ), - ), - ), - ); - - expect(semantics, hasSemantics( - TestSemantics.root( - children: [ - TestSemantics.rootChild( - actions: [ - SemanticsAction.tap, - ], - label: 'ABC', - rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), - transform: Matrix4.translationValues(356.0, 276.0, 0.0), - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isButton, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - ], - ), - ], - ), - ignoreId: true, - )); - - semantics.dispose(); - }); - - testWidgets('Does FlatButton scale with font scale changes', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(), - child: Center( - child: FlatButton( - onPressed: () { }, - child: const Text('ABC'), - ), - ), - ), - ), - ); - - expect(tester.getSize(find.byType(FlatButton)), equals(const Size(88.0, 48.0))); - expect(tester.getSize(find.byType(Text)), equals(const Size(42.0, 14.0))); - - // textScaleFactor expands text, but not button. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 1.3), - child: Center( - child: FlatButton( - onPressed: () { }, - child: const Text('ABC'), - ), - ), - ), - ), - ); - - expect(tester.getSize(find.byType(FlatButton)), equals(const Size(88.0, 48.0))); - // Scaled text rendering is different on Linux and Mac by one pixel. - // TODO(gspencergoog): Figure out why this is, and fix it. https://github.com/flutter/flutter/issues/12357 - expect(tester.getSize(find.byType(Text)).width, isIn([54.0, 55.0])); - expect(tester.getSize(find.byType(Text)).height, isIn([18.0, 19.0])); - - // Set text scale large enough to expand text and button. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 3.0), - child: Center( - child: FlatButton( - onPressed: () { }, - child: const Text('ABC'), - ), - ), - ), - ), - ); - - // Scaled text rendering is different on Linux and Mac by one pixel. - // TODO(gspencergoog): Figure out why this is, and fix it. https://github.com/flutter/flutter/issues/12357 - expect(tester.getSize(find.byType(FlatButton)).width, isIn([158.0, 159.0])); - expect(tester.getSize(find.byType(FlatButton)).height, equals(48.0)); - expect(tester.getSize(find.byType(Text)).width, isIn([126.0, 127.0])); - expect(tester.getSize(find.byType(Text)).height, equals(42.0)); - }); - - testWidgets('FlatButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { - final Key key1 = UniqueKey(); - await tester.pumpWidget( - Theme( - data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded), - child: Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: FlatButton( - key: key1, - child: const SizedBox(width: 50.0, height: 8.0), - onPressed: () { }, - ), - ), - ), - ), - ); - - expect(tester.getSize(find.byKey(key1)), const Size(88.0, 48.0)); - - final Key key2 = UniqueKey(); - await tester.pumpWidget( - Theme( - data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), - child: Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: FlatButton( - key: key2, - child: const SizedBox(width: 50.0, height: 8.0), - onPressed: () { }, - ), - ), - ), - ), - ); - - expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); - }); - - testWidgets('FlatButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { - bool wasPressed; - Finder flatButton; - - Widget buildFrame({ VoidCallback? onPressed, VoidCallback? onLongPress }) { - return Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - onPressed: onPressed, - onLongPress: onLongPress, - child: const Text('button'), - ), - ); - } - - // onPressed not null, onLongPress null. - wasPressed = false; - await tester.pumpWidget( - buildFrame(onPressed: () { wasPressed = true; }), - ); - flatButton = find.byType(FlatButton); - expect(tester.widget(flatButton).enabled, true); - await tester.tap(flatButton); - expect(wasPressed, true); - - // onPressed null, onLongPress not null. - wasPressed = false; - await tester.pumpWidget( - buildFrame(onLongPress: () { wasPressed = true; }), - ); - flatButton = find.byType(FlatButton); - expect(tester.widget(flatButton).enabled, true); - await tester.longPress(flatButton); - expect(wasPressed, true); - - // onPressed null, onLongPress null. - await tester.pumpWidget( - buildFrame(), - ); - flatButton = find.byType(FlatButton); - expect(tester.widget(flatButton).enabled, false); - }); - - testWidgets('FlatButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { - bool didPressButton = false; - bool didLongPressButton = false; - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - onPressed: () { - didPressButton = true; - }, - onLongPress: () { - didLongPressButton = true; - }, - child: const Text('button'), - ), - ), - ); - - final Finder flatButton = find.byType(FlatButton); - expect(tester.widget(flatButton).enabled, true); - - expect(didPressButton, isFalse); - await tester.tap(flatButton); - expect(didPressButton, isTrue); - - expect(didLongPressButton, isFalse); - await tester.longPress(flatButton); - expect(didLongPressButton, isTrue); - }); - - testWidgets('FlatButton responds to density changes.', (WidgetTester tester) async { - const Key key = Key('test'); - const Key childKey = Key('test child'); - - Future buildTest(VisualDensity visualDensity, {bool useText = false}) async { - return tester.pumpWidget( - MaterialApp( - home: Directionality( - textDirection: TextDirection.rtl, - child: Center( - child: FlatButton( - visualDensity: visualDensity, - key: key, - onPressed: () {}, - child: useText ? const Text('Text', key: childKey) : Container(key: childKey, width: 100, height: 100, color: const Color(0xffff0000)), - ), - ), - ), - ), - ); - } - - await buildTest(VisualDensity.standard); - final RenderBox box = tester.renderObject(find.byKey(key)); - Rect childRect = tester.getRect(find.byKey(childKey)); - await tester.pumpAndSettle(); - expect(box.size, equals(const Size(132, 100))); - expect(childRect, equals(const Rect.fromLTRB(350, 250, 450, 350))); - - await buildTest(const VisualDensity(horizontal: 3.0, vertical: 3.0)); - await tester.pumpAndSettle(); - childRect = tester.getRect(find.byKey(childKey)); - expect(box.size, equals(const Size(156, 124))); - expect(childRect, equals(const Rect.fromLTRB(350, 250, 450, 350))); - - await buildTest(const VisualDensity(horizontal: -3.0, vertical: -3.0)); - await tester.pumpAndSettle(); - childRect = tester.getRect(find.byKey(childKey)); - expect(box.size, equals(const Size(108, 100))); - expect(childRect, equals(const Rect.fromLTRB(350, 250, 450, 350))); - - await buildTest(VisualDensity.standard, useText: true); - await tester.pumpAndSettle(); - childRect = tester.getRect(find.byKey(childKey)); - expect(box.size, equals(const Size(88, 48))); - expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); - - await buildTest(const VisualDensity(horizontal: 3.0, vertical: 3.0), useText: true); - await tester.pumpAndSettle(); - childRect = tester.getRect(find.byKey(childKey)); - expect(box.size, equals(const Size(112, 60))); - expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); - - await buildTest(const VisualDensity(horizontal: -3.0, vertical: -3.0), useText: true); - await tester.pumpAndSettle(); - childRect = tester.getRect(find.byKey(childKey)); - expect(box.size, equals(const Size(76, 36))); - expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); - }); - - testWidgets('FlatButton height parameter is used when provided', (WidgetTester tester) async { - const double buttonHeight = 100; - const double buttonDefaultMinHeight = 36.0; - - Future buildWidget({double? buttonHeight}) { - return tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - height: buttonHeight, - child: const Text('button'), - onPressed: () { - /*ununsed*/ - }, - ), - ), - ); - } - - final Finder rawMaterialButtonFinder = find.byType(RawMaterialButton); - - // If height is not provided we expect the default height to be used. - await buildWidget(); - expect(tester.widget(rawMaterialButtonFinder).constraints.minHeight, buttonDefaultMinHeight); - - // When the height is provided we expect that is used by the internal widget. - await buildWidget(buttonHeight: buttonHeight); - expect(tester.widget(rawMaterialButtonFinder).constraints.minHeight, buttonHeight); - }); - - testWidgets('FlatButton minWidth parameter is used when provided', (WidgetTester tester) async { - const double buttonMinWidth = 100; - const double buttonDefaultMinWidth = 88.0; - - Future buildWidget({double? buttonMinWidth}) { - return tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FlatButton( - minWidth: buttonMinWidth, - child: const Text('button'), - onPressed: () { - /*ununsed*/ - }, - ), - ), - ); - } - - final Finder rawMaterialButtonFinder = find.byType(RawMaterialButton); - - // If minWidth is not provided we expect the default minWidth to be used. - await buildWidget(); - expect(tester.widget(rawMaterialButtonFinder).constraints.minWidth, buttonDefaultMinWidth); - - // When minWidth is provided we expect that the internal widget uses it. - await buildWidget(buttonMinWidth: buttonMinWidth); - expect(tester.widget(rawMaterialButtonFinder).constraints.minWidth, buttonMinWidth); - }); -} - -TextStyle? _iconStyle(WidgetTester tester, IconData icon) { - final RichText iconRichText = tester.widget( - find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)), - ); - return iconRichText.text.style; -} diff --git a/packages/flutter/test/material/stepper_test.dart b/packages/flutter/test/material/stepper_test.dart index 9d66e1a400..17b3bf9df3 100644 --- a/packages/flutter/test/material/stepper_test.dart +++ b/packages/flutter/test/material/stepper_test.dart @@ -824,10 +824,6 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async ); } - // The checks that follow verify that the layout and appearance of - // the default enabled Stepper buttons have not changed even - // though the FlatButtons have been replaced by TextButtons. - const OutlinedBorder buttonShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2))); const Rect continueButtonRect = Rect.fromLTRB(24.0, 212.0, 168.0, 260.0); const Rect cancelButtonRect = Rect.fromLTRB(176.0, 212.0, 292.0, 260.0); @@ -882,10 +878,6 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async ); } - // The checks that follow verify that the appearance of the - // default disabled Stepper buttons have not changed even though - // the FlatButtons have been replaced by TextButtons. - await tester.pumpWidget(buildFrame(ThemeData.light())); expect(buttonMaterial('CONTINUE').color!.value, 0); diff --git a/packages/flutter/test/material/theme_defaults_test.dart b/packages/flutter/test/material/theme_defaults_test.dart index 6ad56e0de0..445f3ebde9 100644 --- a/packages/flutter/test/material/theme_defaults_test.dart +++ b/packages/flutter/test/material/theme_defaults_test.dart @@ -11,64 +11,6 @@ const BoxConstraints defaultButtonConstraints = BoxConstraints(minWidth: 88.0, m const Duration defaultButtonDuration = Duration(milliseconds: 200); void main() { - group('FlatButton', () { - testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.light(), - home: Center( - child: FlatButton( - onPressed: () { }, // button.enabled == true - child: const Text('button'), - ), - ), - ), - ); - - final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); - expect(raw.textStyle!.color, const Color(0xdd000000)); - expect(raw.fillColor, null); - expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc) - expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8) - expect(raw.elevation, 0.0); - expect(raw.highlightElevation, 0.0); - expect(raw.disabledElevation, 0.0); - expect(raw.constraints, defaultButtonConstraints); - expect(raw.padding, defaultButtonPadding); - expect(raw.shape, defaultButtonShape); - expect(raw.animationDuration, defaultButtonDuration); - expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); - }); - - testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.light(), - home: const Center( - child: FlatButton( - onPressed: null, // button.enabled == false - child: Text('button'), - ), - ), - ), - ); - - final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); - expect(raw.textStyle!.color, const Color(0x61000000)); - expect(raw.fillColor, null); - // highlightColor, disabled button can't be pressed - // splashColor, disabled button doesn't splash - expect(raw.elevation, 0.0); - expect(raw.highlightElevation, 0.0); - expect(raw.disabledElevation, 0.0); - expect(raw.constraints, defaultButtonConstraints); - expect(raw.padding, defaultButtonPadding); - expect(raw.shape, defaultButtonShape); - expect(raw.animationDuration, const Duration(milliseconds: 200)); - expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); - }); - }); - group('FloatingActionButton', () { const BoxConstraints defaultFABConstraints = BoxConstraints.tightFor(width: 56.0, height: 56.0); const ShapeBorder defaultFABShape = CircleBorder(); diff --git a/packages/flutter_localizations/lib/src/l10n/README.md b/packages/flutter_localizations/lib/src/l10n/README.md index 22a8defbf3..0146fdfe3c 100644 --- a/packages/flutter_localizations/lib/src/l10n/README.md +++ b/packages/flutter_localizations/lib/src/l10n/README.md @@ -43,7 +43,7 @@ names. They correspond to methods from the `MaterialLocalizations` or ```dart Widget build(BuildContext context) { - return FlatButton( + return TextButton( child: Text( MaterialLocalizations.of(context).cancelButtonLabel, ),