原文:watchOS 2 Tutorial Part 2: Tables
歡迎回到 watchOS 2 系列教程!
在第一部分,你通過開發(fā)第一個界面控制器,學習了 watchOS 2 開發(fā)的基礎(chǔ)知識廷蓉。
在教程的第二部分,會向你的 app 添加一個 table 來展示航班列表芋忿。
在這個過程中,你會學到:
- 如何添加一個新的界面控制器,往控制器中添加一個 table,并且設(shè)計原型行通熄。
- 如何創(chuàng)建 WKInterfaceController 的子類來填充這個列表,配置每一行的數(shù)據(jù),并且處理選中事件;
- 如何模態(tài)呈現(xiàn)界面控制器和向它傳遞數(shù)據(jù)來顯示。
介紹了這些,讓我們正式開始吧!
開始
打開 Watch\Interface.storyboard,從對象庫中拖動另一個界面控制器到 storyboard 畫板中,放在已經(jīng)存在的航班控制器的左邊惕鼓。
選中新的界面控制器,打開屬性檢查器然后做如下修改:
- 設(shè)置 Identifier 為 Schedule;
- 設(shè)置 Title 為 Air Aber;
- 勾選 Is Inital Controller;
- 勾選 Display Activity Indicator When Loading
你會注意到截圖的標題是深灰色的,而不是充滿活力的粉紅色。讓我們解決它。
打開文件檢查器然后改變 Globla Tint 為 #FA114F⊙魍玻現(xiàn)在看起來更好一點了:
下一步,從對象庫中拖動一個 Table 到這個新的界面控制器中:
在文本大綱中選中 Table Row Controller:
使用屬性檢查器設(shè)置它的 Identifier 為 FlightRow夷狰。使用 identifier 作為行的類型標示來通知列表哪一行應(yīng)該被實例化,它非常重要,所以需要你去設(shè)置岭皂。
設(shè)計行界面
首先修改行提供的默認布局。從文檔大綱中選擇 table row 中的組,使用屬性檢查器設(shè)置組的 Spacing 為6沼头、Height 為 Size To Fit Content爷绘。
table row 默認有個標準、固定的高度进倍。然而,大多數(shù)時候你會希望能顯示全部添加進去的界面元素,所以總是值得使用這種方式去修改高度屬性土至。
將一個分隔線從對象庫中拖到行中。你不會真的用它去分割什么,而是向你的行里添加一點視覺上的間隔猾昆。選中分割線,使用屬性檢查器做如下修改:
- 設(shè)置 Color 為 #FA114F;
- 設(shè)置 Vertical alignment 為 Center;
- 設(shè)置 Height 為 Relative to Container;
- 設(shè)置 Adjustment 為-4陶因。
最后檢查器應(yīng)該是這樣:
現(xiàn)在是時候填充這一行了!
從對象庫中拖一個Group到到 table row 中,放在分割線的后面。選中組,在屬性檢查器中修改如下屬性:
- 設(shè)置 Layout 為 Vertical;
- 設(shè)置 Spacing 為0;
- 設(shè)置 Width 為 Size To Fit Content垂蜗。
你可能注意到你經(jīng)常設(shè)置的 Spacing 屬性;它的作用僅僅是收緊組中的界面元素之間的間距讓它們在小屏幕上看起來更清晰楷扬。
拖動另一個 Group 到剛才添加的組中,做如下改變:
- 設(shè)置 Spacing 為4;
- 設(shè)置 Height 為 Fixed,值為32解幽。
往這個新的組中,添加一個 Label、一個 Image然后另一個 Label烘苹。這兩個標簽會顯示每個航班的起點和重點躲株。
現(xiàn)在你需要往 image 中添加圖片。下載圖片然后把它添加到 Watch\Assets.xcassets 中镣衡。這次創(chuàng)建一個新的叫做Plane的圖片,放在2x槽中:
重新打開 Watch\Interface.storyboard 然后選擇這個 image霜定。使用屬性檢查器,做如下改變:
- 設(shè)置 Image 為 Plane;
- 設(shè)置 Tint 為 #FA114F;
- 設(shè)置 Vertical alignment 為 Center;
- 設(shè)置 Width 為 Fixed,值為24;
- 設(shè)置 Height 為 Fixed,值為20。
選擇左邊的標簽設(shè)置它的文本為 MAN廊鸥。修改它的 Font 為 System, style 為 Semibold 和20的字體大小望浩。最后設(shè)置它的 Vertical alignment 為 Center。
同樣修改右邊的標簽,但是文本修改成 SFO黍图。你的 table row 現(xiàn)在應(yīng)該是這樣:
界面元素層次結(jié)構(gòu)像下面這樣:
你已經(jīng)完成大多數(shù) table row 界面的設(shè)計;之后需要增加航班號和狀態(tài)了曾雕。
從對象庫中拖動另一個 Group 到 table row ,確保它是包含起點終點標簽的那個組的子節(jié)點:
當你繼續(xù)設(shè)計這個界面,你可以看到更多使用嵌套組與混合布局來創(chuàng)建復(fù)雜布局的例子。根本就沒自動布局的事助被。
拖動兩個 label 到新的組中剖张。再次使用屬性檢查器對最左邊的標簽做如下的改變:
- 設(shè)置 Text 為 AA123;
- 設(shè)置 Text Color 為 Light Gray Color;
- 設(shè)置 Font 為 Caption 2;
- 設(shè)置 Vertical alignment 為 Bottom。
修改右邊的標簽:
- 設(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ù)據(jù)了搔弄。
填充列表
首先創(chuàng)建一個 WKInterfaceController 的子類為列表提供數(shù)據(jù)。
在項目導(dǎo)航中右擊 Watch Extension 組選擇New File...丰滑。在彈出的對話框中選擇 watchOS\Source\WatchKit Class 然后點擊Next顾犹。命名新的類為 ScheduleInterfaceController,確保它是 WKInterfaceController 的子類并且語言設(shè)置為 Swift:
點擊 Next,然后 Create。
當在代碼編輯器中打開了新創(chuàng)建的文件,刪除三個空的方法后就剩下重要的語句和類定義了褒墨。
重新打開 Watch\Interface.storyboard ,選擇新的界面控制器炫刷。在 Identity Inspector,修改 Custom Class\Class 為 ScheduleInterfaceController:
在選中界面控制器的基礎(chǔ)上,打開輔助編輯器確保它顯示的是 ScheduleInterfaceController。然后按住 Ctrl從 Table 往 ScheduleInterfaceController 里面拖拽來創(chuàng)建一個 outlet:
命名 outlet 為 flightTable,確保類型設(shè)置為 WKInterfaceTable 然后點擊 Connect郁妈。
現(xiàn)在你已經(jīng)設(shè)置好自定義的類并且為 table 創(chuàng)建了一個 outlet,是時候填充一些數(shù)據(jù)了!
關(guān)閉輔助編輯器,打開 ScheduleInterfaceController.swift,在 outlet 的下面添加如下代碼
var flights = Flight.allFlights()
這里你僅僅增加了一個 Flight 對象數(shù)組保存所有航班信息浑玛。
下一步,增加 awakeWithContext(_:) 的實現(xiàn):
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
flightsTable.setNumberOfRows(flights.count, withRowType: "FlightRow")
}
這段代碼通知 table 為 flights 數(shù)組中每個 flight 創(chuàng)建一個 Interface Builder 中的行實例。行的數(shù)量等于數(shù)組的大小,行的類型就是你在 storyboard 中設(shè)置的 identifier 的值噩咪。
編譯運行顾彰。你會看到列表已經(jīng)填充幾行數(shù)據(jù)了:
你應(yīng)該注意到列表中顯示的是 Interface Builder 中的占位文本。為了修復(fù)這種情況,我們通過添加 row controller 分別配置每一行的 label胃碾。
添加 Row Controller
在項目導(dǎo)航中右擊 Watch Extension 組然后選擇 New File...涨享。在出現(xiàn)的對話框中選擇 watchOS\Source\WatchKit Class 然后點擊 Next。命名新的類為 FlightRowContorller,確保這個類是 NSObject 的子類并且語言設(shè)置為 Swift 了:
點擊 Next,之后 Create仆百。
當新的文件在代碼編輯器中打開了,在類的頂部增加如下代碼:
@IBOutlet var separator: WKInterfaceSeparator!
@IBOutlet var originLabel: WKInterfaceLabel!
@IBOutlet var destinationLabel: WKInterfaceLabel!
@IBOutlet var flightNumberLabel: WKInterfaceLabel!
@IBOutlet var statusLabel: WKInterfaceLabel!
@IBOutlet var planeImage: WKInterfaceImage!
這里僅僅為每個你添加到 table row 中的 label 添加對應(yīng)的 outlet厕隧。稍后會連接它們。
下一步,在這些 outlet 下面添加如下這個屬性和對應(yīng)的屬性監(jiān)視器:
// 1
var flight: Flight? {
// 2
didSet {
// 3
if let flight = flight {
// 4
originLabel.setText(flight.origin)
destinationLabel.setText(flight.destination)
flightNumberLabel.setText(flight.number)
// 5
if flight.onSchedule {
statusLabel.setText("On Time")
} else {
statusLabel.setText("Delayed")
statusLabel.setTextColor(UIColor.redColor())
}
}
}
}
下面一步步講解是怎么回事:
- 你定義了類型為 Flight 的可選屬性。記住,這個類是在 Flight.swift 中定義的,而 Flight.swift 是你在教程1中添加到 Watch Extension 中的共享代碼的一部分;
- 添加了一個屬性監(jiān)視器,當屬性被賦值的時候會觸發(fā);
- 當 flight 為 nil 的時候會提前退出吁讨。因為它是可選的,只有當 Flight 對象有效的時候才去設(shè)置標簽的屬性帖族。
- 使用 flight 的相關(guān)屬性去設(shè)置標簽。
- 如果航班被延誤了,改變標簽的文本顏色,并相應(yī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。之后進行如下連線:
- destinationLabel: SFO
- flightNumberLabel: AA123
- originLabel: MAN
- statusLabel: On time
最后一步就是更新 ScheduleInterfaceController 來向列表中每個行控制器傳遞 Flight 對象艰亮。
打開 ScheduleInterfaceController.swift 之后在 awakeWithContext(_:) 底下添加如下代碼:
for index in 0..<flightsTable.numberOfRows {
if let controller = flightsTable.rowControllerAtIndex(index) as? FlightRowController {
controller.flight = flights[index]
}
}
這里使用 for 循環(huán)遍歷列表中每一行來訪問指定索引的行控制器闭翩。假如你成功設(shè)置了 controller 的 flight 屬性,會觸發(fā) didSet 監(jiān)視器并且設(shè)置 table row 中所有的標簽。
是時候看看勞動成果了迄埃。編譯運行疗韵。你會看到 table row 已經(jīng)被相關(guān)的航班信息填充了:
響應(yīng)行的選中事件
首先去重寫 WKInterfaceController 中主要負責處理 table row 選中事件方法定義。
往 ScheduleInterfaceController 中添加如下代碼:
override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) {
let flight = flights[rowIndex]
presentControllerWithName("Flight", context: flight)
}
這里使用行的索引來檢索出合適的航班信息侄非。之后顯示航班詳情界面,作為 context 屬性傳遞 flight 給這個界面蕉汪。presentControllerWithName(_:context:) 方法的name參數(shù)是你在 storyboard 中設(shè)置identifier的值。
現(xiàn)在你需要更新 FlightInterfaceController 來使用 context 的值來設(shè)置它的界面逞怨。
打開 FlightInterfaceController.swift,找到 awakeWithContext(_:) 者疤。替換這句代碼:
flight = Flight.allFlights().first!
為如下代碼:
if let flight = context as? Flight { self.flight = flight }
這里嘗試轉(zhuǎn)換 context 為 Flight 對象。如果轉(zhuǎn)換成功就可以使用它來設(shè)置self.flight,這會觸發(fā)屬性監(jiān)視器來設(shè)置界面叠赦。
最后,編譯運行驹马。如果你點擊某個 table row ,你會看到航班詳情界面模態(tài)彈出,顯示你選中的航班的詳情:
恭喜!你已經(jīng)完成你的第一個列表并且使用真實數(shù)據(jù)填充它;太棒了!
總結(jié)
這里目前教程的完整實例項目。
在這片教程中你學習到如何往界面控制器中添加一個列表,設(shè)計 table row 界面,創(chuàng)建一個行控制器,處理 table row 選中,顯示其他界面控制器,傳遞 contexts除秀。在這20分鐘里面做了很多事情!
如果您對本教程有任何疑問或意見糯累,請參加下面的論壇進行討論!