storyboard搭建项目_Storyboard使用教程一
Storyboard是最先在iOS 5引入的一項振奮人心的特性,大幅縮減構建App用戶界面所需的時間。
要介紹Storyboard是什么,我打算從這張圖講起。下面是您將會在本教程中構建的Storyboard:
image
或許你現在并不清楚這個App是用來做什么的,但其中有哪些頁面,還有頁面間的關聯都一目了然。這就是使用Storyboard的力量。
如果App中包括很多不同的頁面,使用Storyboard可以幫你減少實現頁面間跳轉的膠合代碼。過去的開發者對應每個視圖控制器分別創建界面設計文件(即“nib”或“xib”文件),現在,只要一個Storyboard就可以包攬所有視圖控制器的界面設計和他們之間的關聯。
Storyboard有很多優點:
使用Storyboard可以更好地了解App中所有的視圖以及它們之間的關聯的概況。掌控全局更加容易,因為所有的設計都包含在一個文件中,而不是分散在很多單獨的nib文件中。
Storyboard可以描述不同視圖之間的過渡,這種過渡叫做“segue”(譯注:意為“轉場”,而“Storyboard”原意為“分鏡”,均源自電影術語),你可以直接在Storyboard中通過連接不同的視圖控制器來創建轉場。多虧有了轉場,打理界面的代碼比以前要少了。
Storyboard通過新的原型表項(prototype cell)和靜態表項(static cell)特性,讓處理表視圖(table view)的工作更加輕松。幾乎完全可以在Storyboard編輯器里搞定表視圖的設計,同樣也減少了代碼量。
Storyboard使自動布局(Auto Layout)更易用。自動布局功能可以讓你通過界面元素之間的數學關系定義來確定元素的位置和尺寸,極大簡化了不同尺寸屏幕的適配工作。自動布局不在本教程范圍之內,若想了解更多,請參閱自動布局入門。
如果你非常討厭Interface Builder,或者推崇用代碼搞定所有界面的話,Storyboard可能不適合你。個人主張是代碼能少寫就少寫,特別是UI代碼,所以Storyboard簡直就是為我準備的一把利器。
如果你想繼續使用nib,那就繼續用吧,要知道Storyboard里是可以使用nib的,兩者并非互斥關系。
本教程中,你會了解Storyboard可以做什么,我們將構建一個簡單的App,功能大致是創建玩家列表和游戲列表,然后給玩家技能評分。過程中你會學到大多數可以用Storyboard完成的最常見的任務。
準備開始
打開Xcode,創建新項目。選用 Single View Application 模板:
image
如下填寫模板選項:
Product Name: Ratings
Organization Name: 隨意填寫
Company Identifier: 你的App使用的標識符,逆域名記法
Language: Swift
Devices: iPhone
Use Core Data: 不選
項目創建完成后,Xcode的主界面應該如下圖所示:
image
這個新項目包含2個類:AppDelegate 和 ViewController, 此外還有本教程的主角: Main.storyboard 文件。
這是一個只支持豎屏顯示的App,所以在繼續之前,在項目綜合設置上面看到的 Deployment Info - Device Orientation下面把 Landscape Left和Landscape Right 選項勾掉。
接下來我們看一下Storyboard,點擊項目瀏覽器中的 Main.storyboard 就可以在Interface Builder中打開。
一個視圖控制器在Storyboard中的官方術語是“場景(scene)”,但這兩種叫法是相通的。一個視圖控制器在Storyboard中可以叫做場景。
這里可以看到一個包含空視圖的視圖控制器。在這個視圖控制器左邊指向它的箭頭表明它是這個Storyboard中要顯示的第一個視圖控制器。
在Storyboard編輯器中設計布局的方法是從右下角的Object Library(對象庫)中把控件拖入視圖控制器,非常容易。
注:你會注意到默認場景是一個正方形。Xcode 6默認為Storyboard和nib文件開啟自動布局(Auto Layout)和尺寸歸類(Size Classes)。自動布局和尺寸歸類這兩項新技術可以構建易于調整大小的用戶界面,這對支持不同尺寸的iPhone和iPad非常有用。
自動布局由iOS 6引入,尺寸歸類由iOS 8引入。兩者都需要一定的學習曲線,所以本教程中暫不使用,但為了支持不同的設備尺寸,以后還是要接觸到的。
在繼續探索之前,先在當前Storyboard的 File inspector(文件檢查器) 中禁用Auto Layout和Size Classes,如圖:
Xcode詢問操作時,選擇保留 iPhone 的尺寸歸類數據,然后點擊 Disable Size Classes :
現在,場景變成了4英寸iPhone尺寸的樣子。
從右下方的對象庫里把一些控件拖到空的視圖控制器上,感受一下Storyboard編輯器的工作方式:
控件拖進來之后應該會在左邊的文檔大綱(Document Outline)中顯示:
如果沒看到文檔大綱,請點擊Storyboard面板左下角的這個按鈕:
Storyboard顯示所有視圖控制器的內容,當前的Storyboard中僅有一個視圖控制器(場景),在本教程后面我們會添加其他場景。
在場景上面還有一個縮小的文檔大綱,稱作Dock:
Dock顯示場景中最上層的對象,每個視圖都至少有一個 視圖控制器(View Controller) 對象,一個 第一響應者(First Responder) 對象,一個 出口(Exit) 項。除此之外也可以有其他的最上層對象。Dock方便連接outlet和action,當你想把某個對象連接到視圖控制器時,只需把它拖到Dock的圖標上。
注:你可能不常用到First Responder。這是指任意對象在任意時間具有第一響應狀態的代理對象。舉個例子,把一個按鈕的Touch Up Inside事件拖到First Responder的 cut: 選擇器上。如果在某時有一個文本字段具有輸入焦點,此時按下該按鈕,就可以讓該文本字段,也就是現在的第一響應者,把其中的文本剪切到剪貼板。
運行App,它看起來應該和你在編輯器中設計的樣子相同(截圖可能與你的不同,僅供演示參考,教程后面不會用到):
你定義的這個視圖控制器被設定為初始視圖控制器,但App是如何加載的呢?答案就在應用代理(application delegate)當中,打開 AppDelegate.swift ,你會看到如下代碼:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
// Override point for customization after application launch.
return true
}
上面的 @UIApplicationMain 標記指定這個AppDelegate類為該模塊的入口。使用Storyboard時,應用代理必須繼承 UIResponder ,必須含有 UIWindow 屬性,幾乎所有的方法都是空的,甚至 application(_:didFinishLaunchingWithOptions:) 也只是返回true而已。
秘密藏在 Info.plist 文件里,在Supporting Files Group里找到并點擊 Info.plist ,你會看到這一條:
Storyboard用 UIMainStoryboardFile
(即Main storyboard file base name鍵) 來指明App啟動時必須加載的Storyboard的名稱。當設置生效,UIApplication
會加載對應名稱的Storyboard文件,自動將該Storyboard中的初始視圖控制器實例化,并將其納入一個新的 UIWindow
對象中。
在General分頁的Project Settings和Deployment Info中也可以看到:
接下來真正開始創建包含多個視圖控制器的評分App吧。
添加分頁標簽
你要構建的這個評分App中含有由分頁標簽控制的兩個視圖,使用Storyboard創建分頁標簽非常容易。
現在這個Storyboard需要從頭做起,切回 Main.storyboard 然后把剛才做的視圖控制器刪掉。在文檔大綱中點擊 View Controller 并按下delete鍵即可。
把一個 Tab Bar Controller(分頁欄控制器) 從對象庫拖到面板中。你可能需要讓Xcode最大化,因為分頁欄控制器附帶兩個視圖控制器,需要騰出更多空間,你可以雙擊面板進行縮放,或者按住control點擊面板,在彈出的菜單中選擇縮放比例。
一個新增的分頁欄控制器默認附帶兩個額外的視圖控制器,每個分頁標簽一個控制器。由于UITabBarController包含一個或多個其他的視圖控制器,它被稱作 容器視圖控制器。此外還有兩種常見的容器視圖控制器,Navigation Controller(導航控制器)和Split View Controller(分割視圖控制器)。
容器關系由分頁欄控制器和他所包含的視圖控制器之間的箭頭表示,如下圖這個箭頭上的圖標表示嵌入關系。
注:如果你想一起移動分頁欄控制器和附帶的視圖控制器的話,先縮小畫面,然后按住command點擊,或直接拖選多個場景,這樣可以同時移動多個場景。(選中的場景輪廓為淡藍色。)
在第一個視圖控制器(當前名稱為“Item 1”)中拖入一個Label(文本標簽)并將其文本設為 "First Tab",同理,在第二個視圖控制器中加入文本為"Second Tab"的Label,這樣你就可以看到分頁標簽切換后的變化。
注:編輯器縮小時無法向場景內拖入控件,此時需要先在面板上雙擊,回到正常縮放比例。
構建,運行,你會在Console中看到類似信息:
Ratings[18955:1293100] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?
幸運的是這條報錯信息講得很清楚:未設置入口,也就是剛才刪除最先使用的那個場景之后沒設置初始視圖控制器。為解決問題,選中這個分頁欄控制器,然后在 Attributes Inspector(屬性檢查器) 中選定 Is Initial View Controller 。
注:在Xcode 6.2中,上述選項已被控件取代。先選中當前分頁欄控制器,然后從對象庫里把一個Storyboard Entry Point(Storyboard入口)拖上去,可以拖到控制器上面,也可以拖入文檔大綱。
現在,一開始的那個箭頭已經指向當前的分頁欄控制器了:
注:Xcode 6.2 beta在這里可能會崩潰,如果出現問題,請選中該分頁欄控制器的某個視圖控制器,把入口拖上去,然后再把入口箭頭拖到分頁欄控制器上。
這意味著啟動App時, UIApplication 會把此分頁欄控制器作為主畫面。運行App試一試,現在App下面有分頁標簽欄了,可以用分頁標簽在兩個視圖控制器之間切換。
提示:你也可以通過拖拽視圖控制器之間的箭頭來改變初始視圖控制器。
其實在前面你也可以選用Xcode自帶的標簽分頁式App模板(即Tabbed Application模板)創建App,但最好還是了解一下工作原理,以后有必要的時候也能手動創建分頁欄控制器。
注:如果在分頁欄控制器上連接超過5個場景,App在運行時會自動將其歸入一個More分頁標簽,干凈利落。
添加表視圖控制器
現在附屬于分頁欄控制器的兩個場景都是標準UIViewController實例,接下來你會把其中第一個分頁標簽對應的場景替換為UITableViewController。
在文檔大綱中點選第一個視圖控制器并將其刪除,然后從對象庫中把一個新的 Table View Controller(表視圖控制器)拖到原場景所在的地方。
接下來把表視圖控制器放到導航控制器(Navigation Controller)中,選中表視圖控制器,在Xcode菜單中選擇 EditorEmbed InNavigation Controller ,現在面板中又加入了另一個控制器:
你也可以從對象庫中拖入導航控制器后再嵌入表視圖,但這個操作一般來講使用菜單命令會更省時。
與分頁欄控制器類似,導航控制器也是容器視圖控制器,所以有一個關系箭頭指向表視圖控制器,你也可以在文檔大綱中看到這個關系:
注意,嵌入表視圖控制器后,Interface Builder自動給它添加了一個導航欄,因為當前視圖是在導航控制器的框架中顯示的。它并不是實際存在的UINavigationBar對象,只是模擬顯示情況。
打開表視圖控制器的屬性檢查器,上面可以看到 Simulated Metrics(模擬度量)選項:
Storyboard中的默認值為“Inferred(推斷)”,意思是該場景在處于導航控制器中時會顯示導航欄,處于分頁欄控制器中時會顯示分頁欄等等。你可以修改這些設置,但是請記住,這只是方便你設計界面時參考的模擬顯示,并不會在運行時使用,僅僅是視覺設計的輔助工具,用來表示視圖最后應該是什么樣子。
接下來把這兩個新場景連接到分頁欄控制器,按住control從分頁欄控制器拖到導航控制器,松手時會彈出一個小選單,選擇 Relationship Segue – view controllers 選項:
這會在兩個場景間新建一個關系箭頭,與分頁欄控制器包含控制器一樣,都是嵌入關系。
分頁欄控制器有兩個嵌入關系,分別對應兩個分頁標簽。導航控制器上有一個表視圖控制器的嵌入關系。
創建這個連接后,分頁欄控制器中會添加一個新分頁標簽,默認名稱為“Item”。在這個App中,你希望第一個分頁標簽對應這個新場景,直接拖動分頁標簽,更改順序:
運行App試試看,現在第一個分頁標簽中包含一個嵌入在導航控制器中的表視圖。
在添加實際功能之前,你還需要再修整一下Storyboard,將第一個分頁標簽命名為"Players",第二個命名為"Gestures"。不是在分頁欄控制器上修改,而是在這些分頁標簽對應的視圖控制器上修改。
將一個視圖控制器連接到分頁欄控制器后,在場景下面和文檔大綱中會看到它被賦予的 分頁欄項(Tab Bar Item) 對象,可以用來設置分頁標簽的標題和在分頁欄控制器中看到的圖標。
選中導航控制器中的分頁欄項,在屬性檢查器中將標題設為Players:
以同樣的方法把第二個分頁標簽對應場景欄目改名為Gestures。
一個設計精良的App應該為分頁標簽附上圖標。教程資源中有個Image文件夾,把這個文件夾拖入項目,選擇“Copy items if needed”并點擊Finish:
在Players分頁欄項的屬性檢查器中選擇圖片 Players.png 。
你可能已經想到了,給Gestures選擇 Gestures.png 。
嵌入導航控制器的一個視圖控制器包含用于設置導航欄的 Navigation Item(導航項) 。在文檔大綱中選擇表視圖控制器的導航項,在屬性檢查器中把Title改成Players。
或者你也可以雙擊導航欄直接修改title,注意你需要雙擊的是表視圖控制器中的模擬導航欄,而不是導航控制器中的那個導航欄對象。
運行App,欣賞一下這漂亮的分頁標簽欄吧!一行代碼也不用寫哦!
原型表項(Prototype Cell)
原型表項允許你直接在Storyboard編輯器中為表視圖設計自定義布局。
表視圖控制器默認會帶一個空的原型表項。點擊它,在屬性檢查器中設置Style為 Subtitle(副標題)。這會立即改變表項的外觀,使其包含兩個Label。
Storyboard上可以堆疊很多內容,有時可能很難點擊到你想選中的東西。如果遇到困難,有幾種選擇:第一是在面板左側的文檔大綱中選擇,第二是快捷鍵(按住control+option+shift,點擊想選擇的區域后會彈出指針所指區域的所有元素),第三種選擇是Xcode 6的新功能,反復點擊可以在各層之間循環。
如果你之前用過表視圖,還手動創建過自己的表項,你可能會將其認作UITableViewCellStyle.Subtitle樣式。有了原型表項,你可以像剛才那樣選擇系統內建的樣式,也可以自定義設計(我們稍后就要創建了)。
設置Accessory(附件,即表項右側的附屬元素)屬性為 Disclosure Indicator(展開方向標,即右鍵頭),并在 Identifier(標識符) 字段中輸入 PlayerCell。所有的原型表項仍然是標準UITableViewCell對象,所以它們需要一個以供重用的標識符。
運行應用……什么都沒變。這沒什么值得奇怪的,接下來你還需要為這個表指定一個data source(數據源),這樣它才會知道要顯示什么。
在項目中添加一個新文件,選擇iOS/Source下的Cocoa Touch Class模板,命名為 PlayersViewController ,并確保它是UITableViewController的子類。不要選中Also create XIB file選項,因為你已經在Storyboard中設計好了,今天不用nib!選擇Swift語言,點擊Next,然后點擊Create。
回到Storyboard,選擇表視圖控制器(確保你選擇的是視圖控制器而不是其中包含的某個視圖)。在身份檢查器(Identity inspector)中設置它的 Class 為 PlayersViewController。這對于在Storyboard場景中使用自定義視圖控制器的子類很重要,因為如果你不這么做,你的類就都不會被使用!
此后運行App時Storyboard中加載的那個表視圖控制器就是PlayersViewController類的實例。
這個表視圖要顯示玩家列表,所以你需要為App創建主要的數據模型:一個包含Player對象的數組。由iOS/Source下的Swift File模板添加新文件,命名為Player。
在Player.swift中追加以下代碼:
import UIKit
class Player: NSObject {
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
super.init()
}
}
沒什么特別的東西,Player只是容器對象,其中包含三個屬性:玩家名稱,進行的游戲,還有1到5星之間的評分。
接下來要創建一組Player測試對象,并在PlayersViewController中賦值到一個數組。請使用Swift File模板創建名為SampleData的新文件,并在SampleData.swift中追加以下代碼:
//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對象數組賦值給它。
現在在PlayersViewController.swift的class PlayersTableViewController: UITableViewController下面添加一個玩家數組屬性,用來保存玩家列表:
var players: [Player] = playersData
這里,你可能會在PlayersViewController中定義players變量時順帶就把示例數據準備好了,但以后數據可能源自plist或SQL文件,所以,在視圖控制器之外處理數據加載問題是明智之選。
現在你有一個包含多個Player對象的數組,可以在PlayersViewController中綁定數據源了。還是在PlayersViewController.swift中,用以下代碼替換表視圖數據源方法:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return players.count
}
實際工作在cellForRowAtIndexPath中。用以下代碼替換方法(原來的注釋掉):
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
as UITableViewCell
let player = players[indexPath.row] as Player
cell.textLabel?.text = player.name
cell.detailTextLabel?.text = player.game
return cell
}
dequeueReusableCellWithIdentifier(_:forIndexPath:)方法用來檢查是否存在可重用的表項。如果沒有,就返回一個自動分配的原型表項。你只需要提供之前在Storyboard編輯器中給原型表項設定的重用標識符,本例中對應PlayerCell。一定要設置標識符,否則無法正常工作!
運行App,現在表視圖中有玩家項了!
只要寫幾行代碼就可以使用原型表項,贊!
注:該App中只使用了一個原型表項,但如果你的列表需要顯示不同種類的表項,你可以向Storyboard中另外添加原型表項。可以復制現有的表項再進行修改,也可以增大表視圖的Prototype Cells屬性值。記得每個表項都要設置自己的重用標識符。
設計自己的原型表項
對很多App來說使用內建的標準表項樣式已經足夠了,但這個App需要在表項的右側添加一個顯示評分(1星到5星)的圖片。標準表項樣式不支持在這里包含圖片視圖,所以你只能自己創建自定義設計。
切回Main.storyboard,選擇表視圖中的原型表項,在屬性檢查器中設置Style屬性為Custom(自定義),隨后默認的Label不見了。
首先讓表項增高一些,拖動底邊上的小方塊或在尺寸檢查器(Size inspector)中修改Row Height(行高)值,設置表項高度為55點(points)。
從Objects Library拖兩個Label到表項上,把它們放到和之前的標準樣式差不多的地方,你可以在屬性檢查器中隨意設置字體和顏色。設置上面的Label文本為“Name”,下面的為“Game”。
把一個Image View(圖片視圖)拖到表項中,放在右面緊挨展開方向標的地方,設寬度為81點,高度不是很重要。將其Mode設為Center(在屬性檢查器的View下面),保證載入視圖的圖片不會被拉伸。
在尺寸檢查器中設Label寬度為190點。Label不應蓋住Image View。原型表項的最終設計大概是這個樣子:
因為這是一個自定義表項,所以再也不能用 UITableViewCell中的textLabel和detailTextLabel屬性來設置文本了。這些屬性只在標準表項類型中有效,它們指向的label在該表項中已經不存在了。為此,你需要用tag(標記)找到相應的label。
你也可以選擇創建一個繼承UITableViewCell的自定義類并包含對應表項視圖中的label的屬性。而tag可以用來簡化工作,在簡單情況下是很不錯的解決方案。不過本教程后面會嘗試使用自定義類的方法。
在屬性檢查器中設置“Name”Label的tag值為100,“Game”Label為101,Image View為102.
打開PlayersViewController.swift,在后面如下添加新方法imageForRating;
func imageForRating(rating:Int) -> UIImage? {
switch rating {
case 1:
return UIImage(named: "1StarSmall")
case 2:
return UIImage(named: "2StarsSmall")
case 3:
return UIImage(named: "3StarsSmall")
case 4:
return UIImage(named: "4StarsSmall")
case 5:
return UIImage(named: "5StarsSmall")
default:
return nil
}
}
很簡單,該方法根據評分返回不同的星級圖片。依然在PlayersViewController中,如下修改tableView(_:cellForRowAtIndexPath:)方法:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath) as UITableViewCell //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
}
講解一下剛才做的工作:
dequeueReusableCellWithIdentifier在回收表項可重用的情況下會抽出重用標識符為PlayerCell的表項,否則創建一個新表項。
按行號查看Player對象并將其賦值給player。
按表項上的tag找到label和圖片,并參照player對象填充數據。
應該可以了。現在再次運行App,大概會像這樣:
嗯,看起來不大對勁,表項都重疊在一起了。你只修改了原型表項的高度,但是并沒有把表視圖考慮進去。這里有兩個解決方案,一是改變表視圖的Row Height屬性,二是實現tableView(tableView:heightForRowAtIndexPath:)方法。本例中前者更合適,因為只有一種表項,而且我們已經事先了解表項的高度。
注:如果無法事先判定表項的高度,或者各行的高度可能不一致,可以使用tableView(tableView:heightForRowAtIndexPath:)方法。
回到Main.storyboard,在表視圖的尺寸檢查器中設Row Height為55點:
現在運行,看起來好多了!
哦,還有一點,如果之前修改表項高度時沒有手動輸入數據,而是拖動表項邊上的小方塊的話,表視圖的行高屬性也會自動隨之改變。所以在構建過程中你可能并沒碰到上述問題。
使用表項的子類
這個表視圖用起來已經相當不錯了,但我不大喜歡用tag來獲取原型表項的子視圖。如果可能的話,把這些label于outlet連接并使用相應屬性要優雅得多。事實是可行的。
在項目中以Cocoa Touch Class模板添加一個新文件,命名為PlayerCell并令其繼承UITableViewCell。不要選中創建XIB的選項,因為Storyboard里已經有表項了。
在PlayerCell類的類定義下面添加以下屬性
@IBOutlet weak var gameLabel: UILabel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ratingImageView: UIImageView!
這些變量都是IBOutlet,它們可以在Storyboard中與場景建立連接。
回到Main.storyboard,選中原型表項PlayerCell,并在身份檢查器中把它的class改成PlayerCell。現在每當通過dequeueReusableCellWithIdentifier(_:forIndexPath:)向表視圖請求一個新表項時,它會返回PlayerCell實例而不是UITableViewCell。
注意:這里我們把類名跟重用標識符設置成一樣了,都是PlayerCell。這只是因為個人喜歡保持一致,類名跟重用標識符毫不相干,如果你愿意,也可以起不同的名字。
下面令label以及image view與outlet連接。在Storyboard中切到連接檢查器(Connections inspector),然后在面板或文檔大綱中選擇Player Cell,把連接檢查器中的nameLabel outlet拖到Name label對象上。對gameLabel和ratingImageView執行同樣操作。
重點:控件要連接的是表項,而不是視圖控制器!當你的數據源向表視圖通過dequeueReusableCellWithIdentifier索求一個新表項的時候,表視圖并不是把原型表項交給你,而是復制一份給你(或是之前被納入回收空間的一個已有表項)。
這就意味著在同一時間不止有一個PlayerCell的實例,如果把表項中的label連接到了視圖控制器的outlet上,不同的label拷貝會試圖使用同一個outlet,這是自找麻煩。(另一方面,把原型表項連接到視圖控制器的action上是可行的,當你的表項中含有自定義按鈕或者是其他UIControl時可能會用到。)
除使用連接檢查器之外,你也可以按住control從PlayerCell拖到控件上,然后在彈出的選單中選擇outlet名稱。
現在已經綁定屬性,可以稍微簡化數據源的代碼。在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.nameLabel.text = player.name
cell.gameLabel.text = player.game
cell.ratingImageView.image = imageForRating(player.rating)
return cell
}
這就更像樣了。把從dequeueReusableCellWithIdentifier接收的對象轉為一個PlayerCell,然后就可以使用連接到label和圖片視圖的屬性。這樣使用原型表項,表視圖不像以前那么亂了。
運行App試試看。看起來應該和之前一樣,但在幕后,現在使用的已經是你自己的表項子類了!
總結
以上是生活随笔為你收集整理的storyboard搭建项目_Storyboard使用教程一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: storyboard搭建项目_Swift
- 下一篇: asp一句话html,asp常用的一句话