themedSystemNavigationBar static method

SystemUiOverlayStyle themedSystemNavigationBar(
  1. BuildContext? context, {
  2. bool? useDivider,
  3. double opacity = 1,
  4. bool noAppBar = false,
  5. bool invertStatusIcons = false,
  6. FlexSystemNavBarStyle systemNavBarStyle = FlexSystemNavBarStyle.background,
  7. Color? systemNavigationBarColor,
  8. Color? systemNavigationBarDividerColor,
  9. Brightness nullContextBrightness = Brightness.light,
  10. @Deprecated('This property is deprecated use systemNavigationBarColor ' 'instead. Deprecated in v2.0.0.') Color? nullContextBackground,
})

Returns a SystemUiOverlayStyle that by default has a system navigation bar style that matches the current theme.

For its default behavior it requires a build context with access to the inherited theme. This static function is a convenience wrapper for making a SystemUiOverlayStyle that follows current theme. For very customized styles you should use SystemUiOverlayStyle directly.

By default when calling themedSystemNavigationBar with context, it creates a SystemUiOverlayStyle where the system navigator bar uses current theme's ´colorScheme.background´ as its background color and icon colors that match this background, without any divider.

The background color can be modified with systemNavBarStyle that can use: system, surface, background, scaffoldBackground or transparent options as background color options, it defaults to background. See FlexSystemNavBarStyle for more info.

In standard Flutter themes, the surface, background, scaffoldBackground and in light theme, even system are all the same color. For such themes this convenience toggle does not make so much sense. However, if you use FlexColorScheme and its primary color surface branding, these colors are not the same, this toggle then offer a convenient way to switch the background color of your system navigation bar in a way that matches your theme's surface branded background color and to easily choose which one to use easily.

An optional divider on the navigation bar, which is only respected on Android P (= Pie = API 28 = Android 9) or higher, can be turned by setting useDivider to true. This produces a divider on top of the system navigation bar that in light theme uses color 0xFF2C2C2C and in dark mode and 0xFFDDDDDD in light mode.

Be aware that once you have enabled the divider by setting it to true that there is not any convenient way to get rid of it. You can set the value to false, but that will just make the divider same color as your current nav bar background color to make it invisible, it is still there.

You can modify the default color of the divider with the optional systemNavigationBarDividerColor. The call to set and use the divider color is only made once a none null value has been given to useDivider. Android does not use any provided alpha value on the color of the divider color and calling it with null again will not remove it. Unless you are working with experimental transparent system navigation bars. If you are, then transparency or alpha channel on the divider also works.

Use and support for the opacity value on the system navigation bar is EXPERIMENTAL, it ONLY works on Android API 30 (=Android 11) or higher. For more information and a complete example of how it can be used, please see: https://github.com/rydmike/sysnavbar

By default themedSystemNavigationBar does not set any system overlay for the status bar. In Flutter SDK the top status bar has its own built in SystemUiOverlayStyle as a part of AppBar and AppBarTheme. FlexColorScheme also manages the SystemUiOverlayStyle for the status bar via it. However, if your screen has no AppBar you can use the property noAppBar and invertStatusIcons to affect the look of the status icons when there is no AppBar present on the page, this is useful e.g. for splash and intro screens.

Implementation

static SystemUiOverlayStyle themedSystemNavigationBar(
  BuildContext? context, {

  /// Use a divider line on the top edge of the system navigation bar.
  ///
  /// Defaults to null. Keeping it null, by omission or passing null, always
  /// omits the call to set any divider color in the created
  /// [SystemUiOverlayStyle].
  ///
  /// The divider on the navigation bar, is only respected on Android P
  /// (= Pie = API 28 = Android 9) or higher.
  bool? useDivider,

  /// Opacity value for the system navigation bar.
  ///
  /// The opacity value is applied to the provided `systemNavigationBarColor`
  /// or if is null, to the color determined by `systemNavBarStyle`.
  ///
  /// Defaults to 1, fully opaque.
  ///
  /// Use and support for this opacity value is EXPERIMENTAL, it ONLY
  /// works on Android API 30 (=Android 11) or higher. For more information
  /// and complete example of how it can be used, please see:
  /// https://github.com/rydmike/sysnavbar
  double opacity = 1,

  /// Set this to true if you do not use a Material AppBar and want
  /// a uniform background where the status bar's icon region is.
  ///
  /// This would typically be true on pages like splash screens and intro
  /// screens that don't use an AppBar. The Material AppBar uses its own
  /// `SystemUiOverlayStyle` so don't use this with an AppBar, set the style
  /// on the AppBar theme instead. However, if you don't have an [AppBar] this
  /// is a convenient way of to remove the system icons scrim for a more
  /// clean look on Android.
  bool noAppBar = false,

  /// Set to true to invert top status bar icons like, battery, network,
  /// wifi icons etc. in relation to their normal theme brightness related
  /// color.
  ///
  /// Defaults to false.
  ///
  /// This setting works well together with the `noAppBar` flag to make an
  /// even cleaner looking splash screen by making the
  /// top status bar icons less visible or even invisible.
  ///
  /// On a white background the status icons will be invisible, and if a
  /// fully black background is used in dark mode, they will be invisible
  /// in dark mode too. This can be used to create clean screen with no
  /// app bar and no status icons.
  ///
  /// For no status bar and and system navigation bar, you can also try using:
  /// `SystemChrome.setEnabledSystemUIOverlays(<SystemUiOverlay>[]);` to
  /// remove the top status bar and bottom navigation bar completely. When
  /// using that method there are however issues with them showing up again
  /// on navigation and when keyboard becomes visible, or app is restored
  /// from being in the background while using another app. You
  /// also have to manage putting the overlays back yourself manually with
  /// `SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values)` when
  /// moving away from the screen that had removed them. Using an
  /// `AnnotatedRegion` with `themedSystemNavigationBar` and both `noAppBar`
  /// and `invertStatusIcons` set to true, you can avoid these issues. You are
  /// however limited to using background white, in light mode and black in
  /// dark mode, if you want the status bar to be totally invisible and
  /// navigation bar to blend in with the background completely.
  bool invertStatusIcons = false,

  /// The [FlexSystemNavBarStyle] used to determine the background color
  /// for the system navigation bar. Used when systemNavigationBarColor
  /// is null and context is not null, so theme colors corresponding to it
  /// can be used for the background color.
  ///
  /// Defaults to [FlexSystemNavBarStyle.background].
  FlexSystemNavBarStyle systemNavBarStyle = FlexSystemNavBarStyle.background,

  /// Background color of the system navigation bar. If null the theme of
  /// context `colorScheme.background` will be used as background color.
  ///
  /// The point with this static helper is to give you a background color
  /// themed system navigation bar automatically. If you for some reason
  /// want a different color you can still override it this property.
  ///
  /// If `context` is null, `nullContextBrightness` will be used as brightness
  /// value and it will determine if the background is white (for
  /// Brightness.light) or black (for Brightness.dark) if this property is
  /// also null. The null context is mostly used for simple unit testing
  /// with no context, but can also be used to make a `SystemUiOverlayStyle`
  /// with this helper without having a context.
  Color? systemNavigationBarColor,

  /// Optional color for the system navigation bar divider. A divider will
  /// only be present if `useDivider` is true and in this color if a
  /// value was given to it.
  ///
  /// If a color is not given the `Color(0xFF2C2C2C)` will be used in
  /// dark mode and the color `Color(0xFFDDDDDD)` will be used in light mode,
  /// as the divider color for the system navigation bar.
  ///
  /// The divider on the navigation bar, is only respected on Android P
  /// (= Pie = API 28 = Android 9) or higher.
  Color? systemNavigationBarDividerColor,

  /// Brightness used if context is null, mostly used for simple unit testing,
  /// with no context present. However, it can also be used to make a
  /// `SystemUiOverlayStyle` without having a context.
  ///
  /// Defaults to Brightness.light.
  Brightness nullContextBrightness = Brightness.light,

  /// Deprecated property, use systemNavigationBarColor instead.
  @Deprecated('This property is deprecated use systemNavigationBarColor '
      'instead. Deprecated in v2.0.0.')
      Color? nullContextBackground,
}) {
  // Opacity validity checks and enforcement, we ignore the parameter
  // re-assignment lint rule.
  // ignore: parameter_assignments
  if (opacity < 0) opacity = 0;
  // ignore: parameter_assignments
  if (opacity > 1) opacity = 1;

  // If systemNavigationBarColor is null, we assign nullContextBackground
  // to it, that may also be null. This is done for backwards compatibility.
  systemNavigationBarColor ??= nullContextBackground;

  // If the systemNavBarStyle is FlexSystemNavBarStyle.transparent we will
  // override opacity to 0.01.
  if (systemNavBarStyle == FlexSystemNavBarStyle.transparent) {
    opacity = 0.01; // ignore: parameter_assignments
  }
  // If context was null, use nullContextBrightness as brightness value.
  final bool isDark = context != null
      ? Theme.of(context).brightness == Brightness.dark
      : nullContextBrightness == Brightness.dark;

  // Get the defined effective background color for the used style.
  final Color _flexBackground = (context != null)
      ? systemNavBarStyle == FlexSystemNavBarStyle.system
          ? (isDark ? Colors.black : Colors.white)
          : systemNavBarStyle == FlexSystemNavBarStyle.background
              ? Theme.of(context).colorScheme.background
              : systemNavBarStyle == FlexSystemNavBarStyle.surface
                  ? Theme.of(context).colorScheme.surface
                  : systemNavBarStyle ==
                          FlexSystemNavBarStyle.scaffoldBackground
                      ? Theme.of(context).scaffoldBackgroundColor
                      : Theme.of(context).scaffoldBackgroundColor
      : (isDark ? Colors.black : Colors.white);

  // If a systemNavigationBarColor color is given, it will always be used,
  // If it is not given, we use above _flexBackground.
  final Color background = systemNavigationBarColor ?? _flexBackground;

  // A divider will be applied if `useDivider` is true and it will
  // use provided `systemNavigationBarDividerColor` if a value was given
  // or fallback to suitable theme mode default divider colors if no
  // color was given.
  //
  // The used default system navigation bar divider colors below were tuned
  // to fit well with most color schemes and possible surface branding.
  // Using the theme divider color does not work, as Android system calls do
  // not use the alpha channel value in the passed color. Default divider
  // theme color uses alpha, using it here does not look good at all as the
  // alpha channel value is not used. If you are working with enabled
  // transparent system navigation bar on Android API 30 or higher, then
  // opacity on the divider also works as expected.
  //
  // The logic below is intended to keep the `dividerColor` used in the
  // [SystemUiOverlayStyle] as null as long as `useDivider` is null. As soon
  // as it is not, it will set a Divider color, also with `false` value. With
  // false it will be set to resulting background color in order to hide the
  // divider by making it background colored. This is a way to remove
  // the divider if it has been enabled earlier, since you cannot remove it
  // with a null color value after it has been enabled with any known
  // `SystemUiOverlayStyle` and `SystemChrome` call. The false value then
  // provide means to at least hide it again, but it will still be there.
  //
  // Worth noticing is also the the opacity does not really have any effect on
  // divider color in most versions of Android. We apply it here anyway
  // because if you are experimenting with transparent system navigation bar
  // on Android API30 or higher it does work. It would be nice if it worked
  // on lower version and without adjusting the Android embedder, then we
  // could use Flutter default Divider theme color as its color.
  Color? dividerColor;

  if (useDivider == null) {
    // The dividerColor is already null from declaration above with no value,
    // but being explicit that in this case this is the case where we want a
    // null color value for the divider as well in order to not include it
    // in the `SystemUiOverlayStyle`.
    dividerColor = null;
  } else if (useDivider && systemNavigationBarDividerColor == null) {
    // We should have a divider, but have no given color, use defaults.
    dividerColor = isDark
        ? const Color(0xFF2C2C2C).withOpacity(opacity)
        : const Color(0xFFDDDDDD).withOpacity(opacity);
  } else if (useDivider && systemNavigationBarDividerColor != null) {
    // We should have a divider, with a given color.
    dividerColor = systemNavigationBarDividerColor.withOpacity(opacity);
  } else {
    // If this is reached, then useDivider is false and we must define its
    // color to whatever color the background is, in order to hide it as well
    // as possible.
    dividerColor = background.withOpacity(opacity);
  }
  return SystemUiOverlayStyle(
    // The top status bar settings.
    // If no params are set that indicates we on purpose want to adjust it
    // because there is no `AppBar`, we must pass null to avoid changing any
    // of its values controlled by the `AppBar` and its theme.
    statusBarColor: noAppBar ? Colors.transparent : null,
    statusBarBrightness:
        noAppBar ? (isDark ? Brightness.dark : Brightness.light) : null,
    statusBarIconBrightness: noAppBar
        ? invertStatusIcons
            ? (isDark ? Brightness.dark : Brightness.light)
            : (isDark ? Brightness.light : Brightness.dark)
        : null,
    // The bottom navigation bar settings.
    systemNavigationBarColor: background.withOpacity(opacity),
    systemNavigationBarDividerColor: dividerColor,
    systemNavigationBarIconBrightness:
        isDark ? Brightness.light : Brightness.dark,
  );
}