【问题标题】:How to change Status Bar and App Bar color in Flutter?如何在 Flutter 中更改状态栏和应用栏颜色?
【发布时间】:2018-09-01 15:07:42
【问题描述】:

我正在尝试将系统状态栏的颜色更改为黑色。 该配置似乎被 AppBar 类覆盖。我可以通过在创建 Material App 时将主题分配给 ThemeData.dark(),然后指定 appBar attribute 来实现我想要的。但我不想要 AppBar,而且这样做会改变所有字体颜色。

一个可能的解决方案是将 ThemeData.bright() 继承到一个新的类中,然后添加一些只通过改变系统状态栏的东西

setSystemUIOverlayStyle

然后我需要指定 AppBar 并以某种方式使其不可见?

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'),
    ]));

【问题讨论】:

标签: flutter dart flutter-layout statusbar appbar


【解决方案1】:

我尝试了SystemChrome.setSystemUIOverlayStyle() 的方法,据我测试(Flutter SDK v1.9.1+hotfix.2,在 iOS 12.1 上运行),它非常适合 Android。但对于 iOS,例如如果您的第一个屏幕FirstScreen() 没有AppBar,但第二个屏幕SecondScreen() 有,那么在启动时该方法会在FirstScreen() 中设置颜色。但是,从SecondScreen() 导航回FirstScreen() 后,状态栏颜色变为透明。

我想出了一个 hacky 解决方法,将AppBar() 设置为零高度,然后状态栏的颜色被 AppBar 更改,但 AppBar 本身不可见。希望它对某人有用。

// 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()
  }
}

这是FirstScreen在iPhone Xs Max iOS 12.1中的截图:

【讨论】:

  • 我不再做 Android 开发了,所以我无法真正测试这一点,但如果您发布屏幕截图,我可以选择您的作为正确答案。
  • 嗨@8oh8 截图已上传。干杯
  • 那么 Android 呢?这就是我们的目标平台。默认情况下iOS系统栏不是黑色的吗?
  • 我在两个平台上都使用我自己的主题颜色(蓝色)进行了测试,它们的工作方式相同。不,iOS 状态栏默认是透明的。
  • @Nbn 以另一种 hacky 方式实现。您可以将具有另一种颜色背景的Container 设置为AppBar 的actions。但是您需要注意容器内按钮/标题的布局:dart appBar: AppBar( backgroundColor: Colors.black, actions: &lt;Widget&gt;[ Container( width: MediaQuery.of(context).size.width, color: Colors.blue, ),],),
【解决方案2】:

更新:

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

旧解决方案(仍然有效)

iOS 和 Android:

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

仅适用于 Android(更灵活)

您可以使用SystemChrome 类更改状态栏和导航栏颜色。 首次导入

import 'package:flutter/services.dart';

在此之后,您需要添加以下行(放置这些行的更好位置是在您的 main() 方法中)

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

【讨论】:

  • 如果您想为状态栏和导航栏设置整个应用程序明智的颜色,这个答案是一个很好的答案。对于合适的屏幕,您只需编写几行代码即可显示和隐藏 UI 组件,如状态栏。
  • 通过 AppBarTheme 设置 systemNavigationBarColor 不起作用
  • @Jeremi 这就是为什么我也提供了SystemChrome.setSystemUIOverlayStyle 解决方案。
【解决方案3】:

如果你根本不需要 AppBar,那么你可以在主函数中调用setSystemUIOverlayStyle

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

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

如果您在一个脚手架中有一个应用栏,而在另一个脚手架中没有,那就更棘手了。在那种情况下,我必须在使用没有 appbar 的脚手架推送新路线后致电 setSystemUIOverlayStyle

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

  return new Scaffold();
}

【讨论】:

  • 我希望系统栏是黑色的。所以这行不通。
  • SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
  • 这不起作用,因为它会改变应用程序中其他所有内容的颜色。
  • 什么颜色?除了状态栏,我认为它不会影响其他任何东西。
  • 好吧抱歉,我以为你指的是使用 Theme.dark。我尝试了 SystemUiOverlay.dark,但它似乎不起作用。我将我的代码添加到问题中。我还尝试使用带有 'async' 关键字的 main()。没有结果。
【解决方案4】:

我对 StackOverflow 很陌生,而且我从未使用过 Flutter,但我发现 this 包似乎让事情变得相对容易。

方法一:使用包

导入后,您只需添加以下代码片段:

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

替换setStatusBarColor() 的参数应该会给你想要的结果,完整的颜色列表可以在here 找到。

方法二:使用默认函数

如果这不起作用/您不想添加额外的包或库,那么this StackOverflow 的答案可能会有所帮助。

它涉及到使用与上述方法类似的功能:getWindow().setStatusBarColor()getActivity().getWindow().setStatusBarColor()

将参数替换为所需的十六进制代码from the same list as earlier 也可能会产生解决方案。

希望它有效/有帮助!

【讨论】:

    【解决方案5】:

    我已经做到了

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

    逗号后面也可以看到不同的属性

    SystemUiOverlayStyle(statusBarColor: Colors.transparent,)
    

    只需在逗号后使用 ctrl + 空格的组合,你就会得到你可以使用的。

    【讨论】:

      【解决方案6】:

      请阅读此flutter package。要将状态栏文本设置为黑色,您可以设置FlutterStatusbarcolor.setStatusBarWhiteForeground(false)。您需要在 didChangeAppLifecycleState 方法中使用 resume state 这行代码,以便当您转到其他应用程序并返回时,状态栏文本颜色设置为您的初始设置。

      另外,您需要设置 AppBar 的 TextTheme。喜欢以下。

      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
        );
      );
      

      希望这个可以帮助和我有类似问题的人。

      【讨论】:

        【解决方案7】:

        TLDR;您需要使用Scaffold,即使您来回导航,它也会管理颜色。

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

        如果你的屏幕没有应用栏,那么你需要使用AnnotatedRegionwith脚手架才能达到同样的效果。

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

        您可以自定义它而不是SystemUiOverlayStyle.light

        SystemUiOverlayStyle(
          statusBarBrightness: Brightness.light, 
          systemNavigationBarDividerColor: Colors.blue,
          ...
        );
        

        【讨论】:

          【解决方案8】:

          颤振 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.

          旧代码

          brightness: Brightness.dark,

          新代码

          systemOverlayStyle: SystemUiOverlayStyle(
           systemNavigationBarColor: Colors.blue, // Navigation bar
           statusBarColor: Colors.red, // Status bar
          ),
          

          【讨论】:

          • 我收到此错误 -> 未定义命名参数“systemOverlayStyle”。尝试将名称更正为现有命名参数的名称,或使用名称“systemOverlayStyle”定义命名参数。
          • 请检查您的颤振版本。
          猜你喜欢
          • 2023-03-05
          • 1970-01-01
          • 2021-02-04
          • 2020-02-04
          • 1970-01-01
          • 2021-07-31
          • 2021-11-05
          • 1970-01-01
          相关资源
          最近更新 更多