Flutter 设置Android System Navigation/Status Bar背景色

背景

公司要求必须使用Edge-to-Edge不允许使用Android中的theme.xmlstyle.xml资源文件来通过android:navigationBarColorandroid:statusBarColor属性进行对自定义系统Bar的背景进行改色,更不用提android.view.Window.setStatusBarColorandroid.view.Window.setNavigationBarColor方法了
如何设置背景色?在哪里设置?为什么在这里设置?我们带着这三个问题,来对这篇文章进行阅读。

如何设置背景色?

直接上代码

dart 复制代码
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);

SystemChrome.setSystemUIOverlayStyle(
    SystemUiOverlayStyle(
        systemNavigationBarContrastEnforced: false,
        systemNavigationBarIconBrightness: Brightness.dark, // 图标颜色-> dark深色;light亮色
        systemNavigationBarColor: Colors.white, // 设置导航栏(条)背景颜色
        statusBarColor: Colors.white, // 设置状态栏背景颜色
    ),
);

关键点:

  • 开启Edge-to-Edge沉浸模式

  • systemNavigationBarContrastEnforced 设置为 false,这个参数在部分Android系统中(特别是MIUI)中是控制颜色"反转"或"强制对比"的关键,设置成false能确保你指定的颜色不被系统覆盖

在哪里设置?

  1. 使用了MaterialApp组件作为App入口,那么要在builder返回值之前进行设置:
dart 复制代码
void main() {
    WidgetsFlutterBinding.ensureInitialized();
    runApp(ProviderScope(child: const MyApp()));
}

class MyApp extends StatelessWidget {

    const MyApp({super.key});

    @override
    Widget build(BuildContext context) {
        return MaterailApp(

        builder: (context,child){
            // 在此设置
            SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
            SystemChrome.setSystemUIOverlayStyle(
                SystemUiOverlayStyle(
                    systemNavigationBarContrastEnforced: false,
                    systemNavigationBarIconBrightness: Brightness.dark,
                    systemNavigationBarColor: Colors.white,
                    statusBarColor: Colors.white,
                ),
            );
            return child!;
        });
    }
}
  1. 没有使用MaterialApp组件作为App入口,那么要在runApp()方法之前执行设置即可:
dart 复制代码
void main() {
    WidgetsFlutterBinding.ensureInitialized();

    // 在此设置
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
    SystemChrome.setSystemUIOverlayStyle(
        SystemUiOverlayStyle(
            systemNavigationBarContrastEnforced: false,
            systemNavigationBarIconBrightness: Brightness.dark,
            systemNavigationBarColor: Colors.white,
            statusBarColor: Colors.white,
        )
    );
    runApp(ProviderScope(child: const MyApp()));
}

为什么在这里设置?

重点MaterialApp组件中,无论你设置设置怎样的主题样式,都在组件内部调用一次SystemChrome.setSystemUIOverlayStyle函数,这会让你在MaterialApp组件绘制之前设置的SystemBar背景颜色均被MaterialApp的这一次函数调用覆盖。我们来看下源码

dart 复制代码
class MaterialApp extends StatefulWidget {
    ...
    @override
    State<MaterialApp> createState() => _MaterialAppState();
    ...
}

class _MaterialAppState extends State<MaterialApp> {

    @override
    Widget build(BuildContext context) {
        Widget result = _buildWidgetApp(context);
        ...
        return ScrollConfiguration(
            behavior: widget.scrollBehavior ?? const MaterialScrollBehavior(),
            child: HeroControllerScope(controller: _heroController, child: result),
        );
    }

    Widget _buildWidgetApp(BuildContext context) {
        final Color materialColor = widget.color ?? widget.theme?.primaryColor ?? Colors.blue;
        if (_usesRouter) {
            return WidgetsApp.router(
                ...,
                builder: _materialBuilder, // 重点位置
                ...,
            );
        }

        return WidgetsApp(
            ...,
            builder: _materialBuilder, // 重点位置
            ...,
        );
    }

    Widget _materialBuilder(BuildContext context, Widget? child) {
        final ThemeData theme = _themeBuilder(context); // 重点位置
        final Color effectiveSelectionColor =
        theme.textSelectionTheme.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40);
        final Color effectiveCursorColor =
        theme.textSelectionTheme.cursorColor ?? theme.colorScheme.primary;
        Widget childWidget = child ?? const SizedBox.shrink();
        
        // 重点位置
        if (widget.builder != null) {
            childWidget = Builder(
                builder: (BuildContext context) {
                    return widget.builder!(context, child);
                },
            );
        }
        ...
    }

    ThemeData _themeBuilder(BuildContext context) {
        ThemeData? theme;
        ...
        if (useDarkTheme && highContrast && widget.highContrastDarkTheme != null) {
            theme = widget.highContrastDarkTheme;
        } else if (useDarkTheme && widget.darkTheme != null) {
            theme = widget.darkTheme;
        } else if (highContrast && widget.highContrastTheme != null) {
            theme = widget.highContrastTheme;
        }
        theme ??= widget.theme ?? ThemeData();
        // 此处的brightness 是 colorScheme.brightness 无论你设置与否都会将SystemBar 设置成light or dark
        SystemChrome.setSystemUIOverlayStyle(
            theme.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
        ); // 重点位置
        
        return theme;
    }

}
相关推荐
TT_Close6 小时前
别再复制旧 Flutter 工程了,真正拖慢你的不是业务代码
flutter·npm·visual studio code
风华圆舞8 小时前
鸿蒙 + Flutter 下 AI 助手为什么要支持流式输出
人工智能·flutter·harmonyos
Jinkxs9 小时前
Python基础 - 初识内置函数 Python自带的便捷工具
android·java·python
私人珍藏库9 小时前
【Android】VLLO-韩国热门手机剪辑APP
android·app·工具·软件·多功能
Cloud_Shy61810 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第六章 Item 40 - 43)
android·开发语言·人工智能·笔记·python·学习方法
AFinalStone11 小时前
Android12 U盘插拔链路源码全解析(五):Framework层(下) StorageManagerService
android·frameworks
风华圆舞12 小时前
鸿蒙 + Flutter 下 AI 页面的状态协同设计
人工智能·flutter·harmonyos
林九生12 小时前
【实用技巧】MySQL 绿色版一键路径更新脚本详解 —— update_path.bat 深度解析
android·数据库·mysql
故渊at13 小时前
第十三板块:Android 综合架构与未来演进 | 第三十一篇:Android 架构演进与 Fuchsia OS 的挑战
android·架构·宏内核·微内核·fuchsia·ipc 性能博弈
aqi0013 小时前
一文速览 HarmonyOS 6.1.1 推出的十个新特性
android·华为·harmonyos·鸿蒙·harmony