Flutter全屏开发:隐藏Android状态栏后出现黑条问题排查
Flutter全屏组件隐藏状态栏后出现顶部黑条问题
问题现象
在OnePlus 8 Pro(Oxygen OS 13.1,Android 13)上测试Flutter全屏组件时:
- 状态栏未隐藏时,应用占满屏幕高度,状态栏叠加在应用上方
- 调用
SystemChrome.setEnabledSystemUIMode隐藏状态栏后,状态栏图标消失,但顶部出现和状态栏高度一致的黑条 - 底部导航栏隐藏正常
- 测试了
SafeArea、Scaffold、Container、Card等组件,问题一致
复现代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; enum SystemUIOptions { all, statusBar, navigationBar, immersiveSticky } void main() { WidgetsFlutterBinding.ensureInitialized; runApp(const SystemChromeTester()); } class SystemChromeTester extends StatefulWidget { const SystemChromeTester({super.key}); @override State<SystemChromeTester> createState() => _SystemChromeTesterState(); } class _SystemChromeTesterState extends State<SystemChromeTester> { SystemUIOptions? selectedUIOption = SystemUIOptions.all; void printViewInsets() { print('System UI option: ${selectedUIOption!.name}'); print('Height: ${MediaQuery.of(context).size.height}'); print('Viewinsets top: ${MediaQuery.of(context).viewInsets.top}'); print('Viewinsets bottom: ${MediaQuery.of(context).viewInsets.bottom}'); print('Viewpadding: ${MediaQuery.of(context).viewPadding}'); print('Padding: ${MediaQuery.of(context).padding}'); } void toggleSystemUI(SystemUIOptions? selected) { switch (selected) { case SystemUIOptions.all: SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); break; case SystemUIOptions.statusBar: SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); break; case SystemUIOptions.navigationBar: SystemChrome.setEnabledSystemUIMode( SystemUiMode.manual, overlays: [SystemUiOverlay.bottom], ); break; case SystemUIOptions.immersiveSticky: SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); break; default: SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); } setState(() { selectedUIOption = selected; }); } @override Widget build(BuildContext context) { printViewInsets(); return MaterialApp( home: Scaffold( // appBar: AppBar(), backgroundColor: Colors.amber, resizeToAvoidBottomInset: false, body: Center( child: Column( children: [ RadioListTile( title: const Text('Top (status bar) and bottom (navigation bar)'), value: SystemUIOptions.all, groupValue: selectedUIOption, onChanged: toggleSystemUI, ), RadioListTile( title: const Text('Top (status bar) only'), value: SystemUIOptions.statusBar, groupValue: selectedUIOption, onChanged: toggleSystemUI, ), RadioListTile( title: const Text('Bottom (navigation bar) only'), value: SystemUIOptions.navigationBar, groupValue: selectedUIOption, onChanged: toggleSystemUI, ), RadioListTile( title: const Text('Immersive sticky'), value: SystemUIOptions.immersiveSticky, groupValue: selectedUIOption, onChanged: toggleSystemUI, ), ], ), ), ), ); } }
问题分析
这不是Flutter的bug,属于Android 13+ 挖孔屏/刘海屏的系统适配问题:
- 你的设备是挖孔屏,Android 13+ 会默认保留状态栏区域的安全边距,即使隐藏了状态栏,系统也不会自动让应用内容延伸到该区域
- 只调用
setEnabledSystemUIMode隐藏状态栏,没有配置UI覆盖样式,导致顶部区域没有被应用内容填充,显示为黑条
解决方案
需要同时配置SystemChrome.setSystemUIOverlayStyle和调整AndroidManifest.xml的主题设置:
1. 修复Flutter代码核心问题
首先修正main函数里的初始化调用(缺少括号):
void main() { WidgetsFlutterBinding.ensureInitialized(); // 补充括号 runApp(const SystemChromeTester()); }
然后修改toggleSystemUI方法,在切换模式时添加UI覆盖样式配置,让应用内容延伸到状态栏区域:
void toggleSystemUI(SystemUIOptions? selected) { // 基础透明样式配置,让内容延伸到系统UI区域 const baseOverlayStyle = SystemUiOverlayStyle( statusBarColor: Colors.transparent, systemNavigationBarColor: Colors.transparent, ); switch (selected) { case SystemUIOptions.all: SystemChrome.setSystemUIOverlayStyle(baseOverlayStyle); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); break; case SystemUIOptions.statusBar: SystemChrome.setSystemUIOverlayStyle(baseOverlayStyle); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); break; case SystemUIOptions.navigationBar: SystemChrome.setSystemUIOverlayStyle(baseOverlayStyle); SystemChrome.setEnabledSystemUIMode( SystemUiMode.manual, overlays: [SystemUiOverlay.bottom], ); break; case SystemUIOptions.immersiveSticky: SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( statusBarColor: Colors.transparent, systemNavigationBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, systemNavigationBarIconBrightness: Brightness.light, )); SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: []); break; default: SystemChrome.setSystemUIOverlayStyle(baseOverlayStyle); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); } setState(() { selectedUIOption = selected; }); }
2. Android端配置补充
在android/app/src/main/AndroidManifest.xml的Activity标签中添加挖孔屏适配属性:
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:windowLayoutInDisplayCutoutMode="shortEdges"> <!-- 添加此行 --> </activity>
同时在android/app/src/main/res/values/styles.xml中确保主题为全屏:
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> <item name="android:windowFullscreen">true</item> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> </style>
内容的提问来源于stack exchange,提问作者Peter Henter
相关产品推荐
相关产品推荐

