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

}
相关推荐
程序员-珍40 分钟前
报错下载android sdk失败
android·java
齊家治國平天下2 小时前
AAOS 电源管理深度解析:休眠/唤醒/功耗优化
android·车载系统·aaos·aosp·电源管理·休眠唤醒·carpowermanager
Xzaveir2 小时前
企业号码展示不可观测怎么办:状态机、拨测事件与异常回放
android·人工智能
2501_916007472 小时前
iOS和macOS应用程序性能分析和优化工具使用综合指南
android·macos·ios·小程序·uni-app·iphone·webview
黄林晴3 小时前
Nearby Connections 重大变更:不再自动开启 Wi-Fi / 蓝牙,适配指南
android
恋猫de小郭3 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter
woshihuanglaoshi4 小时前
数据迁移与版本管理 - Flutter在鸿蒙平台实现数据库升级策略
数据库·学习·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
GitLqr13 小时前
玩转 WebSocket:从原理到 Flutter 实战
websocket·网络协议·flutter
世人万千丶14 小时前
参数管理_Flutter在鸿蒙平台路由参数最佳实践
学习·flutter·华为·harmonyos·鸿蒙
HLC++16 小时前
Linux的进程间通信
android·linux·服务器