這是一篇翻譯作品,水平有限,希望各位指正。各位同學最好去看原文:
Storyboards Tutorial in iOS 9: Part 1
注意:在04-01-2016更新了Xcode 7.3,iOS 9.3和Swift 2.2
教程團隊成員Matthijs Hollemans的原始貼子
故事板是一個令人興奮的功能,在iOS 5首次引入,為你構(gòu)建用戶界面節(jié)省大量的時間。
讓我用一張圖片向你展示storyboard是什么,這就是你在指南中你在教程中將要構(gòu)建的故事板:

你可能不知道這個應(yīng)用程序的功能,但你可以清楚地看到它有哪些場景,以及它們是如何關(guān)聯(lián)的。
故事板有許多優(yōu)點:
- 您可以在“場景”中直觀地布置所有視圖控制器,并說明它們之間的關(guān)聯(lián)關(guān)系。使用故事板可以更好的概述您的應(yīng)用程序的所有場景。
- 故事板可以描述各種場景的轉(zhuǎn)場。這些轉(zhuǎn)場被稱為"segues",您可以通過在故事板中連接視圖控制器來創(chuàng)建它們。感謝"segues"讓你需要更少的代碼來照顧你的UI。
- 故事板通過原型單元格和靜態(tài)單元格功能,可以更輕松地處理表格視圖。您幾乎可以完全在故事板編輯器中完成您的表格視圖設(shè)計,從而減少您必須編寫的代碼量。
- 故事板使您更容易使用自動布局,該功能允許您定義定義其位置和大小的元素之間的數(shù)學關(guān)系。這個強大的功能使得更容易處理不同屏幕尺寸和尺寸的設(shè)備。在本教程中,您將使用“自動布局”,但不在本教程的范圍之內(nèi)。您可以在自動布局教程 或者 觀看視頻系列獲取更多信息。
在這個故事板的教程中,你創(chuàng)建一個簡單的應(yīng)用程序,可以讓你創(chuàng)建一個游戲和玩家列表,并評估他們的技能水平。在這個過程中,你將學會用故事版完成最常見的任務(wù)。
入門
啟動Xcode并創(chuàng)建一個新項目。使用單視圖應(yīng)用程序模板作為起點。

填寫模板選項如下:
- Product Name: Ratings
- Organization Name: fill this in however you like
- Organization Identifier: the identifier that you use for your apps
- Language: Swift
- Devices: iPhone
- Use Core Data: not checked
- Include Unit Tests and UI Tests: not checked
Xcode創(chuàng)建項目后,Xcode主窗口看起來這樣:

新項目包含兩個類,AppDelegate 和 ViewController,本教程的主角:Main.storyboard文件。
這是一個只有肖像的應(yīng)用程序,繼續(xù)之前,找到 Deployment Info > Device Orientation取消屏幕左右旋轉(zhuǎn)選項。
讓我們看一看這個storyboard文件。在項目導航欄中點擊storyboard文件打開它,在界面生成器編輯器:

一個視圖控制器的官方故事板術(shù)語是“場景”,但你可以互換使用這些術(shù)語。在故事板中一個場景代表一個視圖控制器。
這里您可以看到一個包含空視圖的單視圖控制器。在視圖控制器的左側(cè)有箭頭指向表明,它是故事板的最開始顯示的視圖控制器。
在故事板編輯器中構(gòu)建布局是從對象庫通過拖動控件到你的視圖控制器完成(見右下角)的。
注意:你會注意到默認場景大小是一個正方形。Xcode 7在故事板中使用Auto Layout and Size Classes. Auto Layout and Size Classes允許您制作靈活的用戶界面,可以方便地調(diào)整大小,這對于支持各種大小的iPhone和iPad都很有用。去更多的學習Size Classes,看看我們的Adaptive Layout video tutorial series.
在這個教程中,你可以選擇故事板的大小,這樣可以更容易地了解最終屏幕上的布局。
在你開始之前,調(diào)整模擬器場景大小為iPhone 6 /6。
在視圖列表中選擇View Controller。如果你沒有看到“視圖列表”,單擊故事板畫布左下角的這個按鈕:

選擇Attributes Inspector下的Simulated Metrics,改變Size為iPhone 4.7 inch.

在storyboard的場景將顯示尺寸為iPhone 6/6S,大小為4.7英寸的iPhone模擬器。
“推斷”是在故事板的模擬器指標的默認設(shè)置。模擬器的指標是storyboard的視覺設(shè)計助手,展示最終設(shè)計界面。記住,他們不是在運行時使用的。
去感受storyboard的編輯過程。從右下角的對象庫拖動一些控件到空白視圖控制器。

當拖動控件時,它們將顯示在左邊的視圖列表內(nèi):

故事板顯示所有你的視圖控制器的內(nèi)容。當前在你的故事板只有一個視圖控制器(或場景),但在本教程的過程中,您將添加幾個其他視圖。
有一個視圖列表上面的場景稱為Dock:

碼頭顯示場景中的層級最高的對象。 每個場景至少有一個視圖控制器對象,第一響應(yīng)對象,和一個返回的item,但它也可能有其他頂級對象。碼頭便于連接到接口和方法。如果您需要將某物連接到視圖控制器,您可以簡單地拖動到它的圖標到Dock。
注意:你可能不會經(jīng)常使用第一響應(yīng)對象。這是一個代理對象,指的是任何對象在任何給定的時間具有第一響應(yīng)狀態(tài)。例如,你可以通過按鈕的觸摸事件成為第一響應(yīng)者:選擇器。如果通過按壓某一文本框獲得輸入焦點,也就是現(xiàn)在的第一響應(yīng)者,將文本粘貼進去。
運行這個應(yīng)用程序,它應(yīng)該與編輯器中設(shè)計完全相同(可能看起來不同于下面的截圖-這只是為了演示,并不會在以后的教程中使用):

您定義的單視圖控制器被設(shè)置為初始視圖控制器 – 但是應(yīng)用程序怎么加載它? 查看應(yīng)用程序代理方法找到答案。打開AppDelegate.swift文件,你可以看到下面的源代碼:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, >didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
@UIApplicationMain屬性在AppDelegate類文件的頂部指定為模塊的入口。
使用應(yīng)用程序委托繼承的故事板UIResponder,并具有UIWindow屬性是一項要求。所有的方法實際上都是空的。即使application(_:didFinishLaunchingWithOptions:)簡單地返回true。
秘密在Info.plist文件中。在項目導航器欄中,點擊Info.plist文件你會看到:

應(yīng)用程序的故事板用"UIMainStoryboardFile"作為關(guān)鍵字,亦稱為"Main storyboard file base name",以指定應(yīng)用程序啟動時必須加載的故事板的名稱。當此設(shè)置存在時,UIApplication將加載命名的故事板文件,自動從該故事板實例化“初始視圖控制器”,然后將該控制器的視圖放入一個新UIWindow對象。
您還可以在“常規(guī)選項卡”和“部署信息”部分的“項目設(shè)置”中看到這一點:

現(xiàn)在正式創(chuàng)建評級程序的幾個視圖控制器。
只需要將其添加到我的選項卡
你要建立的評級應(yīng)用程序有一個帶兩個屏幕的選項卡界面。使用故事板創(chuàng)建選項卡很容易。
你將從一個新的故事板開始,所以切換到Main.storyboard文件,刪除之前的視圖控制器。這可以通過單擊視圖列表中的視圖控制器并按“ Delete”鍵來完成。
將Tab Bar Controller從對象庫拖到畫布中。你可能首先想最大化你的Xcode窗口,因為Tab Bar控制器附帶兩個視圖控制器,你需要一些操作的空間。 你可以通過雙擊畫布放大和縮小,也可以通過按住Ctrl鍵單擊畫布并選擇縮放級別來設(shè)置縮放比例。
為了方便起見,請再次更改模擬器以將場景顯示為iPhone。如前所述,,在視圖列表中選擇Tab Bar Controller,在屬性檢查器,改成4.7英寸的尺寸。這也將改變在故事板中的兩個嵌入視圖控制器來模擬iPhone 6或6。

新的Tab Bar Controller預(yù)先配置兩個附加的視圖控制器,分別作為標簽。UITabBarController是所謂的容器視圖控制器因為它包含一個或者多個其他視圖控制器。其他兩個容器控制器是Navigation Controller和 Split View Controller (稍后您將使用Navigation Controller)。
容器關(guān)系由Tab Bar Controller和它包含的視圖控制器之間的箭頭來表示。嵌入關(guān)系,特別是指圖標所看到的箭頭中間的箭頭結(jié)構(gòu)。

注意:如果要將Tab Bar Controller及其附屬視圖控制器移動為一組,雙擊縮小,然后你可以按著?鍵并點擊選中拖動多個場景。可以一起移動他們。(選定的場景有一個淡藍色輪廓。)
將label拖到第一個視圖控制器(當前標題為“ Item 1”)中,雙擊,設(shè)置文字“First Tab”.也將label拖到第二視圖控制器(“Item2”)中,并設(shè)置文字“Second Tab”.你可以在標簽之間切換時看到實際發(fā)生的情況。
注意:編輯器縮放時,不能將控件拖到場景中。您將需要通過雙擊畫布返回到正常的縮放級別。
構(gòu)建并運行,你會在控制臺看到類似的內(nèi)容:
Ratings[18955:1293100] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?
幸運的,這里的錯誤很清楚 - 您從未設(shè)置程序入口,這意味著你在刪除了前面使用的場景后,沒有設(shè)置初始視圖控制器。要解決這個問題,選擇Tab Bar Controller找到屬性檢查器。選中Is Initial View Controller單選框。

在畫布中,指向已刪除視圖控制器的箭頭現(xiàn)在指向 Tab Bar Controller:

這意味著,當你運行應(yīng)用程序,程序會把Tab Bar Controller當做主屏幕。
運行程序試試看。該應(yīng)用程序現(xiàn)在有一個tab bar,您可以在兩個視圖控制器之間切換選項卡:

提示:要更改初始視圖控制器,還可以在視圖控制器之間拖動箭頭。
Xcode實際上是建立一個tabbed應(yīng)用程序模板(難怪叫標簽應(yīng)用模板),你可以使用,為了知道他如何很好的工作,你也可以手動創(chuàng)建一個Tab Bar Controller.
注意:如果連接超過五個場景的Tab Bar Controller,當你運行應(yīng)用程序時會自動獲取更多…選項卡”。相當靈巧!
添加一個Table View Controller
當前連接到Tab Bar Controller的兩個場景都是常規(guī)UIViewController實例。你可以用一個UITableViewController替換第一個場景。
單擊選中視圖列表中的第一個視圖控制器,之后刪除。從對象庫拖動一個新的Table View Controller 到畫布中以前的場景的位置:

現(xiàn)在,您希望將Table View Controller放置在導航控制器中。選擇Table View Controller,選擇Xcode菜單欄Editor\Embed In\Navigation Controller.這將另一個控制器添加到畫布中:

您還可以從對象庫中拖放導航控制器并嵌入表視圖,但嵌入命令可以比普通拖拽方法節(jié)省時間。
因為導航控制器也是一個容器視圖控制器(和Tab Bar Controller類似),它有一個關(guān)系箭頭指向表視圖控制器。您也可以在視圖列表中看到這些關(guān)系:

請注意,嵌入Table View Controller 的控制器給它一個導航欄。界面生成器自動將其放在那里,因為這個場景現(xiàn)在將顯示在導航控制器的框架內(nèi)。那不是一個真實的UINavigationBar 對象,是一個模擬的對象。模擬指標將推斷出場景周圍的環(huán)境,當它位于導航控制器內(nèi)部時,當它位于Tab Bar控制器內(nèi)時的選項卡欄等上顯示導航欄。
新的控制器是方形的。當你嵌入他們的Tab Bar Controller,會在一瞬間,他們將改變他們的模擬大小,以配合父場景。
要將這兩個新場景連接到Tab Bar Controller,從Tab Bar Controller拖拽到導航控制器。放開時,出現(xiàn)一個小的彈出菜單。選擇Relationship Segue – view controllers 選項:

這將在兩個場景之間創(chuàng)建新的關(guān)系箭頭。這也是一種嵌入關(guān)系,您可以看到與Tab Bar Controller所包含的其他控制器。
標簽欄控制器有兩個嵌入關(guān)系,各自是一個標簽。導航控制器本身與Table View Controller有嵌入關(guān)系。
創(chuàng)建此新連接時,將在選項卡欄控制器中添加新選項卡,簡單的命名"item".對于這個應(yīng)用程序,你希望這個新的場景成為第一個標簽,可以拖動選項卡改變他們的位置順序。

運行應(yīng)用程序試一下。第一個選項卡現(xiàn)在包含導航控制器內(nèi)的表視圖。

在添加應(yīng)用程序的一些實際功能之前,您需要理清故事板。您將命名第一個“ Players”標簽和第二個“ Gestures”。您不要在Tab Bar控制器本身上更改此選項,應(yīng)該在連接這些選項卡的視圖控制器中進行更改。
一旦將視圖控制器連接到Tab Bar控制器,就會獲得一個Tab Bar Item對象,您可以在視圖列表或場景底部看到它。您可以使用此標簽欄來配置標簽欄控制器上顯示的標題和圖像。
選擇導航控制器中的標簽欄項目,并在屬性檢查器中將其標題設(shè)置為"Players":

將視圖控制器的標簽欄項目從第二個選項卡重命名為"Gestures",方式相同。
精心設(shè)計的應(yīng)用程序也應(yīng)該在這些選項卡上放置一些照片。在本教程資源包含子文件夾命名的圖像。將該文件夾拖到項目中的Assets.xcassets子文件夾中。
返回Main.storyboard文件,在“ 玩家選項卡欄項目的屬性 ”檢查器中,選擇添加Players.png圖片。

注意視圖列表中的場景標題現(xiàn)在更改為"Players"。
或者,您可以雙擊導航欄并在其中更改標題。請注意,您應(yīng)該雙擊Table View Controller中的模擬導航欄,而不是導航控制器中實際的導航欄對象。
運行應(yīng)用程序,驚嘆標簽欄的神奇,創(chuàng)建不需要編寫一行代碼!

原型Cells
原型單元格允許您直接從故事板編輯器中輕松地為表格視圖單元格設(shè)計自定義布局。
Table View Controller附帶一個空白的原型單元格。單擊該單元格以選擇它,在“ 屬性檢查器”中將“ Style”選項設(shè)置為“ Subtitle”。這會立即改變單元格的外觀,以包含兩個標簽。
在故事板上擁有如此多的可堆疊內(nèi)容,有時可能難以點擊您想要的內(nèi)容。如果感覺麻煩,有幾個選擇。一個是您可以通過項目中畫布左側(cè)的“視圖列表”選擇。第二個是一個方便的快捷鍵:按住Ctrl + Shift并點擊你感興趣的區(qū)域。會彈出窗口,允許您直接通過光標下選擇任何元素。
如果您之前已經(jīng)使用過table views,并且手動創(chuàng)建了自己的單元格,則可以將其視為UITableViewCellStyle.Subtitle樣式。使用原型單元格,您可以像您剛才那樣選擇一種內(nèi)置單元格樣式,也可以創(chuàng)建自己的定制設(shè)計(快速編程)。
將屬性Accessory設(shè)置為Disclosure Indicator,并設(shè)置Identifierw為PlayerCell。所有原型單元都應(yīng)具有重用標識符,以便您可以在代碼中引用它們。

運行應(yīng)用程序,沒有任何改變。這不奇怪:您仍然必須為表添加數(shù)據(jù)源,以便知道要顯示哪些行。這正是你接下來要做的事情。
向項目添加新文件。在iOS / Source下選擇Cocoa Touch Class模板。將類命名為PlayersViewController并將其設(shè)為UITableViewController的子類。取消選中創(chuàng)建XIB文件。選擇Swift語言,然后點擊Next,然后點擊Create。

回到故事板文件并選擇表視圖控制器(確保您選擇實際的視圖控制器,而不是其中的一個視圖)。在身份檢查器中,將其類設(shè)置為PlayersViewController。這是通過您的自定義視圖控制器子類和故事板場景關(guān)聯(lián)的基本步驟。不要忘記這個否則你的類不會被使用!

從現(xiàn)在開始,當您運行應(yīng)用程序時,桌面視圖控制器就是該類的一個實例PlayersViewController。
表視圖應(yīng)顯示players列表,因此現(xiàn)在您將為應(yīng)用程序創(chuàng)建主數(shù)據(jù)模型 - 包含Player對象的數(shù)組。使用iOS / Source下的Swift File模板將命名為Player的新文件添加到項目中。
將Player.swift中的代碼替換為:
import UIKit
struct Player {
var name: String?
var game: String?
var rating: Int
init(name: String?, game: String?, rating: Int) {
self.name = name
self.game = game
self.rating = rating
}
}
這里沒什么特別的。Player只是這三個屬性的容器對象:玩家的名字,他們正在玩的游戲,以及1到5顆星的等級。
接下來,您將創(chuàng)建一個測試Player對象數(shù)組,然后將其賦值給PlayersViewController的一個數(shù)組。首先使用名為SampleData的Swift File模板創(chuàng)建一個新文件。將其添加到SampleData.swift的結(jié)尾:
//Set up sample data
let playersData = [
Player(name:"Bill Evans", game:"Tic-Tac-Toe", rating: 4),
Player(name: "Oscar Peterson", game: "Spin the Bottle", rating: 5),
Player(name: "Dave Brubeck", game: "Texas Hold 'em Poker", rating: 2) ]
在這里,您定義了一個名為playersData的常量,并向其分配了一個硬編碼的Player對象數(shù)組。
現(xiàn)在類 PlayersTableViewController: UITableViewController在PlayersViewController.swift中添加一個Player數(shù)組屬性,以保存玩家列表:
var players:[Player] = playersData
您可以在定義Player變量時簡單地在PlayersViewController中設(shè)置示例數(shù)據(jù)。但是由于以后可能會從plist或SQL文件提供此數(shù)據(jù),因此處理視圖控制器外部的數(shù)據(jù)加載是明智之舉。
現(xiàn)在你有一個充滿Player對象的數(shù)組,可以繼續(xù)把數(shù)據(jù)源和PlayersViewController關(guān)聯(lián)起來。仍然在PlayersViewController.swift中,將表視圖數(shù)據(jù)源方法替換為以下內(nèi)容:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return players.count
}
真正的工作發(fā)生在cellForRowAtIndexPath。將此方法替換為當前注釋掉的方法:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
let player = players[indexPath.row] as Player
cell.textLabel?.text = player.name
cell.detailTextLabel?.text = player.game
return cell
}
該方法dequeueReusableCellWithIdentifier(_:forIndexPath:)將檢查是否存在可再重用的單元格。如果沒有,它將自動分配一個原型單元格并將其返回給您。所有您需要做的是在故事板編輯器中提供您在原型單元格上設(shè)置的重用標識符 - 在本例中為PlayerCell。不要忘記設(shè)置該標識符,否則這個小方案將無法正常工作!
運行應(yīng)用程序,可以看到,桌面視圖中有玩家!

使用這些原型單元只需要幾行代碼。我覺得那真是太棒了。
注意:在這個應(yīng)用程序中,您只使用一個原型單元格,但如果您的表需要顯示不同類型的單元格,那么您可以簡單地向故事板添加其他原型單元格。您可以復制現(xiàn)有的單元格以創(chuàng)建一個新單元格,也可以增加Table View的Prototype Cells屬性的值。確保給每個單元格一個重用標識符。
設(shè)計您自己的原型單元格
使用標準單元格樣式對于許多應(yīng)用程序來說都可以,但是對于這個應(yīng)用程序,您需要在單元格的右側(cè)添加一個顯示Player評級(一到五顆星)的圖像。標準單元格樣式不支持該位置中的圖像視圖,因此您必須進行自定義設(shè)計。
切換回Main.storyboard,在表視圖中選擇原型單元格,并在屬性檢查器上將其Style屬性設(shè)置為Custom。默認標簽現(xiàn)在消失。
首先使cell高一點。更改“ Size inspector”檢查器中的“ Row Height”值(選擇“ Custom”后)或拖動單元格底部的句柄。使cell高60點。
將兩個Label對象從對象庫拖動到單元格中,并將它們大致放在標準標簽之上。只需使用屬性檢查器中的字體和顏色,然后選擇您喜歡的內(nèi)容。將頂部標簽的文本設(shè)置為“ Name”,將底部標簽設(shè)置為“ Game”。
使用Command +單擊選擇視圖列表中的Name和Game標簽,然后選擇Editor\Embed In\Stack View.
注意:堆疊視圖在iOS 9中是新的,并且很好地輕松地布局視圖集合。您可以在我們的新書“iOS 9”中了解有關(guān)堆棧視圖的更多信息。
將圖像視圖拖動到單元格中,并將其放置在公開指示符旁邊的右側(cè)。在尺寸檢查器中,使其寬81點,高35點。將其模式設(shè)置為中心(在“屬性”檢查器中的“查看”下),以便放入此視圖的任何圖像都不會拉伸。
Command +單擊視圖列表中的堆疊視圖和圖像視圖以選擇它們。選擇Editor\Embed in\Stack View. Xcode將創(chuàng)建一個包含這兩個控件的新的水平堆棧視圖。
選擇此新的水平堆棧視圖,并在屬性檢查器中將對齊方式更改為中心,將分布更改為等間距。
現(xiàn)在設(shè)置這個控件的一些簡單的自動布局。在故事板的右下角,點擊圖標:

將頂部約束更改為Top:0,Right:20,Bottom:0和Left:20。確保在值中高亮顯示四個紅色指針,如圖所示。點擊彈出窗口底部的Add 4 Constraints。

如果您的堆棧視圖有橙色約束,表明位置約束警告。要解決這個問題,請選擇水平堆棧視圖,然后選擇 Editor\Resolve Auto Layout Issues\Update Frames(在菜單的所選視圖部分)。堆疊視圖定位正確,橙色約束錯誤消失。
要將圖像視圖放置在堆疊視圖中,請選擇視圖列表中的圖像視圖,然后選擇Editor\Resolve Auto Layout Issues\Add Missing Constraints(在菜單的“所選視圖”部分)。
原型單元的最終設(shè)計看起來像這樣:

因為這是一個專門設(shè)計的cell,你不能再使用UITableViewCell的textLabel和detailTextLabel屬性來放置文本標簽。此單元格不再包含這些屬性標簽; 它們僅適用于標準cell類型。相反,您將使用tag值來查找標簽。
為了簡單起見,這里使用了tag。在本教程的后面,您將創(chuàng)建一個繼承自UITableViewCell的自定義類,并包含與單元格視圖上的標簽相對應(yīng)的屬性。
在“屬性”檢查器中,將“ Name”標簽的tag值設(shè)置為100,將“ Game”標簽的tag設(shè)置為101,將“ Image View”標簽的tag值設(shè)置為102。
然后打開PlayersViewController.swift在類的末尾新添加方法imageForRating,如下所示:
func imageForRating(rating:Int) -> UIImage? {
let imageName = "(rating)Stars"
return UIImage(named: imageName)
}
很簡單 - 根據(jù)評分返回不同的星形圖像。仍然在PlayersViewController中,更改tableView(_:cellForRowAtIndexPath:)方法為以下內(nèi)容:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath) //1
let player = players[indexPath.row] as Player //2
if let nameLabel = cell.viewWithTag(100) as? UILabel { //3
nameLabel.text = player.name
}
if let gameLabel = cell.viewWithTag(101) as? UILabel {
gameLabel.text = player.game
}
if let ratingImageView = cell.viewWithTag(102) as? UIImageView {
ratingImageView.image = self.imageForRating(player.rating)
}
return cell
}
以下是您代碼的含義:
1.dequeueReusableCellWithIdentifier將使用重用標識符(PlayerCell如果可用)將現(xiàn)有單元格出隊,如果不可用則創(chuàng)建一個新的標識符。
2.您查找與Player正在填充的行對應(yīng)的對象并將其分配player。
3.標簽和圖像由單元格上的標簽查找,并填充player對象中的數(shù)據(jù)。
應(yīng)該這樣做 現(xiàn)在再次運行應(yīng)用程序,可能看起來像這樣:

嗯,看起來不是很正確 - cell似乎被擠壓了。你確實改變了原型單元格的高度,但是表格視圖并沒有考慮到這一點。有兩種方法來解決它:您可以更改表視圖的行高屬性,或?qū)崿F(xiàn)該tableView(tableView:heightForRowAtIndexPath:)方法。前者在這種情況下很好,因為我們只有一種類型的單元格,我們提前知道高度。
注意:tableView(tableView:heightForRowAtIndexPath:)如果您提前不知道單元格的高度,或者不同的行可能具有不同的高度,才可以使用。
返回Main.storyboard,在“ 表視圖” 的“ Size inspector”檢查器中,將行高設(shè)置為60:
![]()
再次運行應(yīng)用程序,看起來好多了!
![]()
順便說一下,如果您通過拖動其句柄而不是鍵入值來更改單元格的高度,則表視圖的Row Height屬性也會自動更改。所以這可能是你第一次正常工作。
使用Cell的子類
table view已經(jīng)很好用,但是我不是使用tag值訪問原型cell的標簽和其他子視圖的大粉絲。如果您可以將這些標簽連接到接口,然后使用相應(yīng)的屬性,那將會更加整潔。事實證明,你可以。
使用Cocoa Touch Class模板向項目添加新文件。將它命名為PlayerCell并使它繼承自UITableViewCell。不要選擇創(chuàng)建XIB的選項,因為您的故事板中已有單元格。
在PlayerCell類中添加這些屬性,就在類定義的下面:
@IBOutlet weak var gameLabel: UILabel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ratingImageView: UIImageView!
所有這些變量都是IBOutlets,可以連接到故事板中的場景。
將此屬性添加到IBOutlets下方:
var player: Player! {
didSet {
gameLabel.text = player.game
nameLabel.text = player.name
ratingImageView.image = imageForRating(player.rating)
}
}
無論何時設(shè)置player屬性,它將使用正確的信息更新IBOutlets。
將方法imageForRating(:)從PlayersViewController 移動到PlayerCell類,以將單元格細節(jié)保留在同一個類中。
返回Main.storyboard文件,選擇原型單元格PlayerCell,并將其類更改為Identity inspector上的“PlayerCell”。現(xiàn)在,當您向表單查看數(shù)據(jù)源時dequeueReusableCellWithIdentifier(:forIndexPath:),將返回一個PlayerCell實例,而不是常規(guī)的UITableViewCell。
請注意,您給這個類與重用標識符相同的名稱 - 它們都稱為PlayerCell - 但這只是因為我喜歡保持一致。類名稱和重用標識符無關(guān),因此您可以按照不同的名稱命名。
現(xiàn)在將標簽和圖像視圖連接到這些接口。導航到故事板中的“ Connections Inspector”,然后從畫布或“視圖列表”中選擇“ Player Cell ”。從“ 連接”檢查器中的nameLabel Outlet拖動到“視圖列表”或“畫布” 中的“ Name”標簽對象。為了復用gameLabel和ratingImageView。
![]()
重要:您應(yīng)該將控件連接到table view cell,而不是view controller!您可以看到,無論何時數(shù)據(jù)源通過dequeueReusableCellWithIdentifier方法向表單視圖提供新的單元格,table view 不會提供實際的原型單元格,但是可以復用(或者如果可能的話,可以回收之前的單元格之一)。
這意味著PlayerCell在任何給定的時間將有不止一個實例。如果要將label從cell連接到視圖控制器上的接口,則標簽的幾個副本將嘗試使用相同的接口。這是自找麻煩。(另一方面,將原型單元格連接到視圖控制器上的動作完全正常,如果您UIControls的單元格上有自定義按鈕或其他按鈕,則可以這樣做)。
現(xiàn)在你已經(jīng)連接了這些屬性,你可以簡化數(shù)據(jù)源代碼。在PlayersViewController中,更改tableView(_:cellForRowAtIndexPath:)為:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
as! PlayerCell
let player = players[indexPath.row] as Player
cell.player = player
return cell
}
大概是這個樣子。你現(xiàn)在將通過dequeueReusableCellWithIdentifier方法獲取一個PlayerCell,然后你可以簡單地將正確的player傳遞給cell。在PlayerCell中設(shè)置player變量將自動將傳值到標簽和圖像視圖中,單元格將使用您在故事板中連接的IBOutlet。使用原型單元格如何使表格視圖不那么麻煩呢?
運行應(yīng)用程序并嘗試。它應(yīng)該仍然像以前一樣,但在幕后,它現(xiàn)在使用您自己的表視圖單元格子類!
最后說一句.能力一般,水平有限,歡迎指正,有問題可以發(fā)郵件到1432103394@qq.com