Mac開發(fā)跬步積累(五): Dark Mode下適配你的UI界面

圖片來(lái)自Apple官方

macOS 10.14中,蘋果在系統(tǒng)本身樣式(Light (aqua) appearance
)基礎(chǔ)上推出了暗黑模式(dark appearance),這種模式下可以更突出顯示應(yīng)用窗口中的內(nèi)容,讓用戶的關(guān)注焦點(diǎn)聚集在App本身的視圖中以便獲取更佳的視覺(jué)體驗(yàn).關(guān)于AppKit中的系統(tǒng)視圖,蘋果默認(rèn)已經(jīng)進(jìn)行了暗黑模式適配升級(jí),但對(duì)于許多自定義的View,還是需要我們花一點(diǎn)點(diǎn)時(shí)間處理的.

0x00: 關(guān)于 NSAppearance

macOS 10.9+ 的時(shí)候,蘋果就提供了NSAppearance這個(gè)類來(lái)協(xié)助AppKit管理App的UI控件. NSAppearance決定著AppKit如何渲染每個(gè)UI控件的效果,尤其是與顏色或者圖片相關(guān)的部分.

  • App啟動(dòng)后會(huì)獲取系統(tǒng)當(dāng)前樣式(Light Appearance 或者Dark Appearance).
  • NSWindow會(huì)繼承App的appearance效果;
  • NSView會(huì)繼承其父類或者NSWindowappearance效果;
  • 開發(fā)者可以設(shè)置App的整體或者部分appearance效果;
  • 當(dāng)Appkit繪制UI控件時(shí),會(huì)自動(dòng)將當(dāng)前的appearance賦值給控件的appearance(在當(dāng)前線程中進(jìn)行);
  • NSAppearance會(huì)影響 系統(tǒng)字體(font),顏色(color),文本(text),圖片(image)的相關(guān)繪制路徑(draw path)進(jìn)而影響顯示效果.

0x01: 顏色適配(NSColor)

當(dāng)用戶切換Light / Dark Appearance時(shí),UI控件的顏色有著明顯不同的效果.在macOS 10.14之前我們對(duì)于一個(gè)控件的顏色值經(jīng)常使用硬編碼方式,因此當(dāng)appearance變化時(shí),這些硬編碼的色值就難以適應(yīng)了.

當(dāng)Appearance變化時(shí),關(guān)于NSColor的適配蘋果官方給出兩種簡(jiǎn)單并且易于實(shí)現(xiàn)的方案:

  1. 使用帶有語(yǔ)義的Color:
    那么問(wèn)題來(lái)了,到底什么是帶有語(yǔ)義的Color呢? 看一下蘋果官方的原文:
    Semantic colors let you specify colors based on their intended usage, rather than on the actual color.
    簡(jiǎn)單的說(shuō)就是根據(jù)使用場(chǎng)景來(lái)描述顏色,而不使用確切的值來(lái)描述顏色.
    我們以一個(gè)Label 的例子來(lái)看一下代碼與效果:
    設(shè)置labelColor

運(yùn)行效果:


LabelColor 在Dark 和Light 模式下的效果

系統(tǒng)提供的語(yǔ)義Color可以參考蘋果開發(fā)者文檔中的:UI Element Colors
例如Label相關(guān)的有:labelColor , secondaryLabelColor,tertiaryLabelColor,quaternaryLabelColor等.

除了這些語(yǔ)義Color之外,系統(tǒng)還提供了一下可適配的Color,通常都以system+顏色方式命名.例子如下:

         NSColor.systemRed
         NSColor.systemBlue
         NSColor.systemGray
         NSColor.systemPink
  1. 使用Assets Color:(推薦)
    更多時(shí)候我們希望能夠有更多自己可以定義的顏色,這時(shí)系統(tǒng)提供的語(yǔ)義Color就會(huì)顯得不夠用,這時(shí)我們可以使用Assets Color,具體操作請(qǐng)參考下圖示例:
    Assets Color 設(shè)置

    Appearance 說(shuō)明

    代碼調(diào)用Assets Color: "Color"是在Assets 中創(chuàng)建的顏色名稱
    調(diào)用Assets Color

    運(yùn)行效果:
    Assets Color 運(yùn)行效果

0x02: 圖片適配(NSImage)

App圖片是非常重要的UI資源,為了在合適的Appearance下顯示正確的圖片,主要有下面的三種方式.

  1. Image Assets
    使用Assets ImageAssets Color非常相似,具體請(qǐng)參考操作圖例:
    Assets Image Set

Assets Image 的適配場(chǎng)景(即當(dāng)下面場(chǎng)景變化時(shí),會(huì)Appkit會(huì)自動(dòng)調(diào)整Image進(jìn)行適配):

  • Screen resolution(屏幕分辨率):
    Appkit會(huì)自動(dòng)根據(jù)當(dāng)前屏幕的解析度選取最佳的image進(jìn)行顯示
  • Light and dark appearances (Appearance切換):
    Any Appearance中的圖片會(huì)適配macOS全版本,Light和Dark 僅適用macOS10.14之后的版本
  • High contrast (高對(duì)比度):
    使圖片與周邊的內(nèi)容對(duì)比根據(jù)突出,僅能用于macOS10.14+之后的版本
  1. Template Images
    使用模版圖片也是一種常用的適配解決方案,典型的案例就是設(shè)置控件的icon(比如一個(gè)播放或者暫停的按鈕).這種方法需要配合使用圖片編輯軟件(項(xiàng)目中的話通常就是UI設(shè)計(jì)師來(lái)處理)制作圖片模版,具體使用僅需兩個(gè)步驟即可:
  • UI設(shè)計(jì)師需要根據(jù)場(chǎng)景設(shè)計(jì)圖片,但需要遵守如下規(guī)則:
    template 設(shè)置規(guī)則

    需要忽略的部分使用透明背景
    需要顯示的部分使用黑色或者部分透明的黑色
  • 設(shè)置圖片的渲染模式為Template:
    設(shè)置圖片渲染模式
  1. Drawing Handler
    使用NSImageinit(size:flipped:drawingHandler:)方法可以讓Appkit根據(jù)appearance變化時(shí)自動(dòng)調(diào)用drawingHandler中的代碼進(jìn)行圖片創(chuàng)建,從而實(shí)現(xiàn)適配效果;

0x03: 自定義View 適配(NSView)

當(dāng)改變當(dāng)前的appearance時(shí),AppKit會(huì)自動(dòng)調(diào)用NSView的下面幾個(gè)方法(根據(jù)情況調(diào)用)

  • updateLayer()
  • draw(_:)
  • layout()
  • updateConstraints()
    這樣我們就有機(jī)會(huì)在變更appearance時(shí),通過(guò)重載上面的方法來(lái)實(shí)現(xiàn)自定義view的UI適配工作,示例代碼如下:
override func updateLayer() {
   self.layer?.backgroundColor = NSColor.textBackgroundColor.cgColor

   // Other updates.
}

注意點(diǎn)!!!
NSColor會(huì)立刻生效,但CGColor需要App再次啟動(dòng)才會(huì)生效!

0x04: 定制App的appearance(NSApp)

  • 設(shè)置NSView或者NSWindowappearance:
    NSView Appearance

    注意點(diǎn)!!!
    Appearance是存在繼承關(guān)系的:NSApp->NSWindow->NSView
  • 通過(guò)代碼方式設(shè)置NSViewappearance:
class MyContentView : NSView {
  func adoptAquaAppearance()
      self.appearance = NSAppearance(named: .aqua)
   }
}
  • 設(shè)置NSAppAppearance:
  NSApp.appearance = NSAppearance(named: .darkAqua)

0x05: Visual Effect View

關(guān)于NSVisualEffectViewAppearance適配,蘋果官方建議采用根據(jù)使用明確場(chǎng)景語(yǔ)義枚舉.例如在一個(gè)popOver的窗口中,推薦使用NSVisualEffectView.Material.popover,這樣系統(tǒng)就根據(jù)appearance變化自動(dòng)選擇合適的效果了.同時(shí)系統(tǒng)也廢棄了如下的枚舉:

  • NSVisualEffectView.Material.light Deprecated
  • NSVisualEffectView.Material.dark Deprecated
  • NSVisualEffectView.Material.mediumLight Deprecated
  • NSVisualEffectView.Material.ultraDark Deprecated

0x06: 當(dāng)appearance 切換時(shí),應(yīng)避免耗時(shí)操作

當(dāng)切換系統(tǒng)的Appearance時(shí),AppKit會(huì)同時(shí)更新UI控件,這部分工作通常都是自動(dòng)完成的.但有時(shí)也會(huì)調(diào)用開發(fā)者編寫的代碼,例如你使用了NSImagedraw handler 方式創(chuàng)建圖片對(duì)象,又或者使用了KVO監(jiān)聽一個(gè)視圖或者窗口的effectiveAppearance屬性,因此請(qǐng)需要注意下面幾點(diǎn):

  • 盡可能快的更新UI;
  • 不要執(zhí)行與appearance變更無(wú)關(guān)的任務(wù);
  • appearance變化時(shí)AppKit會(huì)自動(dòng)添加過(guò)渡效果動(dòng)畫,但如果你的更新UI代碼任務(wù)過(guò)重,AppKit將會(huì)丟棄過(guò)渡效果動(dòng)畫!

0x07: one more thing

為了考慮兼容macOS10.14之前的App版本,但又想支持Dark Appearance的效果,那么可以在Info.plist中添加 NSRequiresAquaSystemAppearancekey,并設(shè)置值為true即可.
這樣做的前提是要保證App在macOS10.14的Dark Mode下可以正常適配UI效果~.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1:在線工具 2:免費(fèi)圖片空間 niupic 、picb.cc 3:內(nèi)網(wǎng)映射工具NATAPP 4:在線版B-Tr...
    FFriday閱讀 161評(píng)論 0 0
  • 靈魂導(dǎo)師-張杰,你的歌聲是我不懈奮進(jìn)的力量,是我迷茫時(shí)最溫暖的港灣,我的未來(lái)不是夢(mèng),好久沒(méi)聽了,如今再聽真的太多感...
    百面書生24閱讀 260評(píng)論 0 0
  • 今天,該我上班。下午去接兒子,順便給他帶點(diǎn)好吃的。去的有點(diǎn)晚,我不確定他是否回家,只好打電話問(wèn)鄰居,她也不在家...
    二年級(jí)十班彭朝陽(yáng)媽媽閱讀 237評(píng)論 0 1
  • 大家千萬(wàn)不要以為那照片中的樹叫紅杉樹,紅杉樹只是我對(duì)她親切的叫法。就像你喜歡一個(gè)人就會(huì)給他起個(gè)小名,叫他的愛(ài)稱一樣...
    孔雀東南飛飛閱讀 1,021評(píng)論 1 18

友情鏈接更多精彩內(nèi)容