Flutter - 系統 UI 控制 SystemChrome
===
針對 Flutter 中使用 `SystemChrome` 系統層 UI 控制方式進行說明與實務解法。
## SystemChrome
SystemChrome 是 Flutter 提供用來與底層作業系統(Android / iOS)互動的靜態類別,可控制應用程式的系統 UI 行為。
### 系統 UI 顯示模式
用途: 控制狀態列與導航列的顯示/隱藏方式(全螢幕沉浸模式等)。
```dart
//隱藏底部導航列,狀態列不隱藏
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: [SystemUiOverlay.top],
);
```
| OPPO 底部導覽頁縮合 | iPhone 顏色切換 | Samsung 顏色切換 |
| -------- | -------- | -------- |
||  |  |
#### 系統 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();
});
```