42

I'm trying to change the color of the system status bar to black. The configuration seems to be overridden by the AppBar class. I can achieve what I want by assigning the theme: to ThemeData.dark() when creating the Material App, and then specifying an appBar attribute. But I don't want an AppBar, and also, doing it this way changes all the font colors.

A possible solution is to inherit ThemeData.bright() into a new class, then add something that only changes the system status bar through

setSystemUIOverlayStyle

And then I would need to specify AppBar and make it invisible somehow?

Documentation

main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:english_words/english_words.dart';
import 'layout_widgets.dart' as layout_widgets;

class RandomWords extends StatefulWidget {
  @override
  createState() => new RandomWordsState();
}
class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = new Set<WordPair>();
  final _biggerFont = const TextStyle(fontSize: 18.0);

  void _pushSaved() {
     Navigator.of(context).push(
       new MaterialPageRoute(
           builder: (context) {
             final tiles = _saved.map((pair) {
               return new ListTile(
                 title: new Text(pair.asPascalCase,style:_biggerFont)
               );
              }
             );
             final divided = ListTile.divideTiles(
               context:context,
                 tiles: tiles,).toList();
             return new Scaffold(
               appBar: new AppBar(
                 title: new Text('Saved Suggestions'),
               ),
               body: new ListView(children:divided),
             );
           }
       )
     );
  }

  Widget _buildSuggestions() {
    return new ListView.builder(
      padding: const EdgeInsets.all(16.0),
      // The item builder callback is called once per suggested word pairing,
      // and places each suggestion into a ListTile row.
      // For even rows, the function adds a ListTile row for the word pairing.
      // For odd rows, the function adds a Divider widget to visually
      // separate the entries. Note that the divider may be difficult
      // to see on smaller devices.
      itemBuilder: (context, i) {
        // Add a one-pixel-high divider widget before each row in theListView.
        if (i.isOdd) return new Divider();
        // The syntax "i ~/ 2" divides i by 2 and returns an integer result.
        // For example: 1, 2, 3, 4, 5 becomes 0, 1, 1, 2, 2.
        // This calculates the actual number of word pairings in the ListView,
        // minus the divider widgets.
        final index = i ~/ 2;
        // If you've reached the end of the available word pairings...
        if (index >= _suggestions.length) {
          // ...then generate 10 more and add them to the suggestions list.
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      }
    );
  }

  Widget _buildRow(WordPair pair) {
    final alreadySaved = _saved.contains(pair);
    return new ListTile(
      title: new Text(
          pair.asPascalCase,
        style: _biggerFont,
      ),
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }


  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        actions: <Widget>[
          new IconButton(icon:new Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(),
    );
  }

}


void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Column buildButtonColumn(IconData icon, String label) {
      Color color = Theme.of(context).primaryColor;
      return new Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          new Icon(icon, color: color),
          new Container(
            margin: const EdgeInsets.only(top:8.0),
            child: new Text(
              label,
              style: new TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: color,
              )
            ),
          )
        ],

      );
    }
    Widget titleSection = layout_widgets.titleSection;
    Widget buttonSection = new Container(
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          buildButtonColumn(Icons.contact_mail, "CONTACT"),
          buildButtonColumn(Icons.folder_special, "PORTFOLIO"),
          buildButtonColumn(Icons.picture_as_pdf, "BROCHURE"),
          buildButtonColumn(Icons.share, "SHARE"),
        ],
      )
    );
    Widget textSection = new Container(
      padding: const EdgeInsets.all(32.0),
      child: new Text(
        '''
The most awesome apps done here.
        ''',
        softWrap: true,
      ),
    );
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
    return new MaterialApp(
      title: 'Startup Name Generator',
//      theme: new ThemeData(
//          brightness: Brightness.dark,
//          primarySwatch: Colors.blue,
//      ),
//      theme: new ThemeData(),
      debugShowCheckedModeBanner: false,

      home: new Scaffold(
//        appBar: new AppBar(
////          title: new Text('Top Lakes'),
////          brightness: Brightness.light,
//        ),
//        backgroundColor: Colors.white,
        body: new ListView(
          children: [
            new Padding(
              padding: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 0.0),
              child: new Image.asset(
                  'images/lacoder-logo.png',
                  width: 600.0,
                  height: 240.0,
                  fit: BoxFit.fitHeight,

              ),
            ),

            titleSection,
            buttonSection,
            textSection,
          ],
        ),
      ),
    );
  }
}

layout_widgets.dart

import 'package:flutter/material.dart';

Widget titleSection = new Container(
    padding: const EdgeInsets.all(32.0),
    child: new Row(children: [
      new Expanded(
          child: new Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          new Container(
              padding: const EdgeInsets.only(bottom: 8.0),
              child: new Text(
                "Some-Website.com",
                style: new TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              )
          ),
          new Text(
            'Small details',
            style: new TextStyle(
              color: Colors.grey[500],
            )
          )
        ],
      )),
      new Icon(Icons.star,color: Colors.orange[700]),
      new Text('100'),
    ]));
8oh8
  • 1,247
  • 5
  • 19
  • 35
  • You are saying that you don't want an appbar, but your code clearly contains one. What do you mean when saying you don't want one? – areiser Apr 14 '18 at 17:36
  • I am saying I don't want an app bar, but that is not important. What I am trying to do is have a dark system status bar, that is all. My code has app bar because I was experimenting and trying different things. – 8oh8 Apr 15 '18 at 07:07
  • Does this answer your question? [Flutter - How to set status bar color when AppBar not present](https://stackoverflow.com/questions/50501799/flutter-how-to-set-status-bar-color-when-appbar-not-present) – Hannes Tiltmann Dec 31 '19 at 13:20
  • https://stackoverflow.com/a/59949734/8555008 hey check this out – naman kashyap May 21 '21 at 06:54

10 Answers10

31

I tried the method SystemChrome.setSystemUIOverlayStyle(), as far as I tested (Flutter SDK v1.9.1+hotfix.2, running on iOS 12.1) it works perfect for Android. But for iOS, e.g. if your first screen FirstScreen() doesn't have an AppBar, but the second SecondScreen() does, then at launch the method does set the color in FirstScreen(). However, after navigating back to FirstScreen() from SecondScreen(), the status bar color becomes transparent.

I come up with a hacky workaround by setting an AppBar() with zero height, then status bar's color gets changed by the AppBar, but the AppBar itself is not visible. Hope it would be useful to someone.

// FirstScreen that doesn't need an AppBar
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: PreferredSize(
        preferredSize: Size.fromHeight(0),
        child: AppBar( // Here we create one to set status bar color
          backgroundColor: Colors.black, // Set any color of status bar you want; or it defaults to your theme's primary color
        )
      )
  );
}

// SecondScreen that does have an AppBar
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar()
  }
}

Here is the screenshot of FirstScreen in iPhone Xs Max iOS 12.1:

enter image description here

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Ludy Su
  • 511
  • 5
  • 6
  • I'm not doing Android development anymore so I can't really test this out but if you post a screenshot I can choose yours as right answer. – 8oh8 Sep 24 '19 at 04:33
  • Hi @8oh8 screenshot uploaded. Cheers – Ludy Su Sep 24 '19 at 22:52
  • What about for Android though? that's the platform we were targeting. Aren't system bars black on iOS by default? – 8oh8 Oct 16 '19 at 05:48
  • I tested on both platforms using my own theme color which is blue, they work the same. No, iOS status bar is transparent by default. – Ludy Su Oct 17 '19 at 03:25
  • what if the statusbar color and appbar color are different? – Nabin Dhakal Mar 13 '20 at 05:36
  • 1
    @Nbn Achievable in another hacky way. You can set a `Container` with another color background as the AppBar's `actions`. But you need to take care of the layout of your buttons/titles inside the container: ```dart appBar: AppBar( backgroundColor: Colors.black, actions: [ Container( width: MediaQuery.of(context).size.width, color: Colors.blue, ),],), ``` – Ludy Su Mar 31 '20 at 01:23
  • This should not even be allowed. There is a normal way to achieve this – Dennis Barzanoff May 26 '21 at 09:17
29

UPDATE:

Scaffold(
  appBar: AppBar(
    systemOverlayStyle: SystemUiOverlayStyle(
      systemNavigationBarColor: Colors.blue, // Navigation bar
      statusBarColor: Colors.pink, // Status bar
    ),
  ),
)

Old solution (still works)

Both iOS and Android:

appBar: AppBar(
  backgroundColor: Colors.red, // status bar and navigation bar color
  brightness: Brightness.light, // status bar brightness
)

Only for Android (More flexibility)

You can use SystemChrome class to change Status bar and Navigation bar color. First import

import 'package:flutter/services.dart';

After this, you need to add following lines (better place to put these lines is in your main() method)

void main() {
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
    systemNavigationBarColor: Colors.blue,
    statusBarColor: Colors.pink,
  ));
}

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
  • This answer is a good one if you want to set whole app wise color for status bar and navigation bar. For appropriate screen you just have to write few lines of code to show and hide UI component like statusbar. – Purvik Rana Aug 20 '20 at 06:33
  • Setting `systemNavigationBarColor` via AppBarTheme doesn't work – Jeremi Nov 26 '21 at 21:36
  • @Jeremi Which is why I've provided `SystemChrome.setSystemUIOverlayStyle` solution too. – CopsOnRoad Nov 29 '21 at 17:37
14

If you don't want AppBar at all, then you can just call setSystemUIOverlayStyle in the main function:

void main() async {
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

  runApp(new MaterialApp(
    home: new Scaffold(),
  ));
}

It's more tricky if you have an app bar in one scaffold, and none in another. In that case I had to call setSystemUIOverlayStyle after pushing new route with a scaffold that does not have an appbar:

@override
Widget build(BuildContext context) {
  final page = ModalRoute.of(context);
  page.didPush().then((x) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
  });

  return new Scaffold();
}
szotp
  • 2,472
  • 1
  • 18
  • 21
  • 1
    I want the system bar to be black. So this does not work. – 8oh8 Apr 02 '18 at 08:52
  • 1
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark ); – Raouf Rahiche Apr 02 '18 at 12:49
  • This does not work because it changes the colors of everything else in the app. – 8oh8 Apr 04 '18 at 16:53
  • Colors of what? I don't think it affects anything else besides the status bar. – szotp Apr 05 '18 at 07:19
  • Ok sorry, I thought you were refering to using Theme.dark. I tried the SystemUiOverlay.dark and it doesn't seem to work. I added my code to the question. I also tried using that main() with 'async' keyword. No result. – 8oh8 Apr 10 '18 at 01:15
  • Somehow using the second method above (the `ModalRoute` one) causes the keyboard to disappear (or unable to appear). Any idea why? – Giraldi Nov 12 '18 at 10:50
  • SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( statusBarColor: Color(0xffdad8d9), statusBarIconBrightness: Brightness.dark, )); – Srneczek Aug 18 '19 at 09:41
  • This does NOT work when you also use `Navigator`. Use `AnnotatedRegion` instead – Dennis Barzanoff May 26 '21 at 11:34
5

TLDR; you need to use Scaffold, it manages the colors even if you navigate back and forth.

Scaffold(
    appBar: AppBar(brightness: Brightness.dark), \\ dark content -> white app bar
    body: ...
);

If your screen does not have an app bar, then you need to use AnnotatedRegion with scaffold in order to achieve the same effect.

AnnotatedRegion(
    value: SystemUiOverlayStyle.light, // this will make the app bar white
    child: Scaffold(
          body: 
    ),
);

Instead of SystemUiOverlayStyle.light, you can customize it:

SystemUiOverlayStyle(
  statusBarBrightness: Brightness.light, 
  systemNavigationBarDividerColor: Colors.blue,
  ...
);
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Dennis Barzanoff
  • 363
  • 10
  • 16
3

i have achieved that way

  @override
void initState() {
  super.initState();
  // Transparent status bar
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: Colors.transparent,));
}

you can also see different properties after comma

SystemUiOverlayStyle(statusBarColor: Colors.transparent,)

just use combination of ctrl + space after comma and you will get what you can use.

enter image description here

eko
  • 532
  • 1
  • 5
  • 12
2

I'm quite new to StackOverflow & I've never used Flutter however I have found this package that seems to make things relatively easy.

Method 1: Using the package

Once this is imported all you need to do is add this code fragment:

try {
await FlutterStatusbarcolor.setStatusBarColor(Colors.black);
} on PlatformException catch (e) {
print(e);
}

Replacing the parameter for the setStatusBarColor() should give you the desired result, a full list of colours can be found here.

Method 2: Using default functions

If this doesn't work / you don't want to add extra packages or libraries then perhaps this StackOverflow answer may help.

It involves using a similar function to the above method: getWindow().setStatusBarColor() or getActivity().getWindow().setStatusBarColor()

Replacing the parameter with the desired hex code from the same list as earlier may also result in a solution.

Hope it works/helps!

Loz
  • 41
  • 6
1

Please read this flutter package. To set status bar text as black, you can set FlutterStatusbarcolor.setStatusBarWhiteForeground(false). you need to have this line of code in didChangeAppLifecycleState method with resume state so that when you go to other application and come back, the status bar text color are set to your initial setup.

Also, you need to set the your AppBar's TextTheme. like following.

Widget build(BuildContext context) {
FlutterStatusbarcolor.setStatusBarWhiteForeground(false);
return MaterialApp(
    title:// title goes here
    theme:// your theme goes here
    home:   Scaffold(
      appBar: AppBar(
                      backgroundColor: Colors.white,
                      title: _loadAppBarTitle(),
                      textTheme: Theme.of(context).textTheme),
      body: //body's goes here
  );
);

Hopefully, this one can help somebody who has the similar problem with me.

1

Flutter 2.5.1

'brightness' is deprecated and shouldn't be used. This property is no longer used, please use systemOverlayStyle instead. This feature was deprecated after v2.4.0-0.0.pre.. Try replacing the use of the deprecated member with the replacement.

Old code

brightness: Brightness.dark,

New code

systemOverlayStyle: SystemUiOverlayStyle(
 systemNavigationBarColor: Colors.blue, // Navigation bar
 statusBarColor: Colors.red, // Status bar
),
Vivek
  • 4,916
  • 35
  • 40
  • i am getting this error -> The named parameter 'systemOverlayStyle' isn't defined. Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'systemOverlayStyle'. – Roopak Sep 24 '21 at 17:30
  • Please check your flutter version. – Vivek Oct 06 '21 at 04:32
1

Just write this code inside the AppBar

Scaffold(
          drawer: const SideBar(),
          appBar: AppBar(
            title: const Text("SomeThing"),
            systemOverlayStyle: SystemUiOverlayStyle.dark,//this is what you wanted
          ),
          body: YourWidget()
sarbador_
  • 11
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 23 '22 at 01:23
0

For some reason, it didn't work for me when I put my AppBar directly in my Scaffold, so I added it like this :

Scaffold(
  extendBodyBehindAppBar: true,
  body: Stack (
    children: [
      AppBar(
        automaticallyImplyLeading: false,
        backgroundColor: Colors.transparent,
        systemOverlayStyle: SystemUiOverlayStyle.light,
      ),
      // ... other widgets
    ],
  ),
)

And it changed the color of both my status bar and navigation bar (background of home indicator in Android)

Jack'
  • 1,722
  • 1
  • 19
  • 27