storyboard 使用
生活随笔
收集整理的這篇文章主要介紹了
storyboard 使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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,看起來應該是這樣:
#import?<UIKit/UIKit.h>? ?? @interface?AppDelegate?:?UIResponder?<UIApplicationDelegate>? ?? @property?(strong,?nonatomic)?UIWindow?*window;? ?? @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 如下圖:
#import?<UIKit/UIKit.h>? ?? #import?"AppDelegate.h"? ?? int?main(int?argc,?char?*argv[])? {? ????@autoreleasepool?{? ????????return?UIApplicationMain(argc,?argv,?nil,?NSStringFromClass([AppDelegate?class]));? ????}? }?
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:
#import?<UIKit/UIKit.h>? ?? @interface?PlayersViewController?:?UITableViewController? ?? @property?(nonatomic,?strong)?NSMutableArray?*players;? ?? @end?
該數組將會包含你的應用中的主要數據模型,一個數組包含 Player 對象。使用Objective-C class模板在項目中添加一個新文件,命名為Player, 繼承自 NSObject.
把?Player.h?改成下圖的樣子:
@interface?Player?:?NSObject? ?? @property?(nonatomic,?copy)?NSString?*name;? @property?(nonatomic,?copy)?NSString?*game;? @property?(nonatomic,?assign)?int?rating;? ?? @end?
這并沒有什么特別的. Player ?是一個簡單的容器對象包含三個屬性:玩家名字,游戲名字,他游戲的評級(1-5星)。
在App Delegate 中你需要為這個數組創建一些測試的Player?對象,并且把它分配給PlayersViewController的 players 屬性。
在?AppDelegate.m中,在文件頂部為Player和PlayersViewController添加#import ,并且添加一個實例變量?_players?,如下圖:
#import?"AppDelegate.h"? #import?"Player.h"? #import?"PlayersViewController.h"? ?? @implementation?AppDelegate?? {? ????NSMutableArray?*_players;? }? ?? //?Rest?of?file...?
修改 application:didFinishLaunchingWithOptions: 方法,如下圖
?? -?(BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary?*)launchOptions? {? ????_players?=?[NSMutableArray?arrayWithCapacity:20];? ?? ????Player?*player?=?[[Player?alloc]?init];? ????player.name?=?@"Bill?Evans";? ????player.game?=?@"Tic-Tac-Toe";? ????player.rating?=?4;? ????[_players?addObject:player];? ?? ????player?=?[[Player?alloc]?init];? ????player.name?=?@"Oscar?Peterson";? ????player.game?=?@"Spin?the?Bottle";? ????player.rating?=?5;? ????[_players?addObject:player];? ?? ????player?=?[[Player?alloc]?init];? ????player.name?=?@"Dave?Brubeck";? ????player.game?=?@"Texas?Hold’em?Poker";? ????player.rating?=?2;? ????[_players?addObject:player];? ?? ????UITabBarController?*tabBarController?=?(UITabBarController?*)self.window.rootViewController;? ????UINavigationController?*navigationController?=?[tabBarController?viewControllers][0];? ????PlayersViewController?*playersViewController?=?[navigationController?viewControllers][0];? ????playersViewController.players?=?_players;? ?? ????return?YES;? }?
我們創建了一些 Player 對象并且把它們加到了 _players 數組中,接下來:
UITabBarController?*tabBarController?=?(UITabBarController?*)self.window.rootViewController;? UINavigationController?*navigationController?=?[tabBarController?viewControllers][0];? PlayersViewController?*playersViewController?=?[navigationController?viewControllers][0];? 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中為你的頂層視圖控制器做引用,這很不幸,所以我們一般都手動的寫,就像你現在做的這樣。
讓我們一步一步來
UITabBarController?*tabBarController?=?(UITabBarController?*)self.window.rootViewController;?
你知道 storyboard最初的view controller 是一個Tab Bar Controller,所以你可以指定window的rootViewController 為 UITabBarController.
在第一個tab中,PlayersViewController位于navigation controller,所以你首先要查詢UINavigationController 對象,代碼如下:
UINavigationController?*navigationController?=?[tabBarController?viewControllers][0];?
然后獲取它的root view controller, 這里是PlayersViewController:
PlayersViewController?*playersViewController?=?[navigationController?viewControllers][0];?
為storyboard制作你想要的視圖控制器看來是需要花一些時間的,當然了,如果你想換tab的順序,或者當前應用不是以tab bar controller 作為 rootviewcontroller了,你將不得不修改這個邏輯。
現在我們有了一個包含Player對象的數組了,我們可以為PlayersViewController創建datasource了。打開PlayersViewController,在頂部添加import:
#import?"Player.h"?
修改 table view data source 方法如下
-?(NSInteger)numberOfSectionsInTableView:(UITableView?*)tableView? {? ????return?1;? }? ?? -?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section? {? ????return?[self.players?count];? }?
真正的操作發生在cellForRowAtIndexPath 中,起初方法如下:
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath? {? ????static?NSString?*CellIdentifier?=?@"Cell";? ?? ????UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:CellIdentifier];? ????if?(cell?==?nil)?{? ????????cell?=?[[UITableViewCell?alloc]?initWithStyle:UITableViewCellStyleDefault? ??????????????????????????????????????reuseIdentifier:CellIdentifier];? ????}? ?? ????//?Configure?the?cell...? ????return?cell;? }?
你需要問你的table view 列出一個cell,如果它返回nil?則說明當前并無可重用的cell,所以你需要自己創建一個新的cell類實例,毫無疑問這需要你手寫代碼了,用以下方法代替:
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath? {? ????UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:@"PlayerCell"];? ?? ????Player?*player?=?(self.players)[indexPath.row];? ????cell.textLabel.text?=?player.name;? ????cell.detailTextLabel.text?=?player.game;? ?? ????return?cell;? }?
這看起來很簡單,你只需要像下面獲取cell
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:.
如下:
-?(UIImage?*)imageForRating:(int)rating? {? ????switch?(rating)?{? ????????case?1:?return?[UIImage?imageNamed:@"1StarSmall"];? ????????case?2:?return?[UIImage?imageNamed:@"2StarsSmall"];? ????????case?3:?return?[UIImage?imageNamed:@"3StarsSmall"];? ????????case?4:?return?[UIImage?imageNamed:@"4StarsSmall"];? ????????case?5:?return?[UIImage?imageNamed:@"5StarsSmall"];? ????}? ????return?nil;? }?
把tableView:cellForRowAtIndexPath: 改成:
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath? {? ????UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:@"PlayerCell"];? ?? ????Player?*player?=?(self.players)[indexPath.row];? ?? ????UILabel?*nameLabel?=?(UILabel?*)[cell?viewWithTag:100];? ????nameLabel.text?=?player.name;? ?? ????UILabel?*gameLabel?=?(UILabel?*)[cell?viewWithTag:101];? ????gameLabel.text?=?player.game;? ?? ????UIImageView?*ratingImageView?=?(UIImageView?*)[cell?viewWithTag:102];? ????ratingImageView.image?=?[self?imageForRating:player.rating];? ?? ????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:
@interface?PlayerCell?:?UITableViewCell? ?? @property?(nonatomic,?weak)?IBOutlet?UILabel?*nameLabel;? @property?(nonatomic,?weak)?IBOutlet?UILabel?*gameLabel;? @property?(nonatomic,?weak)?IBOutlet?UIImageView?*ratingImageView;? ?? @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 類:
#import?"PlayerCell.h"?
然后把cellForRowAtIndexPath 改為:
-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath? {? ????PlayerCell?*cell?=?(PlayerCell?*)[tableView?dequeueReusableCellWithIdentifier:@"PlayerCell"];? ?? ????Player?*player?=?(self.players)[indexPath.row];? ????cell.nameLabel.text?=?player.name;? ????cell.gameLabel.text?=?player.game;? ????cell.ratingImageView.image?=?[self?imageForRating:player.rating];? ?? ????return?cell;? }?
更喜歡它了吧,現在你通過dequeueReusableCellWithIdentifier ?獲取PlayerCell的實例,然后可以設置 它的 labels 以及 imageview。
運行應用,它看起來跟之前沒什么不同,但是要注意到,你現在已經用的是自定義的tableviewcell 的子類了。
何去何從?
點擊查看該教程的第二部分,它涵蓋了segues,靜態table view cells以及下載示例工程等。
總結
以上是生活随笔為你收集整理的storyboard 使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xcode11新项目删除main.sto
- 下一篇: 零中频接收机频率转换图_【新品情报站】俄