navigationDrawerTheme static method
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,
);
}),
);
}