主題 Theme:黑暗、光明與 UI 設計更自由
WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.
Article info
This article is part of:
Categories:
Tags:
Date:
Published: 2021/07/11 - Updated: 2022/02/10
Total: 6456 words
Like
or Dislike
About the Author
很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯
More to explore
這一篇希望可以解救工程師的靈魂,因為有太多的工程師因為 UX/UI 的改來改去而氣到翻臉,哎,何必呢,除了要訓練自己的時時保持出世與正向外,儘早將 UX/UI 的控制獨立,會是最好的解決方式。相信我,老闆跟 designer 也不是故意玩你,他們只是天生善變而已。
Flutter 有非常強大的 UX/UI 管理能力,在我們深入暸解它之前,讓我們先來聞香一下,先有個概念。
延續我們的程式碼,如果有人現在才加入,目前階段的程式碼請自行參考本書:程式碼備份中的 Code milestone 2。
支援黑暗模式
話說蘋果在 2019 年底發佈的 iOS 13 時,加入了黑暗模式,之後,很多的網站及 App 就開始將黑暗模式列為必須,想像一下各位就是負責黑暗模式的開發人員,先請想想看:開發這項功能難不難?會需要改變些什麼?⋯⋯ 我想大家一定馬上就會想到:文字的顏色要反轉,背景、按鈕、Title 等的顏色都要改變,嗯,要改的東西可真多啊,黑暗模式並不是一件簡單的事。
但是,在 Flutter,黑暗模式卻相對簡單多了,讓我們先執行目前的程式,看看目前的,也就是預設的,淺色 Light 主題,然後,請更改:
lib/main.dart:
再執行一次,哇,黑暗模式出現了!
左邊就是改變前預設的淺色 Light 模式,右邊就是改成 ThemeData.dark 的黑暗模式,Flutter 很厲害吧,只要簡單幾個字,就把黑暗模式做出來了。
等等,你現在可能馬上就有第一個問題了:「我怎麼知道可以用 ThemeData.dark?文件在哪裏?」來,分享你一個秘笈,很簡單,請將程式中的 ThemeData 選起來,也就是點兩下將它 hightlight ,然後按
Command-b
,鐺鐺,Flutter 的 theme 原始碼 theme_data.dart 就跳出來了,這其實就是 flutter 的一種文件,Flutter 的原始碼都有很完整的註解,你所要找的設定與使用方法,都寫在上面,這原始碼上有很清楚的註解:啊,原來 Flutter 除了 dark 外,還有 light 跟 from,也就是「黑暗」、「光明」與「自由配」。
Android Studio on Mac 常用的快捷鍵
用 Android Studio 寫 Flutter 有一些你一定要知道的超好用快捷鍵,以下是我最常用的:
設計語言
Flutter 內建支援兩個設計語言,也就是近年來被當神來拜的 UX,其實,這就是設計的一慣性。在 Flutter 中,一般都會在 main.dart 的程式碼中選定用那一個:
這兩個設計語言的風格當然不同,一般會希望跑在 iPhone 上的就用 CupertinoApp,在 Android 上,就用 MaterialApp,當然也可以都不用,混用,甚至依使用平台自動切換,不過,我們剛學,就先以 MaterialApp 為基礎,先學走再學跑。
話說,怎麼沒人理微軟的 Fluent 呢?Flutter 的產品經理說:「沒有開發計畫,但是如果社群有人想開發,可以幫忙。」
Material Design
Google 的 Material Design 是一個大傢伙,各位一定到這個官網看看,這個設計語言包含了 Icon、字體、元件、顏色等等,要完全搞懂還真不容易,不過,Flutter 已經都幫你準備好了,所以我們只要負責用,真的容易太多了,我也建議在 Flutter 中,就以 Material deisgn 為主,畢竟,這是 Google 的主場,何必強人所難。
我不是設計師,但是我覺得下面的這個幕後花絮影片很棒,可以快速了解 Material design 的起點。
Material design Google Developers — YouTube
依照系統的黑暗模式 ~ 超簡單
現在讓我們來讓這個 App 支援系統的黑暗模式,也就是當系統設定為黑暗模式時,App 也會自動轉成黑暗模式。
如同我們之前強調的寫作風格與管理,我們應該要將 UI 的設定獨立出來,並獨立放在 theme 目錄內。UI 是個人人有意見,天天都會變的惡魔,一個整合的 UI 設定檔會讓寫程式的人生由黑白變彩色,所以一開始就應該將它分開,我們現在就將它分開,新增一個 style.dart 程式檔,未來所有 theme 的設定都會放在這裡。
lib/theme/style.dart:
再來就是將 main 中的 MaterialApp 設定為依照系統設定。
lib/main.dart:
當然不要忘了在 main.dart 的前面 import style.dart:
趕快再來執行一次,如果你的模擬器沒改變的話,綠色頭的淺色模式就出現了,現在請將模擬器設定到暗黑模式,在 iOS 上就是:Home > Settings > 最下面的 developer > Dark Appearance,如下圖:
把 Dark Appearance 黑暗模式打開,切回到 App,哇,黑暗模式出現了!這未免也太簡單了吧!沒錯,因為 Flutter 已經把設計語言整合進來了,而且這也是一條正確的路,不要再想自己搞一套設計語言或是色系了,不是說你不行,Flutter 也沒有限制,但是絕不是一件簡單的事。
Material design 的顏色系統
Material Design 有一套很完整的顏色系統,顏色理論 (Color theory) 雖然是個從牛頓就已經有的老東西,但是要搞懂還真不容易,我也不懂,所以我們不會深入討論,如果對 Material design 的色系有興趣,可以點這裡進去看看。
Material Design 內定了一些色系,當然也允許自定色系,事實上,我們上面所使用的 dark 及light 就等於:
使用 Flutter 內定的顏色是最簡單的路,但是如果一定要自訂顏色,也一點都不難,只是好不好看而已,我們可以很簡單的增加一的自訂的 theme,如下:
我們在 lib/theme/style.dart 下面增加一個 themeCustom:
Flutter 中 ThemeData 可以設定的東西可多了,還記得我們的祕技 Control-J 嗎?打開它,哇,有那麼多可以設定,是要花一些時間才會摸熟 Widget 與顏色的對應關係。
好啦,我們再來就把 main.dart 中的 theme 改成用這個:
在模擬器上執行它,別忘了要切回系統預設的明亮模式,鐺鐺,我的驚世駭俗 UI 色系就出現了:
這真是一個難以形容的怪色調,不過也許有人就是喜歡,UI 是個永遠的爭論,自訂顏色在 Flutter 上真的一點都不難,但是要好看,就真的很難,所以關於選顏色這件事,我們就可以把 style.dart 交給設計,讓專業的來吧,現在知道爲什麼一定要將 style 獨立出來了吧。
material Colors vs 絕對顏色 Color
上面我們已經看到 Colors 跟 Color 這兩個 class 是完全不同的應用,沒有「s」的 Color 是 dart 的內建 class,可以用來自由的設定任何顏色。有「s」的 Colors 就不一樣了,它是 Flutter 中的 material class,所以它就只能選已經預先設定好的 material color,詳細的說明可以看文件,但是很難懂,所以我們來做個簡介:
好啦,這樣就很清楚知道什麼是有「s」的 Colors 了。
黑白色很特別,嚴格來說,它們並不是 material color,各位可以試試把 style.dart 中的 primarySwatch 改成黑色,如:
Flutter 很快就告訴你說,不行,Colors.black38 不是 material color,不能用來指定 primarySwatch 色盤顏色,色盤顏色必須要是 Material design 的主色,它要有十個色階,其實 primarySwatch 就是用來快速一次設好整個顏色主題 theme 用的,它會將不同的色階用在不同的地方。
要自訂 material color 其實也不難,如下:
所以你可以將任何顏色設定為 material color,再套入 primarySwatch 中,就是你的自訂色盤了。
除了 primarySwatch 色盤外,你可以在 theme 中用任何顏色,包含黑白,只是還是我那句老話:自訂顏色在 Flutter 上真的一點都不難,但是要好看,就真的很難。
ThemeData.from
所以如果你的需求又要顏色來自別人,又想要可以重新設定,就可以用 ThemeData.from,範例如下:
只是,這樣的使用情境好像很少,有用到的留個言吧,我還真想不到。
不要個別的設定 widget 顏色
將模擬器切到黑暗模式,執行 App,我們看到 ListView > Card 裡面的箭頭是藍色的:
說實話,好看嗎?見仁見智了,不過我們知道,這個顏色是寫死在 my_home_page.dart 裡的:
這就一定是個「笨」寫法,想想看,當你的程式寫到幾千行時,有一天你的老闆或業主走過來說:所有的 Play 箭頭顏色都要改成紅的,你可能就要加班了,所以,我的建議就是:絕對不要將顏色寫死在個別的 widget 或 screen 中,將他們統一寫到 style.dart 裡面!
建議使用 theme
顏色的協調一直都是 UI 設計的重點,也是每一個設計語言的重點,既然我們都已經定好了 theme 的顏色,就應該使用它,讓這個箭頭的顏色跟整個 theme 一致,使用 theme 顏色也非常簡單,就是選一個 theme 的顏色,如下:
在這個例子裡,我們是使用 theme 中的 primaryColor 來當作這個箭頭的顏色,UI 變成:
不知道各位讀者覺得如何,我是覺得這樣好看也一致多了,但是不要忘記了,這可只是黑暗模式,另一還有個淺色模式,使用 Theme.of(content) 的好處是一次就可以將兩個模式都整合設定好,要調整也是整個 App 一起調,協調性與方便性都最好!
不管,我就是要一個特別色!
也許,不知道什麼理由,你的這個顏色就是要不同於 Theme 的顏色,強烈建議將這個顏色寫在 style.dart 中,如:
然後就可以到處用,如:
color: cardListArrow,
就這樣,不管是用不用 theme 顏色,所有的顏色就都統一寫到 style.dart 裡面了,再也不怕要改顏色了。
widget 的預設顏色
事實上,所有的 Widget 都有使用 Theme 的預設顏色,我們現在就可以把這個 play arrow 的顏色 remark 起來,再執行一次,來看看 Flutter 的預設顏色是什麼:
嗯,很不錯呢,所以其實大部分的情況下,我們都「應該」使用預設的顏色,因為 Flutter 已經根據 material design 將顏色都預設好了,改一髮動全身,只有必要時,才需要自己設定顏色。
你可能會問,那要怎麼查每一個 widget 預設的 theme 顏色呢?好問題,Flutter 的文件關於這方面寫得很差,也可以說根本就沒寫,如果真的很想要知道,目前大概只能從原始碼中查到,整合的文件只有這個,但也還在開發中。還好,實務上,我們一般的用法都是:
實際開發的使用建議
建議就是使用 material 的預設,當你能夠接受一切都是使用 Flutter 的 Material design 預設為主時,這是最簡單,也可能是最「好」的方法,直接就延伸 light 或是 dark 的 theme 就好,簡單又美麗,要做一些小幅的改變,再用 ThemeData.light()/dark().copyWith(),是的,這樣用會有很多限制,例如不能用 primarySwatch 改色盤、字體、等等 ⋯⋯,這很自然,你就是使用 Flutter 的 Material design 預設了,自然不能改變。
如果你就是一定要自己來,那你就應該要全面重新自定一個 theme,記住,這絕不是一件簡單的事,但是,這樣做有最大的彈性,如果這是你所要的,那就請繼續看下去:
自定 theme
我很不建議這樣用,但是,這篇文章這本書就是學 Flutter,所以當然也應該要知道如何自定 theme,自定 theme 很麻煩,也很不容易做出一個好看的 UI,但是,卻有巨大的彈性,什麼都可以改,不只顏色,包含字體、形狀、等等 ⋯⋯ 都可以改,真的很強。
自定 theme 也一樣要寫在 lib/theme/style.dart 中,將以下的程式碼加入其中:
自選字體
在 style.dart 的第 41~52 行中,我們的 fontFamily 指定了一個 'JBMono',這就是自選字體,在 Flutter 中自選字體很簡單,特別是字體來自 Google Font,程序如下:
這樣就將新字體加好了,可以用 fontFamily 來指定,沒指定就是用預設字體,想知道 Flutter 的預設字體嗎?不要太好奇,這其實並不簡單,想想看,在每一個平台上的預載字體都不一樣,Flutter 的預設字體自然也要不同,真想知道可以看 sdk 中的:
/flutter/packages/flutter/lib/src/material/typography.dart 原始碼
使用自定的 theme
自定 theme 的名稱變了,當然在 main.dart 中要記得改,如下:
好啦,那我們要怎麼使用自定的 theme 呢,我先把改好的圖讓大家看,再來看怎麼寫的:
好不好看不討論,見仁見智,我們是以學習分享為主,現在我們就來看看在 widget 中是怎麼用的:
你看看,自定 theme 真是麻煩啊,光改這麼小的一個 App,就要寫這麼多行程式碼,而且還要事先做好規劃,更不要忘了,這還是我們將 App 中的 theme 設定完全分離後「乾淨版」!
在這篇文章中,我們全部都是使用 theme,也證明 theme 中可以使用任何顏色,我們盡量不使用自訂的顏色,這點很重要,要知道,App 並不是單獨的存在與執行,它是跑在 Andriod、iOS 或是 Windows 上的,一個與作業系統不同的主題色系的 App 真的會很怪異的存在,除非設計功力超強,不然真的不建議。
好啦,基本上到此,我們就已經對 material color 在 Flutter 中有足夠的了解了。
最後的程式碼,請自行參考本書:程式碼備份中的 Code milestone 3。
進階討論
如果你剛剛一步一步的看到這裡,那你還是菜鳥,可以跳過這段,下面是一些進階的 Theme 使用方法,放在這裡方便未來查詢。
我們要怎麼知道目前 App 是在黑暗還是明亮模式?
有一個觀念很重要,App 的 Theme 模式與電腦系統的 Theme 模式是獨立的兩個系統,舉個例子,你的電腦系統可以設定為黑暗模式,但是在 App 中,你可設定為明亮模式,所以,上面這個問題就要問:你要知道的是 App 目前的 Theme 還是電腦系統目前的 Theme,兩個的讀取方法不同:
App 目前的 Theme,可以用下面的方法知道:
電腦系統目前的 Theme:
我是不大喜歡第 3 行的用法,不過它不用依靠 context,有其市場。