在iOS 7中使用storyboard(part 1)

 
感謝翻譯小組成員 heartasice熱心翻譯。若是您有不錯的原創或譯文,歡迎提交給咱們,更歡迎其餘朋友加入咱們的翻譯小組(聯繫qq:2408167315)。
==========================================================================================
Storyboard是一項使人興奮的功能,在iOS5中首次推出,在開發app的界面時能夠極大地節省時間。
 
以下圖所示,這就是一個完整的應用的storyboard,接下來咱們要學習如何經過這種方式建立應用。
 
如今你可能還不是很精確地知道咱們的應用能夠作什麼,可是經過上圖,咱們能夠很清晰的明白這些視圖之間的關係。這就是使用storyboard的強大之處。
 
當你的應用有許多不一樣頁面的時候,經過使用storyboard,能夠大大減小頁面之間跳轉的代碼。過去咱們爲每一個視圖控制器建立一個nib文件,如今,只須要使用一個storyboard,它包含了你應用中全部的視圖控制器以及它們之間的關係。
 
相比傳統的nib文件,storyboard有不少優勢:
1.使用storyboard,能夠更好地理解應用中全部視圖在概念上的概覽以及它們之間的關係。掌控全部的視圖變得很容易,由於全部的設計都是在一個文件中,而不是在不少單獨的nib文件中。
2.storyboard描述了視圖之間的動畫,這些動畫叫作"segues"你能夠很容易的經過從一個視圖控制器(點ctrl-dragging)拖拽到另外一個來實現,感謝"segues"讓咱們不須要寫代碼去控制頁面跳轉了。
3.storyboard經過新的cell原型,以及靜態cell的特性,讓表格控制器實現起來更容易了。你近乎能夠徹底的經過storyboard來設計你的表格控制器,這也大大的減小了你不得不寫的代碼量。.
 
並非全部的都是那麼完美,固然使用storyboard也是有一些限制的,storyboard的Interface builder 遠沒有舊版nib編輯器那麼強大,而且有一些東西只能在nib中作而不能在storyboard編輯器中作。還有,你須要一個大號的顯示器,尤爲是在開發iPad應用的時候。
 
若是你是那種不喜歡用Interface builder 畫界面而是用代碼直接寫界面的人,很遺憾,storyboard並不適合你。就我的而言,我比較傾向於寫的代碼越少越好,特別是控制UI的那種,因此storyboard簡直就是爲我準備的一把利器。
 
固然了,若是你想繼續使用nib,那麼繼續用好了,你須要知道的是你能夠經過storyboard來綁定各視圖控制器,對於使用storyboard,仍是舊版的nib,不是一個非作選擇不可的事,隨你好了。
 
在這個例子中,咱們將會學到--經過storyboard咱們能夠作什麼,咱們將會建立一個簡單的應用,功能大體是有一個現實玩家,遊戲,以及玩家技能評分的這麼一個列表。在學習過程當中,你幾乎能夠學到大多數經過故事板能夠作到的事。
 
storyboard教程 : iOS 7 版
打開Xcode建立一個新項目,這裏咱們用 Single View Application 模板:
按照下面的方式填寫模板中的選項:
1.Product Name: Ratings
2.Organization Name: 隨便寫點什麼都行
3.Company Identifier:域名反過來寫,例如com.xx.xx
4.Class Prefix: 空着就行
5.Devices: iPhone
 
用舊版Xcode的時候你須要特別指定下這個新項目是用storyboard的,但XCode5以後,再也不有這個選項了,默認就是用storyboard建立的項目。
 
在Xcode建立完項目以後,Xcode的主界面上應該以下圖所示:
這個新項目包含2個類:AppDelegate 和 ViewController, 以及咱們這個例子中的明星: Main.storyboard 文件. 請注意,這個項目中並無xib文件。
 
這是一個只支持豎屏的應用,因此在繼續以前, 鉤掉 Deployment Info, Device Orientation下面的 Landscape Left和Landscape Right 選項。
 
接下來讓咱們看一下storyboard,點擊列表中的 Main.storyboard 在interface builder中打開它。
在Interface builder中編輯storyboard就跟編輯nib文件差很少,你能夠從Object Library中拖拽新的元素到視圖控制器中,而且能夠編輯它的佈局。區別在於storyboard不只僅有一個視圖控制器,它把你應用中的全部視圖控制器全都包含了。
 
按標準的storyboard的說法,一個視圖控制器就是一個"場景"。你能夠交替的使用這個模式,"場景"是呈如今storyboard中的視圖控制器,以往,你可能爲每個"場景"/視圖控制器建立一個nib文件。如今你只須要把他們都集中在一個storyboard裏。在iPhone中,一次只能看到一個場景,而iPad應用中,一次可能會看到多個。例如"master/detail "或者 "popover"
 
注意: Xcode 5默認storyboard以及nib中的 Auto Layout屬性是打開的。 Auto Layout 是一個新的很帥氣的能夠自動調整控件大小的這麼一個技術,在應用適配iPad以及iPhone5的時候尤爲有用,惋惜它只能在 iOS 6 以上運行。固然了,它也須要必定的學習曲線,這個例子中咱們不會詳細的說這點。若是你有興趣瞭解 Auto Layout,請參閱咱們的書籍《 iOS 6 by Tutorials andiOS 7 by Tutorials》.
 
在storyboard中的File inspector  禁用Auto Layout選項,以下圖:
拖拽一些控件到空的視圖控制器上,感覺一些storyboard編輯器是如何工做的。
在storyboard編輯頁面中找到下面這個標上紅色左箭頭的按鈕
點擊它打開左側的 Document Outline 視圖
當編輯nib的時候,列表中顯示的是這個nib中全部的控件,但對於storyboard,它會顯示你的應用中的全部視圖控制器的內容。上圖只有一個視圖控制器,在接下來的例子中,咱們會增長其餘的。
 
在scene下面有微型版的Document Outline,叫作Dock, 以下圖:
什麼是 Dock ?
它顯示了當前視圖的最上層對象,每一個視圖都至少有一個View Controller 對象,一個First Responder 對象,一個Exit 項目。固然了,它也可能會有其餘的最上層對象。使用Dock 去鏈接outlets 和 actions變的很是容易,當你想把某個對象鏈接到視圖控制器中時,只需簡單地把它的圖標拖拽到Dock上。
 
注意: 你極可能沒怎麼用過First Responder。這是指任何物體在任何給定時間具備第一響應狀態的代理對象。它一直在你的nib中,你極可能歷來沒有必要使用它。舉個例子,按鈕中有個Touch Up Inside事件,把它拖給First Responder的 cut: selector。若是在某一點的文本字段具備輸入焦點,那麼你能夠按下該按鈕,使文字欄位,也就是如今的第一響應者,切其文本到剪貼板。
 
運行該app,它看起來應該和你在編輯器中設計的同樣(此處使用了運行iOS 7的4-inch Retina iPhone simulator):
若是你寫過以nib爲基礎的應用,一般會有一個叫作MainWindow.xib的文件。這個文件有一個UIWindow對象指向App Delegate,以及其餘視圖控制器。當你想用storyboard作這些的時候,就不須要MainWindow.xib了。那麼storyboard是如何加載到應用中的呢?
 
讓咱們看看應用的 application delegate。 打開 AppDelegate.h,看起來應該是這樣:
 
  1. #import <UIKit/UIKit.h> 
  2.   
  3. @interface AppDelegate : UIResponder <UIApplicationDelegate> 
  4.   
  5. @property (strong, nonatomic) UIWindow *window; 
  6.   
  7. @end 
 
使用storyboard,應用代理必須繼承自UIResponder,而且有一個 UIWindows 屬性。下面打開AppDelegate.m,這裏設麼都沒有,全部的方法都是空的,甚至application:didFinishLaunchingWithOptions:  也僅僅是返回了一個YES。
 
祕密藏在Ratings-Info.plist 裏,讓咱們在Supporting Files group 裏找到並打開它,以下圖:
 
storyboard使用UIMainStoryboardFile 或者"Main storyboard file base name" 來指定當應用啓動的時候,哪個storyboard是必須被加載的。當設置生效,UIApplication會自動加載叫這個被命名的storyboard文件,並把它第一個視圖控制器顯示到UIWindow中。這些都沒必要寫代碼去實現。這些你還能夠經過修改 Project Settings下面的Project Settings來實現,以下圖:
 
出於完整性, 打開 main.m 以下圖:
 
  1. #import <UIKit/UIKit.h> 
  2.   
  3. #import "AppDelegate.h" 
  4.   
  5. int main(int argc, char *argv[]) 
  6.     @autoreleasepool { 
  7.         return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 
  8.     } 
 
app delegate 並非storyboard的一部分,咱們須要把它的名字指定給UIApplicationMain() 不然,應用就會找不到它。
 
把它加到標籤上 
 
這個Ratings 應用是由標籤控制的2個視圖 ,使用storyboard,建立標籤很容易。
 
回到Main.storyboard, 把一個Tab Bar Controller 從Object Library 拖到面板中。你可能須要最大化你的XCode,由於Tab Bar Controller 默認會帶 2個視圖控制器,你須要能完整的看到他們,經過右下角的小浮動窗口,能夠縮小這個面板。
 
一個新的Tab Bar Controller 默認會帶2個視圖管理器,一個標籤一個。UITabBarController也被叫作容器視圖控制器,由於通常它都會包含一個以上的視圖控制器。此外還有其餘兩種容器控制器:Navigation Controller和the Split View Controller。
 
容器控制器經過箭頭管理它的視圖,以下圖
 
注意: 若是你想把Tab Bar Controller 的全部視圖一塊兒移動,你須要點?-click選中這些視圖,而後再移動他們(被選中的視圖會有一個藍色的下劃線)。
 
在第一個視圖控制器中拖入一個label而且設置它的text 爲 "First Tab",同理,在第二個視圖管理器中加入"Second Tab" 這可讓你看到標籤切換後會發生什麼狀況。
 
注意: 在編輯器縮小的時候你不能向面板中拖入控件,你要先恢復到正常縮放水平,雙擊當前面板就能夠作到。
 
選中Tab Bar Controller 看下面板中的 Attributes inspector。選中那一欄指的是 Initial View Controller。以下圖:
 
在畫布上,先由一個箭頭指向Tab bar controller
 
這意味着啓動app時, UIApplication 會把Tabbarcontroller 做爲主控制器。storyboard同伴有一個獨立的視圖控制器,他是特定的" initial view controller", 它是storyboard的切入點。
 
提示: 改變 initial view controller ,你能夠經過拖拽在視圖控制器之間的箭頭。
 
運行應用試試吧,如今應用的效果是有一個tab bar 而且能夠經過tab 去切換視圖。以下圖:
Xcode 能夠建立一個以tab爲模板的項目(Tabbed Application template) ,你之前應該用過, 最好理解下它是如何工做的,若是非手動建立,也不至於手足無措。
 
注意: 當你想Tabbarcontroller 中加入超過5個視圖的時候,它會自動的生產一個 More的tab。
 
刪除模板自帶的那個視圖控制器,如今storyboard中只有一個tab bar 以及兩個tab各自對應的一個視圖。
 
添加一個Table View Controller
 
兩個scene隸屬的Tab Bar Controller都是標準的 UIViewControllers,下面咱們用UITableViewController 替換掉 第一個tab 中的scene。
 
點擊並選中第一個視圖控制器,而後刪除它,從Object Library中拖拽一個新的 Table View Controller 到先前被刪除的scene所處的位置。以下圖:
當Table View Controller選中時,在Xcode菜單欄選擇 Editor\Embed In\Navigation Controller ,如今另外一個視圖控制器被加到畫板中了:
你還須要從Object Library中拖一個Navigation Controller,但這種嵌入在命令行中同樣簡單。
 
由於Navigation Controller 也是一個容器視圖控制器(跟Tab Bar Controller同樣), 它有一個關係箭頭指向Table View Controller,你還能夠在 Document Outline看到這個關係:
注意:嵌入Table View Controller給了它一個navigation bar,Interface Builder 自動加上它的,由於當前視圖會顯示在Navigation Controller的frame裏。它並非一個真的UINavigationBar ,只是一個模擬的。
 
打開Table View Controller的 Attributes inspector, 你會看到上方有 Simulated Metrics 選項,以下圖:
"Inferred" 做爲storyboards的默認值,它意味着視圖將會顯示一個navigation bar,當它處於Navigation Controller中時,顯示一個tab bar 當它處於Tab Bar Controller中時。你能夠修改這些默認設置,可是注意,這裏只是方便你設計用的,"Simulated Metrics"並不會在運行時出現,他們是指一個虛擬的設計,用來展現你的視圖最終會是什麼樣子。
 
把這兩個視圖鏈接到Tab Bar Controller,按Ctrl-drag 從 the Tab Bar Controller 到 the Navigation Controller以下圖:
鬆手的時候, 出現一個彈出窗口以下圖:
 
選擇 Relationship Segue - view controllers,它爲2個視圖建立了一個關係箭頭以下圖:
Tab Bar Controller有2個關係, 給每一個tab都有一個。Navigation Controller本身有一個關係指向Table View Controller。還有另外一種類型的箭頭"segue" 稍後咱們會講到它。
 
建立完這個新的鏈接後,一個新的tab 添加到 Tab Bar Controller了, 簡單的命名爲 "Item"。對於這個應用,你但願這個新視圖做爲第一個tab,因此拖動tabs,改變他們的順序以下圖:
 
運行應用,第一個tab顯示了一個包含在navagationcontroller 下面的 table view,以下圖:
在你爲應用添加具體的功能以前,讓咱們先整理下storyboard,分別把第一個tab 第二個tab 命名爲  "Players" 和"Gestures"。並不像你指望的那樣,你不能在Tab Bar Controller 上改動,只能夠在tab 指向的那個視圖控制器上作。
 
一旦你把一個視圖控制器連上了Tab Bar Controller,它默認會給一個 Tab Bar Item 對象。用這個Tab Bar Item 去改變tab的名字跟圖片。
 
選中Navigation Controller裏的Tab Bar Item ,在Attributes inspector中把title 設置爲 Players,以下圖:
同理把第二個tab 設置爲 Gestures.
 
一個設計良好的應用須要在tab 上有圖標。 這裏例子代碼中 有個Images 的文件夾在 resource 文件夾下 把這個文件夾加入到項目中 ,選中Players Tab Bar的 Item的 Attributes inspector ,把 Players.png 填進去. 同理處理 Gestures item the 圖片爲 Gestures.png.
 
一個嵌入在Navigation Controller  的視圖控制器有一個 Navigation Item,它是用來配製navigation bar的。在Table View Controller 中選中Navigation Item (在Document Outline能夠找到)在 Attributes inspector 中把title改爲  Players.
 
此外, 你能夠雙擊navigation bar 直接修改title. (注意: 你須要雙擊table view controller 中的simulated navigation bar,並非Navigation Controller 中的真正的那個Navigation Bar 對象),以下圖  
運行應用,看看這使人驚歎的tab bar吧,這一切,一行代碼都不用寫喔~
Prototype cells
 
Prototype cells 容許你在storyboard編輯器中直接爲table view 設計自定義cell。
 
默認Table View Controller 會帶一個空的cell. 點擊它,設置 Attributes inspector 中的 Style 爲 Subtitle. 這會讓你的cell 包含2個 labels.若是你之前爲table view 作過自定義cell,你可能注意到,這就是UITableViewCellStyleSubtitle 風格。經過 prototype cells你能夠像剛剛那樣直接選擇自帶的cell 風格,或者純粹本身作一個設計。
 
設置 Accessory attribute 爲 Disclosure Indicator 在 Identifier 中輸入 PlayerCell. 全部的 prototype cells 仍然是 UITableViewCell 類型 因此它們須要一個reuse identifier,以下圖:
運行應用…什麼都沒變?這並無什麼值得奇怪的,你還須要爲 這個tableview 指定一個data source,這樣它纔會知道顯示什麼。
 
添加一個新文件,選擇 Objective-C class 模板,命名爲 PlayersViewController ,而且確保它是UITableViewController 的子類。不要選中With XIB for user interface 選項,由於你已經在storyboard中設計好它了,以下圖:
 
回到storyboard選擇Table View Controller (確保你只選擇了 tableviewcontroller 並無其餘的view 包含在內)。在 Identity inspector中設置它的 Class 爲 PlayersViewController. 這對於在storyboard中使用你本身定義的 視圖控制器的類很重要,由於若是你不這麼作,你的類永遠都不會被使用!以下圖:
到目前爲止 當你運行應用的時候,你的tableviewcontroller 是從storyboard中加載的你的PlayersViewController 的實例。
 
添加一個 mutable array property 到 PlayersViewController.h:
 
  1. #import <UIKit/UIKit.h> 
  2.   
  3. @interface PlayersViewController : UITableViewController 
  4.   
  5. @property (nonatomic, strong) NSMutableArray *players; 
  6.   
  7. @end 
 
該數組將會包含你的應用中的主要數據模型,一個數組包含 Player 對象。使用Objective-C class模板在項目中添加一個新文件,命名爲Player, 繼承自 NSObject.
 
把 Player.h 改爲下圖的樣子:
 
  1. @interface Player : NSObject 
  2.   
  3. @property (nonatomic, copy) NSString *name; 
  4. @property (nonatomic, copy) NSString *game; 
  5. @property (nonatomic, assign) int rating; 
  6.   
  7. @end 
 
 
這並無什麼特別的. Player  是一個簡單的容器對象包含三個屬性:玩家名字,遊戲名字,他遊戲的評級(1-5星)。
 
在App Delegate 中你須要爲這個數組建立一些測試的Player 對象,而且把它分配給PlayersViewController的 players 屬性。
 
在 AppDelegate.m中,在文件頂部爲Player和PlayersViewController添加#import ,而且添加一個實例變量 _players ,以下圖:
 
  1. #import "AppDelegate.h" 
  2. #import "Player.h" 
  3. #import "PlayersViewController.h" 
  4.   
  5. @implementation AppDelegate  
  6.     NSMutableArray *_players; 
  7.   
  8. // Rest of file... 
 
修改 application:didFinishLaunchingWithOptions: 方法,以下圖
 
  1.   
  2. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
  3.     _players = [NSMutableArray arrayWithCapacity:20]; 
  4.   
  5.     Player *player = [[Player alloc] init]; 
  6.     player.name = @"Bill Evans"; 
  7.     player.game = @"Tic-Tac-Toe"; 
  8.     player.rating = 4; 
  9.     [_players addObject:player]; 
  10.   
  11.     player = [[Player alloc] init]; 
  12.     player.name = @"Oscar Peterson"; 
  13.     player.game = @"Spin the Bottle"; 
  14.     player.rating = 5; 
  15.     [_players addObject:player]; 
  16.   
  17.     player = [[Player alloc] init]; 
  18.     player.name = @"Dave Brubeck"; 
  19.     player.game = @"Texas Hold’em Poker"; 
  20.     player.rating = 2; 
  21.     [_players addObject:player]; 
  22.   
  23.     UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController; 
  24.     UINavigationController *navigationController = [tabBarController viewControllers][0]; 
  25.     PlayersViewController *playersViewController = [navigationController viewControllers][0]; 
  26.     playersViewController.players = _players; 
  27.   
  28.     return YES; 
 
咱們建立了一些 Player 對象而且把它們加到了 _players 數組中,接下來:
 
  1. UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController; 
  2. UINavigationController *navigationController = [tabBarController viewControllers][0]; 
  3. PlayersViewController *playersViewController = [navigationController viewControllers][0]; 
  4. playersViewController.players = _players; 
 
嗯?! 咱們想把 _players array 分配給PlayersViewController 的 players property,那樣它才能把這個數組做爲它的data source,可是 app delegate並不知道 PlayersViewController是什麼玩意,它會經過storyboard找到它。
 
注意:這是storyboard的一個限制。用nib的時候你須要在App Delegate 中指定MainWindow.xib 的引用,你能夠經過鏈接頂層的視圖控制器到你的App Delegate中。在storyboard裏,這是不可能的,你不能在app delegate中爲你的頂層視圖控制器作引用,這很不幸,因此咱們通常都手動的寫,就像你如今作的這樣。
 
讓咱們一步一步來
 
  1. UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController; 
你知道 storyboard最初的view controller 是一個Tab Bar Controller,因此你能夠指定window的rootViewController 爲 UITabBarController.
 
在第一個tab中,PlayersViewController位於navigation controller,因此你首先要查詢UINavigationController 對象,代碼以下:
 
  1. UINavigationController *navigationController = [tabBarController viewControllers][0]; 
而後獲取它的root view controller, 這裏是PlayersViewController:
 
  1. PlayersViewController *playersViewController = [navigationController viewControllers][0]; 
爲storyboard製做你想要的視圖控制器看來是須要花一些時間的,固然了,若是你想換tab的順序,或者當前應用不是以tab bar controller 做爲 rootviewcontroller了,你將不得不修改這個邏輯。
 
如今咱們有了一個包含Player對象的數組了,咱們能夠爲PlayersViewController建立datasource了。打開PlayersViewController,在頂部添加import:
 
  1. #import "Player.h" 
修改 table view data source 方法以下
 
  1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
  2.     return 1; 
  3.   
  4. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
  5.     return [self.players count]; 
 
真正的操做發生在cellForRowAtIndexPath 中,起初方法以下:
 
  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  2.     static NSString *CellIdentifier = @"Cell"; 
  3.   
  4.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
  5.     if (cell == nil) { 
  6.         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
  7.                                       reuseIdentifier:CellIdentifier]; 
  8.     } 
  9.   
  10.     // Configure the cell... 
  11.     return cell; 
 
你須要問你的table view 列出一個cell,若是它返回nil 則說明當前並沒有可重用的cell,因此你須要本身建立一個新的cell類實例,毫無疑問這須要你手寫代碼了,用如下方法代替:
 
  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  2.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"]; 
  3.   
  4.     Player *player = (self.players)[indexPath.row]; 
  5.     cell.textLabel.text = player.name; 
  6.     cell.detailTextLabel.text = player.game; 
  7.   
  8.     return cell; 
 
 
這看起來很簡單,你只須要像下面獲取cell
 
  1. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"]; 
若是當前沒有一個能夠重用的cell 它會自動返回一個prototype cell 的copy 而且返給你。下面你就須要使用在storyboard編輯器中設置的re-use identifier,這裏是"PlayerCell"
運行應用,table view以下圖所示:
僅僅須要一行代碼就能夠實現這個新奇的prototype cells。
 
注意:這個應用咱們只用到了一種prototype的cell,若是你想用更多種類的cell,只須要簡單地把那些額外的prototype cell 加到storyboard上,你也能夠複製當前存在的cell 去作一個新的,或者增長當前table view 的Prototype cell的屬性,可是要確保一點,每一個cell都須要有一個只屬於它本身的re-use identifier
 
設計你本身的Prototype Cells
 
不少app 都是使用 默認的cell style的,可是對於這個應用,cell 的右側有一個圖片用來顯示這個用戶的得分(從1星到5星),默認的cell不帶這種具備image的style,因此這裏咱們須要本身設計一個。
 
回到Main.storyboard,選擇table view 中的prototype cell並把它的Style attribute 設置爲Custom,默認的labels 如今沒有了。
 
第一步把cell 稍微加高一點,經過拖拽它的下邊,或者改變Size inspector中的Row Height值均可以。 把cell的高度設置爲55 points。從Objects Library 拽2個 Label 到cell 上, 把他們放在剛纔那個label 所在的地方,隨便改改顏色 字圖或者寫點什麼都行。
 
拖一個Image View 到cell 上,並讓它居於cell的右側,緊挨着disclosure indicator 設置它的Mode 爲 Center (在Attributes inspector的view 下面),這樣不管你防止什麼樣的圖片到這個Imageview 上它都不會被拉伸。
 
設置 labels 的寬度爲190 points 這樣他們就不會擋住image view。
 
最終的效果以下圖所示:
 
由於這是一個自定義cell因此你不再須要 UITableViewCell 中的textLabel和detailTextLabel 屬性來設置text。由於這些屬性指向的 labels 在這個cell中並不存在了。做爲替代,你須要使用tags 來找到這些labels。
 
給Name label 的tag 設置爲100,Game 的label 設置爲101,Image View 的tag設置爲102,經過Attributes inspector 能夠找到。
 
下面打開PlayersViewController.m 增長一個方法,imageForRating:.
以下:
 
  1. - (UIImage *)imageForRating:(int)rating 
  2.     switch (rating) { 
  3.         case 1: return [UIImage imageNamed:@"1StarSmall"]; 
  4.         case 2: return [UIImage imageNamed:@"2StarsSmall"]; 
  5.         case 3: return [UIImage imageNamed:@"3StarsSmall"]; 
  6.         case 4: return [UIImage imageNamed:@"4StarsSmall"]; 
  7.         case 5: return [UIImage imageNamed:@"5StarsSmall"]; 
  8.     } 
  9.     return nil; 
 
把tableView:cellForRowAtIndexPath: 改爲:
  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  2.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"]; 
  3.   
  4.     Player *player = (self.players)[indexPath.row]; 
  5.   
  6.     UILabel *nameLabel = (UILabel *)[cell viewWithTag:100]; 
  7.     nameLabel.text = player.name; 
  8.   
  9.     UILabel *gameLabel = (UILabel *)[cell viewWithTag:101]; 
  10.     gameLabel.text = player.game; 
  11.   
  12.     UIImageView *ratingImageView = (UIImageView *)[cell viewWithTag:102]; 
  13.     ratingImageView.image = [self imageForRating:player.rating]; 
  14.   
  15.     return cell; 
 
下面運行app ,效果以下:
 
哎呦~,看起來不怎麼對哈,這些cell 都重疊在一塊兒了,你只改變了prototype cell的高度,可是並無把table view考慮進去。這裏有2個解決方案,1 改變tableview 的Row Height 屬性或者執行tableView:heightForRowAtIndexPath:
 
注意:你可能須要hightForRowAtIndexPath,若是你不知道你的cell的具體高度,或者不一樣的行有不一樣的高度。
.
回到Main.storyboard,在Table View 的Size inspector 設置Row Height 爲55:
再運行app,看起來好多了。
 
順路說一嘴,當你經過拖拽cell下沿的方式而不是直接設置值的方式去改變cell的高度,那麼table view 的row 高度屬性自動會變,當你第一次這麼作的使用它就會好用。
 
Using a Subclass for the Cell
 
這個table view 已經看起來至關不錯了,但我對於經過tag 去獲取 label 或者 這個cell 的其餘子視圖不感冒,把這些labels 與類的outlet鏈接起來並使用相應性應該是更好的方式,事實證實你能夠。經過Objective-C class template爲項目添加一個新文件,命名爲PlayerCell,並使它繼承自,繼承自UITableViewCell:
  1. @interface PlayerCell : UITableViewCell 
  2.   
  3. @property (nonatomic, weak) IBOutlet UILabel *nameLabel; 
  4. @property (nonatomic, weak) IBOutlet UILabel *gameLabel; 
  5. @property (nonatomic, weak) IBOutlet UIImageView *ratingImageView; 
  6.   
  7. @end 
 
這個類自己並無作什麼事情,僅僅是增長了幾個屬性nameLabel,gameLabel以及ratingImageView ,而且是Outlets。
 
回到Main.storyboard,選中prototype cell,並在Identity inspector中把它的class改爲PlayerCell 。如今不管何時你經過dequeueReusableCellWithIdentifier向tableview請求一個新的cell 時,它會返回PlayerCell 實例而不是 UITableViewCell 。
 
注意:這裏咱們把類名跟reuse identifier 設置成同樣了,PlayerCell 這只是個人習慣而已,類名跟reuse identifier 並無什麼關係,因此若是你想起不同的,隨你好了。
 
下面鏈接 labels 以及 imageview 的outlet,選擇label的onnections inspector 中的New Referencing Outlet 拖拽到 table view cell 上,分別選中nameLabel ,gameLabel:
重點:你須要把controls 與table view cell鏈接起來,而不是視圖控制器。當你的data source 要求那個table view 經過dequeueReusableCellWithIdentifier 要一個新的cell 的時候,table view 並非給你一個真實的prototype cell,而是複製一份給你(或者重用以前那些cell中一個也說不定)。這就意味着在同一時間不止有一個PlayerCell  的實例。而後不一樣的label 拷貝視圖訪問一個outlet,這是自找麻煩(從另外一方面,把prototype cell 的 actions鏈接到 視圖控制器上是可行的,當你的cell 中有自定義按鈕或者是其餘繼承於UIControls )
 
如今你已經鏈接好這些屬性了,你只須要寫點點data source代碼。首先在PlayersViewController.m中引入PlayerCell 類:
  1. #import "PlayerCell.h" 
而後把cellForRowAtIndexPath 改成:
  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  2.     PlayerCell *cell = (PlayerCell *)[tableView dequeueReusableCellWithIdentifier:@"PlayerCell"]; 
  3.   
  4.     Player *player = (self.players)[indexPath.row]; 
  5.     cell.nameLabel.text = player.name; 
  6.     cell.gameLabel.text = player.game; 
  7.     cell.ratingImageView.image = [self imageForRating:player.rating]; 
  8.   
  9.     return cell; 
更喜歡它了吧,如今你經過dequeueReusableCellWithIdentifier  獲取PlayerCell的實例,而後能夠設置 它的 labels 以及 imageview。
 
運行應用,它看起來跟以前沒什麼不一樣,可是要注意到,你如今已經用的是自定義的tableviewcell 的子類了。
 
何去何從?
點擊查看該教程的 第二部分,它涵蓋了segues,靜態table view cells以及下載示例工程等。

CocoaChina是全球最大的蘋果開發中文社區,官方微信每日定時推送各類精彩的研發教程資源和工具,介紹app推廣營銷經驗,最新企業招聘和外包信息,以及Cocos2d引擎、Cocos Studio開發工具包的最新動態及培訓信息。關注微信能夠第一時間瞭解最新產品和服務動態,微信在手,天下我有!php

請搜索微信號「CocoaChina」關注咱們!html

 

原文:http://www.cocoachina.com/industry/20131213/7537.htmlios

相關文章:數組

http://blog.csdn.net/ryantang03/article/details/7919234微信

http://www.cnblogs.com/haichao/archive/2012/11/23/2784144.htmlapp

http://www.2cto.com/kf/201303/196163.html編輯器

相關文章
相關標籤/搜索