天天看點

簡單使用storyboard

原文: Storyboards Tutorial in iOS 7: Part 1         感謝翻譯小組成員 heartasice熱心翻譯。如果您有不錯的原創或譯文,歡迎送出給我們,更歡迎其他朋友加入我們的翻譯小組(聯系qq:2408167315)。 ========================================================================================== Storyboard是一項令人興奮的功能,在iOS5中首次推出,在開發app的界面時可以極大地節省時間。   如下圖所示,這就是一個完整的應用的storyboard,接下來我們要學習如何通過這種方式建立應用。  

簡單使用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 模闆:

簡單使用storyboard

按照下面的方式填寫模闆中的選項: 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的主界面上應該如下圖所示:

簡單使用storyboard

這個新項目包含2個類: AppDelegate 和  ViewController, 以及我們這個例子中的明星:  Main.storyboard 檔案. 請注意,這個項目中并沒有xib檔案。   這是一個隻支援豎屏的應用,是以在繼續之前, 鈎掉  Deployment Info, Device Orientation下面的 Landscape Left和Landscape Right 選項。   接下來讓我們看一下storyboard,點選清單中的 Main.storyboard 在interface builder中打開它。

簡單使用storyboard

在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編輯器是如何工作的。

簡單使用storyboard

在storyboard編輯頁面中找到下面這個标上紅色左箭頭的按鈕

簡單使用storyboard

點選它打開左側的 Document Outline 視圖

簡單使用storyboard

當編輯nib的時候,清單中顯示的是這個nib中所有的控件,但對于storyboard,它會顯示你的應用中的所有視圖控制器的内容。上圖隻有一個視圖控制器,在接下來的例子中,我們會增加其他的。   在scene下面有微型版的Document Outline,叫做Dock, 如下圖:

簡單使用storyboard

什麼是 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):

簡單使用storyboard

如果你寫過以nib為基礎的應用,通常會有一個叫做MainWindow.xib的檔案。這個檔案有一個UIWindow對象指向App Delegate,以及其他視圖控制器。當你想用storyboard做這些的時候,就不需要MainWindow.xib了。那麼storyboard是如何加載到應用中的呢?   讓我們看看應用的 application delegate。 打開 AppDelegate.h,看起來應該是這樣:  

  1. #import <UIKit/UIKit.h> 
  2. @interface AppDelegate : UIResponder <UIApplicationDelegate> 
  3. @property (strong, nonatomic) UIWindow *window; 
  4. @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來實作,如下圖:  

簡單使用storyboard

出于完整性, 打開 main.m 如下圖:  

  1. #import <UIKit/UIKit.h> 
  2. #import "AppDelegate.h" 
  3. int main(int argc, char *argv[]) 
  4.     @autoreleasepool { 
  5.         return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 
  6.     } 

  app delegate 并不是storyboard的一部分,我們需要把它的名字指定給 UIApplicationMain() 否則,應用就會找不到它。   把它加到标簽上    這個Ratings 應用是由标簽控制的2個視圖 ,使用storyboard,建立标簽很容易。   回到 Main.storyboard, 把一個Tab Bar Controller 從Object Library 拖到面闆中。你可能需要最大化你的XCode,因為Tab Bar Controller 預設會帶 2個視圖控制器,你需要能完整的看到他們,通過右下角的小浮動視窗,可以縮小這個面闆。

簡單使用storyboard

  一個新的Tab Bar Controller 預設會帶2個視圖管理器,一個标簽一個。UITabBarController也被叫做容器視圖控制器,因為一般它都會包含一個以上的視圖控制器。此外還有其他兩種容器控制器:Navigation Controller和the Split View Controller。   容器控制器通過箭頭管理它的視圖,如下圖

簡單使用storyboard

  注意: 如果你想把Tab Bar Controller 的所有視圖一起移動,你需要點?-click選中這些視圖,然後再移動他們(被選中的視圖會有一個藍色的下劃線)。   在第一個視圖控制器中拖入一個label并且設定它的text 為 "First Tab",同理,在第二個視圖管理器中加入"Second Tab" 這可以讓你看到标簽切換後會發生什麼情況。   注意: 在編輯器縮小的時候你不能向面闆中拖入控件,你要先恢複到正常縮放水準,輕按兩下目前面闆就可以做到。   選中Tab Bar Controller 看下面闆中的  Attributes inspector。選中那一欄指的是  Initial View Controller。如下圖:

簡單使用storyboard

  在畫布上,先由一個箭頭指向Tab bar controller

簡單使用storyboard

  這意味着啟動app時,  UIApplication 會把Tabbarcontroller 作為主要制器。storyboard同伴有一個獨立的視圖控制器,他是特定的" initial view controller", 它是storyboard的切入點。   提示: 改變 initial view controller ,你可以通過拖拽在視圖控制器之間的箭頭。   運作應用試試吧,現在應用的效果是有一個tab bar 并且可以通過tab 去切換視圖。如下圖:

簡單使用storyboard

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所處的位置。如下圖:

簡單使用storyboard

當Table View Controller選中時,在Xcode菜單欄選擇  Editor\Embed In\Navigation Controller ,現在另一個視圖控制器被加到畫闆中了:

簡單使用storyboard

你還需要從Object Library中拖一個Navigation Controller,但這種嵌入在指令行中一樣簡單。   因為Navigation Controller 也是一個容器視圖控制器(跟Tab Bar Controller一樣), 它有一個關系箭頭指向Table View Controller,你還可以在 Document Outline看到這個關系:

簡單使用storyboard

注意:嵌入Table View Controller給了它一個navigation bar,Interface Builder 自動加上它的,因為目前視圖會顯示在Navigation Controller的frame裡。它并不是一個真的UINavigationBar ,隻是一個模拟的。   打開Table View Controller的  Attributes inspector, 你會看到上方有 Simulated Metrics 選項,如下圖:

簡單使用storyboard

"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如下圖:

簡單使用storyboard

松手的時候, 出現一個彈出視窗如下圖:  

簡單使用storyboard

選擇 Relationship Segue - view controllers,它為2個視圖建立了一個關系箭頭如下圖:

簡單使用storyboard

Tab Bar Controller有2個關系, 給每個tab都有一個。Navigation Controller自己有一個關系指向Table View Controller。還有另一種類型的箭頭"segue" 稍後我們會講到它。   建立完這個新的連接配接後,一個新的tab 添加到 Tab Bar Controller了, 簡單的命名為 "Item"。對于這個應用,你希望這個新視圖作為第一個tab,是以拖動tabs,改變他們的順序如下圖:

簡單使用storyboard

  運作應用,第一個tab顯示了一個包含在navagationcontroller 下面的 table view,如下圖:

簡單使用storyboard

在你為應用添加具體的功能之前,讓我們先整理下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,如下圖:

簡單使用storyboard

同理把第二個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 對象),如下圖  

簡單使用storyboard

運作應用,看看這令人驚歎的tab bar吧,這一切,一行代碼都不用寫喔~

簡單使用storyboard

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,如下圖:

簡單使用storyboard

運作應用…什麼都沒變?這并沒有什麼值得奇怪的,你還需要為 這個tableview 指定一個data source,這樣它才會知道顯示什麼。   添加一個新檔案,選擇  Objective-C class 模闆,命名為  PlayersViewController ,并且確定它是 UITableViewController 的子類。不要選中With XIB for user interface 選項,因為你已經在storyboard中設計好它了,如下圖:  

簡單使用storyboard

回到storyboard選擇Table View Controller (確定你隻選擇了 tableviewcontroller 并沒有其他的view 包含在内)。在 Identity inspector中設定它的 Class 為 PlayersViewController. 這對于在storyboard中使用你自己定義的 視圖控制器的類很重要,因為如果你不這麼做,你的類永遠都不會被使用!如下圖:

簡單使用storyboard

到目前為止 當你運作應用的時候,你的tableviewcontroller 是從storyboard中加載的你的 PlayersViewController 的執行個體。   添加一個  mutable array property 到  PlayersViewController.h:  

  1. #import <UIKit/UIKit.h> 
  2. @interface PlayersViewController : UITableViewController 
  3. @property (nonatomic, strong) NSMutableArray *players; 
  4. @end 

  該數組将會包含你的應用中的主要資料模型,一個數組包含 Player 對象。使用Objective-C class模闆在項目中添加一個新檔案,命名為Player, 繼承自 NSObject.   把  Player.h 改成下圖的樣子:  

  1. @interface Player : NSObject 
  2. @property (nonatomic, copy) NSString *name; 
  3. @property (nonatomic, copy) NSString *game; 
  4. @property (nonatomic, assign) int rating; 
  5. @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. @implementation AppDelegate  
  5.     NSMutableArray *_players; 
  6. // Rest of file... 

  修改 application:didFinishLaunchingWithOptions: 方法,如下圖  

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
  2.     _players = [NSMutableArray arrayWithCapacity:20]; 
  3.     Player *player = [[Player alloc] init]; 
  4.     player.name = @"Bill Evans"; 
  5.     player.game = @"Tic-Tac-Toe"; 
  6.     player.rating = 4; 
  7.     [_players addObject:player]; 
  8.     player = [[Player alloc] init]; 
  9.     player.name = @"Oscar Peterson"; 
  10.     player.game = @"Spin the Bottle"; 
  11.     player.rating = 5; 
  12.     [_players addObject:player]; 
  13.     player = [[Player alloc] init]; 
  14.     player.name = @"Dave Brubeck"; 
  15.     player.game = @"Texas Hold’em Poker"; 
  16.     player.rating = 2; 
  17.     [_players addObject:player]; 
  18.     UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController; 
  19.     UINavigationController *navigationController = [tabBarController viewControllers][0]; 
  20.     PlayersViewController *playersViewController = [navigationController viewControllers][0]; 
  21.     playersViewController.players = _players; 
  22.     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. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
  4.     return [self.players count]; 

  真正的操作發生在cellForRowAtIndexPath 中,起初方法如下:  

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  2.     static NSString *CellIdentifier = @"Cell"; 
  3.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
  4.     if (cell == nil) { 
  5.         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
  6.                                       reuseIdentifier:CellIdentifier]; 
  7.     } 
  8.     // Configure the cell... 
  9.     return cell; 

  你需要問你的table view 列出一個cell,如果它傳回 nil 則說明目前并無可重用的cell,是以你需要自己建立一個新的cell類執行個體,毫無疑問這需要你手寫代碼了,用以下方法代替:  

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  2.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"]; 
  3.     Player *player = (self.players)[indexPath.row]; 
  4.     cell.textLabel.text = player.name; 
  5.     cell.detailTextLabel.text = player.game; 
  6.     return cell; 

    這看起來很簡單,你隻需要像下面擷取cell  

  1. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"]; 

如果目前沒有一個可以重用的cell 它會自動傳回一個prototype cell 的copy 并且返給你。下面你就需要使用在storyboard編輯器中設定的re-use identifier,這裡是"PlayerCell" 運作應用,table view如下圖所示:

簡單使用storyboard

僅僅需要一行代碼就可以實作這個新奇的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。   最終的效果如下圖所示:

簡單使用storyboard

  因為這是一個自定義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.     Player *player = (self.players)[indexPath.row]; 
  4.     UILabel *nameLabel = (UILabel *)[cell viewWithTag:100]; 
  5.     nameLabel.text = player.name; 
  6.     UILabel *gameLabel = (UILabel *)[cell viewWithTag:101]; 
  7.     gameLabel.text = player.game; 
  8.     UIImageView *ratingImageView = (UIImageView *)[cell viewWithTag:102]; 
  9.     ratingImageView.image = [self imageForRating:player.rating]; 
  10.     return cell; 

  下面運作app ,效果如下:

簡單使用storyboard

  哎呦~,看起來不怎麼對哈,這些cell 都重疊在一起了,你隻改變了prototype cell的高度,但是并沒有把table view考慮進去。這裡有2個解決方案,1 改變tableview 的Row Height 屬性或者執行 tableView:heightForRowAtIndexPath:   注意:你可能需要 hightForRowAtIndexPath,如果你不知道你的cell的具體高度,或者不同的行有不同的高度。 . 回到 Main.storyboard,在Table View 的 Size inspector 設定Row Height 為55:

簡單使用storyboard

再運作app,看起來好多了。

簡單使用storyboard

  順路說一嘴,當你通過拖拽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. @property (nonatomic, weak) IBOutlet UILabel *nameLabel; 
  3. @property (nonatomic, weak) IBOutlet UILabel *gameLabel; 
  4. @property (nonatomic, weak) IBOutlet UIImageView *ratingImageView; 
  5. @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:

簡單使用storyboard

重點:你需要把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.     Player *player = (self.players)[indexPath.row]; 
  4.     cell.nameLabel.text = player.name; 
  5.     cell.gameLabel.text = player.game; 
  6.     cell.ratingImageView.image = [self imageForRating:player.rating]; 
  7.     return cell; 

更喜歡它了吧,現在你通過 dequeueReusableCellWithIdentifier  擷取PlayerCell的執行個體,然後可以設定 它的 labels 以及 imageview。   運作應用,它看起來跟之前沒什麼不同,但是要注意到,你現在已經用的是自定義的tableviewcell 的子類了。