[譯] 如何在 macOS 上使用 NSTouchBar

本文翻譯自 raywenderlich.comHow to Use NSTouchBar on macOS,已咨詢對方網站,可至多翻譯 10 篇文章。
各位若有英語閱讀能力的話,還是先打賞然后去閱讀英文原吧??。
綜上,此翻譯版本僅供參考,謝絕轉載

也歡迎你點擊我的頭像查看我翻譯的其他 macOS 開發教程??

對了我跟著這個教程敲代碼的時候發現文中所有的 @available(OSX 10.12.1, *) 其實應為 @available(OSX 10.12.2, *),但是出于對原文的尊重沒有修改,請各位注意~

等了好久好久終于等到今天之后,Apple 終于發布了新款的 MacBook Pro,它最惹人矚目的應該就是那塊(小小的)觸屏了吧。

新款設備用全新的 Touch Bar 替代了原有的功能鍵,它們可擴展、支持多點觸控,更重要的是,Touch Bar 對開發者們完全開放,這意味著你的 macOS app 可以獲得一種全新的交互方式。

如果你是一個 macOS 開發者,你一定很希望自己的 app 能夠立刻使用上這項前沿科技。在這個教程中,我會將向你們展示如何使用全新的 NSTouchBar API 來為你的 macOS app 創建一個動態的 Touch Bar。

注意:這個教程需要 Xcode 8.1 或更高版本以及 macOS 10.12.1 (Build 16B2657) 或更高版本,否則的話你將無法運行 Touch Bar 模擬器。你可以在 ?關于本機里點擊數字版本號來查看 build 版本。


如果你的版本不夠,你可以在 Apple 的網站上 下載。

Touch Bar 是個啥?

如上文所述,Touch Bar 是一塊安裝在鍵盤上方的細長形的觸摸屏,它允許用戶使用一種全新的方式來與 app(以及 Mac)進行交互。

在 Touch Bar 上有三個默認的部分:

  • 系統按鈕:根據運行的 app,這里將會顯示一個系統級的按鈕,比如 esc;
  • App 區域:你的 app 可以控制的顯示區域,也就是我們的主舞臺;
  • 控制條:這里用于顯示你熟悉的控制按鈕,比如亮度、音量等。

和其它許多 Apple 的新科技一樣,Touch Bar 也擁有自己的《人機交互則例(Human Interface Guidelines)》,為了你的 app 和其它 Mac app 擁有統一的用戶體驗,你應當遵循這份則例。你可以點擊這里閱讀它。

概括說來,這份則例中比較重要的幾點有:

  • App 中的某個功能不應該只能在 Touch Bar 中使用:即使部份用戶還未升級到最新的硬件,你的 app 也應該盡量為他們提供一樣的功能。如果你決定為 Touch Bar 加入某些功能,請確保這個功能也能在 app 的其他某處也可以訪問到。另外 Touch Bar 是可以被用戶禁用的,所以也別太指望你的用戶能一直看到它;
  • Touch Bar 是鍵盤的延伸,而不是一個顯示屏:誠然,Touch Bar 是一個顯示屏,但是它不是顯示器的延伸,而是一個與 app 交互的窗口。你不應該在 Touch Bar 上用滾來滾去的內容或 blingbling 的警告打擾用戶的視線;
  • 快速響應:用戶在鍵盤上按下一個真實的按鍵時,按鍵會立即給予一個反饋(也就是被按下去了)。同理,用戶在 Touch Bar 上按下一個虛擬按鈕時,你也應該給他們提供即時的反饋。

如何讓你的 app 支持 Touch Bar

要讓你的 app 支持 Touch Bar,你需要使用 Apple 提供的兩個類:NSTouchBarNSTouchBarItem(當然還有他們的子類)。

某些 NSTouchBarItem 的子類提供了這些功能:

  • Slider:滑動調節某個值;
  • Popover:把更多功能藏入一個二級菜單中;
  • Color Picker:和名字一樣,用來選取顏色的咯???♀?;
  • Custom:這個子類是你的天下,你可以在它的里面塞入文本、按鈕以及其他各種各樣的控件。

從文字大小顏色到圖片內容,你可以隨意自定義你的 item,從而為你的用戶提供一個傳統鍵盤無法提供的、更加牛×的交互方式,但是請時刻請謹記《人機交互則例》。現在我們要開始動工啦。

準備開始

在開始敲代碼之前,請先點擊這里下載初始項目的源代碼。

我們要編寫的 app 是一個簡單的旅行記錄 app。打開初始項目,如果你的設備不支持 Touch Bar,請點擊 Xcode 菜單欄上的 WindowShow Touch Bar,Touch Bar 的模擬器就會出現在屏幕上。

編譯并運行你的 app,你將會看到 Touch Bar 上除了 esc 按鈕和控制條以外空空如也。

我們要做的第一步是告訴系統我們的 app 需要自定義 Touch Bar。打開 AppDelegate.swift,將這些代碼添加到 applicationDidFinishLaunching(_:) 方法中:

func applicationDidFinishLaunching(_ aNotification: Notification) {
  if #available(OSX 10.12.1, *) {
    NSApplication.shared().isAutomaticCustomizeTouchBarMenuItemEnabled = true
  }
}

這些代碼將會幫你搞定啟用 Touch Bar 所需要的各種操作,(在寫這篇文章的時候)Xcode 還沒有 macOS 10.12.1 的配套 SDK,所以你需要在 Touch Bar 相關的代碼周邊添加 #available(OS X 10.12.1, *),當然如果你忘了這件事,Xcode 會給你一個溫馨的提醒??。

打開 WindowController.swift,找到 makeTouchBar(),這個方法用于檢測 ViewController 是否含有一個可以被返回的 Touch Bar,如果有,它會把這個 Touch Bar 返回給 Window,然后呈現給用戶。現在,我們還沒有創建 Touch Bar,所以什么也不會發生。

在你開始創建自己的 Touch Bar 和 Touch Bar Item 之前,你需要注意這些類都需要獨一無二的 identifier(標識符),打開 TouchBarIdentifiers.swift,你將能看到兩個擴展定義了一些標識符:NSTouchBarCustomizationIdentifierNSTouchBarItemIdentifier

前往 ViewController.swift,并把這些帶碼添加到文件最后 // MARK: - TouchBar Delegate 注釋的后方:

@available(OSX 10.12.1, *)
extension ViewController: NSTouchBarDelegate {
  override func makeTouchBar() -> NSTouchBar? {
    // 1
    let touchBar = NSTouchBar()
    touchBar.delegate = self
    // 2
    touchBar.customizationIdentifier = .travelBar
    // 3
    touchBar.defaultItemIdentifiers = [.infoLabelItem]
    // 4
    touchBar.customizationAllowedItemIdentifiers = [.infoLabelItem]
    return touchBar
  }
}

在此處,通過重寫 makeTouchBar() 方法,你給你的 View 或 Window 創建了一個 Touch Bar,在這個方法中:

  1. 創建一個新的 TouchBar 并設置它的 delegate;
  2. 設置 customizationIdentifier(自定義標識符),每個 TouchBarTouchBarItem 都需要一個獨一無二的標識符;
  3. 設置 Touch Bar 的默認 item 標識符,這將會告訴 Touch Bar 它將會容納哪些 item;
  4. 這一步是允許用戶可以自定義的 item。作為參考,你可以打開 Finder,點擊菜單欄上的 顯示自定 Multi-Touch Bar看看自定義 Touch Bar 是什么效果。

接下來,我們還需要設置 .infoLabelItem 是什么樣子的,在同一個 extension 中添加:

func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItemIdentifier) -> NSTouchBarItem? {
    switch identifier {
    case NSTouchBarItemIdentifier.infoLabelItem:
      let customViewItem = NSCustomTouchBarItem(identifier: identifier)
      customViewItem.view = NSTextField(labelWithString: "\u{1F30E} \u{1F4D3}")
      return customViewItem
    default:
      return nil
    }
}

通過實現touchBar(_:makeItemForIdentifier:) 方法,你可以自定義你的 Touch Bar Item,在段代碼里,你創建了一個 NSCustomTouchBarItem,并把它的 view 設置為了 NSTextField

編譯并運行你的 app,你可以看到 Touch Bar 多了一個 item。

耶??!通過一番努力你得到了……兩個 emoji…好吧,現在我們來添加一些別的控件。

Text Field 和 Scrubber

makeTouchBar() 里,把 touchBar.defaultItemIdentifiers = [.infoLabelItem] 修改為:

touchBar.defaultItemIdentifiers = [.infoLabelItem, .flexibleSpace, .ratingLabel, .ratingScrubber]

這些代碼會讓 Touch Bar 顯示三個 item:一個 label、一個 scrubber 以及一個 .flexibleSpace。這是一個動態的間距,它可以把各種 item 按組進行整潔的分類。此外你還可以使用 .fixedSpaceSmall.fixedSpaceLarge 這兩個固定間距。

和之前的那個 label 一樣,你也需要自定義這些 item,把這些 cases 添加到 touchBar(_:makeItemForIdentifier:) 里的 switch

case NSTouchBarItemIdentifier.ratingLabel:
  // 1
  let customViewItem = NSCustomTouchBarItem(identifier: identifier)
  customViewItem.view = NSTextField(labelWithString: "Rating")
  return customViewItem
case NSTouchBarItemIdentifier.ratingScrubber:
  // 2
  let scrubberItem = NSCustomTouchBarItem(identifier: identifier)   
  let scrubber = NSScrubber()
  scrubber.scrubberLayout = NSScrubberFlowLayout()
  scrubber.register(NSScrubberTextItemView.self, forItemIdentifier: "RatingScrubberItemIdentifier")
  scrubber.mode = .fixed
  scrubber.selectionBackgroundStyle = .roundedBackground
  scrubber.delegate = self
  scrubber.dataSource = self
  scrubberItem.view = scrubber
  scrubber.bind("selectedIndex", to: self, withKeyPath: #keyPath(rating), options: nil)    
  return scrubberItem

一步一步來看:

  1. 為「評分」新建了一個新的 label item;
  2. 然后創建一個新的 item 用來展示 NSScrubber。這是一個 Touch Bar 特有的控件,它允許你在若干個項目中進行選擇。Scrubber 需要一個代理來處理事件,你需要做的是設置一個 delegate(初始項目的源代碼已經在 ViewController 里實現過這個協議了)。

編譯并運行你的 app,你將會看到 Touch Bar 里多出了兩個新的 item,當你點擊某個 scrubber 里的項目后,在 app 的主窗口里能看到數值的調整。

Segmented Control

接下來,我們來添加一個 Segmented Control。這個控件沒有使用 Delegate 模式,因此這剛好可以讓你體驗一下怎么設置 Touch Bar 里的 Target-Action(目標動作)。回到 makeTouchBar() 中,把這三個 item 添加到 defaultItemIdentifiers 里:

touchBar.defaultItemIdentifiers = [.infoLabelItem, .flexibleSpace, .ratingLabel, .ratingScrubber, .flexibleSpace, .visitedLabelItem, .visitedItem, .visitSegmentedItem]

以及把最后的三個 case 添加到 touchBar(_:makeItemForIdentifier:) 中:

case NSTouchBarItemIdentifier.visitedLabelItem:
  // 1
  let customViewItem = NSCustomTouchBarItem(identifier: identifier)
  customViewItem.view = NSTextField(labelWithString: "Times Visited")
  return customViewItem
case NSTouchBarItemIdentifier.visitedItem:
  // 2
  let customViewItem = NSCustomTouchBarItem(identifier: identifier)
  customViewItem.view = NSTextField(labelWithString: "--")
  customViewItem.view.bind("value", to: self, withKeyPath: #keyPath(visited), options: nil)
  return customViewItem
case NSTouchBarItemIdentifier.visitSegmentedItem:
  // 3
  let customActionItem = NSCustomTouchBarItem(identifier: identifier)
  let segmentedControl = NSSegmentedControl(images: [NSImage(named: NSImageNameRemoveTemplate)!, NSImage(named: NSImageNameAddTemplate)!], trackingMode: .momentary, target: self, action: #selector(changevisitedAmount(_:)))
  segmentedControl.setWidth(40, forSegment: 0)
  segmentedControl.setWidth(40, forSegment: 1)
  customActionItem.view = segmentedControl
  return customActionItem

一步一步看:

  1. 和之前一樣,創建一個簡單的 Label;
  2. 創建另一個 Label,但這一次使用 bind 來把 Label 要顯示的文本綁定到一個屬性上;
  3. 最后,創建一個 Segmented Control,并設置它的 action。你可以看到,為它設置一個 action 和其他常見控件是完全一樣的。

編譯并運行,除了 Scrubber,你現在還可以和 Segmented Control 交互了。此外,在 Touch Bar 里修改一個數值,app 的主窗口中也會顯示出來,反之亦然。

彩色按鈕

能讓用戶使用 Touch Bar 來進行「保存」操作是一個不錯的點子,因為這個按鈕和別的按鈕都不一樣,我們可以把它設置成綠色的。你可以使用 NSButtonbezelColor 屬性來給它設置一個特殊的顏色。

打開 TouchBarIdentifiers.swift,在 NSTouchBarItemIdentifier extension 里,添加這些代碼:

static let saveItem = NSTouchBarItemIdentifier("com.razeware.SaveItem")

這將會從頭開始創建一個標識符,以此允許你在 Touch Bar 里添加一個 item。

返回 ViewController.swift,添加一個新的 .flexSpace.saveItem 到 Touch Bar 的 defaultItemIdentifiers 里:

touchBar.defaultItemIdentifiers = [.infoLabelItem, .flexibleSpace, .ratingLabel, .ratingScrubber, .flexibleSpace, .visitedLabelItem, .visitedItem, .visitSegmentedItem, .flexibleSpace, .saveItem]

基本上完成了,最后一步是對按鈕進行一些設置。在 touchBar(_:makeItemForIdentifier:) 中添加最后一個 case

case NSTouchBarItemIdentifier.saveItem:
  let saveItem = NSCustomTouchBarItem(identifier: identifier)
  let button = NSButton(title: "Save", target: self, action: #selector(save(_:)))
  button.bezelColor = NSColor(red:0.35, green:0.61, blue:0.35, alpha:1.00)
  saveItem.view = button
  return saveItem

通過 bezelColor,你已經把這個按鈕成功地修改成了綠色。

編譯并運行,你會看到 Touch Bar 上有了一個綠色的按鈕,它和窗口中的 Save 按鈕擁有一樣的功能。

現在該做些啥?

你可以點擊這里下載最終完成的項目。

這些就是 Touch Bar 的基礎了。顯然,Apple 希望 Touch Bar 的開發過程越簡單越好,因此你可以盡快把這些特性盡快地帶給新 MacBook Pro 的用戶。

在這個教程中,你學到了:

  1. 如何設置你的 app,讓它能顯示 Touch Bar;
  2. 如何在 Touch Bar 里顯示靜止的 Label;
  3. 如何使用 binding(綁定)來添加一個動態的 Label;
  4. 如何在 Touch Bar 中添加控件,并處理它們的事件。

請不要在此停下!NSTouchBarNSTouchBarItem 中還有很多值得探索的特性。你可以試著在 Touch Bar 里添加一個 Popover,或者也可以試試在你的 app 里格式化一個文本,你還可以在試著去在 Interface Builder 里創建一個 Touch Bar。

How to Use NSTouchBar on macOS

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,460評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,067評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,467評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,468評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,184評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,582評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,616評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,794評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,343評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,096評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,291評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,863評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,513評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,941評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,190評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,026評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,253評論 2 375

推薦閱讀更多精彩內容

  • [譯] 零基礎 macOS 應用開發(二) 本文翻譯自 raywenderlich.com 的 macOS 開發經...
    SR2k閱讀 3,645評論 1 3
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,692評論 25 708
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,158評論 4 61
  • 李子+雞肉,還有一個不知名的涼性菜,這個六月的最后一周感受了斷食,當然,原因是拉肚子,第一天將近十次,水狀,第二天...
    團的花園閱讀 284評論 0 0
  • 老家的藍天是具有獨特氣質的。天氣晴朗時碧空如洗,藍的讓人陶醉,像是精美水粉畫;偶爾飄著幾多白云,潔潤鮮柔,...
    寨泉閱讀 1,056評論 1 7