[譯] 零基礎(chǔ) macOS 應(yīng)用開發(fā)(二)
本文翻譯自 raywenderlich.com 的 macOS 開發(fā)經(jīng)典入門教程 ,已咨詢對(duì)方網(wǎng)站殉了,可至多翻譯 10 篇文章开仰。
還是 先打賞 然后去閱讀英文原吧,畢竟無論是 Xcode,抑或是官方的文檔众弓,還是各種最前沿的資訊都只有英文版本恩溅。
綜上,此翻譯版本僅供參考谓娃,謝絕轉(zhuǎn)載脚乡。
相關(guān)鏈接
零基礎(chǔ) macOS 應(yīng)用開發(fā)(一): 原文 / 譯文
零基礎(chǔ) macOS 應(yīng)用開發(fā)(二): 原文 / 譯文(本文)
零基礎(chǔ) macOS 應(yīng)用開發(fā)(三): 原文 / 譯文
歡迎回到我們的零基礎(chǔ) macOS 應(yīng)用開發(fā)教程的第二部分(共三部分)!
在第一部分(原文 / 譯文)滨达,你了解了如何安裝 Xcode奶稠、如何創(chuàng)建一個(gè)新的 app、添加 UI捡遍、連接代碼與 UI锌订、運(yùn)行 app、調(diào)試 app画株,以及尋求幫助辆飘。如果你對(duì)上述內(nèi)容還有任何不確定之處,再回去瀏覽一遍第一部分吧污秆。
在這一部分劈猪,你將會(huì)創(chuàng)建一個(gè)界面更加復(fù)雜的 app。你將會(huì)學(xué)到如何應(yīng)對(duì)可調(diào)整大小的窗口良拼,以及設(shè)計(jì)第二個(gè)頁面——偏好設(shè)置頁面战得,并讓你的 app 能跳轉(zhuǎn)到這個(gè)新創(chuàng)建的頁面。
準(zhǔn)備開始
和第一部分一樣庸推,打開 Xcode 并在歡迎頁面點(diǎn)擊 Create a new Xcode project常侦,或選擇 File 菜單中的 New Project…。接下來在 macOS 下的 Application 標(biāo)簽頁中選擇 Cocoa Application贬媒,并點(diǎn)擊 Next聋亡,把你的 app 命名為 EggTimer,確保 Language 選項(xiàng)為 Swift 以及 Use Storyboards 被選中际乘。點(diǎn)擊 Next 然后找一個(gè)合適的地方存儲(chǔ)這個(gè)項(xiàng)目坡倔。
編譯并運(yùn)行你的 app 來確保一切正常赡译。
EggTimer App
你將會(huì)開發(fā)的 app 叫做 EggTimer雇盖,它能幫助用戶倒計(jì)時(shí)搓谆,并顯示剩余的時(shí)間枚尼。App 的界面上會(huì)有一個(gè)雞蛋的圖標(biāo)成畦,隨著時(shí)間的臨近蜒什,雞蛋會(huì)被慢慢煮熟管毙;當(dāng)你的雞蛋煮熟時(shí)背桐,還會(huì)有一個(gè)提示音关拒。App 內(nèi)還有一個(gè)頁面會(huì)顯示此 app 的偏好設(shè)置佃蚜。
在 Project Navigator(項(xiàng)目導(dǎo)航器)中打開 Main.storyboard庸娱,正如第一部分所說的,你已經(jīng)擁有了三個(gè)場(chǎng)景:
- Application Scene(應(yīng)用場(chǎng)景)包含了只要 app 運(yùn)行著就會(huì)顯示的菜單欄谐算。
- Window Controller(窗口控制器)是定義了 app 窗口有怎樣行為(怎么調(diào)整大小熟尉、窗口怎么出現(xiàn)、app 是否會(huì)記住上次調(diào)整的大小和位置等等)的部分洲脂;其實(shí)一個(gè) Window Controller 可以管理多個(gè)窗口臣樱,但如果它們的屬性不同,你就需要多個(gè) Windows Controller 了腮考。
- View Controller 則顯示了窗口中的用戶界面——也就是你對(duì) UI 進(jìn)行布局的地方雇毫。
你注意到了嗎?有一個(gè)箭頭指向了 Window Controller踩蔚,這表明它是 app 啟動(dòng)時(shí)的 initial display(初始頁面)棚放。你可以在 Document Outline(文檔大綱)中選擇 Window Controller,然后在 Attributes Inspector(屬性檢查器)中查看這個(gè)設(shè)置馅闽。取消勾選 Is Initial Controller(用作首要控制器)后飘蚯,箭頭就消失了。因?yàn)槟阈枰鼇碜鳛槭滓目刂破鞲R玻?qǐng)把這個(gè)選項(xiàng)勾選上局骤。
Window Controller(窗口控制器)
在你開始著手 UI 前,請(qǐng)確保你已經(jīng)在 Project Navigator(項(xiàng)目導(dǎo)航器)中選擇了 Main.storyboard暴凑。點(diǎn)擊來選擇其中的 window(窗口)峦甩。在可視化編輯器中,Window Controller顯示了「View Controller」這行字现喳,因?yàn)樗粋€(gè) View Controller(視圖控制器)凯傲。在這個(gè) app 中,我們不希望用戶將窗口調(diào)整到 346 × 471 像素以下嗦篱,這兩個(gè)數(shù)值也將會(huì)是 app 啟動(dòng)時(shí)窗口的默認(rèn)大小冰单。
在 Utilities(工具集)面板中前往 Size Inspector(尺寸檢查器),設(shè)置 Content Size Width(內(nèi)容寬度)和 Content Size Height(內(nèi)容高度)分別為 346灸促;勾選 Minimum Content Size(最小內(nèi)容尺寸)的復(fù)選框诫欠,并確保其數(shù)值與內(nèi)容尺寸相同。現(xiàn)在浴栽,在可視化編輯器里的 Window Controller 的尺寸應(yīng)該已經(jīng)發(fā)生了變化荒叼,因此可能會(huì)蓋住其他元素,你可能需要重新排列一下它們吃度。
雖然不是必須的甩挫,但當(dāng)你把 View Controller 和承放它的 Window Controller 調(diào)整到一樣的大小后贴硫,后續(xù)操作會(huì)直觀很多椿每。點(diǎn)擊并選中 View Controller伊者,在 Size Inspector(尺寸檢查器)中設(shè)置 Width 和 Height 分別為 346 和 471。如果需要的話间护,重新排列一下界面上的各個(gè)元素防止它們重疊∫嗌現(xiàn)在可視化編輯器里的 Window Controller 和 View Controller 都有著一樣的尺寸了。
選中 WindowController 里的 Window汁尺,在 Attributes Inspector(屬性檢查器)中把它的名字更改為 Egg Timer法精,設(shè)置 Autosave name 為 EggTimerMainWindow,這樣用戶上次調(diào)整的窗口的尺寸和大小在 app 下次啟動(dòng)時(shí)就都會(huì)被記住了痴突。
如果你是一個(gè) iOS 開發(fā)者搂蜓,你應(yīng)該已經(jīng)處理過不同設(shè)備、屏幕尺寸辽装、屏幕旋轉(zhuǎn)方向下的適配問題了帮碰。在 macOS 開發(fā)過程中,你必須處理無限多種窗口尺寸和長寬比拾积,因此我在這里把窗口的默認(rèn)尺寸調(diào)整成了這么一個(gè)奇怪的數(shù)字殉挽。不過好消息是,Auto Layout 幫助你解決了這個(gè)問題拓巧。
布局 UI(一)
基本的 UI 包含了兩個(gè) Stack View(堆疊視圖):第一部分包含顯示剩余時(shí)間的 Label 和雞蛋的圖標(biāo)斯碌。第二個(gè)則在底部包含三個(gè)按鈕,我們先來制作按鈕:
- 在 Object Library(控件庫)中搜索「Button」
- 向 View Controller 中拖動(dòng)一個(gè) Gradient button
- 使用 Attributes Inspector(屬性檢查器)刪除它的圖像肛度,并把它 Title 設(shè)置為 Start
-
把字體改成 System 24
- 把按鈕拖大一些讓文字能顯示完全
- 選中 Start 按鈕傻唾,按下 Command? + D 兩次來復(fù)制兩份
- 把新復(fù)制的按鈕向右拖動(dòng)一些,并把他們的 Title 改成 Stop 和 Reset
- 同時(shí)選中三個(gè)按鈕承耿,然后點(diǎn)擊菜單欄上的 Editor → Embed In → Stack View
為了讓按鈕填滿整個(gè) Stack View策吠,選擇新創(chuàng)建的 Stack View,然后在 Attributes Inspector(屬性檢查器)里做出如下更改:
- Distribution(分配): Fill Equally(均分填滿)
- Spacing(間距): 0
在可視化編輯器的底部點(diǎn)擊 Add New Constraints(添加新的約束條件)瘩绒,設(shè)置左邊猴抹、右邊锁荔、底部和高度如上圖所示阳堕。將 Update Frames 設(shè)置為 Items of New Constraints跋理,然后點(diǎn)擊 Apply 4 Constraints(應(yīng)用四條約束)恬总。
Stack View 現(xiàn)在已經(jīng)放置好了,但這些按鈕似乎比 Stack View 矮了一些壹堰,在 Document Outline(文檔大綱) 中骡湖,按住 Control? 鍵的同時(shí)拖動(dòng) Start 按鈕到 Stack View 上响蕴,并選擇 Equal Heights(高度等同)浦夷。對(duì)另外兩個(gè)按鈕進(jìn)行同樣的操作劈狐。
現(xiàn)在懈息,包含了按鈕的 Stack View 已經(jīng)完全是我們想要的樣子了辫继。
編譯并運(yùn)行你的 app姑宽,嘗試著改變窗口的大小炮车,這些按鈕會(huì)緊緊地貼在窗口的底部,并自動(dòng)填滿整個(gè)窗口的寬度酣溃。
最后一步赊豌,在 Attributes Inspector(屬性檢查器)中取消選中 Enabled 來禁用 Stop 按鈕和 Reset 按鈕碘饼,在計(jì)時(shí)開始前艾恼,這兩個(gè)按鈕不應(yīng)該被啟用钠绍。
布局 UI(二)
第二個(gè) Stack View 包含剩余的時(shí)間以及雞蛋的圖片柳爽。向 View Controller 拖入一個(gè) Label,把它的 Title(標(biāo)題)設(shè)置為 6:00 并把 Alignment(對(duì)齊)設(shè)置為 center(居中)。默認(rèn)的字體(San Francisco)會(huì)自動(dòng)調(diào)整字符的間距——這意味著:隨著倒計(jì)時(shí)的時(shí)間的變化腋粥,數(shù)字會(huì)來回跳躍——這會(huì)很煩人隘冲。
把字體改成 Helvetica Neue 來避免這樣,然后把 Size(字體大新拚洹)設(shè)置為 100覆旱。這會(huì)使文字超出 Label 的范圍扣唱,所以調(diào)整 Label 的大小直到你可以看到完整的文字噪沙。
現(xiàn)在我們需要添加一張圖片正歼,在 Object Library(控件庫)的搜索框中輸入「image」朋腋,這會(huì)過濾出很多長得很像的控件,你需要的是 Image View穷绵,將它拖動(dòng)到 View Controller 中剩余時(shí)間 Label 的下方仲墨。
下載這個(gè)工程需要的資源文件(一些圖片和一個(gè)聲音文件)目养,解壓碎并打開 Egg Images 文件夾癌蚁∨停回到 Xcode伐蒂,在 Project Navigator(項(xiàng)目導(dǎo)航器)中點(diǎn)擊 Assets.xcassets恩沛。
把這六個(gè)圖片拖動(dòng)到 Assets Library(資產(chǎn)庫)中复唤,然后它們就可以在你的 app 中使用了佛纫。因?yàn)閳D片的文件名中帶有「@2x」呈宇,它們會(huì)被自動(dòng)分配到各個(gè)圖像資產(chǎn)的 @2x 區(qū)域。
關(guān)于 @2x 請(qǐng)自行搜索 Mac/iOS 的 HiDPI適應(yīng)蜈漓,譯者注
前往 Main.storyboard融虽,選中你剛剛添加的 Image View有额,在 Attributes Inspector(屬性檢查器)中點(diǎn)擊 Image(圖像)下拉框茴迁,在這個(gè)下拉框中你可以看到很多內(nèi)置的圖片以及你剛剛添加的圖片堕义,選中 stopped倦卖。
現(xiàn)在我們來制作第二個(gè) Stack View:選中顯示剩余時(shí)間的 Label 和剛剛調(diào)整好的 Image View糖耸,在菜單欄上點(diǎn)擊 Editor → Embed In → Stack View邦危。然后我們來調(diào)整一下這個(gè) Stack View倦蚪,使它填滿剩余的空間陵且。點(diǎn)擊可視化編輯器底部的 Add New Constrains(添加新的約束)慕购,然后添加下圖所示的約束條件:
正我們所需要的获洲,Stack View 填滿了剩下的空間贡珊,但這個(gè) Image View 太小了门岔,選中它,將它左右兩您的約束按照下圖設(shè)置為 User Standard Value(使用標(biāo)準(zhǔn)值):
在 Attributes Inspector(屬性檢查器)中牢裳,設(shè)置 Scaling(縮放) 為 Proportionally Up or Down(等比放大或縮型)局嘁。
編譯并運(yùn)行 app悦昵,調(diào)整窗口的大小但指,看看 UI 元素是否如預(yù)期地自動(dòng)地適應(yīng)了窗口尺寸棋凳。
連接 UI 和代碼
在第一部分(原文 / 譯文)中,你已經(jīng)知道了你需要使用 @IBOutlets
和 @IBActions
來連接你的 UI 和代碼拍棕。在這個(gè)例子中,你需要為以下元素設(shè)置 @IBOutlets
:
- 剩余時(shí)間的 Label
- 顯示雞蛋的 Image View
- 三個(gè)按鈕
此外幅垮,這三個(gè)按鈕還需要@IBAction
來響應(yīng)用戶的點(diǎn)擊操作忙芒。在 Project Navigator(項(xiàng)目導(dǎo)航器)中,先選中 Main.storyboard潮峦,再按住 Option?忱嘹,點(diǎn)擊 ViewController.swift拘悦,這樣就可以在 Assistant Editor(輔助編輯器分苇,即左右分欄)中打開它了医寿。如果你的屏幕空間不足靖秩,點(diǎn)擊右上角的按鈕來隱藏 Utilities(工具集) 和 Navigator(導(dǎo)航器) 面板柒爸。
和第一部分一樣捎稚,選中剩余時(shí)間的 Label今野,按住 Control? 鍵的同時(shí)拖動(dòng)它到 ViewController
類中催什,將名稱設(shè)置為 timeLeftField
蒲凶,對(duì)雞蛋的 Image View 進(jìn)行一樣的操作旋圆,它的名字設(shè)置為 eggImageView
。然后是三個(gè)按鈕刻肄,他們的名字分別設(shè)置成 startButton
敏弃、stopButton
和 resetButton
虹茶。
這三個(gè)按鈕還需要 @IBAction
蝴罪,按住 Control? 并拖動(dòng) Start 按鈕到代碼中,但這次在彈出窗口中將 Connection 設(shè)置為 Action欢搜,并把它的名字設(shè)置為 startButtonClicked
炒瘟,對(duì)另外兩個(gè)按鈕重復(fù)以上動(dòng)作,為它們添加名為 stopButtonClicked
和 resetButtonClicked
的 @IBAction廓推。
如果你和我一樣也經(jīng)常忘了把 Connection 修改為 Action 的話,你會(huì)得到 @IBOutlets
而不是 @IBAction
专缠,如果你要?jiǎng)h除這些多余的 @IBOutlet
藤肢,先把這一行代碼刪除省骂,再轉(zhuǎn)到 Utilities(工具集)里的 Connections Inspector(連接檢查器)钞澳,你會(huì)看到 Referencing Outlets 部分里有兩個(gè)項(xiàng)目,點(diǎn)擊錯(cuò)誤連接旁的 × 來刪除它兰吟,然后重新連接你的 @IBAction
(這一次別忘了修改 Action 哦??)混蔼。
ViewController
里的代碼現(xiàn)在看起來應(yīng)該像這樣:
在第三部分中悔政,你將會(huì)給這些動(dòng)作添加代碼谋国,現(xiàn)在我們關(guān)閉 Assistant Editor(輔助編輯器)闷盔,如果你剛剛隱藏了 Navigator(導(dǎo)航器) 和 Utilities(工具集),重新打開它們藐吮。
菜單
在 Main.storyboard,在 Application Scene(應(yīng)用場(chǎng)景) 中點(diǎn)擊 menu bar(菜單欄)泥从,Xcode 提供的模版已經(jīng)內(nèi)置了一些默認(rèn)的按鈕纱烘,但是在這個(gè) app 中擂啥,很多按鈕都派不上用場(chǎng),最簡單的辦法來瀏覽菜單里的項(xiàng)目是使用 Document Outline(文檔大綱)山宾,點(diǎn)擊左側(cè)的小三角來顯示 View 菜單和里邊的內(nèi)容。
菜單欄的結(jié)構(gòu)是由一些 Menus(菜單)和 Menu Items(菜單項(xiàng)目)組成的,切換到 Utilities(工具集)里的 Identity Inspector(身份檢查器)接剩,這樣你就能看到,當(dāng)你點(diǎn)擊各個(gè)菜單項(xiàng)目的時(shí)候鹃两,真正觸發(fā)的東西是什么了俊扳。Main Menu 是 NSMenu
的實(shí)例,它包含了 NSMenuItem
組成的數(shù)組:View 菜單就是這個(gè)數(shù)組的一個(gè)成員梯醒。
View 菜單包含一個(gè)子菜單(NSMenu
),里面包含了它自己的 NSMenuItems
号胚,值得注意的是嗡综,Separator
(分割線)是 NSMenuItem
的特殊形式极景。
我們要做的第一件事是刪除這個(gè) app 里不需要的菜單項(xiàng)驾茴,在 Document Outline(文檔大綱)中選中 File 菜單盼樟,按下鍵盤上的 Delete? 鍵把它刪掉。如果你是在 Visual Editor(可視化編輯器)中選中它并刪除的話锈至,你會(huì)把 File 菜單里的菜單項(xiàng)都刪掉晨缴,然后只剩下一個(gè)空空如也的菜單峡捡,如果你不小心這樣做了击碗,選中那個(gè)空白然后再次按下 Delete? 來移除它。
這段話的后半段沒有看太明白们拙,望各位指正稍途,原文是: If you select it in the Visual Editor and delete, you will only have deleted the menu inside the File menu item, so you will be left with a space in the menu bar. If this happens, select the space and press Delete again to remove it.
繼續(xù)刪除其他的 Menu,直到你只剩下了 EggTimer砚婆、Window 和 Help 菜單械拍。
現(xiàn)在你需要添加一個(gè)新的菜單來模擬三個(gè)按鈕的操作,在 Object Library(控件庫) 中搜索 「menu」装盯,請(qǐng)注意坷虑,菜單欄中的每一個(gè)項(xiàng)目(如 File、Help )都是 Menu Item埂奈,點(diǎn)擊它之后打開的才是 Menu迄损,拖動(dòng)一個(gè) Menu Item 到菜單欄中 Egg Timer 和 Window 之間的地方,它會(huì)顯示成一個(gè)藍(lán)色的方框挥转,這是因?yàn)樗鼉?nèi)部還沒有一個(gè)帶有標(biāo)題的 Menu海蔽。
現(xiàn)在想那個(gè)藍(lán)色的方框拖入一個(gè) Menu,如果你覺得那個(gè)方框太小拖不準(zhǔn)的話绑谣,你也可以拖到 Document Outline(文檔大綱)里我們剛剛創(chuàng)建的 Item 的下方。新的 Menu 還沒有標(biāo)題拗引,但他已經(jīng)有了三個(gè)菜單項(xiàng)借宵。
選中 Menu(不是 item),切換到 Attributes Inspector(屬性檢查器)并把 Title(標(biāo)題)設(shè)置為 Timer矾削,選中 Item 1壤玫,雙擊它(或在屬性檢查器里)把他的標(biāo)題改為 Start豁护。
在 Attributes Inspector(屬性檢查器)中點(diǎn)擊 Key Equivalent(快捷鍵),然后按下 Command? + S 來設(shè)置快捷鍵欲间。通常情況下 Command? + S 是保存的快捷鍵楚里,但是你已經(jīng)刪除了 File 菜單,這樣的設(shè)置并不會(huì)有沖突猎贴,但在一般情況下我們還是不要復(fù)用常見快捷鍵的比較好班缎。
用同樣的方法把第二、三個(gè) item 的標(biāo)題分別設(shè)置為設(shè)置為 Stop 和 Reset她渴,快捷鍵分別為 Command? + X 和 Command? + R达址。
在可視化編輯器中 Menu Bar 的上方,你能看到三個(gè)按鈕趁耗,切換到 Identity Inspector(身份檢查器)沉唠,然后依次點(diǎn)擊這三個(gè)按鈕,你可以看到苛败,他們分別連接著 Application满葛、First Responder、和 AppDelegate罢屈。First Responder 通常就是當(dāng)前處于最前端的 View Controller纱扭,它可以從 Menu Item 那里接收動(dòng)作。
按住 Option? 的同時(shí)點(diǎn)擊 ViewController.swift儡遮,然后在你剛剛為按鈕們添加的 @IBAction
的下方添加以下代碼:
// MARK: - IBActions - menus
@IBAction func startTimerMenuItemSelected(_ sender: Any) {_
startButtonClicked(sender)
}
@IBAction func stopTimerMenuItemSelected(_ sender: Any) {
stopButtonClicked(sender)
}
@IBAction func resetTimerMenuItemSelected(_ sender: Any) {
resetButtonClicked(sender)
}
這些方法會(huì)在菜單項(xiàng)被點(diǎn)擊時(shí)被調(diào)用乳蛾,然后它們會(huì)去調(diào)用界面上那三個(gè)按鈕的 IBAction 方法。其實(shí)鄙币,你可以讓 Menu Item 直接調(diào)用按鈕的方法(即把 Menu Item 的 IBAction 也拖到之前定義的按鈕的 IBAction 上)肃叶,但在這里我選擇這種方式,因?yàn)檫@樣的話十嘿,調(diào)試時(shí)這一系列事件會(huì)更加清晰明了∫虿眩現(xiàn)在保存文件并退出 Assistant Editor(協(xié)助編輯器)。
按住 Control? 鍵的同時(shí)绩衷,把 Start 菜單項(xiàng)拖動(dòng)到象征著 First Responder 的橙色立方體上蹦魔,一個(gè)包含了很多選項(xiàng)的窗口會(huì)彈出來,在鍵盤上輸入「sta」來快速滾動(dòng)到我們所需要的 startTimerMenuItemSelected 并選擇它咳燕。
用同樣的方法把 Stop 菜單項(xiàng)和 Reset 菜單項(xiàng)分別連接至 stopTimerMenuItemSelected
和 resetTimerMenuItemSelected
∥鹁觯現(xiàn)在當(dāng) EggTimer 窗口處于最前端時(shí),點(diǎn)擊菜單上的按鈕將會(huì)調(diào)用這些方法招盲。
但是還有一個(gè)問題:這三個(gè)按鈕在同一時(shí)刻并非同時(shí)都是可用的低缩,而且菜單欄上的按鈕需要體現(xiàn)出他們是否可用。這個(gè)功能無法在 ViewController
里實(shí)現(xiàn)曹货,因?yàn)樗粫?huì)一直處于 First Responder 的狀態(tài)咆繁,所以我們需要轉(zhuǎn)戰(zhàn) AppDelegate
讳推。
打開 Main.storyboard 并確保這幾個(gè) Menu 都處于可見狀態(tài),在 Project Navigator(項(xiàng)目導(dǎo)航器)中按住 Option? 鍵的同時(shí)點(diǎn)擊 AppDelegate.swift玩般,按住 Control? 鍵的同時(shí)把 Start 菜單項(xiàng)拖動(dòng)到 AppDelegate
中银觅,創(chuàng)建一個(gè)名為 startTimerMenuItem
的 IBOutlet。
用同樣的方法為另外兩個(gè)菜單項(xiàng)創(chuàng)建名為 stopTimerMenuItem
的 resetTimerMenuItem
IBOutlet坏为。
在第三部分中你將了解到如何用代碼來根據(jù)需要啟用和禁用這些菜單項(xiàng)究驴,但是現(xiàn)在你需要做的是關(guān)閉自動(dòng)啟用與禁用,因?yàn)樵谝话闱闆r下久脯,app 會(huì)檢測(cè)當(dāng)前的 First Responder 是否包含了 menu item 所連接的 action(一般就是 IBAction)纳胧,如果沒有,就會(huì)將他們禁用帘撰。在這個(gè) app 中跑慕,我們希望自己來控制這件事情,所以選中 Timer 菜單項(xiàng)摧找,在 Attributes Inspector(屬性檢查器) 中取消選中 Auto Enables Item(自動(dòng)啟用項(xiàng)目)核行。
偏好設(shè)置窗口
現(xiàn)在 EggTimer app 的主界面已經(jīng)看起來很好了,但他還需要一個(gè)偏好設(shè)置窗口來讓用戶選擇他們想把雞蛋煮多熟蹬耘。
偏好設(shè)置界面將會(huì)顯示在一個(gè)單獨(dú)的窗口中芝雪,且擁有它自己的 Window Controller。這是因?yàn)楸M管在一個(gè) Window Controller 中顯示多個(gè) View Controller 是完全可行的综苔,但它們會(huì)共享這個(gè) Window Controller 的所有屬性惩系,而偏好設(shè)置窗口的默認(rèn)大小與主窗口不一樣,而且不可以調(diào)整大小如筛。
打開 Main.storyboard堡牡,如果 Assistant Editor(輔助編輯器)還處于打開狀態(tài),把它關(guān)閉杨刨。在 Objects Library(控件庫)中搜索「window」晤柄,向 Visual Editor(可視化編輯器)中拖入一個(gè) Window Controller,Xcode 會(huì)自動(dòng)為你創(chuàng)建一個(gè) View Controller 來盛放需要現(xiàn)實(shí)的內(nèi)容妖胀。重新排列一下窗口中的內(nèi)容以便你能更清楚地看清所有內(nèi)容芥颈,并讓你新創(chuàng)建的 Window Controller 更靠近菜單欄。
打開菜單欄上的 EggTimer 菜單赚抡,按住 Control? 鍵的同時(shí)拖動(dòng) Preferences… 菜單項(xiàng)到我們新創(chuàng)建的 Window Controller 上爬坑,這將會(huì)創(chuàng)建一個(gè) Segue(轉(zhuǎn)場(chǎng)),也就是說用戶點(diǎn)擊 Preferences… 時(shí)怕品,這個(gè) Window Controller 就會(huì)把我們新創(chuàng)建的 View Controller 給顯示出來妇垢。
偏好設(shè)置面板需要顯示一個(gè)新的 View Controller,所以你需要為它創(chuàng)建一個(gè)新的 View Controller 類肉康。在 Project Navigator(項(xiàng)目導(dǎo)航器)中闯估,選中已經(jīng)存在了的 ViewController.swift 文件,這會(huì)確保新建的文件存儲(chǔ)在與之相同的組中(Xcode 用 Group 來管理文件)吼和,然后在 Xcode 的菜單上點(diǎn)擊 File → New → File…涨薪。
選擇 macOS → Cocoa Class 然后點(diǎn)擊 Next,設(shè)置類名為 PrefsViewController
炫乓,父類為 NSViewController
刚夺,語言選擇 Swift,不要勾選 Also create XIB file for user interface(同時(shí)為 UI 創(chuàng)建 XIB 文件)末捣,然后點(diǎn)擊 Next 和 Create 來保存文件侠姑。
回到 Main.storyboard,選中我們新創(chuàng)建的 View Controller箩做,請(qǐng)確保你選擇的是 View Controller 而不是它的 View莽红,在 Document Outline(文檔大綱)里選擇會(huì)更容易些。在 Identity Inspector(身份檢查器)中邦邦,把它的 Class 設(shè)置為 PrefsViewController
安吁。
選擇偏好設(shè)置窗口里的 Window Controller,前往 Attributes Inspector(屬性檢查器)把它的標(biāo)題設(shè)置為 ** Preferences**燃辖。Autosave Name 保持留空鬼店,這樣每次窗口出現(xiàn)的時(shí)候都會(huì)出現(xiàn)在桌面的中央。取消選中 Minimize 和 Resize 復(fù)選框黔龟,這樣窗口的大小就是固定的了妇智。
前往 Size Inspector(屬性檢查器),把 Content Size 設(shè)置為寬 416 高 214氏身。在 Initial Position(默認(rèn)位置) 下方的兩個(gè)下拉框中分別選擇 Center Horizontally 和 Center Vertically巍棱。
選中 View 中的 PrefsViewController,在 Size Inspector(尺寸檢查器)中把它的寬和高分別設(shè)置為 416 和 214观谦。
PrefsViewController
需要顯示一個(gè)用來選擇時(shí)間的下拉框和一個(gè)用來選擇時(shí)間的滑塊拉盾,它們都包含各自的 Label 用于顯示標(biāo)題,還有兩個(gè)按鈕:Cancel 和 OK豁状,以及一個(gè)用于顯示當(dāng)前選擇時(shí)間的 Label捉偏。
拖動(dòng)以下控件到 View Controller 中并按下表設(shè)置它們的屬性:
Label | 設(shè)置 title 為「Preset Egg Timings:」 |
Pop Up Button | |
Label | 設(shè)置 title 為「Custom Egg Timing:」 |
Label | 設(shè)置 title 為 「6 minutes」 |
Horizontal Slider | |
Push Button | 設(shè)置 title 為 「Cancel」 |
Push Button | 設(shè)置 title 為「OK」 |
因?yàn)檫@個(gè)窗口不能調(diào)整大小,控件們會(huì)按照你的布局進(jìn)行顯示泻红,所以我們不需要給它設(shè)置 Auto-layout 約束條件夭禽。把界面上的元素排列好,Xcode 自動(dòng)會(huì)用藍(lán)色的參考線來幫助你進(jìn)行對(duì)齊谊路。將顯示「6 minutes」的 Label 的右邊拖動(dòng)到幾乎與邊界持平讹躯,因?yàn)樗赡苄枰@示更多內(nèi)容。雙擊 Pop Up Button,你會(huì)看到三個(gè)子項(xiàng)潮梯,把他們的標(biāo)題分別設(shè)置為:
- For runny soft-boiled eggs (barely set whites): 3 minutes
- For slightly runny soft-boiled eggs: 4 minutes
- For custardy yet firm soft-boiled eggs: 6 minutes
再從 ** Objects Library(控件庫)**中拖動(dòng)兩個(gè) Menu Item骗灶、一個(gè) Separator Menu Item 和另一個(gè) Menu Item 到下拉框中,如果你覺得直接拖動(dòng)它們到界面上有點(diǎn)難度的話秉馏,也可以拖動(dòng)到 Document Outline(文檔大綱)的相應(yīng)位置耙旦。
給剛剛拖入的三個(gè)子項(xiàng)分別設(shè)置標(biāo)題:
- For firm yet still creamy hard-boiled eggs: 10 minutes
- For very firm hard-boiled eggs: 15 minutes
- Custom
我其實(shí)一點(diǎn)都不知道怎么煮雞蛋,所以我從 The Kitchn 找到了以上的時(shí)間和描述萝究。
選中下拉框本體(而不是那幾個(gè)子項(xiàng))免都,把它的 Selected Item(已選中項(xiàng)目)設(shè)置為那個(gè)「6 minute」的選項(xiàng)。
現(xiàn)在你需要讓你的 app 知道用戶在下拉框中到底選擇了哪個(gè)子項(xiàng)帆竹,依次選中下拉菜單中的每一個(gè)自子項(xiàng)绕娘,在 Attributes Inspector(屬性檢查器)中設(shè)置它們的 Tag 分別為對(duì)應(yīng)的分鐘數(shù):3、4栽连、6险领、10、15(Custom 子項(xiàng)設(shè)置為 0)升酣。
現(xiàn)在選擇 Slider舷暮,在 Attributes Inspector(屬性檢查器)中將 Tick marks(刻度數(shù)) 設(shè)置為 25,Minimum Valve 設(shè)置為 1噩茄,Maximum Valve 設(shè)置為 25下面,并勾選 Only stop on tick marks(只能選擇刻度),你需要將滑塊向下移動(dòng)一些來適應(yīng)新出現(xiàn)的刻度绩聘。因?yàn)橹挥挟?dāng)用戶在下拉框種選擇了 Custom 的時(shí)候才會(huì)啟用沥割,所以我們還需要取消選擇 Enabled。
連接偏好設(shè)置里的元素和代碼
在 Project Navigator(項(xiàng)目導(dǎo)航器)中按住 Option? 鍵的同時(shí)點(diǎn)擊 PrefsViewController凿菩,如果你需要更多空間的話隱藏掉側(cè)邊面板机杜。你需要為下拉框、滑動(dòng)條和顯示“6 minutes”的 Label 添加 @IBOutlet
衅谷。把它們依次拖動(dòng)到 PrefsViewController.swift
中椒拗,并給這些 IBOutlet 分別起名:
- Popup:
presetsPopup
- Slider:
customSlider
- Label:
customTextField
接下來,按住 Control? 鍵的同時(shí)拖動(dòng)以下項(xiàng)目來創(chuàng)建 @IBAction
(別忘了把 Connection 改成 Action 哦~):
- Popup:
popupValueChanged
- Slider:
sliderValueChanged
- Cancel button:
cancelButtonClicked
- OK button:
okButtonClicked
現(xiàn)在你的代碼看起來應(yīng)該像這樣:
至此获黔,偏好設(shè)置面板窗口的布局就已經(jīng)完成了蚀苛,編譯并運(yùn)行你的 app 并在 EggTimer 菜單中選擇 Preferences 菜單,檢查一下打開的偏好設(shè)置窗口玷氏,然后點(diǎn)擊紅色的關(guān)閉按鈕來關(guān)閉這個(gè)窗口堵未。
App 圖標(biāo)
UI 部分還剩一步:為你的 app 添加圖標(biāo)。你之前已經(jīng)下載了一個(gè)包含了這個(gè) app 所需要的所有文件的資產(chǎn)文件夾盏触,而且已經(jīng)添加了一些圖片到 Assets.xcassets 中渗蟹,現(xiàn)在我們需要打開這個(gè)文件夾并找到 egg-icon.png 文件块饺。
在 Project Navigator(項(xiàng)目導(dǎo)航器)中選擇 Assests.xcassets,點(diǎn)擊 AppIcon 并拖動(dòng) egg-icon.png 到 Mac 256pt 1x 的方框中雌芽。正如第一部分所說的授艰,在真正的產(chǎn)品中你需要提供所有尺寸的圖標(biāo),但在這個(gè) app 中膘怕,一個(gè)圖標(biāo)就足夠了想诅。
編譯并運(yùn)行你的 app召庞,看看新的圖標(biāo)有沒有出現(xiàn)在 Dock 中岛心,如果沒有,你可能需要在 Xcode 的 Product 菜單中點(diǎn)擊 Clean篮灼,然后再試一次忘古。