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

}
相关推荐
黄林晴43 分钟前
重磅官宣:Android UI 开发正式进入 Compose-first 时代
android·google io
Kapaseker1 小时前
搞懂变换!精通 Compose 绘制(二)
android·kotlin
美狐美颜SDK开放平台1 小时前
美颜SDK开发详解:如何优化美颜SDK在低端安卓机上的性能?
android·ios·音视频·直播美颜sdk·视频美颜sdk
Gary Studio1 小时前
深入MTK Android BSP:如何确定编译目标与查找项目设备树
android
casual_clover1 小时前
【Android】实现状态栏背景透明,系统时间/图标直接显示在页面背景上
android·透明状态栏
blackorbird1 小时前
Android Pixel 10 零点击漏洞利用链
android
_kerneler1 小时前
[qemu+kvm] vfio-platform irq 注入过程
android
亚空间仓鼠2 小时前
Docker容器化高可用架构部署方案(十一)
android·docker·架构
我命由我123452 小时前
Android 开发问题:TextView 内容超过宽度时,默认不会换行
android·开发语言·java-ee·android studio·android jetpack·android-studio·android runtime
shandianchengzi3 小时前
【科普】安卓|安卓手机上如何简便实现Ctrl+Z(需要键盘或一台Windows电脑)
android·windows·智能手机·计算机外设·安卓·科普·记录