How to change status bar text color in Flutter

⋅ 7 min read ⋅ Flutter

Table of Contents

App-wide

If you want to change a status bar text color across your app, a theme is always the right choice for this kind of task. To do that, set brightness property in AppBarTheme to either Brightness.dark or Brightness.light.

Brightness (Obsolete)

class StatusBarApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: AppBarTheme(
brightness: Brightness.dark,
),
),
home: StatusBarPage(),
debugShowCheckedModeBanner: false,
);
}
}
  • Brightness.dark means app bar color is dark and will require a light text color to achieve readable contrast.
  • Brightness.light means app bar color is light and will require a dark text color to achieve readable contrast.
Left: Brightness.light app bar, Right Brightness.dark app bar.
Left: Brightness.light app bar, Right Brightness.dark app bar.
Left: Brightness.light app bar, Right Brightness.dark app bar.
Left: Brightness.light app bar, Right Brightness.dark app bar.

But this brightness property is obsolete, and Flutter recommended we use systemOverlayStyle instead.

SystemOverlayStyle

To use systemOverlayStyle, we need to also set backwardsCompatibility to false so the system knows which property to use (brightness and systemOverlayStyle).

class StatusBarApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: AppBarTheme(
backwardsCompatibility: false, // 1
systemOverlayStyle: SystemUiOverlayStyle.light, // 2
),
),
home: StatusBarPage(),
debugShowCheckedModeBanner: false,
);
}
}

<1> Set backwardsCompatibility to false to tell the system that we are going to use systemOverlayStyle not brightness.
<2> Use systemOverlayStyle to control status bar text color.

One thing to note here is that SystemUiOverlayStyle.dark/light refers to the text, not that app bar color like what Brightness.dark/light did. So the result might be the reverse of what you thought.

  • SystemUiOverlayStyle.dark means System overlays text should be drawn with a dark color. Intended for applications with a light background.
  • SystemUiOverlayStyle.light means System overlays text should be drawn with a light color. Intended for applications with a dark background.

This is more align with what iOS have UIStatusBarStyle.darkContent and UIStatusBarStyle.lightContent.

Left: SystemUiOverlayStyle.dark, Right SystemUiOverlayStyle.light.
Left: SystemUiOverlayStyle.dark, Right SystemUiOverlayStyle.light.
Left: SystemUiOverlayStyle.dark, Right SystemUiOverlayStyle.light.
Left: SystemUiOverlayStyle.dark, Right SystemUiOverlayStyle.light.

Specific View with an AppBar

If you want to change a status bar text color for a specific view (with an app bar), you can use the exact property we employ in the theme, but this time set it to the AppBar.

class StatuBarsPage extends StatelessWidget {

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Flutter Demo',
),
// brightness: Brightness.light,
systemOverlayStyle: SystemUiOverlayStyle.dark, // 1
),
body: ...
);
}
}

<1> Set brightness or systemOverlayStyle to the AppBar. We don't need backwardsCompatibility here since it will inherit from the theme.

Dynamically change the status bar text color

If you need to change the status bar text color dynamically, e.g., when you want it to change based on the scrollable content or some condition, you can extract systemOverlayStyle to variable and change it with setState.

class StatusBarPage extends StatefulWidget {

_StatusBarPageState createState() => _StatusBarPageState();
}

class _StatusBarPageState extends State<StatusBarPage> {
var overlayStyle = SystemUiOverlayStyle.light; // 1


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Flutter Demo',
),
systemOverlayStyle: overlayStyle, // 2
),
body: Center(
child: Center(
child: ElevatedButton(
child: Text('Toggle'),
onPressed: () {
setState(() { // 3
if (overlayStyle == SystemUiOverlayStyle.light) {
overlayStyle = SystemUiOverlayStyle.dark;
} else {
overlayStyle = SystemUiOverlayStyle.light;
}
});
},
),
),
),
);
}
}

<1> Declare variable for SystemUiOverlayStyle.
<2> Use this variable for app bar.
<3> Change it with setState whene needed.

Specific View without an AppBar

SystemUiOverlayStyle

If your page doesn't have an app bar, you can set a status bar text color with setSystemUIOverlayStyle method. To do that call SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light) anywhere in your build method.


Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light); // 1
return const Placeholder();
}

<1> Call SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light) in your build method.

Dynamically change the status bar text color

If you use setSystemUIOverlayStyle to control your status bar text color, you can easily change your style by calling SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light) again. No variable or set state needed.

class StatusBarPage extends StatelessWidget {

Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light); // 1

return Center(
child: ElevatedButton(
child: Text('Toggle'),
onPressed: () {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark); // 2
},
),
);
}
}

<1> Start with white status bar text color.
<2> Tap the button will change it to black.

Specific View without an AppBar (Advanced)

Suppose you want to create a custom widget with the ability to control status bar text color (just like app bar). In that case, the AnnotatedRegion widget is more appropriate than calling setSystemUIOverlayStyle directly.

AnnotatedRegion

If the annotated region widget is found under that status and navigation bar (top area of the app), its value will be used to configure the system styles.

Here is fake app bar I created using AnnotatedRegion. It is a simple pink bar with a white status bar text color.

class FakeAppBar extends StatelessWidget {

Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
height: 100,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.pink,
),
),
);
}
}

Place this AnnotatedRegion widget around the top area, and the system will configure the system styles based on its value.

class StatusBarApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: AppBarTheme(
backwardsCompatibility: false,
systemOverlayStyle: SystemUiOverlayStyle.light,
),
),
home: Column(
children: [
FakeAppBar(), // 1
SizedBox(
height: 100,
),
],
),
debugShowCheckedModeBanner: false,
);
}
}

<1> Put it at the very top.

Status bar text color change according to our FakeAppBar.
Status bar text color change according to our FakeAppBar.

If the AnnotatedRegion widget isn't placed around the top area, the value won't be used. This makes perfect sense since the widget color won't interfere with the status bar, so it shouldn't affect the status bar style.

class StatusBarApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: AppBarTheme(
backwardsCompatibility: false,
systemOverlayStyle: SystemUiOverlayStyle.light,
),
),
home: Column(
children: [
SizedBox( // 1
height: 100,
),
FakeAppBar(),
],
),
debugShowCheckedModeBanner: false,
);
}
}

<1> Put SizedBox above FakeAppBar push our widget away from the status bar area make it no longer affect the status bar style.

FakeAppBar won't have an effect on the status bar style if it doesn't sit at the top part of the screen.
FakeAppBar won't have an effect on the status bar style if it doesn't sit at the top part of the screen.

Dynamically change the status bar text color

You can change style dynamically just like an app bar with variable and setState because internally, AppBar also uses AnnotatedRegion. I won't repeat the process here. You can look in the Local AppBar section.

The following is a part of AppBar implementation taken from the source code.


Widget build(BuildContext context) {

....

return Semantics(
container: true,
child: AnnotatedRegion<SystemUiOverlayStyle>( // 1
value: overlayStyle,
child: Material(
color: backgroundColor,
elevation: widget.elevation
?? appBarTheme.elevation
?? _defaultElevation,
shadowColor: widget.shadowColor
?? appBarTheme.shadowColor
?? _defaultShadowColor,
shape: widget.shape,
child: Semantics(
explicitChildNodes: true,
child: appBar,
),
),
),
);
}

<1> AppBar use AnnotatedRegion internally.


Read more article about Flutter or see all available topic

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Tweet Share
Previous
How to change a back button color in Flutter

Learn different ways to change the back button color in Flutter.

Next
Pull to refresh in SwiftUI with refreshable

SwiftUI got a native way to add UIRefreshControl in iOS 15. Let's find out how to add it in the list view and even your custom view.

← Home