datePickerTheme static method

DatePickerThemeData datePickerTheme({
  1. required ColorScheme colorScheme,
  2. Color? backgroundColor,
  3. SchemeColor? backgroundSchemeColor,
  4. SchemeColor? headerBackgroundSchemeColor,
  5. double? elevation,
  6. double? radius,
  7. InputDecorationTheme? inputDecorationTheme,
  8. bool? useInputDecoratorTheme,
  9. Color? shadowColor,
  10. Color? surfaceTintColor,
})

An opinionated DatePickerThemeData with custom corner radius.

Corner radius defaults to kDialogRadius 28dp.

Implementation

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

  /// Dialog background color.
  ///
  /// If null and [backgroundSchemeColor] is also null, then it
  /// gets default via Dialog's default null theme behavior.
  ///
  /// If [backgroundSchemeColor] is defined, it will override any color
  /// passed in here.
  ///
  /// Can be used to make a custom themed dialog with own background color,
  /// even after the [ThemeData.dialogBackgroundColor] property is
  /// is deprecated in Flutter SDK. See
  /// https://github.com/flutter/flutter/issues/91772).
  final Color? backgroundColor,

  /// Selects which color from the passed in colorScheme to use as the dialog
  /// background color.
  ///
  /// If not defined, then the passed in [backgroundColor] will be used,
  /// which may be null too and dialog then falls back to Flutter SDK default
  /// value for TimePickerDialog, which is [colorScheme.surface].
  ///
  /// FlexColorScheme sub-theming uses this property to match the background
  /// color of this dialog to other standard dialogs. It sets it via
  /// [FlexSubThemesData] to [SchemeColor.surface].
  final SchemeColor? backgroundSchemeColor,

  /// Overrides the header's default background fill color.
  ///
  /// The dialog's header displays the currently selected date.
  ///
  /// Defaults to primary in M2 and to surface in M3.
  ///
  /// The foreground color will use the correct contrast pair for selected
  /// [SchemeColor]
  final SchemeColor? headerBackgroundSchemeColor,

  /// Dialog elevation.
  ///
  /// If not defined, defaults to [kDialogElevation] = 6.
  final double? elevation,

  /// Outer corner radius.
  ///
  /// If not defined, defaults to [kDialogRadius] 28dp,
  /// based on M3 Specification
  /// https://m3.material.io/components/dialogs/specs
  final double? radius,

  /// An input decoration theme, for the time picker.
  ///
  /// You would typically pass in one that matches the main used input
  /// decoration theme in order to get same input style with possible
  /// rounding used in the app otherwise on the input fields in the picker.
  ///
  /// It adds the custom overrides to the passed in decorator, that the widget
  /// does internally to the default null InputDecorationTheme. There is
  /// no need to add those in the passed in InputDecorationTheme. Just pass
  /// in your overall used app InputDecorationTheme.
  final InputDecorationTheme? inputDecorationTheme,

  /// Set to true to not use the provided [inputDecorationTheme].
  ///
  /// If this flag is false, the provided [inputDecorationTheme] is not used,
  /// additionally the theme fix this theme helper does internally is
  /// not applied and pure null value is passed. This enables getting the
  /// default widget behavior input decorator, or opting in on getting the
  /// provided inputDecorationTheme with the internal style fix for issue
  /// https://github.com/flutter/flutter/issues/54104 applied automatically
  /// to the provided inputDecorationTheme.
  ///
  /// If not defined, defaults to false.
  final bool? useInputDecoratorTheme,

  /// Overrides the default value of [Dialog.shadowColor].
  final Color? shadowColor,

  /// Overrides the default value of [Dialog.surfaceTintColor].
  final Color? surfaceTintColor,
}) {
  InputDecorationTheme datePickerDefaultInputDecorationTheme() {
    const BorderRadius defaultRadius = BorderRadius.all(Radius.circular(4.0));
    return InputDecorationTheme(
      filled: false,
      hoverColor: colorScheme.brightness == Brightness.dark
          ? Colors.white.withOpacity(0.04)
          : Colors.black.withOpacity(0.04),
      focusColor: colorScheme.brightness == Brightness.dark
          ? Colors.white.withOpacity(0.12)
          : Colors.black.withOpacity(0.12),
      border: OutlineInputBorder(
        borderRadius: defaultRadius,
        borderSide: BorderSide(color: colorScheme.primary, width: 1),
      ),
      enabledBorder: OutlineInputBorder(
        borderRadius: defaultRadius,
        borderSide: BorderSide(color: colorScheme.outline, width: 1),
      ),
      errorBorder: OutlineInputBorder(
        borderRadius: defaultRadius,
        borderSide: BorderSide(color: colorScheme.error, width: 1),
      ),
      focusedBorder: OutlineInputBorder(
        borderRadius: defaultRadius,
        borderSide: BorderSide(color: colorScheme.primary, width: 2),
      ),
      focusedErrorBorder: OutlineInputBorder(
        borderRadius: defaultRadius,
        borderSide: BorderSide(color: colorScheme.error, width: 2),
      ),
      disabledBorder: OutlineInputBorder(
        borderRadius: defaultRadius,
        borderSide: BorderSide(
            color: colorScheme.onSurface.withOpacity(0.12), width: 1),
      ),
      floatingLabelStyle:
          MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
        // These styles are copied for M# default, we are not going to test
        // them again.
        // coverage:ignore-start
        if (states.contains(MaterialState.disabled)) {
          return TextStyle(color: colorScheme.onSurface.withOpacity(0.38));
        }
        if (states.contains(MaterialState.error)) {
          if (states.contains(MaterialState.hovered)) {
            return TextStyle(color: colorScheme.onErrorContainer);
          }
          if (states.contains(MaterialState.focused)) {
            return TextStyle(color: colorScheme.error);
          }
          return TextStyle(color: colorScheme.error);
        }
        if (states.contains(MaterialState.hovered)) {
          return TextStyle(color: colorScheme.onSurfaceVariant);
        }
        if (states.contains(MaterialState.focused)) {
          return TextStyle(color: colorScheme.primary);
        }
        return TextStyle(color: colorScheme.onSurfaceVariant);
        // coverage:ignore-end
      }),
    );
  }

  final bool useDecorator = useInputDecoratorTheme ?? false;
  final Color? background = backgroundSchemeColor == null
      ? backgroundColor // might be null, then SDK theme defaults.
      : schemeColor(backgroundSchemeColor, colorScheme);

  final Color? headerBackgroundColor = headerBackgroundSchemeColor == null
      ? null
      : schemeColor(headerBackgroundSchemeColor, colorScheme);
  final Color? headerForegroundColor = headerBackgroundSchemeColor == null
      ? null
      : schemeColorPair(headerBackgroundSchemeColor, colorScheme);

  return DatePickerThemeData(
    backgroundColor: background,
    headerBackgroundColor: headerBackgroundColor,
    headerForegroundColor: headerForegroundColor,
    elevation: elevation ?? kDialogElevation,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.all(
        Radius.circular(radius ?? kDialogRadius),
      ),
    ),
    shadowColor: shadowColor,
    surfaceTintColor: surfaceTintColor,
    inputDecorationTheme: useDecorator
        ? inputDecorationTheme
        // TODO(rydmike): Raise DatePicker decorator merge issue.
        // Getting back to default style with an elaborate back to default
        // input decorator does not work due to this:
        // https://github.com/flutter/flutter/pull/128950#issuecomment-1657177393
        : datePickerDefaultInputDecorationTheme(),
  );
}