在開始這章以前,先作個說明,從這篇開始,我所使用的xcode更新成了最新的版本,版本是4.6.1(4H512),以下:web
你們能夠打開本身電腦上的App Store,而後搜索xcode,第一個出現的就是Xcode,而後直接點擊安裝就行,很方便且智能,若是你的電腦上有舊版本的xcode,它還會提示你刪除,反正整個過程我按住下來仍是很容易的。xcode
另外,從這篇開始,我使用的教程也作了相應的升級,如今使用的教程爲
這個你們去搜一下就能夠找到,很方便。app
好了,其餘的沒什麼不一樣,下面開始咱們這一篇的學習。iphone
1)Storyboard簡介
此次學習的內容是在iOS 5的時候才加入的一個新的東西:Storyboard,簡單的翻譯成「故事版」(好吧,我以爲這個名字蠻挫的),它簡化了一些開發app時的一些步驟,例如自動爲咱們添加必要的delegate/dataSource,在多個view之間的切換,使用圖和線鏈接各個view,讓咱們可以清晰的看到各個view之間的先後關係。這樣的好處是減輕了咱們在管理view以前切換時的工做量,可以讓咱們把更多的注意力集中在具體的功能實現上,而後是咱們對整個的app view之間的關係有一個總體的瞭解。ide
Storyboard仍是基於xib(Xcode's Interface Builder),可是一個Storyboard中又能夠包含多個xib,每一個xib都一個它本身的controller綁定。好像,下面先舉一個簡單的例子,來直觀的感覺一下什麼是Storyboard。佈局
2)Create a Simple Storyboard
建立一個project,左邊選擇Application,右邊選擇Single View Application,點擊Next學習
將項目命名爲「Simple Storyboard」,而後選中Use Storyboards,單擊Next字體
找個地方保存新建的項目,完成建立ui
在project navigator中,默認幫咱們建立的文件有不少都是和以前同樣的,有BIDAppDelegate,BIDViewController,可是咱們沒有發現xib文件,取而代之的是一個MainStoryboard.storyboard,在這個storyboard中,藏着一個系統默認幫咱們建立的xib,選中MainStoryboard.storyboard,在editor area中,會出現一個xib,而整個xib的controller文件正是BIDViewController,至此全部默認建立的文件都已經對上號了。this
打開dock,選中View Controller節點並展開,你會發現,在layout area下的一個黑色區域中顯示的圖標和dock中是同樣的,這個黑色區域和上方的view組成了一個場景,叫作scene。(在scene中還有一個Exit,這個就不做介紹了,由於書本里面也是省略的)在view的左邊有一個大大的箭頭,這個箭頭是用來講明該app的起始view是哪一個。
在layout area的右下方有一個小圖標,這個是用來切換iphone4和iphone5的(咱們的這個例子仍是基於iphone4的界面)
好了,簡單的介紹就到這裏,下面繼續咱們這個例子,從Object library中拖一個Label放到view的中間,雙擊Label,輸入「Simple」
好了編譯運行你的程序,一個最簡單的Storyboard app完成了
當咱們使用Storyboard開發app的時候,不少事情程序都會幫咱們完成,包括如何載入默認的xib。若是你選中project navigator中的項目名稱
在editing pane中你能夠找到程序默認載入的storyboard,這裏例子中默認的storyboard是MainStoryboard.storyboard
3)Storyboard with UITableViewController
在以前幾篇的例子中,咱們已經不少次的使用到了UITableViewController,對其操做的方式應該已經很熟悉了,通常是tableview中包含不少個cell,每一個cell有一個identifier,建立cell的時候用到的方法是cellForRowAtIndexPath。在storyboard中,仍是會用到這些,可是會相對簡單一些,下面咱們接着上面的例子作下去。
選中Project navigator中的Simple Storyboard文件夾,單擊鼠標右鍵,選擇「New File...」,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點擊Next按鈕,在下一個窗口中將class命名爲BIDTaskListController,Subclass of命名爲UITableViewController,點擊Next按鈕,完成建立。
接着選中MainStoryboard.storyboard,從Object library中拖一個Table View Controller到layout area
在dock中,選中剛纔拖入的Table View Controller(這樣可以抱着咱們選中的是layout area中整個的Table View Controller)
打開Identity inspector,將Class設置爲BIDTaskListController,當設置完成後,dock中的table view會變成Task List Controller
這樣咱們新加的TableViewController就和它的類對應起來了,tableview也知道它能夠去哪裏取得它所須要的數據。
在拖入的Table View Controller上,有一個默認的cell(Prototype Cells),咱們能夠爲其添加identifier,在其上面定製本身的cell樣式(注意,咱們能夠添加任意多個Prototype Cells,每一個cell用identifier來區分,定製不一樣的樣式,這裏的cell只是一個原型,根據原型cell生成正式的cell,以後會有一個這樣的例子)。咱們選中整個默認的cell,並打開attributes inspector,找到Identifier,輸入plainCell
而後從object library中,拖一個Label放到原型cell上,Label如何佈局看我的愛好,選中Label,在attributes inspector中找到Tag,將其值設爲1,這樣在code中就能夠經過Tag的值找到Label了。
接着,咱們選中整個的cell,你也能夠到dock中去選,這樣比較準確,而後按Command + D,或者從菜單欄中選擇Edit>Duplicate,複製一個cell,這樣在table view中就有2個prototype cell了
(這裏有一個很是有用的小技巧,當你想直接在view中選擇本身想要的元素時,可是又礙於一個view上疊加的元素太多很難直接選中,那麼在這時,你同時按住鍵盤上的shift和control鍵,而後在你想選擇的元素上點擊鼠標,會彈出一個窗口,上面羅列了鼠標點擊的位置下全部存在的元素,而後你再去進行選擇會變的異常的簡單。
例如我在cell中的Label上點鼠標
鼠標點擊的位置一共有4個層疊元素
若是咱們在cell上點擊鼠標
Label不見了,只有三個元素。
這麼樣,用這樣的方法去選擇元素很簡單吧,仍是蠻佩服蘋果在細節方面的考慮和設計的。)
選中新加的cell,在attributes inspector中將Identifier賦值爲attentionCell
選中Label,在attributes inspector中將其顏色設置爲紅色
好了,對於這個table view的操做所有完成,在開始具體的編寫代碼以前,還有一件事情,將layout area中的那個大大的箭頭移到這個table view上,這樣程序在載入的時候默認的會顯示這個view
保存一下MainStoryboard.storyboard,下面開始具體的編碼。
打開BIDTaskListController.m文件,你會發現不少經常使用的方法已經存在:
viewDidLoad
didReceiveMemoryWarning
numberOfSectionsInTableView
numberOfRowsInSection
cellForRowAtIndexPath
didSelectRowAtIndexPath
咱們只要直接往這些方法中填代碼就能夠了,添加以下代碼
#import "BIDTaskListController.h" @interface BIDTaskListController () @property (strong, nonatomic) NSArray *tasks; @end @implementation BIDTaskListController ...... - (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; self.tasks = @[@"Walk the dog", @"URGENT: Buy milk", @"Clean hidden lair", @"Invent miniature dolphins", @"Find new henchmen", @"Get revenge on do-gooder heroes", @"URGENT: Fold laundry", @"Hold entire world hostage", @"Manicure"]; } ...... #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Potentially incomplete method implementation. // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete method implementation. // Return the number of rows in the section. return [self.tasks count]; }
首先和以前同樣,定義一個NSArray類型的tasks,用於保存table view中的行,而後在viewDidLoad中對tasks進行賦值(這裏的語法和以前我看到的賦值方法有點不一樣,越到後面,語句寫的越是精煉啊),在numberOfSectionsInTableView中,返回1,表示只有一個section,在numberOfRowsInSection中返回section中row的數量。這些都很簡單,接着添加代碼
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; NSString *identifier = nil; NSString *task = [self.tasks objectAtIndex:indexPath.row]; NSRange urgentRange = [task rangeOfString:@"URGENT"]; if (urgentRange.location == NSNotFound) { identifier = @"plainCell"; } else { identifier = @"attentionCell"; } UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; // Configure the cell... UILabel *cellLabel = (UILabel *)[cell viewWithTag:1]; NSMutableAttributedString *richTask = [[NSMutableAttributedString alloc] initWithString:task]; NSDictionary *urgentAttributes = @{NSFontAttributeName : [UIFont fontWithName:@"Courier" size:24], NSStrokeWidthAttributeName : @3.0}; [richTask setAttributes:urgentAttributes range:urgentRange]; cellLabel.attributedText = richTask; return cell; }
代碼一開始定義了一個identifier,而後根據indexPath得到tasks中的task,NSRange能夠認爲是一個範圍或者一種排列,它根據這個範圍或者排列到另外一個對象去尋找,若是找到了就返回開始的位置,若是沒有找到就返回NSNotFound。NSRange的對象urgentRange定義了一個字段「URGENT」,它在task中進行匹配,若是存在,那麼這個cell就把plainCell賦給identifier,若是不存在則將attentionCell賦給identifier。而後根據identifier從tableView的方法dequeueReusableCellWithIdentifier中獲得相應的cell。
以後的一段是對cell上的label進行操做,還記得剛纔咱們在attributes inspector中將Label的Tag設置爲1了嗎?這裏就用到了,使用viewWithTag的方法在cell中找到Label,而後對Label進行賦值,以後的一些操做是對特定的字符串「URGENT」進行操做,更改它的字體屬性。這些就一筆帶過吧,畢竟咱們的注意力不是集中在這個上面,對Label操做完後,將其賦給cellLabel,最後返回cell。
好了,編譯運行(編譯時會有warning產生,這個不用去理會,編譯仍是會成功,這些warning是告訴你在Storyboard中有xib是沒有被使用的,咱們的箭頭沒有指向它且和當前的view又沒有聯繫,因此不會對其進行操做,有warning是正常的),效果以下
若是task中包含字符串「URGENT」那麼將會使用identifier爲attentionCell的cell,不然就使用identifier爲plainCell的cell。
4)Static Cells
在大部分的狀況下,table view中的cell都是須要動態生成了,app運行時,根據source的不一樣生成不一樣數量或者樣式的cell,可是在某些狀況下,咱們能夠事先知道將要生成的cell是什麼樣子的,且它是固定不變的,咱們把這樣的cell稱之爲Static Cells,與其對應的則是dynamic cell。在這裏咱們舉一個簡單的例子來講明這種狀況。
咱們不用建立一個新的project,直接在上面的程序中接着添加代碼。選中Project navigator中的Simple Storyboard文件夾,單擊鼠標右鍵,選擇「New File...」,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點擊Next按鈕,在下一個窗口中將class命名爲BIDStaticCellsController,Subclass of命名爲UITableViewController,點擊Next按鈕,完成建立。
選中MainStoryboard.storyboard,再從Object library中拖一個Table View Controller到layout area,就放在原有2個view的右邊,接着將箭頭指向這個新添加的view
圖中最右邊的是新添加的view,這些view看上去比較小,是由於我了layout area右下角的,這樣能夠方便觀察每個view(固然在縮小的狀態下,是沒有辦法對view進行操做的,只能移動其位置,要操做view,必須將view放大回正常的大小)
選中剛纔添加的controller中的table view,打開attributes inspector,找到Content,在其下拉框中選擇「Static Cells」,找到Style,在其下拉框中選擇「Grouped」
table view的樣式也隨之發生了變化,出現了3行row,section的樣式變成了一個圓角矩形
選中section,在其attributes inspector設置以下,Rows改成2,Header中填寫「Silliest Clock Ever」
改完後的section
下面對2個cell進行設置,選中第一個cell,在attributes inspector中將其Style設置爲「Left Detail」
而後雙擊Title,改爲「The Date」,重複上面的步驟,將第二個cell的Title改爲「The Time」,改完後的效果
以後,咱們將建立兩個outlet對象,分別指向2個Detail,這樣在app運行後,就能夠改變它們的值了。
如今先關聯這個table view controller和它的類,在dock中選中Table View Controller,而後打開identity inspector,在Class中輸入「BDIStaticCellsController」,dock中的名字也隨之發生改變
仍是在dock中選中controller的狀態下,將Editor的模式設置成Assistant editor,這樣BIDStaticCellsController.h文件會打開(若是打開的不是這個文件,那麼就手動打開吧),選中第一個cell中的Detail,而後control-drag到BIDStaticCellsController.h中並釋放,會彈出個窗口,將Name命名爲「dateLabel」
對第二個cell中的Detail進行相同的操做,將Name命名爲「timeLabel」,添加完成後的BIDStaticCellsController.h
#import <UIKit/UIKit.h>
@interface BIDStaticCellsController : UITableViewController
@property (weak, nonatomic) IBOutlet UILabel *dateLabel; @property (weak, nonatomic) IBOutlet UILabel *timeLabel; @end
下面開始編寫代碼,打開BIDStaticCellsController.m,先將下面三個方法刪除
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Potentially incomplete method implementation. // Return the number of sections. return 0; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete method implementation. // Return the number of rows in the section. return 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; // Configure the cell... return cell; }
由於咱們使用的是static cell,所以table view中section的數量,section中cell的數量都是固定不變的,咱們也不須要重新建立cell,cell一共才2個,會一直顯示在屏幕上。
接着添加下面的代碼
- (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; NSDate *now = [NSDate date]; self.dateLabel.text = [NSDateFormatter localizedStringFromDate:now dateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterNoStyle]; self.timeLabel.text = [NSDateFormatter localizedStringFromDate:now dateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterLongStyle]; }
在viewDidLoad中,分別對dateLabel和timeLabel進行了設置,至於NSDate和NSDateFormatter的說明你們就去google一下吧,這裏不作詳細解釋了。
編譯運行,效果以下