| // 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 'dart:math' as math; |
| import 'dart:ui' show lerpDouble; |
| |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| import 'button_style.dart'; |
| import 'button_style_button.dart'; |
| import 'color_scheme.dart'; |
| import 'colors.dart'; |
| import 'constants.dart'; |
| import 'filled_button_theme.dart'; |
| import 'ink_well.dart'; |
| import 'material_state.dart'; |
| import 'theme.dart'; |
| import 'theme_data.dart'; |
| |
| enum _FilledButtonVariant { filled, tonal } |
| |
| /// A Material Design filled button. |
| /// |
| /// Filled buttons have the most visual impact after the [FloatingActionButton], |
| /// and should be used for important, final actions that complete a flow, |
| /// like **Save**, **Join now**, or **Confirm**. |
| /// |
| /// A filled button is a label [child] displayed on a [Material] |
| /// widget. The label's [Text] and [Icon] widgets are displayed in |
| /// [style]'s [ButtonStyle.foregroundColor] and the button's filled |
| /// background is the [ButtonStyle.backgroundColor]. |
| /// |
| /// The filled button's default style is defined by |
| /// [defaultStyleOf]. The style of this filled button can be |
| /// overridden with its [style] parameter. The style of all filled |
| /// buttons in a subtree can be overridden with the |
| /// [FilledButtonTheme], and the style of all of the filled |
| /// buttons in an app can be overridden with the [Theme]'s |
| /// [ThemeData.filledButtonTheme] property. |
| /// |
| /// The static [styleFrom] method is a convenient way to create a |
| /// filled button [ButtonStyle] from simple values. |
| /// |
| /// If [onPressed] and [onLongPress] callbacks are null, then the |
| /// button will be disabled. |
| /// |
| /// To create a 'filled tonal' button, use [FilledButton.tonal]. |
| /// |
| /// {@tool dartpad} |
| /// This sample produces enabled and disabled filled and filled tonal |
| /// buttons. |
| /// |
| /// ** See code in examples/api/lib/material/filled_button/filled_button.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [ElevatedButton], a filled button whose material elevates when pressed. |
| /// * [OutlinedButton], a button with an outlined border and no fill color. |
| /// * [TextButton], a button with no outline or fill color. |
| /// * <https://material.io/design/components/buttons.html> |
| /// * <https://m3.material.io/components/buttons> |
| class FilledButton extends ButtonStyleButton { |
| /// Create a FilledButton. |
| /// |
| /// The [autofocus] and [clipBehavior] arguments must not be null. |
| const FilledButton({ |
| super.key, |
| required super.onPressed, |
| super.onLongPress, |
| super.onHover, |
| super.onFocusChange, |
| super.style, |
| super.focusNode, |
| super.autofocus = false, |
| super.clipBehavior = Clip.none, |
| super.statesController, |
| required super.child, |
| }) : _variant = _FilledButtonVariant.filled; |
| |
| /// Create a filled button from [icon] and [label]. |
| /// |
| /// The icon and label are arranged in a row with padding at the start and end |
| /// and a gap between them. |
| /// |
| /// The [icon] and [label] arguments must not be null. |
| factory FilledButton.icon({ |
| Key? key, |
| required VoidCallback? onPressed, |
| VoidCallback? onLongPress, |
| ValueChanged<bool>? onHover, |
| ValueChanged<bool>? onFocusChange, |
| ButtonStyle? style, |
| FocusNode? focusNode, |
| bool? autofocus, |
| Clip? clipBehavior, |
| MaterialStatesController? statesController, |
| required Widget icon, |
| required Widget label, |
| }) = _FilledButtonWithIcon; |
| |
| /// Create a tonal variant of FilledButton. |
| /// |
| /// A filled tonal button is an alternative middle ground between |
| /// [FilledButton] and [OutlinedButton]. They’re useful in contexts where |
| /// a lower-priority button requires slightly more emphasis than an |
| /// outline would give, such as "Next" in an onboarding flow. |
| /// |
| /// The [autofocus] and [clipBehavior] arguments must not be null. |
| const FilledButton.tonal({ |
| super.key, |
| required super.onPressed, |
| super.onLongPress, |
| super.onHover, |
| super.onFocusChange, |
| super.style, |
| super.focusNode, |
| super.autofocus = false, |
| super.clipBehavior = Clip.none, |
| super.statesController, |
| required super.child, |
| }) : _variant = _FilledButtonVariant.tonal; |
| |
| /// Create a filled tonal button from [icon] and [label]. |
| /// |
| /// The icon and label are arranged in a row with padding at the start and end |
| /// and a gap between them. |
| /// |
| /// The [icon] and [label] arguments must not be null. |
| factory FilledButton.tonalIcon({ |
| Key? key, |
| required VoidCallback? onPressed, |
| VoidCallback? onLongPress, |
| ValueChanged<bool>? onHover, |
| ValueChanged<bool>? onFocusChange, |
| ButtonStyle? style, |
| FocusNode? focusNode, |
| bool? autofocus, |
| Clip? clipBehavior, |
| MaterialStatesController? statesController, |
| required Widget icon, |
| required Widget label, |
| }) { |
| return _FilledButtonWithIcon.tonal( |
| key: key, |
| onPressed: onPressed, |
| onLongPress: onLongPress, |
| onHover: onHover, |
| onFocusChange: onFocusChange, |
| style: style, |
| focusNode: focusNode, |
| autofocus: autofocus, |
| clipBehavior: clipBehavior, |
| statesController: statesController, |
| icon: icon, |
| label: label, |
| ); |
| } |
| |
| /// A static convenience method that constructs a filled button |
| /// [ButtonStyle] given simple values. |
| /// |
| /// The [foregroundColor], and [disabledForegroundColor] colors are used to create a |
| /// [MaterialStateProperty] [ButtonStyle.foregroundColor] value. The |
| /// [backgroundColor] and [disabledBackgroundColor] are used to create a |
| /// [MaterialStateProperty] [ButtonStyle.backgroundColor] value. |
| /// |
| /// The button's elevations are defined relative to the [elevation] |
| /// parameter. The disabled elevation is the same as the parameter |
| /// value, [elevation] + 2 is used when the button is hovered |
| /// or focused, and elevation + 6 is used when the button is pressed. |
| /// |
| /// Similarly, the [enabledMouseCursor] and [disabledMouseCursor] |
| /// parameters are used to construct [ButtonStyle.mouseCursor]. |
| /// |
| /// All of the other parameters are either used directly or used to |
| /// create a [MaterialStateProperty] with a single value for all |
| /// states. |
| /// |
| /// All parameters default to null, by default this method returns |
| /// a [ButtonStyle] that doesn't override anything. |
| /// |
| /// For example, to override the default text and icon colors for a |
| /// [FilledButton], as well as its overlay color, with all of the |
| /// standard opacity adjustments for the pressed, focused, and |
| /// hovered states, one could write: |
| /// |
| /// ```dart |
| /// FilledButton( |
| /// style: FilledButton.styleFrom(foregroundColor: Colors.green), |
| /// onPressed: () {}, |
| /// child: const Text('Filled button'), |
| /// ); |
| /// ``` |
| /// |
| /// or for a Filled tonal variant: |
| /// ```dart |
| /// FilledButton.tonal( |
| /// style: FilledButton.styleFrom(foregroundColor: Colors.green), |
| /// onPressed: () {}, |
| /// child: const Text('Filled tonal button'), |
| /// ); |
| /// ``` |
| static ButtonStyle styleFrom({ |
| Color? foregroundColor, |
| Color? backgroundColor, |
| Color? disabledForegroundColor, |
| Color? disabledBackgroundColor, |
| Color? shadowColor, |
| Color? surfaceTintColor, |
| double? elevation, |
| TextStyle? textStyle, |
| EdgeInsetsGeometry? padding, |
| Size? minimumSize, |
| Size? fixedSize, |
| Size? maximumSize, |
| BorderSide? side, |
| OutlinedBorder? shape, |
| MouseCursor? enabledMouseCursor, |
| MouseCursor? disabledMouseCursor, |
| VisualDensity? visualDensity, |
| MaterialTapTargetSize? tapTargetSize, |
| Duration? animationDuration, |
| bool? enableFeedback, |
| AlignmentGeometry? alignment, |
| InteractiveInkFeatureFactory? splashFactory, |
| }) { |
| final MaterialStateProperty<Color?>? backgroundColorProp = |
| (backgroundColor == null && disabledBackgroundColor == null) |
| ? null |
| : _FilledButtonDefaultColor(backgroundColor, disabledBackgroundColor); |
| final Color? foreground = foregroundColor; |
| final Color? disabledForeground = disabledForegroundColor; |
| final MaterialStateProperty<Color?>? foregroundColorProp = |
| (foreground == null && disabledForeground == null) |
| ? null |
| : _FilledButtonDefaultColor(foreground, disabledForeground); |
| final MaterialStateProperty<Color?>? overlayColor = (foreground == null) |
| ? null |
| : _FilledButtonDefaultOverlay(foreground); |
| final MaterialStateProperty<MouseCursor?> mouseCursor = _FilledButtonDefaultMouseCursor(enabledMouseCursor, disabledMouseCursor); |
| |
| return ButtonStyle( |
| textStyle: MaterialStatePropertyAll<TextStyle?>(textStyle), |
| backgroundColor: backgroundColorProp, |
| foregroundColor: foregroundColorProp, |
| overlayColor: overlayColor, |
| shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor), |
| surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor), |
| elevation: ButtonStyleButton.allOrNull(elevation), |
| padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding), |
| minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize), |
| fixedSize: ButtonStyleButton.allOrNull<Size>(fixedSize), |
| maximumSize: ButtonStyleButton.allOrNull<Size>(maximumSize), |
| side: ButtonStyleButton.allOrNull<BorderSide>(side), |
| shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape), |
| mouseCursor: mouseCursor, |
| visualDensity: visualDensity, |
| tapTargetSize: tapTargetSize, |
| animationDuration: animationDuration, |
| enableFeedback: enableFeedback, |
| alignment: alignment, |
| splashFactory: splashFactory, |
| ); |
| } |
| |
| final _FilledButtonVariant _variant; |
| |
| /// Defines the button's default appearance. |
| /// |
| /// The button [child]'s [Text] and [Icon] widgets are rendered with |
| /// the [ButtonStyle]'s foreground color. The button's [InkWell] adds |
| /// the style's overlay color when the button is focused, hovered |
| /// or pressed. The button's background color becomes its [Material] |
| /// color. |
| /// |
| /// All of the ButtonStyle's defaults appear below. In this list |
| /// "Theme.foo" is shorthand for `Theme.of(context).foo`. Color |
| /// scheme values like "onSurface(0.38)" are shorthand for |
| /// `onSurface.withOpacity(0.38)`. [MaterialStateProperty] valued |
| /// properties that are not followed by a sublist have the same |
| /// value for all states, otherwise the values are as specified for |
| /// each state, and "others" means all other states. |
| /// |
| /// The `textScaleFactor` is the value of |
| /// `MediaQuery.textScalerOf(context).textScaleFactor` and the names of the |
| /// EdgeInsets constructors and `EdgeInsetsGeometry.lerp` have been |
| /// abbreviated for readability. |
| /// |
| /// The color of the [ButtonStyle.textStyle] is not used, the |
| /// [ButtonStyle.foregroundColor] color is used instead. |
| /// |
| /// * `textStyle` - Theme.textTheme.labelLarge |
| /// * `backgroundColor` |
| /// * disabled - Theme.colorScheme.onSurface(0.12) |
| /// * others - Theme.colorScheme.secondaryContainer |
| /// * `foregroundColor` |
| /// * disabled - Theme.colorScheme.onSurface(0.38) |
| /// * others - Theme.colorScheme.onSecondaryContainer |
| /// * `overlayColor` |
| /// * hovered - Theme.colorScheme.onSecondaryContainer(0.08) |
| /// * focused or pressed - Theme.colorScheme.onSecondaryContainer(0.12) |
| /// * `shadowColor` - Theme.colorScheme.shadow |
| /// * `surfaceTintColor` - null |
| /// * `elevation` |
| /// * disabled - 0 |
| /// * default - 0 |
| /// * hovered - 1 |
| /// * focused or pressed - 0 |
| /// * `padding` |
| /// * `textScaleFactor <= 1` - horizontal(16) |
| /// * `1 < textScaleFactor <= 2` - lerp(horizontal(16), horizontal(8)) |
| /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) |
| /// * `3 < textScaleFactor` - horizontal(4) |
| /// * `minimumSize` - Size(64, 40) |
| /// * `fixedSize` - null |
| /// * `maximumSize` - Size.infinite |
| /// * `side` - null |
| /// * `shape` - StadiumBorder() |
| /// * `mouseCursor` |
| /// * disabled - SystemMouseCursors.basic |
| /// * others - SystemMouseCursors.click |
| /// * `visualDensity` - Theme.visualDensity |
| /// * `tapTargetSize` - Theme.materialTapTargetSize |
| /// * `animationDuration` - kThemeChangeDuration |
| /// * `enableFeedback` - true |
| /// * `alignment` - Alignment.center |
| /// * `splashFactory` - Theme.splashFactory |
| /// |
| /// The default padding values for the [FilledButton.icon] factory are slightly different: |
| /// |
| /// * `padding` |
| /// * `textScaleFactor <= 1` - start(12) end(16) |
| /// * `1 < textScaleFactor <= 2` - lerp(start(12) end(16), horizontal(8)) |
| /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) |
| /// * `3 < textScaleFactor` - horizontal(4) |
| /// |
| /// The default value for `side`, which defines the appearance of the button's |
| /// outline, is null. That means that the outline is defined by the button |
| /// shape's [OutlinedBorder.side]. Typically the default value of an |
| /// [OutlinedBorder]'s side is [BorderSide.none], so an outline is not drawn. |
| /// |
| /// ## Material 3 defaults |
| /// |
| /// If [ThemeData.useMaterial3] is set to true the following defaults will |
| /// be used: |
| /// |
| /// * `textStyle` - Theme.textTheme.labelLarge |
| /// * `backgroundColor` |
| /// * disabled - Theme.colorScheme.onSurface(0.12) |
| /// * others - Theme.colorScheme.secondaryContainer |
| /// * `foregroundColor` |
| /// * disabled - Theme.colorScheme.onSurface(0.38) |
| /// * others - Theme.colorScheme.onSecondaryContainer |
| /// * `overlayColor` |
| /// * hovered - Theme.colorScheme.onSecondaryContainer(0.08) |
| /// * focused or pressed - Theme.colorScheme.onSecondaryContainer(0.12) |
| /// * `shadowColor` - Theme.colorScheme.shadow |
| /// * `surfaceTintColor` - Colors.transparent |
| /// * `elevation` |
| /// * disabled - 0 |
| /// * default - 1 |
| /// * hovered - 3 |
| /// * focused or pressed - 1 |
| /// * `padding` |
| /// * `textScaleFactor <= 1` - horizontal(24) |
| /// * `1 < textScaleFactor <= 2` - lerp(horizontal(24), horizontal(12)) |
| /// * `2 < textScaleFactor <= 3` - lerp(horizontal(12), horizontal(6)) |
| /// * `3 < textScaleFactor` - horizontal(6) |
| /// * `minimumSize` - Size(64, 40) |
| /// * `fixedSize` - null |
| /// * `maximumSize` - Size.infinite |
| /// * `side` - null |
| /// * `shape` - StadiumBorder() |
| /// * `mouseCursor` |
| /// * disabled - SystemMouseCursors.basic |
| /// * others - SystemMouseCursors.click |
| /// * `visualDensity` - Theme.visualDensity |
| /// * `tapTargetSize` - Theme.materialTapTargetSize |
| /// * `animationDuration` - kThemeChangeDuration |
| /// * `enableFeedback` - true |
| /// * `alignment` - Alignment.center |
| /// * `splashFactory` - Theme.splashFactory |
| /// |
| /// For the [FilledButton.icon] factory, the start (generally the left) value of |
| /// [padding] is reduced from 24 to 16. |
| @override |
| ButtonStyle defaultStyleOf(BuildContext context) { |
| switch (_variant) { |
| case _FilledButtonVariant.filled: |
| return _FilledButtonDefaultsM3(context); |
| case _FilledButtonVariant.tonal: |
| return _FilledTonalButtonDefaultsM3(context); |
| } |
| } |
| |
| /// Returns the [FilledButtonThemeData.style] of the closest |
| /// [FilledButtonTheme] ancestor. |
| @override |
| ButtonStyle? themeStyleOf(BuildContext context) { |
| return FilledButtonTheme.of(context).style; |
| } |
| } |
| |
| EdgeInsetsGeometry _scaledPadding(BuildContext context) { |
| final bool useMaterial3 = Theme.of(context).useMaterial3; |
| final double padding1x = useMaterial3 ? 24.0 : 16.0; |
| return ButtonStyleButton.scaledPadding( |
| EdgeInsets.symmetric(horizontal: padding1x), |
| EdgeInsets.symmetric(horizontal: padding1x / 2), |
| EdgeInsets.symmetric(horizontal: padding1x / 2 / 2), |
| MediaQuery.textScalerOf(context).textScaleFactor, |
| ); |
| } |
| |
| @immutable |
| class _FilledButtonDefaultColor extends MaterialStateProperty<Color?> with Diagnosticable { |
| _FilledButtonDefaultColor(this.color, this.disabled); |
| |
| final Color? color; |
| final Color? disabled; |
| |
| @override |
| Color? resolve(Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return disabled; |
| } |
| return color; |
| } |
| } |
| |
| @immutable |
| class _FilledButtonDefaultOverlay extends MaterialStateProperty<Color?> with Diagnosticable { |
| _FilledButtonDefaultOverlay(this.overlay); |
| |
| final Color overlay; |
| |
| @override |
| Color? resolve(Set<MaterialState> states) { |
| if (states.contains(MaterialState.pressed)) { |
| return overlay.withOpacity(0.12); |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return overlay.withOpacity(0.08); |
| } |
| if (states.contains(MaterialState.focused)) { |
| return overlay.withOpacity(0.12); |
| } |
| return null; |
| } |
| } |
| |
| @immutable |
| class _FilledButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor?> with Diagnosticable { |
| _FilledButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor); |
| |
| final MouseCursor? enabledCursor; |
| final MouseCursor? disabledCursor; |
| |
| @override |
| MouseCursor? resolve(Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return disabledCursor; |
| } |
| return enabledCursor; |
| } |
| } |
| |
| class _FilledButtonWithIcon extends FilledButton { |
| _FilledButtonWithIcon({ |
| super.key, |
| required super.onPressed, |
| super.onLongPress, |
| super.onHover, |
| super.onFocusChange, |
| super.style, |
| super.focusNode, |
| bool? autofocus, |
| Clip? clipBehavior, |
| super.statesController, |
| required Widget icon, |
| required Widget label, |
| }) : super( |
| autofocus: autofocus ?? false, |
| clipBehavior: clipBehavior ?? Clip.none, |
| child: _FilledButtonWithIconChild(icon: icon, label: label) |
| ); |
| |
| _FilledButtonWithIcon.tonal({ |
| super.key, |
| required super.onPressed, |
| super.onLongPress, |
| super.onHover, |
| super.onFocusChange, |
| super.style, |
| super.focusNode, |
| bool? autofocus, |
| Clip? clipBehavior, |
| super.statesController, |
| required Widget icon, |
| required Widget label, |
| }) : super.tonal( |
| autofocus: autofocus ?? false, |
| clipBehavior: clipBehavior ?? Clip.none, |
| child: _FilledButtonWithIconChild(icon: icon, label: label) |
| ); |
| |
| @override |
| ButtonStyle defaultStyleOf(BuildContext context) { |
| final bool useMaterial3 = Theme.of(context).useMaterial3; |
| final EdgeInsetsGeometry scaledPadding = useMaterial3 ? ButtonStyleButton.scaledPadding( |
| const EdgeInsetsDirectional.fromSTEB(16, 0, 24, 0), |
| const EdgeInsetsDirectional.fromSTEB(8, 0, 12, 0), |
| const EdgeInsetsDirectional.fromSTEB(4, 0, 6, 0), |
| MediaQuery.textScalerOf(context).textScaleFactor, |
| ) : ButtonStyleButton.scaledPadding( |
| const EdgeInsetsDirectional.fromSTEB(12, 0, 16, 0), |
| const EdgeInsets.symmetric(horizontal: 8), |
| const EdgeInsetsDirectional.fromSTEB(8, 0, 4, 0), |
| MediaQuery.textScalerOf(context).textScaleFactor, |
| ); |
| return super.defaultStyleOf(context).copyWith( |
| padding: MaterialStatePropertyAll<EdgeInsetsGeometry>(scaledPadding), |
| ); |
| } |
| } |
| |
| class _FilledButtonWithIconChild extends StatelessWidget { |
| const _FilledButtonWithIconChild({ required this.label, required this.icon }); |
| |
| final Widget label; |
| final Widget icon; |
| |
| @override |
| Widget build(BuildContext context) { |
| final double scale = MediaQuery.textScalerOf(context).textScaleFactor; |
| // Adjust the gap based on the text scale factor. Start at 8, and lerp |
| // to 4 based on how large the text is. |
| final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; |
| return Row( |
| mainAxisSize: MainAxisSize.min, |
| children: <Widget>[icon, SizedBox(width: gap), Flexible(child: label)], |
| ); |
| } |
| } |
| |
| // BEGIN GENERATED TOKEN PROPERTIES - FilledButton |
| |
| // Do not edit by hand. The code between the "BEGIN GENERATED" and |
| // "END GENERATED" comments are generated from data in the Material |
| // Design token database by the script: |
| // dev/tools/gen_defaults/bin/gen_defaults.dart. |
| |
| class _FilledButtonDefaultsM3 extends ButtonStyle { |
| _FilledButtonDefaultsM3(this.context) |
| : super( |
| animationDuration: kThemeChangeDuration, |
| enableFeedback: true, |
| alignment: Alignment.center, |
| ); |
| |
| final BuildContext context; |
| late final ColorScheme _colors = Theme.of(context).colorScheme; |
| |
| @override |
| MaterialStateProperty<TextStyle?> get textStyle => |
| MaterialStatePropertyAll<TextStyle?>(Theme.of(context).textTheme.labelLarge); |
| |
| @override |
| MaterialStateProperty<Color?>? get backgroundColor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return _colors.onSurface.withOpacity(0.12); |
| } |
| return _colors.primary; |
| }); |
| |
| @override |
| MaterialStateProperty<Color?>? get foregroundColor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return _colors.onSurface.withOpacity(0.38); |
| } |
| return _colors.onPrimary; |
| }); |
| |
| @override |
| MaterialStateProperty<Color?>? get overlayColor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.pressed)) { |
| return _colors.onPrimary.withOpacity(0.12); |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return _colors.onPrimary.withOpacity(0.08); |
| } |
| if (states.contains(MaterialState.focused)) { |
| return _colors.onPrimary.withOpacity(0.12); |
| } |
| return null; |
| }); |
| |
| @override |
| MaterialStateProperty<Color>? get shadowColor => |
| MaterialStatePropertyAll<Color>(_colors.shadow); |
| |
| @override |
| MaterialStateProperty<Color>? get surfaceTintColor => |
| const MaterialStatePropertyAll<Color>(Colors.transparent); |
| |
| @override |
| MaterialStateProperty<double>? get elevation => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return 0.0; |
| } |
| if (states.contains(MaterialState.pressed)) { |
| return 0.0; |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return 1.0; |
| } |
| if (states.contains(MaterialState.focused)) { |
| return 0.0; |
| } |
| return 0.0; |
| }); |
| |
| @override |
| MaterialStateProperty<EdgeInsetsGeometry>? get padding => |
| MaterialStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context)); |
| |
| @override |
| MaterialStateProperty<Size>? get minimumSize => |
| const MaterialStatePropertyAll<Size>(Size(64.0, 40.0)); |
| |
| // No default fixedSize |
| |
| @override |
| MaterialStateProperty<Size>? get maximumSize => |
| const MaterialStatePropertyAll<Size>(Size.infinite); |
| |
| // No default side |
| |
| @override |
| MaterialStateProperty<OutlinedBorder>? get shape => |
| const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()); |
| |
| @override |
| MaterialStateProperty<MouseCursor?>? get mouseCursor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return SystemMouseCursors.basic; |
| } |
| return SystemMouseCursors.click; |
| }); |
| |
| @override |
| VisualDensity? get visualDensity => Theme.of(context).visualDensity; |
| |
| @override |
| MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; |
| |
| @override |
| InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; |
| } |
| |
| // END GENERATED TOKEN PROPERTIES - FilledButton |
| |
| // BEGIN GENERATED TOKEN PROPERTIES - FilledTonalButton |
| |
| // Do not edit by hand. The code between the "BEGIN GENERATED" and |
| // "END GENERATED" comments are generated from data in the Material |
| // Design token database by the script: |
| // dev/tools/gen_defaults/bin/gen_defaults.dart. |
| |
| class _FilledTonalButtonDefaultsM3 extends ButtonStyle { |
| _FilledTonalButtonDefaultsM3(this.context) |
| : super( |
| animationDuration: kThemeChangeDuration, |
| enableFeedback: true, |
| alignment: Alignment.center, |
| ); |
| |
| final BuildContext context; |
| late final ColorScheme _colors = Theme.of(context).colorScheme; |
| |
| @override |
| MaterialStateProperty<TextStyle?> get textStyle => |
| MaterialStatePropertyAll<TextStyle?>(Theme.of(context).textTheme.labelLarge); |
| |
| @override |
| MaterialStateProperty<Color?>? get backgroundColor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return _colors.onSurface.withOpacity(0.12); |
| } |
| return _colors.secondaryContainer; |
| }); |
| |
| @override |
| MaterialStateProperty<Color?>? get foregroundColor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return _colors.onSurface.withOpacity(0.38); |
| } |
| return _colors.onSecondaryContainer; |
| }); |
| |
| @override |
| MaterialStateProperty<Color?>? get overlayColor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.pressed)) { |
| return _colors.onSecondaryContainer.withOpacity(0.12); |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return _colors.onSecondaryContainer.withOpacity(0.08); |
| } |
| if (states.contains(MaterialState.focused)) { |
| return _colors.onSecondaryContainer.withOpacity(0.12); |
| } |
| return null; |
| }); |
| |
| @override |
| MaterialStateProperty<Color>? get shadowColor => |
| MaterialStatePropertyAll<Color>(_colors.shadow); |
| |
| @override |
| MaterialStateProperty<Color>? get surfaceTintColor => |
| const MaterialStatePropertyAll<Color>(Colors.transparent); |
| |
| @override |
| MaterialStateProperty<double>? get elevation => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return 0.0; |
| } |
| if (states.contains(MaterialState.pressed)) { |
| return 0.0; |
| } |
| if (states.contains(MaterialState.hovered)) { |
| return 1.0; |
| } |
| if (states.contains(MaterialState.focused)) { |
| return 0.0; |
| } |
| return 0.0; |
| }); |
| |
| @override |
| MaterialStateProperty<EdgeInsetsGeometry>? get padding => |
| MaterialStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context)); |
| |
| @override |
| MaterialStateProperty<Size>? get minimumSize => |
| const MaterialStatePropertyAll<Size>(Size(64.0, 40.0)); |
| |
| // No default fixedSize |
| |
| @override |
| MaterialStateProperty<Size>? get maximumSize => |
| const MaterialStatePropertyAll<Size>(Size.infinite); |
| |
| // No default side |
| |
| @override |
| MaterialStateProperty<OutlinedBorder>? get shape => |
| const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()); |
| |
| @override |
| MaterialStateProperty<MouseCursor?>? get mouseCursor => |
| MaterialStateProperty.resolveWith((Set<MaterialState> states) { |
| if (states.contains(MaterialState.disabled)) { |
| return SystemMouseCursors.basic; |
| } |
| return SystemMouseCursors.click; |
| }); |
| |
| @override |
| VisualDensity? get visualDensity => Theme.of(context).visualDensity; |
| |
| @override |
| MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; |
| |
| @override |
| InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; |
| } |
| |
| // END GENERATED TOKEN PROPERTIES - FilledTonalButton |