bottomNavigationBar static method
An opinionated BottomNavigationBarThemeData with custom elevation.
This sub-theme uses a style that prefers single use config parameters over the ones that combines many styling options into TextStyle and icon sub-theme properties. This is simpler to use when you want to modify a single property like size and rest is fine. This of course comes at the expense that the sub-theme instead has more properties.
Its elevation
defaults to kBottomNavigationBarElevation
= 0.
The bottom navigation bar uses opinionated colors choices from the passed
colorScheme
to style the bottom navigation bar.
Background opacity
can be set.
Implementation
static BottomNavigationBarThemeData bottomNavigationBar({
/// Typically you would pass the same [ColorScheme] that is also used in
/// your [ThemeData] definition.
required final ColorScheme colorScheme,
/// Optional text style for the [BottomNavigationBar] labels.
///
/// If [useFlutterDefaults] is false, the text style
/// [FlexColorScheme.m3TextTheme.bodyMedium]
/// will be used as base style for the text style.
///
/// If [useFlutterDefaults] is true, null will be passed to
/// [FlexSubThemes.bottomNavigationBar] and along to theme creation, if all
/// labeling modifying properties (size and scheme color) are also null, it
/// will then be passed along as null, allowing it to remain undefined
/// and widget default behavior sets the default. If label size or scheme
/// is defined, a default TextStyle() will be created, if
/// [bottomNavigationBarLabelTextStyle] is undefined, that gets th size and
/// color applied.
///
/// The size and colors defined in any of the text size and color properties
/// are applied as overrides on the text style.
final TextStyle? labelTextStyle,
/// The size of the text label on selected [BottomNavigationBar] item.
///
/// If defined, it overrides the font size on effective label TextStyle
/// on selected item, 14 is used as fallback if needed.
final double? selectedLabelSize,
/// The size of the text label on unselected [BottomNavigationBar] items.
///
/// If defined, it overrides the font size on effective label TextStyle
/// on unselected items. Defaults to [selectedLabelSize] - 2, but min 8.
/// Smaller than 8dp is not legible on most screens.
///
/// [BottomNavigationBar] uses this -2dp smaller font on the unselected
/// label as default, since it is so based on Material 2 spec. By assigning
/// same value as to selectedLabelSize, you can make them the same size.
final double? unselectedLabelSize,
/// Select which color from the theme's [ColorScheme] to use as base for
/// the [BottomNavigationBar]'s selected label text color.
///
/// All colors in the color scheme are not good choices, but some work well.
///
/// Defaults to [SchemeColor.primary].
///
/// If [useFlutterDefaults] is true, and this property and all other
/// label modifying properties are undefined, including the text style,
/// the effective color will be [ColorScheme.primary] in light theme and
/// [ColorScheme.dark] theme mode.
final SchemeColor? selectedLabelSchemeColor,
/// Select which color from the passed in [ColorScheme] to use for
/// the [BottomNavigationBar]'s unselected items text color.
///
/// All colors in the color scheme are not good choices, but some work well.
///
/// If null, defaults to using [Theme]'s [ColorScheme.onSurface] via the
/// [NavigationRail]'s default un-themed behavior.
///
/// FlexColorScheme will use [SchemeColor.onSurface] via [FlexSubThemesData]
/// property default.
final SchemeColor? unselectedLabelSchemeColor,
/// If true, the unselected labels in the [BottomNavigationBar] use a
/// more muted color version of the color defined by
/// [unselectedLabelSchemeColor].
///
/// If null, defaults to true.
final bool? mutedUnselectedLabel,
/// The size of the icon on selected [BottomNavigationBar] item.
///
/// If undefined, it defaults to 24.
final double? selectedIconSize,
/// The size of the icons on unselected [BottomNavigationBar] items.
///
/// If undefined, defaults to [selectedIconSize].
final double? unselectedIconSize,
/// Select which color from the theme's [ColorScheme] to use as base for
/// the [BottomNavigationBar]'s selected item icon color.
///
/// All colors in the color scheme are not good choices, but some work well.
///
/// If undefined, defaults to [SchemeColor.primary].
///
/// If [useFlutterDefaults] is true, and this property and all other icon
/// modifying properties are undefined, the effective color will be
/// [ColorScheme.dark] in dark theme mode.
final SchemeColor? selectedIconSchemeColor,
/// Select which color from the passed in [ColorScheme] to use as base for
/// the [BottomNavigationBar]'s unselected items icon color.
///
/// All colors in the color scheme are not good choices, but some work well.
///
/// Defaults to [SchemeColor.onSurface], and adds an alpha blend and
/// opacity, if [bottomNavigationBarMutedUnselectedLabel] is true.
///
/// If [useFlutterDefaults] is true, and this property and all other
/// icon modifying properties are undefined,
/// the effective color will be [ThemeData.unselectedWidgetColor]
/// which is [Colors.black54] in light mode and [Colors.white70] in dark.
final SchemeColor? unselectedIconSchemeColor,
/// If true, the unselected icon in the [BottomNavigationBar] use a more
/// muted color version of the color defined by
/// [bottomNavigationBarUnselectedIconSchemeColor].
/// The muting is unselected color with
/// blendAlpha(unselected color, [kUnselectedBackgroundPrimaryAlphaBlend])
/// and withAlpha([kUnselectedAlphaBlend]).
///
/// If undefined, defaults to true.
final bool? mutedUnselectedIcon,
/// Select which color from the theme's [ColorScheme] to use as background
/// color for the [BottomNavigationBar].
///
/// All colors in the color scheme are not good choices, but some work well.
///
/// If undefined, defaults to [SchemeColor.background].
///
/// If [useFlutterDefaults] true, and this property is undefined,
/// the effective background color will also be [ColorScheme.background].
///
/// FlexColorScheme sets background defaults of [BottomNavigationBar],
/// [NavigationBar] and [BottomNavigationBar] to [SchemeColor.background]
/// when it is using component sub-themes.
/// Flutter SDK uses different colors on all three widgets. Our opinion is
/// that they should all default to using the same [ColorScheme] based
/// color. FlexColorScheme uses the background color as this default.
final SchemeColor? backgroundSchemeColor,
/// BottomNavigationBar background opacity.
///
/// The opacity value is only applied when a none null value is selected
/// in [backgroundSchemeColor], it cannot be applied to the default
/// Flutter SDK background color available when backgroundSchemeColor is
/// null.
///
/// If undefined, defaults to 1, fully opaque.
final double? opacity,
/// [BottomNavigationBar] container elevation.
///
/// If not defined, defaults to [kBottomNavigationBarElevation] = 3.
final double? elevation,
/// Whether the labels are shown for the selected
/// [BottomNavigationBarItem].
final bool? showSelectedLabels,
/// Whether the labels are shown for the unselected
/// [BottomNavigationBarItem]s.
final bool? showUnselectedLabels,
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// With [BottomNavigationBarType.fixed] the items have fixed width.
/// With [BottomNavigationBarType.shifting], the location and size of the
/// items animate and labels fade in when they are tapped.
///
/// If undefined, defaults to Flutter SDK default. Where
/// If type is provided, it is returned. Next, if the bottom navigation bar
/// theme provides a type, it is used. Finally, the default behavior will be
/// [BottomNavigationBarType.fixed] for 3 or fewer items, and
/// [BottomNavigationBarType.shifting] is used for 4+ items.
final BottomNavigationBarType? type,
/// The arrangement of the bar's [items] when the enclosing
/// [MediaQueryData.orientation] is [Orientation.landscape].
///
/// The following alternatives are supported:
///
/// * [BottomNavigationBarLandscapeLayout.spread] - the items are
/// evenly spaced and spread out across the available width. Each
/// item's label and icon are arranged in a column.
/// * [BottomNavigationBarLandscapeLayout.centered] - the items are
/// evenly spaced in a row but only consume as much width as they
/// would in portrait orientation. The row of items is centered within
/// the available width. Each item's label and icon are arranged
/// in a column.
/// * [BottomNavigationBarLandscapeLayout.linear] - the items are
/// evenly spaced and each item's icon and label are lined up in a
/// row instead of a column.
///
/// Defaults to [BottomNavigationBarLandscapeLayout.spread] via
/// Widget's default un-themed behavior.
final BottomNavigationBarLandscapeLayout? landscapeLayout,
/// The icon color alpha blend value for unselected items, used on icon when
/// [mutedUnselectedIcon] is true and on label when
/// [mutedUnselectedLabel] is true.
///
/// Defaults to [kUnselectedBackgroundPrimaryAlphaBlend], which is
/// 0x66 = 102 = 40%.
///
/// This setting is not exposed via [FlexSubThemesData], but can be if
/// needed later.
final int unselectedAlphaBlend = kUnselectedBackgroundPrimaryAlphaBlend,
/// The icon alpha value for unselected item, used on icon when
/// [mutedUnselectedIcon] is true and on label when
/// [mutedUnselectedLabel] is true.
///
/// Defaults to [kUnselectedAlphaBlend], which is
/// 0xA5 = 165 = 65%
///
/// This setting is not exposed via [FlexSubThemesData], but can be if
/// needed later.
final int unselectedAlpha = kUnselectedAlphaBlend,
/// Set to true to use Flutter SDK defaults for [BottomNavigationBar]
/// theme when its color, size and text style properties are undefined,
/// instead of using [FlexColorScheme]'s own defaults.
///
/// Recommend keeping it **false** for a more color harmonized component
/// theme starting point. This flag may be helpful if you want to create
/// custom sub-themes starting from less opinionated settings.
///
/// When all required properties are undefined and flag is false or true,
/// the effective default styles for undefined inputs become:
///
/// ```
/// FCS defaults Flutter defaults
/// useFlutterDefaults false true
/// - background background background
/// - selected icon primary light: theme primary, dark: secondary
/// - Selected label primary light: theme primary, dark: secondary
/// - unselected icon onSurface light: black54, dark: white70
/// - unSelected label onSurface light: black54, dark: white70
/// ```
/// FCS further applies both an alpha blend and slight opacity to
/// unselected icon and unselected label, but only if
/// [bottomNavigationBarMutedUnselectedIcon] and
/// [bottomNavigationBarMutedUnselectedLabel] are true respectively,
/// this also applies to undefined color inputs.
///
/// When muted unselected options are true, the difference to Flutter
/// default for unselected items is subtle, FCS has a bit more contrast.
final bool useFlutterDefaults = false,
}) {
// Determine if we can even use default text styles, only when all are null,
// can we fall back to Flutter SDK default.
final bool useDefaultTextStyle = labelTextStyle == null &&
selectedLabelSize == null &&
unselectedLabelSize == null &&
selectedLabelSchemeColor == null &&
unselectedLabelSchemeColor == null &&
useFlutterDefaults;
// Determine if we can even use default icon styles, only when all are null,
// can we fall back to Flutter SDK default.
final bool useDefaultIconTheme = selectedIconSize == null &&
unselectedIconSize == null &&
selectedIconSchemeColor == null &&
unselectedIconSchemeColor == null &&
useFlutterDefaults;
// Get text color, defaults to primary in light and to secondary in dark.
final Color labelColor = schemeColor(
selectedLabelSchemeColor ??
(colorScheme.brightness == Brightness.dark && useDefaultTextStyle
? SchemeColor.secondary
: SchemeColor.primary),
colorScheme);
// Get unselected label color, defaults to onSurface.
final Color unselectedLabelColor = schemeColor(
unselectedLabelSchemeColor ?? SchemeColor.onSurface, colorScheme);
// Get selected text style, defaults to TextStyle(), we can use it since
// size and color are applied to is separately.
final TextStyle textStyle = labelTextStyle ?? const TextStyle();
// Get effective text sizes.
final double labelSize = selectedLabelSize ?? textStyle.fontSize ?? 14;
// If not specified, unselected is label size, use 2dp smaller than
// selected, but always at least 8dp.
final double effectiveUnselectedLabelSize =
unselectedLabelSize ?? math.max(labelSize - 2, 8);
// Get icon color, defaults to primary in light, and secondary in dark.
final Color iconColor = schemeColor(
selectedIconSchemeColor ??
(useDefaultIconTheme && colorScheme.brightness == Brightness.dark
? SchemeColor.secondary
: SchemeColor.primary),
colorScheme);
// Get unselected icon color, defaults to onSurface.
final Color unselectedIconColor = schemeColor(
unselectedIconSchemeColor ?? SchemeColor.onSurface, colorScheme);
// Get effective icons sizes.
final double iconSize = selectedIconSize ?? 24;
final double effectiveUnselectedIconSize = unselectedIconSize ?? iconSize;
// Background color, when using normal default, falls back to background.
final Color backgroundColor = schemeColor(
backgroundSchemeColor ?? SchemeColor.background, colorScheme)
.withOpacity(opacity ?? 1.0);
return BottomNavigationBarThemeData(
backgroundColor: backgroundSchemeColor == null
? useFlutterDefaults
? null
: backgroundColor
: backgroundColor,
elevation: useFlutterDefaults && elevation == null
? null
: elevation ?? kBottomNavigationBarElevation,
unselectedIconTheme: useDefaultIconTheme
? null
: IconThemeData(
size: effectiveUnselectedIconSize,
opacity: 1,
color: (mutedUnselectedIcon ?? true)
? unselectedIconColor
.blendAlpha(unselectedIconColor, unselectedAlphaBlend)
.withAlpha(unselectedAlpha)
: unselectedIconColor,
),
selectedIconTheme: useDefaultIconTheme
? null
: IconThemeData(
size: iconSize,
opacity: 1,
color: iconColor,
),
selectedItemColor: useDefaultTextStyle ? null : labelColor,
unselectedItemColor: useDefaultTextStyle
? null
: (mutedUnselectedLabel ?? true)
? unselectedLabelColor
.blendAlpha(unselectedLabelColor, unselectedAlphaBlend)
.withAlpha(unselectedAlpha)
: unselectedLabelColor,
unselectedLabelStyle: useDefaultTextStyle
? null
: textStyle.copyWith(
fontSize: effectiveUnselectedLabelSize,
color: (mutedUnselectedLabel ?? true)
? unselectedLabelColor
.blendAlpha(unselectedLabelColor, unselectedAlphaBlend)
.withAlpha(unselectedAlpha)
: unselectedLabelColor,
),
selectedLabelStyle: useDefaultTextStyle
? null
: textStyle.copyWith(
fontSize: labelSize,
color: labelColor,
),
showSelectedLabels: showSelectedLabels,
showUnselectedLabels: showUnselectedLabels,
type: type,
landscapeLayout: landscapeLayout,
);
}