三十而立,從零開始學ios開發(十七):Storyboards(上)

來源:互聯網
上載者:User

在開始這章之前,先做個說明,從這篇開始,我所使用的xcode更新成了最新的版本,版本是4.6.1(4H512),如下:

大家可以開啟自己電腦上的App Store,然後搜尋xcode,第一個出現的就是Xcode,然後直接點擊安裝就行,很方便且智能,如果你的電腦上有舊版本的xcode,它還會提示你刪除,反正整個過程我按住下來還是很容易的。

另外,從這篇開始,我使用的教程也做了相應的升級,現在使用的教程為

這個大家去搜一下就可以找到,很方便。

好了,其他的沒什麼不同,下面開始我們這一篇的學習。

1)Storyboard簡介
這次學習的內容是在iOS 5的時候才加入的一個新的東西:Storyboard,簡單的翻譯成“故事版”(好吧,我覺得這個名字蠻挫的),它簡化了一些開發app時的一些步驟,例如自動為我們添加必要的delegate/dataSource,在多個view之間的切換,使用圖和線串連各個view,讓我們能夠清晰的看到各個view之間的前後關係。這樣的好處是減輕了我們在管理view之前切換時的工作量,能夠讓我們把更多的注意力集中在具體的功能實現上,然後是我們對整個的app view之間的關係有一個整體的瞭解。

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

找個地方儲存建立的項目,完成建立

在project navigator中,預設幫我們建立的檔案有很多都是和之前一樣的,有BIDAppDelegate,BIDViewController,但是我們沒有發現xib檔案,取而代之的是一個MainStoryboard.storyboard,在這個storyboard中,藏著一個系統預設幫我們建立的xib,選中MainStoryboard.storyboard,在editor area中,會出現一個xib,而整個xib的controller檔案正是BIDViewController,至此所有預設建立的檔案都已經對上號了。

開啟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,但是在某些情況下,我們可以事Crowdsourced Security Testing道將要產生的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一下吧,這裡不做詳細解釋了。

編譯運行,效果如下

 

Simple Storyboard

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.