在flutter更改单个页面导航栏和状态栏的颜色,push页面或返回恢复

最近更换播放器需求,需要对播放器页面单独设置状态栏和导航栏,而在其他页面恢复之前系统设置的颜色:
1.进入播放页面之前状态栏为(SystemUiOverlayStyle.dark)文字/icon为黑色,背景白色;
2.播放页面背景黑色,自定义状态栏/导航栏背景透明、文字icon为白色(SystemUiOverlayStyle.light);
3.播放器push的新页面或者播放器页面返回到其他页面,恢复之前系统设置的状态栏、导航栏颜色;

一、main.dart 对全局导航栏状态栏的设置

class MyApp extends App {
  final CustomRouteObserver<PageRoute> routeObserver =
      CustomRouteObserver<PageRoute>();

  MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomGetMaterialApp(
      enableLog: false,
      darkTheme: appThemeData,
      debugShowCheckedModeBanner: false,
      onInit: () {
        ///-------默认设置状态栏文字icon为黑色-------
        SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
      },
      title: 'appXXX',
      navigatorKey: appNavigatorKey,
      theme: appThemeData,
      color: primaryColor,
     ///-------默认为浅色模式,app不受系统暗黑模式影响-----
      themeMode: ThemeMode.light,
      builder: bundleBaseAppTransitionBuilder(
          builder: (_, child) =>
              TopBannerWidget(child: AppListenerWidget(child: child!))),
      ///-----路由监听------
      navigatorObservers: [
        BotToastNavigatorObserver(),
        RouteObserverUtil().routeObserver,
        routeObserver
      ],
      initialRoute: PageAddress.MainPage,
      onGenerateRoute: super.onGenerateRoute,
      onUnknownRoute: super.onUnknownRoute,
      unknownRoute: unknownRoute,
      localizationsDelegates: super.localizationsDelegates([
        AppLocalizationDelegate.delegate,
        ///必须:否则播放器页面会报错! 播放器UI国际化
        if (FunctionRegistry.callMaybe('@SuperPlayerWidgetLocals') != null)
          FunctionRegistry.callMaybe('@SuperPlayerWidgetLocals'),
        GlobalWidgetsLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ]),
      supportedLocales: const [
        Locale.fromSubtags(languageCode: 'en'),
        Locale.fromSubtags(languageCode: 'zh'),
      ],
      locale: const Locale('zh', 'CN'),
      getPages: super.initGetPages,
    );
  }


ThemeData appThemeData = ThemeData(
  brightness: Brightness.light,
  platform: TargetPlatform.iOS,
  primarySwatch: primaryColor,
  splashColor: Colors.transparent,
  highlightColor: Colors.transparent,

  /// 用于界面主色 按钮颜色、重要提示、按钮等
  // primaryColor: const Color(0xFF65C5BC),//old
  primaryColor: primaryColor,

  /// 警示色用于文字图标icon等
  errorColor: redColor,

  /// 禁用按钮色
  disabledColor: const Color(0x99D3D3E2),

  /// 少量用于链接色
  // accentColor: Color(0xFF2A7BFF),

  /// 指示器颜色
  indicatorColor: primaryColor,

  /// 按钮水波纹
  // splashColor: Colors.transparent,

  /// 表单输入文字提示的颜色
  hintColor: const Color(0xFFB7BBBF),
  appBarTheme: defAppBarTheme,
  textTheme: const TextTheme(
    /// 大标题,粗体 24
    headline5: TextStyle(
      color: textBigTitleColor,
      fontSize: 24,
      // overflow: TextOverflow.ellipsis,
    ),

    ///标题,粗体 16
    subtitle1: TextStyle(
      color: textTitleColor,
      fontSize: 16,
      // overflow: TextOverflow.ellipsis,
    ),

    /// 次要信息文字,粗体 14
    subtitle2: TextStyle(
      color: textTitleColor,
      fontSize: 15,
      // overflow: TextOverflow.ellipsis,
    ),

    bodyText1: TextStyle(
      color: textTitleColor,
      fontSize: 13,
      // overflow: TextOverflow.ellipsis,
    ),

    bodyText2: TextStyle(
      color: textHelpColor,
      fontSize: 12,
      // overflow: TextOverflow.ellipsis,
    ),
  ),

  /// 文字类
  inputDecorationTheme: const InputDecorationTheme(
    hintStyle: TextStyle(
      color: Color(0xFFB7BBBF), // 表单输入文字提示的颜色
    ),
  ),

  /// 背景色
  scaffoldBackgroundColor: Colors.white,
  // scaffoldBackgroundColor: backgroundColor,
  backgroundColor: Colors.white,

  /// 分割线
  dividerColor: dividerColor,

  // tabBarTheme: TabBarTheme(
  //   unselectedLabelColor: Color(0xFF9F9FB2),
  // ),

  unselectedWidgetColor: const Color(0xFFB7BBBF),

  textButtonTheme: TextButtonThemeData(
      style: TextButton.styleFrom(
    padding: EdgeInsets.zero,
    splashFactory: const NoSplashFactory(),
    backgroundColor: Colors.transparent,
    textStyle: const TextStyle(color: Colors.white, fontSize: 14),
  )),
  elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
    primary: primaryColor,
    splashFactory: const NoSplashFactory(),
    textStyle: const TextStyle(color: Colors.white, fontSize: 16),
  )),
  outlinedButtonTheme: OutlinedButtonThemeData(
      style: OutlinedButton.styleFrom(
    primary: primaryColor,
    splashFactory: const NoSplashFactory(),
    textStyle: const TextStyle(color: primaryColor, fontSize: 14),
  )),
  iconTheme: const IconThemeData(
    color: iconGrayColor,
  ),
  primaryIconTheme: const IconThemeData(
    color: Colors.deepPurpleAccent,
  ),
  dividerTheme: const DividerThemeData(
    thickness: 0.5,
  ),
  bottomSheetTheme: const BottomSheetThemeData(
    backgroundColor: Colors.white,
  ),
  buttonTheme: const ButtonThemeData(),
  toggleableActiveColor: primaryColor[250],
  checkboxTheme: const CheckboxThemeData(
    shape: CircleBorder(),
    side: BorderSide(width: 1.5, color: grayColor),
    splashRadius: 0,
  ),
);

二、播放器页面对导航栏状态栏的修改设置


  @override
  Widget build(BuildContext context) {
    super.build(context);
    SystemUiOverlayStyle value;
    if(Platform.isAndroid){
      value = SystemUiOverlayStyle(
        statusBarColor: Colors.transparent,/// 安卓系统状态栏存在底色,所以需要加这个
        systemNavigationBarColor:  Colors.transparent,
        systemNavigationBarIconBrightness: Brightness.light,
        statusBarIconBrightness: Brightness.light,/// 状态栏字体颜色
        statusBarBrightness: Brightness.light,
      );
    }else{
     ///iOS设置状态栏的正确姿势
      value = SystemUiOverlayStyle.light;
    }
    return WillPopScope(
      onWillPop: () async {
       ///页面返回时,恢复全局设置的系统导航栏颜色
        SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
        _backBtnActionOrPip();
        return true;
      },
      ///重点来了:单独对某个页面设置导航栏需要使用AnnotatedRegion这个小部件-----
      child: AnnotatedRegion<SystemUiOverlayStyle>(
        value: value,
        child: Scaffold(
         ///--------设置页面背景色黑色----------
          backgroundColor: Colors.black,
          body: SafeArea(
            bottom: false,
            child: Stack(
              children: [
                Column(
                  children: [
                        ///三、导航:返回按钮、下载、分享
                        Container(
                          decoration: const BoxDecoration(
                            gradient: LinearGradient(
                                colors: [
                                  Color.fromRGBO(0, 0, 0, 0.2),
                                  Color.fromRGBO(0, 0, 0, 0),
                                ],
                                begin: Alignment.topCenter,
                                end: Alignment.bottomCenter),
                          ),
                          child: AppBar(
                            ///--------设置背景色透明----------
                            backgroundColor: Colors.transparent,
                            leading: BackButton(
                              color: Colors.white,
                              onPressed: _backBtnActionOrPip,
                            ),
                            actions: [],
                        ),
                    ....
             ],
          ....
),

 ///页面返回时,恢复全局设置的系统导航栏颜色
  @override
  void dispose() {
    super.dispose();
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
  }

三、播放器push到其他 页面对导航栏状态栏的恢复设置

思路一:push的页面,对导航栏状态栏的重新设置

总结下来,iOS想设置恢复成原来的状态栏颜色,要设置2步 ;安卓可以不要设置,自动读取全局设置的系统状态栏颜色,请看代码:

 @override
  Widget build(BuildContext context) {
    SystemUiOverlayStyle value;
   ///安卓不设置也会自动取全局系统设置的颜色
    if(Platform.isAndroid){
      value = SystemUiOverlayStyle(
        statusBarColor: Colors.transparent,/// 安卓系统状态栏存在底色,所以需要加这个
        systemNavigationBarColor:  Colors.transparent,
        systemNavigationBarIconBrightness: Brightness.dark,
        statusBarIconBrightness: Brightness.dark,/// 状态栏字体颜色
        statusBarBrightness: Brightness.dark,
      );
    }else{
      ///1.iOS恢复到黑色模式
      value = SystemUiOverlayStyle.dark;
    }
    return Scaffold(
        appBar: AppBar(
            ///2.对当个页面设置状态栏
          systemOverlayStyle: value,
          title: JUIText( '写笔记'),
          actions: [
            JUIButton.themeBackground(
                onPressed: () {
                  ///发布按钮点击事件
                  _publishButtonClick();
                },
                width: 55,
                height: 28,
                title: '发布',
                fontSize: 14,
                 radius: 7,
                isShowOnAppBar: true,
            )
          ],
        ),
        body: SafeArea(
          ...
      )
   )

这个是我对单个页面设置状态栏颜色的踩坑记录,如果老铁有好的解决思路,欢迎留言分享。

思路二:添加路由监听
///添加路由监听
class _LessonDetailPageState extends State<LessonDetailPage>
    with RouteAware {

}
...
 @override
  void didChangeDependencies() {
    RouteObserverUtil()
        .routeObserver
        .subscribe(this, ModalRoute.of(context) as ModalRoute); //订阅
    super.didChangeDependencies();
  }

  @override
  void didPush() {
    super.didPush();
  }

  @override
  void didPop() {
    super.didPop();
  }

  @override
  void didPopNext() {
    super.didPopNext();
  }

  @override
  void didPushNext() {
   ///这里延迟0.1秒执行,是为了确保已经push到其他页面了,当前页面路由已修改,再去修改导航栏状态栏,否则可能会被覆盖
    Future.delayed(const Duration(milliseconds: 100)).then((value) {
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
    });
    super.didPushNext();
  }

  ///页面释放,恢复之前系统的导航栏黑色设置
  @override
  void dispose() {
    super.dispose();
    RouteObserverUtil().routeObserver.unsubscribe(this);
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
}


 @override
  Widget build(BuildContext context) {
    super.build(context);
    return WillPopScope(
      onWillPop: () async {
        SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
        return true;
      },
      ///状态栏小工具设置状态栏为白色
      child: StatusBarChangeWidget(
        isDark: false,
        child: Scaffold(
          backgroundColor: Colors.black,
          body: SafeArea(
           ...
          )
       )
    )
}

封装了一个小工具类,需要的小伙伴可以直接拿去用:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class StatusBarChangeWidget extends StatelessWidget {
  final Widget child;
  final bool isDark;

  const StatusBarChangeWidget({
    Key? key,
    required this.child,
    this.isDark = false,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: getSystemUiOverlayStyle(isDark: isDark),
      child: child,
    );
  }
}

///状态栏颜色设置,此方法抽出来了,全项目可以直接调用
getSystemUiOverlayStyle({bool isDark = true}) {
  SystemUiOverlayStyle value;
  if (Platform.isAndroid) {
    value = SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,

      /// 安卓系统状态栏存在底色,所以需要加这个
      systemNavigationBarColor: Colors.transparent,
      systemNavigationBarIconBrightness:
          isDark ? Brightness.dark : Brightness.light,
      statusBarIconBrightness: isDark ? Brightness.dark : Brightness.light,

      /// 状态栏字体颜色
      statusBarBrightness: isDark ? Brightness.dark : Brightness.light,
    );
  } else {
    value = isDark ? SystemUiOverlayStyle.dark : SystemUiOverlayStyle.light;
  }
  return value;
}

RouteObserver工具类代码

import 'package:flutter/material.dart';

//RouteObserver工具类
class RouteObserverUtil{
  static final _observerUtil = RouteObserverUtil._internal();
  final RouteObserver<ModalRoute> _routeObserver = RouteObserver();
  factory RouteObserverUtil(){
    return _observerUtil;
  }

  RouteObserverUtil._internal();

  RouteObserver<ModalRoute> get routeObserver => _routeObserver;

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容