Flutter中的沉浸式模式设置
为什么会想要设置沉浸式模式?
Flutter中关于尺寸的适配问题需要避开顶部状态栏与底部导航条,为了方便这些尺寸的书写以及好看。
接下来说说沉浸式模式遇到的几种坑,以及沉浸式最终的实现方式:
最终实现方案:
沉浸式适配工具类:
dart
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class ImmersiveUtil {
static Future<void> init() async {
final deviceInfo = DeviceInfoPlugin();
final androidInfo = await deviceInfo.androidInfo;
final sdk = androidInfo.version.sdkInt; // 直接拿到 SDK 数字,比如 33 = Android 13
final release = androidInfo.version.release; // Android 版本字符串,比如 "13"
logger.d(release);
if (sdk >= 34) {
// Android 14、15 用 immersiveSticky
_immersiveSticky();
} else {
// Android 13 及以下用透明状态栏+导航栏
_edgeToEdge();
}
}
/// 透明状态栏 + 导航栏
static void _edgeToEdge() {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: [SystemUiOverlay.top],
);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarContrastEnforced: false,
),
);
}
/// 自动沉浸式(手势呼出后几秒自动隐藏)
static void _immersiveSticky() {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.immersiveSticky,
overlays: [],
);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarContrastEnforced: false,
),
);
}
}
调用:
dart
await ImmersiveUtil.init();
runApp(OKToast(child: Phoenix(child: MyApp())));
遇到的问题:
为什么要采用不同Android版本来进行不同的沉浸式适配呢?
我起初因为导航条的黑色背景想要全局设置透明,但是一直不生效;所以采用自动沉浸式模式,来实现系统几秒后自动关闭状态栏和导航栏。经过测试SystemUiMode.immersiveSticky
的自动沉浸式在Android13版本下会出现顶部状态栏虽然消失但是状态栏的位置会留下一条黑色背景。于是采用分版本显示,但是导航栏的颜色还是设置不了影响体验,经过最终尝试把systemNavigationBarContrastEnforced:false, // 控制系统是否强制确保导航栏按钮(返回、主页、最近任务)与导航栏背景颜色有足够的对比度,以保证图标可读性。
的这个属性设置为false就实现了导航栏透明,其他的导航栏配置都是不起作用的,只能通过这个属性来控制导航栏的黑色与透明(可能是系统厂商的高度定制问题)
各属性配置代表什么:
这里主要是配置状态栏和导航栏怎么样显示以及显示哪些:
dart
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: [SystemUiOverlay.top],
);
📌 SystemUiMode
枚举的可选值及作用:
SystemUiMode.manual
- 手动控制显示哪些系统 UI(通过
overlays
参数指定)。 - 一般配合
SystemUiOverlay.values
(即statusBar
和navigationBar
)使用。 - 适合需要自己决定显示/隐藏状态栏、导航栏的情况。
ini
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: [SystemUiOverlay.top], // 只显示状态栏
);
SystemUiMode.leanBack
- 轻量全屏模式。
- 系统栏(状态栏、导航栏)会被隐藏,但用户 轻触屏幕任意位置时会再次显示。
- 适合临时全屏,比如视频播放时。
SystemUiMode.immersive
- 沉浸模式。
- 系统栏会隐藏,用户需要 从屏幕边缘滑动 才能唤出。
- 唤出后会 停留,直到用户手动操作。
- 常用于游戏或需要较强沉浸感的应用。
SystemUiMode.immersiveSticky
- 粘性沉浸模式。
- 系统栏同样需要 从屏幕边缘滑动 才能唤出,但 几秒后会自动隐藏。
- 常用于阅读器、沉浸式视频播放等场景。
SystemUiMode.edgeToEdge
- 边到边模式。
- 状态栏和导航栏会保持显示,但应用内容可以绘制到系统栏的区域(需设置透明背景色)。
- 常用于现代应用的沉浸式设计(比如顶部大图延伸到状态栏)。
less
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.transparent,
),
);
✅ 总结对比:
模式 | 系统栏显示 | 唤出方式 | 适用场景 |
---|---|---|---|
manual |
自定义 | 根据 overlays | 精细控制 |
leanBack |
隐藏,点屏幕可唤出 | 点击 | 视频播放 |
immersive |
隐藏,边缘滑动可唤出 | 滑动边缘 | 游戏 |
immersiveSticky |
隐藏,滑动边缘可唤出,几秒后自动隐藏 | 滑动边缘 | 阅读、全屏视频 |
edgeToEdge |
显示(透明) | 常显 | 现代 UI、沉浸式布局 |
这里主要是配置状态栏和导航栏的颜色样式:
dart
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarContrastEnforced: false,
),
);
我设置了很多不起作用,只能说这里想要全局底部导航栏透明设置:
dart
systemNavigationBarContrastEnforced: false, // 控制 系统是否强制确保导航栏按钮(返回、主页、最近任务)与导航栏背景颜色有足够的对比度,以保证图标可读性。
就可以了,设置其他属性状态栏颜色导航栏颜色什么的都不起作用。