navigationDrawerTheme static method

NavigationDrawerThemeData navigationDrawerTheme({
  1. required ColorScheme colorScheme,
  2. SchemeColor? backgroundSchemeColor,
  3. double? indicatorWidth,
  4. double? indicatorRadius,
  5. TextStyle? textStyle,
  6. SchemeColor? indicatorSchemeColor,
  7. double? indicatorOpacity,
  8. SchemeColor? selectedItemSchemeColor,
  9. SchemeColor? unselectedItemSchemeColor,
  10. Color? shadowColor,
  11. Color? surfaceTintColor,
})

An opinionated NavigationDrawerThemeData theme with simpler API.

Can set indicatorWidth, indicatorRadius, backgroundSchemeColor and indicatorSchemeColor plus its opacity indicatorOpacity and colors for selected and unselected items selectedItemSchemeColor, unselectedItemSchemeColor.

Implementation

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

  /// Defines which [Theme] based [ColorScheme] based background color
  /// of [NavigationDrawer].
  ///
  /// If not defined will default to [Drawer] theme
  /// background color. If it is not defined, then Flutter default uses
  /// uses surface color as default in M3, and background in M2.
  /// FCS uses surface in both modes.
  final SchemeColor? backgroundSchemeColor,

  /// Defines the width of [NavigationDrawer]'s indicator.
  ///
  /// If not defined, defaults to 336dp
  /// via Flutter SDK defaults for M3/M2. The 336dp width values is derived
  /// from the M3 padding spec of 12dp around both sides of the M3 drawers
  /// default width of 360dp.
  final double? indicatorWidth,

  /// Border radius of the selection indicator on the [NavigationDrawer].
  ///
  /// If not defined, defaults to [StadiumBorder].
  ///
  /// FCS default, follows the Material M3 guide:
  /// https://m3.material.io/components/navigation-drawer/specs
  final double? indicatorRadius,

  /// The TextStyle of the labels.
  ///
  /// You would pass in Theme.of(context).textTheme.labelLarge
  /// for correct M3 style.
  final TextStyle? textStyle,

  /// Defines which [Theme] based [ColorScheme] based color [NavigationDrawer]
  /// uses as as its background color on the selection indicator.
  ///
  /// If undefined, defaults to [SchemeColor.secondaryContainer].
  final SchemeColor? indicatorSchemeColor,

  /// The opacity of the used indicator.
  ///
  /// Defaults to 1, fully opaque if not defined.
  final double? indicatorOpacity,

  /// Defines which [Theme] based [ColorScheme] based color [NavigationDrawer]
  /// uses as as its selected item color.
  ///
  /// If undefined, defaults to correct contrast color pair
  /// for [indicatorSchemeColor].
  final SchemeColor? selectedItemSchemeColor,

  /// Defines which [Theme] based [ColorScheme] based color [NavigationDrawer]
  /// uses as as its unselected item color.
  ///
  /// If undefined, defaults to correct contrast color pair for
  /// [backgroundSchemeColor].
  final SchemeColor? unselectedItemSchemeColor,

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

  /// Overrides the default value of [NavigationDrawer.surfaceTintColor].
  final Color? surfaceTintColor,
}) {
  // TODO(rydmike): Drawer indicator tint effect, not supported in Flutter yet
  // See issue: https://github.com/flutter/flutter/issues/123507
  // final bool tintInteract = useTintedInteraction ?? true;

  // Get selected background color, defaults to surface.
  final Color backgroundColor =
      schemeColor(backgroundSchemeColor ?? SchemeColor.surface, colorScheme);
  final Color onBackGroundColorFallback = schemeColorPair(
      backgroundSchemeColor ?? SchemeColor.surface, colorScheme);
  final Color onBackgroundColor = unselectedItemSchemeColor != null
      ? schemeColor(unselectedItemSchemeColor, colorScheme)
      : onBackGroundColorFallback;

  // Selected indicator color
  final Color indicatorColor = schemeColor(
      indicatorSchemeColor ?? SchemeColor.secondaryContainer, colorScheme);
  final Color onIndicatorColorFallback = schemeColorPair(
      indicatorSchemeColor ?? SchemeColor.secondaryContainer, colorScheme);
  final Color onIndicatorColor = selectedItemSchemeColor != null
      ? schemeColor(selectedItemSchemeColor, colorScheme)
      : onIndicatorColorFallback;

  // Indicator size based on provided width
  final Size indicatorSize = Size(indicatorWidth ?? 336, 56);

  // TextStyle
  final TextStyle style = textStyle ?? const TextStyle();

  // TODO(rydmike): Removed interaction tint, not supported in Flutter yet.
  // See issue: https://github.com/flutter/flutter/issues/123507
  //
  // // Using these tinted overlay variables in all themes for ease of
  // // reasoning and duplication.
  // final Color overlay = backgroundColor;
  // final Color tint = indicatorColor;
  // final double factor =
  // _tintAlphaFactor(tint, colorScheme.brightness, true);

  // TODO(rydmike): Would need something like this for tinted indicator.
  // See issue: https://github.com/flutter/flutter/issues/123507
  //  This does not work due to limitations in Flutter SDK implementation.
  //  All we can get is ThemeData based themed hover, press, focus
  //  Report this limitation!

  // Color? indicatorStateColor() =>
  //     MaterialStateColor.resolveWith((Set<MaterialState> states) {
  //       if (states.contains(MaterialState.selected)) {
  //         if (states.contains(MaterialState.pressed)) {
  //           if (tintInteract) return tintedPressed(overlay, tint, factor);
  //           return indicatorColor.withAlpha(kAlphaPressed);
  //         }
  //         if (states.contains(MaterialState.hovered)) {
  //           if (tintInteract) return tintedHovered(overlay, tint, factor);
  //           return indicatorColor.withAlpha(kAlphaHovered);
  //         }
  //         if (states.contains(MaterialState.focused)) {
  //           if (tintInteract) return tintedFocused(overlay, tint, factor);
  //           return indicatorColor.withAlpha(kAlphaFocused);
  //         }
  //         return indicatorColor;
  //       }
  //
  //       if (states.contains(MaterialState.hovered)) {
  //         if (tintInteract) return tintedPressed(overlay, tint, factor);
  //         return colorScheme.primary.withAlpha(kAlphaPressed);
  //       }
  //       if (states.contains(MaterialState.hovered)) {
  //         if (tintInteract) return tintedHovered(overlay, tint, factor);
  //         return colorScheme.onSurface.withAlpha(kAlphaHovered);
  //       }
  //       if (states.contains(MaterialState.focused)) {
  //         if (tintInteract) return tintedHovered(overlay, tint, factor);
  //         return colorScheme.primary.withAlpha(kAlphaHovered);
  //       }
  //       return Colors.transparent;
  //     });

  return NavigationDrawerThemeData(
    backgroundColor: backgroundColor,
    indicatorColor: indicatorColor.withOpacity(indicatorOpacity ?? 1.0),
    indicatorSize: indicatorSize,
    surfaceTintColor: surfaceTintColor,
    shadowColor: shadowColor,
    indicatorShape: indicatorRadius == null
        ? null
        : RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(indicatorRadius),
            ),
          ),
    labelTextStyle:
        MaterialStateProperty.resolveWith((Set<MaterialState> states) {
      return style.apply(
        color: states.contains(MaterialState.selected)
            ? onIndicatorColor
            : onBackgroundColor,
      );
    }),
    iconTheme: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
      return IconThemeData(
        size: 24.0,
        color: states.contains(MaterialState.selected)
            ? onIndicatorColor
            : onBackgroundColor,
      );
    }),
  );
}