inputDecorationTheme static method

InputDecorationTheme inputDecorationTheme({
  1. required ColorScheme colorScheme,
  2. SchemeColor? baseSchemeColor,
  3. double? radius,
  4. FlexInputBorderType? borderType,
  5. bool filled = true,
  6. Color? fillColor,
  7. double? focusedBorderWidth,
  8. double? unfocusedBorderWidth,
  9. double gapPadding = 4,
  10. bool unfocusedHasBorder = true,
  11. bool unfocusedBorderIsColored = true,
  12. bool useMaterial3 = false,
})

An opinionated OutlineInputBorder or UnderlineInputBorder using InputDecorationTheme, with optional fill color and adjustable corner radius.

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

The corner radius can be adjusted, it defaults to kInputDecoratorRadius (20), which currently matches the border radius default used used on buttons in M3 specification. This value is not specified in the M3 design guide, and this default border radius may be changed later to match the M3 spec when it is known.

Implementation

static InputDecorationTheme inputDecorationTheme({
  /// Typically the same [ColorScheme] that is also use for your [ThemeData].
  required final ColorScheme colorScheme,

  /// Selects which color from the passed in colorScheme to use for the border
  /// and fill color of the input decorator.
  ///
  /// 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,

  /// The decorated input fields corner border radius.
  ///
  /// If not defined, defaults to [kInputDecoratorRadius] 16dp.
  /// When opting in on using Material3 with `useMaterial3` set to true,
  /// FlexColorScheme will [kInputDecoratorM3Radius] is value is not
  /// otherwise specified.
  final double? radius,

  /// Selects input border type.
  ///
  /// If undefined, defaults to [FlexInputBorderType.outline].
  final FlexInputBorderType? borderType,

  /// If true the decoration's container is filled with [fillColor].
  ///
  /// Typically this field set to true if [border] is an
  /// [UnderlineInputBorder].
  ///
  /// The decoration's container is the area, defined by the border's
  /// [InputBorder.getOuterPath], which is filled if [filled] is
  /// true and bordered per the [border].
  ///
  /// Defaults to true.
  final bool filled = true,

  /// An optional totally custom fill color used to fill the
  /// `InputDecorator` background with, when `filled` is true.
  ///
  /// If null, defaults to color scheme color defined by `baseColor`
  /// withAlpha(0x0D) (5%) if color scheme is light and withAlpha(0x14) (8%)
  /// if color scheme is dark.
  final Color? fillColor,

  /// The border width when the input is selected.
  ///
  /// If null, defaults to [kThickBorderWidth] = 2.
  final double? focusedBorderWidth,

  /// The border width when the input is unselected or disabled.
  ///
  /// If null, defaults to [kThinBorderWidth] = 1.
  final double? unfocusedBorderWidth,

  /// Horizontal padding on either side of the border's
  /// [InputDecoration.labelText] width gap.
  ///
  /// Defaults to 4, which is also the default in SDK default input decorator.
  final double gapPadding = 4,

  /// Unfocused input decoration has a border.
  ///
  /// Defaults to true.
  ///
  /// Applies to both outline and underline mode. You would typically
  /// use this in a design where you use a fill color and want unfocused
  /// input fields to only be highlighted by the fill color and not even
  /// have an unfocused input border style.
  ///
  /// When set to false, there is no border bored on states enabledBorder and
  /// disabledBorder, there is a border on focusedBorder, focusedErrorBorder
  /// and errorBorder, so error thus has a border also when it is not focused.
  final bool unfocusedHasBorder = true,

  /// Unfocused input decoration border uses the color baseScheme color.
  ///
  /// Applies to both outline and underline mode.
  ///
  /// When set to true, the unfocused borders also uses the [baseSchemeColor]
  /// as its border color, but with alpha [kEnabledBorderAlpha] (90%).
  ///
  /// If set to false, the color uses the SDK default unselected border color,
  /// which is [ColorScheme.onSurface] with 38% opacity.
  ///
  /// The unfocused border color selection also applies to it hovered state.
  ///
  /// Defaults to true.
  final bool unfocusedBorderIsColored = true,

  /// A temporary flag used to opt-in to new 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 defaults values.
  ///
  /// The M2/M3 SDK defaults will only be used for properties that are not
  /// defined, if defined they keep their defined values.
  final bool useMaterial3 = false,
}) {
  // Get selected color, defaults to primary.
  final Color baseColor =
      schemeColor(baseSchemeColor ?? SchemeColor.primary, colorScheme);

  final Color usedFillColor = fillColor ??
      (colorScheme.brightness == Brightness.dark
          ? baseColor.withAlpha(kFillColorAlphaDark)
          : baseColor.withAlpha(kFillColorAlphaLight));

  final Color enabledBorder = unfocusedBorderIsColored
      ? baseColor.withAlpha(kEnabledBorderAlpha)
      : colorScheme.onSurface.withOpacity(0.38);

  // Default border radius.
  final double effectiveRadius = radius ??
      (useMaterial3 ? kInputDecoratorM3Radius : kInputDecoratorRadius);

  // Default outline widths.
  final double unfocusedWidth = unfocusedBorderWidth ?? kThinBorderWidth;
  final double focusedWidth = focusedBorderWidth ?? kThickBorderWidth;

  switch (borderType ?? FlexInputBorderType.outline) {
    case FlexInputBorderType.outline:
      return InputDecorationTheme(
        floatingLabelStyle:
            MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
          if (states.contains(MaterialState.error) &&
              states.contains(MaterialState.focused)) {
            return TextStyle(color: colorScheme.error);
          }
          if (states.contains(MaterialState.error)) {
            return TextStyle(
              color: colorScheme.error.withAlpha(kEnabledBorderAlpha),
            );
          }
          if (states.contains(MaterialState.disabled)) {
            return TextStyle(
              color: baseColor
                  .blendAlpha(colorScheme.onSurface, kDisabledAlphaBlend)
                  .withAlpha(kDisabledBackgroundAlpha),
            );
          }
          return TextStyle(color: baseColor);
        }),
        filled: filled,
        fillColor: usedFillColor,
        hoverColor: baseColor.withAlpha(kHoverBackgroundAlpha),
        focusColor: baseColor.withAlpha(kFocusBackgroundAlpha),
        focusedBorder: OutlineInputBorder(
          gapPadding: gapPadding,
          borderRadius: BorderRadius.all(Radius.circular(effectiveRadius)),
          borderSide: BorderSide(
            color: baseColor,
            width: focusedWidth,
          ),
        ),
        enabledBorder: OutlineInputBorder(
          gapPadding: gapPadding,
          borderRadius: BorderRadius.all(Radius.circular(effectiveRadius)),
          borderSide: unfocusedHasBorder
              ? BorderSide(
                  color: enabledBorder,
                  width: unfocusedWidth,
                )
              : BorderSide.none,
        ),
        disabledBorder: OutlineInputBorder(
          gapPadding: gapPadding,
          borderRadius: BorderRadius.all(Radius.circular(effectiveRadius)),
          borderSide: unfocusedHasBorder
              ? BorderSide(
                  color: baseColor
                      .blendAlpha(colorScheme.onSurface, kDisabledAlphaBlend)
                      .withAlpha(kDisabledBackgroundAlpha),
                  width: unfocusedWidth,
                )
              : BorderSide.none,
        ),
        focusedErrorBorder: OutlineInputBorder(
          gapPadding: gapPadding,
          borderRadius: BorderRadius.all(Radius.circular(effectiveRadius)),
          borderSide: BorderSide(
            color: colorScheme.error,
            width: focusedWidth,
          ),
        ),
        errorBorder: OutlineInputBorder(
          gapPadding: gapPadding,
          borderRadius: BorderRadius.all(Radius.circular(effectiveRadius)),
          borderSide: BorderSide(
            color: colorScheme.error.withAlpha(kEnabledBorderAlpha),
            width: unfocusedWidth,
          ),
        ),
      );
    case FlexInputBorderType.underline:
      return InputDecorationTheme(
        floatingLabelStyle:
            MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
          if (states.contains(MaterialState.error) &&
              states.contains(MaterialState.focused)) {
            return TextStyle(color: colorScheme.error);
          }
          if (states.contains(MaterialState.error)) {
            return TextStyle(
              color: colorScheme.error.withAlpha(kEnabledBorderAlpha),
            );
          }
          if (states.contains(MaterialState.disabled)) {
            return TextStyle(
              color: baseColor
                  .blendAlpha(colorScheme.onSurface, kDisabledAlphaBlend)
                  .withAlpha(kDisabledBackgroundAlpha),
            );
          }
          return TextStyle(color: baseColor);
        }),
        filled: filled,
        fillColor: usedFillColor,
        hoverColor: baseColor.withAlpha(kHoverBackgroundAlpha),
        focusColor: baseColor.withAlpha(kFocusBackgroundAlpha),
        focusedBorder: UnderlineInputBorder(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(effectiveRadius),
            topRight: Radius.circular(effectiveRadius),
          ),
          borderSide: BorderSide(
            color: baseColor,
            width: focusedWidth,
          ),
        ),
        enabledBorder: UnderlineInputBorder(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(effectiveRadius),
            topRight: Radius.circular(effectiveRadius),
          ),
          borderSide: unfocusedHasBorder
              ? BorderSide(
                  color: enabledBorder,
                  width: unfocusedWidth,
                )
              : BorderSide.none,
        ),
        disabledBorder: UnderlineInputBorder(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(effectiveRadius),
            topRight: Radius.circular(effectiveRadius),
          ),
          borderSide: unfocusedHasBorder
              ? BorderSide(
                  color: baseColor
                      .blendAlpha(colorScheme.onSurface, kDisabledAlphaBlend)
                      .withAlpha(kDisabledBackgroundAlpha),
                  width: unfocusedWidth,
                )
              : BorderSide.none,
        ),
        focusedErrorBorder: UnderlineInputBorder(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(effectiveRadius),
            topRight: Radius.circular(effectiveRadius),
          ),
          borderSide: BorderSide(
            color: colorScheme.error,
            width: focusedWidth,
          ),
        ),
        errorBorder: UnderlineInputBorder(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(effectiveRadius),
            topRight: Radius.circular(effectiveRadius),
          ),
          borderSide: BorderSide(
            color: colorScheme.error.withAlpha(kEnabledBorderAlpha),
            width: unfocusedWidth,
          ),
        ),
      );
  }
}