原文:watchOS 2 Tutorial Part 2: Tables
歡迎回到 watchOS 2 系列教程!
在第一部分,你通過開發(fā)第一個(gè)界面控制器,學(xué)習(xí)了 watchOS 2 開發(fā)的基礎(chǔ)知識(shí)坯临。
在教程的第二部分,會(huì)向你的 app 添加一個(gè) table 來展示航班列表沪曙。
在這個(gè)過程中,你會(huì)學(xué)到:
如何添加一個(gè)新的界面控制器,往控制器中添加一個(gè) table,并且設(shè)計(jì)原型行扶踊。
如何創(chuàng)建 WKInterfaceController 的子類來填充這個(gè)列表,配置每一行的數(shù)據(jù),并且處理選中事件;
如何模態(tài)呈現(xiàn)界面控制器和向它傳遞數(shù)據(jù)來顯示雇寇。
介紹了這些,讓我們正式開始吧!
開始
打開 Watch\Interface.storyboard,從對(duì)象庫中拖動(dòng)另一個(gè)界面控制器到 storyboard 畫板中,放在已經(jīng)存在的航班控制器的左邊魄缚。
選中新的界面控制器,打開屬性檢查器然后做如下修改:
設(shè)置 Identifier 為 Schedule;
設(shè)置 Title 為 Air Aber;
勾選 Is Inital Controller;
勾選 Display Activity Indicator When Loading
你會(huì)注意到截圖的標(biāo)題是深灰色的,而不是充滿活力的粉紅色君丁。讓我們解決它锨亏。
打開文件檢查器然后改變 Globla Tint 為 #FA114F。現(xiàn)在看起來更好一點(diǎn)了:
下一步,從對(duì)象庫中拖動(dòng)一個(gè) Table 到這個(gè)新的界面控制器中:
在文本大綱中選中 Table Row Controller:
使用屬性檢查器設(shè)置它的 Identifier 為 FlightRow棵癣。使用 identifier 作為行的類型標(biāo)示來通知列表哪一行應(yīng)該被實(shí)例化,它非常重要,所以需要你去設(shè)置。
設(shè)計(jì)行界面
首先修改行提供的默認(rèn)布局夺衍。從文檔大綱中選擇 table row 中的組,使用屬性檢查器設(shè)置組的 Spacing 為6狈谊、Height 為 Size To Fit Content。
table row 默認(rèn)有個(gè)標(biāo)準(zhǔn)沟沙、固定的高度河劝。然而,大多數(shù)時(shí)候你會(huì)希望能顯示全部添加進(jìn)去的界面元素,所以總是值得使用這種方式去修改高度屬性。
將一個(gè)分隔線從對(duì)象庫中拖到行中矛紫。你不會(huì)真的用它去分割什么,而是向你的行里添加一點(diǎn)視覺上的間隔赎瞎。選中分割線,使用屬性檢查器做如下修改:
設(shè)置 Color 為 #FA114F;
設(shè)置 Vertical alignment 為 Center;
設(shè)置 Height 為 Relative to Container;
設(shè)置 Adjustment 為-4。
最后檢查器應(yīng)該是這樣:
現(xiàn)在是時(shí)候填充這一行了!
從對(duì)象庫中拖一個(gè)Group到到 table row 中,放在分割線的后面颊咬。選中組,在屬性檢查器中修改如下屬性:
設(shè)置 Layout 為 Vertical;
設(shè)置 Spacing 為0;
設(shè)置 Width 為 Size To Fit Content务甥。
你可能注意到你經(jīng)常設(shè)置的 Spacing 屬性;它的作用僅僅是收緊組中的界面元素之間的間距讓它們?cè)谛∑聊簧峡雌饋砀逦?/p>
拖動(dòng)另一個(gè) Group 到剛才添加的組中,做如下改變:
設(shè)置 Spacing 為4;
設(shè)置 Height 為 Fixed,值為32。
往這個(gè)新的組中,添加一個(gè) Label喳篇、一個(gè) Image然后另一個(gè) Label敞临。這兩個(gè)標(biāo)簽會(huì)顯示每個(gè)航班的起點(diǎn)和重點(diǎn)。
現(xiàn)在你需要往 image 中添加圖片麸澜。下載圖片然后把它添加到 Watch\Assets.xcassets 中挺尿。這次創(chuàng)建一個(gè)新的叫做Plane的圖片,放在2x槽中:
重新打開 Watch\Interface.storyboard 然后選擇這個(gè) image。使用屬性檢查器,做如下改變:
設(shè)置 Image 為 Plane;
設(shè)置 Tint 為 #FA114F;
設(shè)置 Vertical alignment 為 Center;
設(shè)置 Width 為 Fixed,值為24;
設(shè)置 Height 為 Fixed,值為20炊邦。
選擇左邊的標(biāo)簽設(shè)置它的文本為 MAN编矾。修改它的 Font 為 System, style 為 Semibold 和20的字體大小。最后設(shè)置它的 Vertical alignment 為 Center铣耘。
同樣修改右邊的標(biāo)簽,但是文本修改成 SFO洽沟。你的 table row 現(xiàn)在應(yīng)該是這樣:
界面元素層次結(jié)構(gòu)像下面這樣:
你已經(jīng)完成大多數(shù) table row 界面的設(shè)計(jì);之后需要增加航班號(hào)和狀態(tài)了。
從對(duì)象庫中拖動(dòng)另一個(gè) Group 到 table row ,確保它是包含起點(diǎn)終點(diǎn)標(biāo)簽的那個(gè)組的子節(jié)點(diǎn):
當(dāng)你繼續(xù)設(shè)計(jì)這個(gè)界面,你可以看到更多使用嵌套組與混合布局來創(chuàng)建復(fù)雜布局的例子蜗细。根本就沒自動(dòng)布局的事裆操。
拖動(dòng)兩個(gè) label 到新的組中。再次使用屬性檢查器對(duì)最左邊的標(biāo)簽做如下的改變:
設(shè)置 Text 為 AA123;
設(shè)置 Text Color 為 Light Gray Color;
設(shè)置 Font 為 Caption 2;
設(shè)置 Vertical alignment 為 Bottom炉媒。
修改右邊的標(biāo)簽:
設(shè)置 Text 為 On time;
設(shè)置 Text Color 為 #04DE71;
設(shè)置 Font 為 Caption 2;
設(shè)置 Horizontal alignment 為 Right;
設(shè)置 Vertical alignment 為 Bottom踪区。
做完這些改變后,最后的 table row 看起來應(yīng)該像這樣:
列表在 Interface Builder 中開發(fā)完成,是時(shí)候填充一些數(shù)據(jù)了。
填充列表
首先創(chuàng)建一個(gè) WKInterfaceController 的子類為列表提供數(shù)據(jù)吊骤。
在項(xiàng)目導(dǎo)航中右擊 Watch Extension 組選擇New File...缎岗。在彈出的對(duì)話框中選擇 watchOS\Source\WatchKit Class 然后點(diǎn)擊Next。命名新的類為 ScheduleInterfaceController,確保它是 WKInterfaceController 的子類并且語言設(shè)置為 Swift:
點(diǎn)擊 Next,然后 Create白粉。
當(dāng)在代碼編輯器中打開了新創(chuàng)建的文件,刪除三個(gè)空的方法后就剩下重要的語句和類定義了传泊。
重新打開 Watch\Interface.storyboard ,選擇新的界面控制器鼠渺。在 Identity Inspector,修改 Custom Class\Class 為 ScheduleInterfaceController:
在選中界面控制器的基礎(chǔ)上,打開輔助編輯器確保它顯示的是 ScheduleInterfaceController。然后按住 Ctrl從 Table 往 ScheduleInterfaceController 里面拖拽來創(chuàng)建一個(gè) outlet:
命名 outlet 為 flightTable,確保類型設(shè)置為 WKInterfaceTable 然后點(diǎn)擊 Connect眷细。
現(xiàn)在你已經(jīng)設(shè)置好自定義的類并且為 table 創(chuàng)建了一個(gè) outlet,是時(shí)候填充一些數(shù)據(jù)了!
關(guān)閉輔助編輯器,打開 ScheduleInterfaceController.swift,在 outlet 的下面添加如下代碼
varflights = Flight.allFlights()
這里你僅僅增加了一個(gè) Flight 對(duì)象數(shù)組保存所有航班信息拦盹。
下一步,增加 awakeWithContext(_:) 的實(shí)現(xiàn):
override funcawakeWithContext(context: AnyObject?){super.awakeWithContext(context)? flightsTable.setNumberOfRows(flights.count, withRowType:"FlightRow")}
這段代碼通知 table 為 flights 數(shù)組中每個(gè) flight 創(chuàng)建一個(gè) Interface Builder 中的行實(shí)例。行的數(shù)量等于數(shù)組的大小,行的類型就是你在 storyboard 中設(shè)置的 identifier 的值溪椎。
編譯運(yùn)行普舆。你會(huì)看到列表已經(jīng)填充幾行數(shù)據(jù)了:
你應(yīng)該注意到列表中顯示的是 Interface Builder 中的占位文本。為了修復(fù)這種情況,我們通過添加 row controller 分別配置每一行的 label校读。
添加 Row Controller
在項(xiàng)目導(dǎo)航中右擊 Watch Extension 組然后選擇 New File...沼侣。在出現(xiàn)的對(duì)話框中選擇 watchOS\Source\WatchKit Class 然后點(diǎn)擊 Next。命名新的類為 FlightRowContorller,確保這個(gè)類是 NSObject 的子類并且語言設(shè)置為 Swift 了:
點(diǎn)擊 Next,之后 Create歉秫。
當(dāng)新的文件在代碼編輯器中打開了,在類的頂部增加如下代碼:
@IBOutletvar separator: WKInterfaceSeparator!@IBOutletvar originLabel: WKInterfaceLabel!@IBOutletvar destinationLabel: WKInterfaceLabel!@IBOutletvar flightNumberLabel: WKInterfaceLabel!@IBOutletvar statusLabel: WKInterfaceLabel!@IBOutletvar planeImage: WKInterfaceImage!
這里僅僅為每個(gè)你添加到 table row 中的 label 添加對(duì)應(yīng)的 outlet蛾洛。稍后會(huì)連接它們。
下一步,在這些 outlet 下面添加如下這個(gè)屬性和對(duì)應(yīng)的屬性監(jiān)視器:
// 1varflight: Flight? {// 2didSet {// 3ifletflight = flight {// 4originLabel.setText(flight.origin)? ? ? destinationLabel.setText(flight.destination)? ? ? flightNumberLabel.setText(flight.number)// 5ifflight.onSchedule {? ? ? ? statusLabel.setText("On Time")? ? ? }else{? ? ? ? statusLabel.setText("Delayed")? ? ? ? statusLabel.setTextColor(UIColor.redColor())? ? ? }? ? }? }}
下面一步步講解是怎么回事:
你定義了類型為 Flight 的可選屬性端考。記住,這個(gè)類是在 Flight.swift 中定義的,而 Flight.swift 是你在教程1中添加到 Watch Extension 中的共享代碼的一部分;
添加了一個(gè)屬性監(jiān)視器,當(dāng)屬性被賦值的時(shí)候會(huì)觸發(fā);
當(dāng) flight 為 nil 的時(shí)候會(huì)提前退出雅潭。因?yàn)樗强蛇x的,只有當(dāng) Flight 對(duì)象有效的時(shí)候才去設(shè)置標(biāo)簽的屬性。
使用 flight 的相關(guān)屬性去設(shè)置標(biāo)簽却特。
如果航班被延誤了,改變標(biāo)簽的文本顏色,并相應(yīng)地更新文本扶供。
當(dāng) row controller 設(shè)置完成,現(xiàn)在需要更新 table row 來使用它。
打開 Watch\Interface.storyboard 然后在文檔大綱中選擇 FlightRow裂明。使用 Identity Inspector,設(shè)置 Custom Class\Class 為 FlightRowController椿浓。
下一步,在文檔大綱中右擊FlightRow:
連接 planeImage 和 table row 中的 image,separator 與 table row 中的 separator。之后進(jìn)行如下連線:
destinationLabel: SFO
flightNumberLabel: AA123
originLabel: MAN
statusLabel: On time
最后一步就是更新 ScheduleInterfaceController 來向列表中每個(gè)行控制器傳遞 Flight 對(duì)象闽晦。
打開 ScheduleInterfaceController.swift 之后在 awakeWithContext(_:) 底下添加如下代碼:
forindexin0..
這里使用 for 循環(huán)遍歷列表中每一行來訪問指定索引的行控制器扳碍。假如你成功設(shè)置了 controller 的 flight 屬性,會(huì)觸發(fā) didSet 監(jiān)視器并且設(shè)置 table row 中所有的標(biāo)簽。
是時(shí)候看看勞動(dòng)成果了仙蛉。編譯運(yùn)行笋敞。你會(huì)看到 table row 已經(jīng)被相關(guān)的航班信息填充了:
響應(yīng)行的選中事件
首先去重寫 WKInterfaceController 中主要負(fù)責(zé)處理 table row 選中事件方法定義。
往 ScheduleInterfaceController 中添加如下代碼:
override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) {letflight = flights[rowIndex]? presentControllerWithName("Flight", context: flight)}
這里使用行的索引來檢索出合適的航班信息荠瘪。之后顯示航班詳情界面,作為 context 屬性傳遞 flight 給這個(gè)界面夯巷。presentControllerWithName(_:context:) 方法的name參數(shù)是你在 storyboard 中設(shè)置identifier的值。
現(xiàn)在你需要更新 FlightInterfaceController 來使用 context 的值來設(shè)置它的界面哀墓。
打開 FlightInterfaceController.swift,找到 awakeWithContext(_:) 趁餐。替換這句代碼:
flight = Flight.allFlights().first!
為如下代碼:
ifletflight = contextas? Flight { self.flight = flight }
這里嘗試轉(zhuǎn)換 context 為 Flight 對(duì)象。如果轉(zhuǎn)換成功就可以使用它來設(shè)置self.flight,這會(huì)觸發(fā)屬性監(jiān)視器來設(shè)置界面篮绰。
最后,編譯運(yùn)行后雷。如果你點(diǎn)擊某個(gè) table row ,你會(huì)看到航班詳情界面模態(tài)彈出,顯示你選中的航班的詳情:
恭喜!你已經(jīng)完成你的第一個(gè)列表并且使用真實(shí)數(shù)據(jù)填充它;太棒了!
總結(jié)
這里目前教程的完整實(shí)例項(xiàng)目。
在這片教程中你學(xué)習(xí)到如何往界面控制器中添加一個(gè)列表,設(shè)計(jì) table row 界面,創(chuàng)建一個(gè)行控制器,處理 table row 選中,顯示其他界面控制器,傳遞 contexts。在這20分鐘里面做了很多事情!