outlinedButtonTheme static method

OutlinedButtonThemeData outlinedButtonTheme(
  1. {required ColorScheme colorScheme,
  2. SchemeColor? baseSchemeColor,
  3. SchemeColor? outlineSchemeColor,
  4. double? radius,
  5. double? pressedOutlineWidth,
  6. double? outlineWidth,
  7. EdgeInsetsGeometry? padding,
  8. Size? minButtonSize,
  9. MaterialStateProperty<TextStyle?>? textStyle,
  10. bool? useTintedInteraction,
  11. InteractiveInkFeatureFactory? splashFactory,
  12. bool? useTintedDisable,
  13. bool? useMaterial3}
)

An opinionated OutlinedButtonThemeData theme.

Requires a ColorScheme. The color scheme would typically be equal the color scheme also used to define the color scheme for your app theme.

The adjustable button corner radius defaults to 20. This is the new default in M3, Flutter SDK M2 defaults to 4.

Implementation

static OutlinedButtonThemeData outlinedButtonTheme({
  /// Typically the same [ColorScheme] that is also used for your [ThemeData].
  required final ColorScheme colorScheme,

  /// Selects which color from the passed in colorScheme to use as the main
  /// color for the button.
  ///
  /// All colors in the color scheme are not good choices, but some work well.
  ///
  /// If not defined, [colorScheme.primary] will be used.
  final SchemeColor? baseSchemeColor,

  /// Defines which [Theme] based [ColorScheme] based color, that the
  /// [OutlinedButton] uses as its outline color.
  ///
  /// If [useMaterial3] is false, and the [baseSchemeColor] is not defined,
  /// the [baseSchemeColor] is used as default button
  /// outline color, following M2 style.
  ///
  /// If [useMaterial3] is true, and the [outlineSchemeColor] is
  /// not defined, the [colorScheme.outline] is used as default button
  /// outline color in M3 style.
  final SchemeColor? outlineSchemeColor,

  /// The button corner border radius.
  ///
  /// If not defined, defaults to [kButtonRadius] 40dp in M2. When using
  /// M3 it defaults to Stadium border based on
  /// https://m3.material.io/components/buttons/specs
  final double? radius,

  /// The outline thickness when the button is pressed or in error state.
  ///
  /// If null, defaults to [kThickBorderWidth] = 2, when
  /// [useMaterial3] is false, and to 1 when [useMaterial3] is true.
  final double? pressedOutlineWidth,

  /// The outline thickness when the button is not selected and not pressed.
  ///
  /// If null, defaults to [kThinBorderWidth] = 1.0.
  final double? outlineWidth,

  /// Padding for the button theme.
  ///
  /// Defaults to null and uses `styleFrom` constructors default padding.
  ///
  /// M3 has more horizontal padding 24dp, but the tighter default padding
  /// in M2 that is 16dp looks fine as well when using stadium borders
  /// as in M3.
  ///
  /// If null and [useMaterial3] is true in the context, the correct M3
  /// button theme default computed button padding for M3 will be used.
  final EdgeInsetsGeometry? padding,

  /// Minimum button size.
  ///
  /// If null, defaults to [kButtonMinSize] (`const Size(40.0, 40.0)`) when
  /// [useMaterial3] is false and to `const Size(64.0, 40.0)` when
  /// [useMaterial3] is true.
  final Size? minButtonSize,

  /// The style for the button's [Text] widget descendants.
  ///
  /// The color of the [textStyle] is typically not used directly, the
  /// [foregroundColor] is used instead.
  final MaterialStateProperty<TextStyle?>? textStyle,

  /// Defines if the theme uses tinted interaction effects.
  ///
  /// If undefined, defaults to false.
  final bool? useTintedInteraction,

  /// Creates the [InkWell] splash factory, which defines the appearance of
  /// "ink" splashes that occur in response to taps.
  ///
  /// In M2 mode FlexColorScheme passes in the effective splashFactory
  /// from splashFactory override value or the result from
  /// [FlexSubThemesData] adaptive splash settings. In M3 mode it is kept
  /// null and the default comes via ThemeData.splashFactory, that is has
  /// also defined.
  final InteractiveInkFeatureFactory? splashFactory,

  /// Defines if the theme uses tinted disabled color.
  ///
  /// If undefined, defaults to false.
  final bool? useTintedDisable,

  /// A temporary flag used to opt-in to Material 3 features.
  ///
  /// If set to true, the theme will use Material3 default styles when
  /// properties are undefined, if false defaults will use FlexColorScheme's
  /// own opinionated default values.
  ///
  /// The M2/M3 defaults will only be used for properties that are not
  /// defined, if defined they keep their defined values.
  ///
  /// If undefined, defaults to false.
  final bool? useMaterial3,
}) {
  final bool useM3 = useMaterial3 ?? false;
  final bool tintInteract = useTintedInteraction ?? false;
  final bool tintDisable = useTintedDisable ?? false;

  // Get selected color, defaults to primary.
  final Color baseColor =
      schemeColor(baseSchemeColor ?? SchemeColor.primary, colorScheme);

  // Outline color logic with different M2 and M3 defaults.
  final Color outlineColor = outlineSchemeColor == null
      ? useM3
          ? schemeColor(SchemeColor.outline, colorScheme)
          : baseColor
      : schemeColor(outlineSchemeColor, colorScheme);

  // Using these tinted overlay variables in all themes for ease of
  // reasoning and duplication.
  final Color overlay = colorScheme.surface;
  final Color tint = baseColor;
  final double factor = _tintAlphaFactor(tint, colorScheme.brightness);

  // Default outline widths.
  final double normalWidth = outlineWidth ?? kThinBorderWidth;
  final double pressedWidth =
      pressedOutlineWidth ?? (useM3 ? kThinBorderWidth : kThickBorderWidth);

  // We only define theme props for foregroundColor and overlayColor, if we
  // have some settings the default widget behavior does not handle.
  MaterialStateProperty<Color?>? foregroundColor;
  MaterialStateProperty<Color?>? overlayColor;
  if (baseSchemeColor != null || tintInteract || tintDisable) {
    foregroundColor =
        MaterialStateProperty.resolveWith((Set<MaterialState> states) {
      if (states.contains(MaterialState.disabled)) {
        if (tintDisable) {
          return tintedDisable(colorScheme.onSurface, baseColor);
        }
        return colorScheme.onSurface.withAlpha(kAlphaDisabled);
      }
      return baseColor;
    });

    overlayColor =
        MaterialStateProperty.resolveWith((Set<MaterialState> states) {
      if (states.contains(MaterialState.hovered)) {
        if (tintInteract) return tintedHovered(overlay, tint, factor);
        return baseColor.withAlpha(kAlphaHovered);
      }
      if (states.contains(MaterialState.focused)) {
        if (tintInteract) return tintedFocused(overlay, tint, factor);
        return baseColor.withAlpha(kAlphaFocused);
      }
      if (states.contains(MaterialState.pressed)) {
        if (tintInteract) return tintedPressed(overlay, tint, factor);
        return baseColor.withAlpha(kAlphaPressed);
      }
      return null;
    });
  }

  // Define side if its widths or color has any custom definition, if not
  // we fall back to default theme.
  MaterialStateProperty<BorderSide?>? side;
  if (outlineSchemeColor != null ||
      outlineWidth != null ||
      pressedOutlineWidth != null ||
      tintDisable ||
      !useM3) {
    side = MaterialStateProperty.resolveWith((Set<MaterialState> states) {
      if (states.contains(MaterialState.disabled)) {
        if (tintDisable) {
          return BorderSide(
            color: tintedDisable(colorScheme.onSurface, outlineColor)
                .withAlpha(kAlphaLowDisabled),
            width: normalWidth,
          );
        }
        return BorderSide(
          color: colorScheme.onSurface.withAlpha(kAlphaVeryLowDisabled),
          width: normalWidth,
        );
      }
      if (states.contains(MaterialState.error)) {
        return BorderSide(
          color: colorScheme.error,
          width: pressedWidth,
        );
      }
      if (states.contains(MaterialState.pressed)) {
        return BorderSide(
          color: outlineColor,
          width: pressedWidth,
        );
      }
      return BorderSide(
        color: outlineColor,
        width: normalWidth,
      );
    });
  }

  return OutlinedButtonThemeData(
    style: ButtonStyle(
      splashFactory: splashFactory,
      textStyle: textStyle,
      foregroundColor: foregroundColor,
      overlayColor: overlayColor,
      minimumSize: ButtonStyleButton.allOrNull<Size>(
        minButtonSize ?? (useM3 ? null : kButtonMinSize),
      ),
      padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
      side: side,
      shape: radius == null && useM3
          ? null
          : ButtonStyleButton.allOrNull<OutlinedBorder>(
              RoundedRectangleBorder(
                borderRadius: BorderRadius.all(
                  Radius.circular(radius ?? kButtonRadius),
                ),
              ),
            ),
    ),
  );
}