在 Flutter 中,所謂的隨機顏色,是指從 0 到 255 之間各抽出三個整數,分別填入紅、綠、藍三個通道,再將它們傳入 `Color.fromARGB(255, r, g, b)`,或使用簡寫建構式 `Color(0xFFRRGGBB)` 所產生的任何 `Color` 值。Flutter 內建了 `dart:math` 函式庫,其中提供了一個 `Random` 類別,只要一行就能產生這些整數,因此在簡單的情境下,開發者幾乎不需要仰賴第三方套件。根據 MDN 上關於 CSS 顏色值的文件,每通道 8 位元的 RGB 模型是螢幕顏色的主流表示方式,而 Flutter 完全對應這個模型,這就是為什麼貼上的 HEX 值可以直接映射到 Dart 程式碼中。
開發者想在 Flutter 中產生隨機顏色,通常是出於以下三個原因之一:在等待設計師提供設計符號 (design tokens) 之前先建立一個佔位 UI、為螢幕擷圖與行銷素材產生展示用資料,或是為互動式 widget 提供點擊後即變換背景色的功能。這三種情境各自有不同的最佳解法,本文的後半段將逐一說明原生寫法、套件寫法,以及當你完全不想寫程式碼時,最快速的「設計優先」做法。

使用 dart:math 產生隨機顏色
`dart:math` 函式庫屬於 Dart 的核心程式庫,因此不需要在 `pubspec.yaml` 中額外加入任何套件。只要在你要使用它的檔案頂端匯入它,接著建立一個 `Random` 實例,呼叫 `nextInt(256)` 三次,即可填入紅、綠、藍三個通道。最後再用 alpha 值 255 包進 `Color.fromARGB`,就能得到一個完全不透明的色塊。
這個做法最具可攜性,也是最適合用來教初學者的方式,因為它完全不依賴外部套件。當你傳入一個固定的 `seed` 給 `Random` 建構式時,它同時也具備確定性 (deterministic),這對 widget 測試來說非常理想——你可以直接對特定顏色值進行斷言,而不必去模擬 (mock) 隨機來源。它的缺點是分佈在整個 RGB 空間上是均勻的,所以大約每 256 個顏色中就會有一個接近黑色,另一個接近白色;比起設計師討喜的配色,你更常會得到混濁的中間色調。
使用 pub.dev 上的 random_color 套件
若希望輸出更美觀,pub.dev 上的 random_color 套件封裝了 David Aerne 的「nice color」演算法,該演算法會傾向產生飽和且中等亮度的色相,在 UI 模型中看起來效果較佳。請將它加入你的相依套件中:
- 開啟 `pubspec.yaml`,在 `dependencies:` 下方加入 `random_color: ^2.0.0`(或 pub.dev 上顯示的最新版本)。
- 執行 `flutter pub get` 來取得該套件。
- 使用 `import 'package:random_color/random_color.dart';` 將它匯入。
- 呼叫 `RandomColor().randomColor()`,即可得到一個可直接用於任何 widget 的 `Color`。
這個套件接受 `colorSaturation`、`colorBrightness` 與 `colorHue` 等選項,讓你可以將輸出範圍縮減為粉彩、暗黑模式色塊,或單一色相系列。它也提供 `randomColors(count: 20)` 方法,單次呼叫即可回傳一個 `List
使用 setState 觸發顏色變更
產生一個隨機顏色,在畫面上其實不會發生任何事,直到框架重新建構 (rebuild) 為止。在 `StatefulWidget` 中,請將顏色儲存在一個欄位 (field) 中,並在每次想要新值時呼叫 `setState`:
- 在你的 `State` 類別中宣告一個欄位 `Color _bg = const Color(0xFFFFFFFF);`。
- 在 `onPressed`、`onTap` 或 `onLongPress` 處理函式裡,將 `_bg = RandomColor().randomColor();`(或使用對等的 `dart:math` 寫法)指定給 `_bg`。
- 在指定值之後,立即呼叫 `setState(() {})`,讓 Flutter 把 widget 標記為「髒 (dirty)」,並安排一個新幀。
- 將 `_bg` 綁定到你的 widget 樹上——例如,在 `AppBar` 上使用 `backgroundColor: _bg`,或在 `Container` 上使用 `color: _bg`。
如果你正在使用 Provider、Riverpod 或 Bloc 等狀態管理函式庫,請改為透過該狀態系統來公開顏色,並在數值變更時重新建構 (rebuild) 消費端的 widget。顏色的產生邏輯完全相同,只有重新建構的機制不同。
將挑選的 HEX 值轉換為 Flutter 顏色
設計師交給你的顏色,通常是六位數的 HEX 字串,例如 `#3B82F6`。Flutter 在 `Color` 建構式中加上 `0xFF` 前綴並移除井字號後,即可直接接受這些值:`Color(0xFF3B82F6)`。其中的 `0xFF` 部分會將 alpha 設定為完全不透明,這正是實心背景與填色所需要的結果。
如果要使用支援 alpha 的顏色,請使用八位數的形式 `Color(0xAARRGGBB)`,或具名建構式 `Color.fromARGB(a, r, g, b)`。前兩位十六進位數字會控制透明度,其中 `00` 表示完全透明,`FF` 表示完全不透明。這與 MDN 上關於十六進位顏色的參考文件所描述的模型一致,因此從 CSS 轉過來的設計師會感到非常熟悉。
如果你想跳過手動轉換、直接取得可用的 HEX 值,可以開啟隨機顏色產生器 (Random Color Generator),點擊任何一個色塊即可複製其 HEX,然後直接貼入 `Color(0xFF...)` 中。同一個色塊在你需要 RGB 與 HSL 字串格式(用於文件或設計交付)時,也會一併提供。
為你的情境選擇合適的方法
| 情境 | 建議方法 | 為何適合 |
|---|---|---|
| 單元測試與 widget 測試 | 來自 `dart:math` 的 `Random(seed: 42)` | 確定性的輸出可讓斷言在多次執行中保持穩定。 |
| 原型或展示 App | `random_color` 套件 | 無需任何設計輸入,即可產生視覺上令人愉悅的配色。 |
| 正式的的品牌顏色 | 寫死的 `Color(0xFF...)` 常數 | 品牌規範絕不應依賴隨機性。 |
| 點擊切換互動 | 在 `setState` 中使用 `dart:math` | 輕量、零相依套件,在每個幀預算內皆可執行。 |
| 行銷擷圖 | 線上產生器 + 貼上 HEX | 讓設計師無需撰寫程式碼,即可挑選精確的色塊。 |
在不產生脆弱測試的前提下測試隨機顏色
未植入種子的隨機產生是穩定測試套件的天敵。如果一個 widget 測試預期某個特定顏色,但實作端使用的是一個剛植入新種子的 `Random`,那麼這個測試在某次執行時會通過、下一次執行時就會失敗。解決方法是注入 `Random` 實例——可以透過 widget 的建構式參數、`main.dart` 中的全域覆寫,或 Riverpod 中的提供者,並在測試內部傳入一個已植入種子的值。你也可以將產生的顏色儲存在一個普通的 `Color?` 欄位中,並斷言它不為 null 且落在有效的 0–255 範圍內,而不是去檢查精確的 RGB 元組。
在 Flutter 中產生隨機顏色的常見陷阱
有幾個常見的錯誤經常出現。第一,在 `build` 中呼叫 `Random()`,會在每次重新建構時建立一個新的隨機來源,這會讓 `setState` 失效並產生畫面閃爍。請把 `Random` 實例移到欄位或頂層的 final 變數中。第二,使用 `Color.fromRGBO` 並搭配 0 到 1 之間的隨機 alpha,常常會產生看不見的 widget;若你需要透明度,請從一組離散值中挑選,例如 `[0.2, 0.5, 0.8, 1.0]`。第三,同時匯入 `dart:math` 與 `flutter/material.dart`,會在 `Color` 上發生命名衝突;請為其中一個設定別名(例如 `import 'dart:math' as math;`),或改用完整名稱 `math.Random()`。
將隨機顏色與其他工具搭配使用
單一的隨機色塊很少是故事的結尾。一旦你得到一個喜歡的基礎顏色,便可以使用配色產生器 (Color Palette Generator),圍繞它建立互補、類似與三等分配色。若要檢查文字在隨機背景上的可讀性,請將兩者一起送進顏色對比檢查工具 (Color Contrast Checker)。想了解更多跨平台的隨機顏色工作流程,可以參考我們的指南:在 JavaScript 中產生隨機顏色代碼,以及快速的 CSS 做法;如果是試算表使用者,Excel 快速做法則會在儲存格中介紹相同的概念。不想撰寫任何程式碼、卻需要靈感啟發的設計師,可以瀏覽一鍵為設計專案產生隨機顏色 (Generate Random Colors for Design Projects in One Click),其中提供了精選過的工作流程。