Flutter - 系統 UI 控制 SystemChrome === 針對 Flutter 中使用 `SystemChrome` 系統層 UI 控制方式進行說明與實務解法。 ## SystemChrome SystemChrome 是 Flutter 提供用來與底層作業系統(Android / iOS)互動的靜態類別,可控制應用程式的系統 UI 行為。 ### 系統 UI 顯示模式 用途: 控制狀態列與導航列的顯示/隱藏方式(全螢幕沉浸模式等)。 ```dart //隱藏底部導航列,狀態列不隱藏 SystemChrome.setEnabledSystemUIMode( SystemUiMode.manual, overlays: [SystemUiOverlay.top], ); ``` | OPPO 底部導覽頁縮合 | iPhone 顏色切換 | Samsung 顏色切換 | | -------- | -------- | -------- | |![](https://hackmd.io/_uploads/S1p6IPz0yx.gif)| ![](https://hackmd.io/_uploads/r1C9eDf01e.gif) | ![](https://hackmd.io/_uploads/HyzqmwfC1l.gif) | #### 系統 UI 模式(SystemUiMode) ##### 參數說明 | 模式 | 說明 | 適用場景 | |-------------------|------|----------| | `edgeToEdge` | 顯示狀態列與導航列,內容延伸至螢幕邊緣(可設透明) | 多數一般應用 | | `immersive` | 隱藏所有系統 UI,需滑動喚出,不會自動隱藏 | 遊戲、全螢幕展示 | | `immersiveSticky` | 同上,但喚出 UI 後會自動隱藏 | 電子書、影片播放 | | `leanBack` | 觸控時顯示 UI,僅支援較舊 Android 裝置 | 特殊需求 | | `manual` | 自訂要顯示的 overlay(top/bottom) | 精細控制場景 | ##### 程式範例 ```dart SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); ``` #### 系統 UI 樣式(SystemUiOverlayStyle) ##### 參數說明 | 參數 | 說明 | |------|------| | `statusBarColor` | 狀態列背景顏色 | | `statusBarIconBrightness` | 狀態列 icon 的顏色(light = 白,dark = 黑) | | `statusBarBrightness` | 僅 iOS:控制狀態列背景亮度 | | `systemNavigationBarColor` | 底部導覽列背景色 | | `systemNavigationBarIconBrightness` | 導覽列 icon 顏色亮度 | | `systemStatusBarContrastEnforced` | 是否強制套用背景對比(Android 10+) | | `systemNavigationBarContrastEnforced` | 同上,針對導覽列 iOS 僅支援: * statusBarBrightness(決定文字為黑或白) * 不支援 statusBarIconBrightness ##### 程式範例 ```dart // 亮色模式 SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.transparent, // 狀態列背景透明(iOS/Android) statusBarIconBrightness: Brightness.dark, // Android:黑色 icon(亮背景) statusBarBrightness: Brightness.light, // iOS:亮模式 systemNavigationBarColor: Colors.transparent, // 導航列背景透明 systemNavigationBarIconBrightness: Brightness.dark, systemStatusBarContrastEnforced: false, systemNavigationBarContrastEnforced: false, ), ); // 暗色模式 SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, // Android:白色 icon(暗背景) statusBarBrightness: Brightness.dark, // iOS:暗模式 systemNavigationBarColor: Colors.transparent, systemNavigationBarIconBrightness: Brightness.light, systemStatusBarContrastEnforced: false, systemNavigationBarContrastEnforced: false, ), ); ``` ### 裝置方向鎖定 用途: 限制螢幕方向(如:僅允許直立或橫向模式)。 #### 裝置方向鎖定(Device Orientation Lock) ##### 參數說明 | 參數 | 說明 | |-------------------------------------|------------------------| | `DeviceOrientation.portraitUp` | 垂直向上(預設手機直立) | | `DeviceOrientation.portraitDown` | 垂直向下(較少用) | | `DeviceOrientation.landscapeLeft` | 橫向:向左旋轉 | | `DeviceOrientation.landscapeRight` | 橫向:向右旋轉 | ##### 程式範例 ```dart // 僅允許直立模式 await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); // 僅允許橫向模式(左右都可以) await SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); // 取消方向鎖定,允許系統根據裝置方向自動切換 await SystemChrome.setPreferredOrientations([]); //------------------- // 動態切換方向(例如影片播放頁面進入橫向,返回時恢復直立) @override void didChangeDependencies() { super.didChangeDependencies(); // 進入頁面時 SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, ]); } @override void dispose() { // 離開頁面時恢復直立 SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); super.dispose(); } ``` ## 常見問題與平台差異 ### 狀態列出現黑邊(OPPO、小米等機型) - **原因**:部分 Android 裝置(如 OPPO、小米)在 immersive 模式下,即使隱藏狀態列,系統仍會保留繪製背景區塊,預設為黑色。 補充 OPPO、小米、Vivo 等裝置可能即使已設為透明,建議實機測試,另外目前有遇到縮合 status bar 會造成使用者有感 APP 重新繪製造成體感不佳的問題,建議不縮合 status bar ### immersive 模式下 AppBar 無法點擊 - **原因**:Android 系統保留頂部約 24dp 區域用於手勢偵測(從上滑動喚出系統 UI),App 無法接收該區域的觸控事件。 ### 鍵盤彈出導致 UI 設定失效 - **原因**:Android 在鍵盤開啟時會暫時強制顯示系統 UI,關閉後不會自動恢復原本設定。 - **解法**: - 鍵盤關閉後,延遲一段時間再呼叫: ```dart WidgetsBinding.instance.addPostFrameCallback((_) { SystemChrome.restoreSystemUIOverlays(); }); ```