Flutter自助终端应用:SystemChrome.setSystemUIChangeCallback在导航栏显示时未触发
问题解决:Flutter自助终端滑动调出导航栏后自动隐藏失效
问题原因
SystemChrome.setSystemUIChangeCallback 在**沉浸式粘性模式(immersiveSticky)**下存在局限性:当用户滑动调出临时显示的系统栏时,系统不会触发该回调(因为系统将其视为临时状态,不通知应用),导致你无法捕获导航栏显示的事件。
解决方案
方案1:定时检查系统栏状态(简单兼容)
通过定时任务周期性检查当前系统UI模式,若偏离沉浸式粘性模式则重新设置,适合快速解决问题:
import 'dart:async'; import 'package:flutter/services.dart'; class MyHomePageState extends State<MyHomePage> { Timer? _systemBarWatcher; @override void initState() { super.initState(); _hideSystemBars(); _startSystemBarWatcher(); } @override void dispose() { _systemBarWatcher?.cancel(); super.dispose(); } Future<void> _hideSystemBars() async { await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); } void _startSystemBarWatcher() { // 每隔300ms检查一次系统栏状态 _systemBarWatcher = Timer.periodic( const Duration(milliseconds: 300), (timer) async { final currentMode = await SystemChrome.getEnabledSystemUIMode(); if (currentMode != SystemUiMode.immersiveSticky) { await _hideSystemBars(); } }, ); } }
方案2:监听窗口Metrics变化(跨平台优雅方案)
利用Flutter的WidgetsBindingObserver监听窗口布局变化,系统栏显示/隐藏时会触发窗口Metrics更新,以此判断并重新隐藏系统栏:
import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; class MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _hideSystemBars(); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeMetrics() { super.didChangeMetrics(); // 延迟100ms确保系统栏状态稳定后再检查 Future.delayed(const Duration(milliseconds: 100), () async { final currentMode = await SystemChrome.getEnabledSystemUIMode(); if (currentMode != SystemUiMode.immersiveSticky) { await _hideSystemBars(); } }); } Future<void> _hideSystemBars() async { await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); } }
方案3:Android原生监听(最可靠,仅针对Android终端)
自助终端通常基于Android系统,直接在原生层监听系统UI变化,能做到无延迟响应:
Android端(MainActivity.kt):
import android.os.Bundle import android.view.View import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { private val CHANNEL = "com.your.package/kiosk" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "hideSystemBars" -> { hideSystemBars() result.success(null) } } } // 监听系统UI可见性变化 window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { // 系统栏已显示,立即隐藏 hideSystemBars() } } } private fun hideSystemBars() { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) } override fun onResume() { super.onResume() hideSystemBars() } }
Flutter端:
import 'package:flutter/services.dart'; class MyHomePageState extends State<MyHomePage> { static const MethodChannel _channel = MethodChannel('com.your.package/kiosk'); @override void initState() { super.initState(); _hideSystemBars(); } Future<void> _hideSystemBars() async { try { await _channel.invokeMethod('hideSystemBars'); } on PlatformException catch (e) { print("隐藏系统栏失败: ${e.message}"); } } }
方案选择
- 跨平台应用优先选方案2,兼顾优雅性和兼容性;
- 仅Android终端推荐方案3,响应无延迟,稳定性最高;
- 快速验证可选方案1,实现成本最低。
内容的提问来源于stack exchange,提问作者jstuardo
相关产品推荐
相关产品推荐

