Flutter中的沉浸式模式设置

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(即 statusBarnavigationBar)使用。
  • 适合需要自己决定显示/隐藏状态栏、导航栏的情况。
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, // 控制 系统是否强制确保导航栏按钮(返回、主页、最近任务)与导航栏背景颜色有足够的对比度,以保证图标可读性。

就可以了,设置其他属性状态栏颜色导航栏颜色什么的都不起作用。

相关推荐
游荡de蝌蚪2 小时前
快速打造Vue后台管理系统
前端·javascript·vue.js
code_YuJun2 小时前
3. 修改 vue.config.js 配置完成打包分析和优化
前端
文心快码BaiduComate2 小时前
轻松实践:用Python实现“名字大作战”游戏,表白Zulu!
前端·后端·微信小程序
神毓逍遥kang3 小时前
最近学习rust,然后使用rust构建你的前端cli工具助力前端生态
前端
1024小神3 小时前
Android冷启动和热启动以及温启动都是什么意思
前端
程序员老刘3 小时前
跨平台开发地图:客户端技术选型指南 | 2025年9月
flutter·客户端
June_liu3 小时前
列太多vxe-table自动启用横向虚拟滚动引起的bug
前端·javascript
齐杰拉3 小时前
useSse 开源:如何把流式数据请求/处理简化到极致
前端·chatgpt
起风了啰3 小时前
Android & IOS兼容性问题
前端