由於最近才接觸到IOS,蘋果已經建議storyboard來搭建所有界面了,於是我也追隨時尚,直接開始使用storyboard。(不料在涉及到頁面跳轉的時候,遇到的問題是:點擊後沒有任何反應)衆所周知,在storyboard中,界面的跳轉是通過segue來實現的,利用它,省去了方法內寫入跳轉的代碼。
一 視圖跳轉
《StoryBoard下的視圖跳轉》
我們知道:segue共有三種類型:push,modal,和custom。如下圖://01
簡單說下這三個的作用:使用導航欄壓進新的控制器(push),模態的加載視圖控制器(modal),自定義(custom)。
好了,廢話少說,現在開始我們的旅行。
1,首先建立一個Single View 模板的項目,記得勾選上storyboard。然後打開它,在rootViewController(也就是我們的主視圖)添加一些label和一個button。
2,在右邊的庫中拖入一個ViewController,也添加一個Label。具體如下圖所示://02
3,選中button,右鍵(或control+鼠標左鍵)拖拽到第二個ViewController中,選擇:Modal,然後記得save。這個時候,運行模擬器,點擊button,你會發現成功跳轉到了第二個界面。我們沒有在代碼區做任何操作,甚至連button和第二個ViewController都沒有創建,確實就是這麼的簡單。//03
好了,到了這裏,簡單說一下storyboard下,利用segue界面跳轉一共有兩種方式:
第一種就是以上我的例子,利用button組件,拖拽添加segue,直接運行就可以用。
第二種是利用ViewController與ViewController之間,拖拽添加segue。不過,這種方法就需要在相應需要跳轉的方法內寫入代碼,手動去設置它的跳轉。
4,把剛纔例子設置button的segue刪除(右鍵,點X),一切恢復了最初時的狀態,我們給buttom添加一個點擊的方法,然後在ViewController.m中實現此方法,在方法體內寫入這樣的代碼://04
5,注意看方法參數:@"second",這個second是我自命名的一個標示符,一會你就會遇到。
6,save保存,打開storyboard,選中rootViewController,右鍵拖拽到第二個ViewController,在彈出的界面同樣選擇:modal。//05
7,打開這個segue的設置頁面:設置其identifier爲second,就是我在代碼中的那個自命名參數。
8,save保存,運行模擬器,你會驚奇的發現,實現了同樣的跳轉。
到現在爲止,我們一共用兩種簡單的方式實現了視圖的跳轉:1是設置button的segue,2是設置viewcontroller與viewcontroller之間的segue,只是後者需要在代碼中手動管理跳轉。
看似很簡單的事情,卻讓我耽誤一些時間,主要是因爲我在網上看的好多例子都是以UINavigationController爲rootviewController(這樣省事省時,跳轉後還可以利用系統爲我們創建的返回按鈕返回到rootViewController),然後用button拖拽到第二個視圖時選擇的push,由於當時不理解push相關的類型含義,所以在寫的時候,我總是選擇push,造就了點擊後無法跳轉。現在終於明朗了,記錄下來,供不明白的同學學習。
----------------------------------------------------------------------------------------------------
//根據 segue Identifier跳轉界面
[self performSegueWithIdentifier:@"GotoTwo" sender:self];
//以modal 方式跳轉
[self presentModalViewController:nil animated:YES];
//壓進一個viewcontroller
[self.navigationController pushViewController:nil animated:YES];
//彈出一個viewcontroller 相當與返回上一個界面
[self.navigationController popViewControllerAnimated:YES];
// 以 modal跳轉的返回方法
[self dismissModalViewControllerAnimated:YES];
-----------------------------------------------------------------------------------------------------再寫一下關於segue三個類型的詳解:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在storyboard中,segue有幾種不同的類型,在iphone和ipad的開發中,segue的類型是不同的。
在iphone中,segue有:push,modal,和custom三種不同的類型,這些類型的區別在與新頁面出現的方式。
而在ipad中,有push,modal,popover,replace和custom五種不同的類型。
modal
最常用的場景,新的場景完全蓋住了舊的那個。用戶無法再與上一個場景交互,除非他們先關閉這個場景。
是在viewController中的標準切換的方式,包括淡出什麼的,可以選切換動畫。
Modalview:就是會彈出一個view,你只能在該view上操作,而不能切換到其他view,除非你關閉了modalview.
Modal View對應的segue type就是modal segue。
*Modal:Transition to another scene for the purposes of completing a task.當user在彈出的modalview裏操作完後,就應該dismiss the modal view scene然後切換回the originalview.
push
Push類型一般是需要頭一個界面是個Navigation Controller的。
是在navigation View Controller中下一級時使用的那種從右側劃入的方式
*Push:Create a chain of scenes where the user can move forward or back.該segue type是和navigation viewcontrollers一起使用。
popover(iPad only)
popover 類型,就是採用浮動窗的形式把新頁面展示出來
*Popover(iPad only):Displays the scene in a pop-up “window” over top of the current view.
Replace (iPad only):
替換當前scene,
Replace the current scene with another. This is used in some specialized iPad viewcontrollers (e.g. split-view controller).
custom
就是自定義跳轉方式啦。
*Custom:Used for programming a customtransition between scenes.
在Storyboard中使用自定義的segue類型
參考http://ryan.easymorse.com/?p=72
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
《Xib下的視圖跳轉》
現在說一下,沒有使用Storyboard,直接創建xib時的頁面跳轉,其實也很簡單,只要理解了,都不是問題。我也是從java剛轉過來,起初感覺很不適應,但是現在發現interface builder真的是太強大了。
1,創建一個項目,我用的是Empty Application模版,這種模版創建出來的項目只包含一個Appdelegate.h和Appdelegate.m文件,rootviewController需要我們自行創建。(注意:最新的版本,apple把MainWindow.xib文件取消了,所以無法打開xib查看包含的圖標)此時運行模擬器只會顯示空白的界面。好了,File-newFile 創建一個Object-C class,打開後,subclass of 選擇默認的UIViewController,注意,需要勾選上With XIB for user interface,不然一會無法創建主視圖。
2,創建好後,打開其xib文件,簡單添加一些button組件。此時保存運行程序還是無法顯示我們創建的RootViewController。【有時如果你在項目清單下的user interface 選擇此MainViewController運行後臺還會報:Applications are expected to have a root view controller at the end of application launch的錯誤,原因都是項目的Delegate無法發現一個rootViewContrller】所以這就需要我們手動在AppDelegate中讓它們關聯起來。
AppDelegate.h
AppDelegate.m
[self.viewController就是我們在.h文件中聲明的]
3,好了,保存後,這個時候運行就能顯示我們的界面了~同樣也很簡單吧!好了,我們現在參照以上的方法,再創建一個SecondViewController(記得勾選xib),然後我們給rootviewcontroller視圖的 button添加一個事件方法,可以讓它點擊後跳轉到SecondViewController。
(首先創建了一個SecondViewController並實例化,intitWithNibName的參數一定要正確寫控制器配對的xib文件的名稱,調用presentModalViewController:controller 就可以跳轉啦。)
發現了把,其實都挺簡單的,本來可以創建single View Application模板的,這樣就省去創建rootViewController和在Delegate中寫那些代碼了,我這樣也就是讓大家感受一下,xib,delagate,stroyboard之間的區別和聯繫,都嘗試一下,你們就會明白他們之間的機制,至少可以會寫界面和跳轉的方法啦。哈哈,有什麼問題大家一起交流,我也是初學者,可以給我留言噢。~~~
二 頁面傳值
方法一使用segue傳遞數據,繼續上面的項目例子。
1,在rootViewController聲明一個UITextField並與storyboard關聯上。File-add添加一個SecondViewController(繼承UIViewController),然後在keyboard第二個viewcontroller的屬性設置其class關聯。同樣在SecondViewController聲明一個UITextField並關聯。如圖所示://06
2,然後在rootViewController.m的文件中覆蓋名稱爲:prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender的方法,並寫入如下語句,如圖://07
3,我們獲取了主視圖的文本框內容,並通過segue的方法發送了出去,接下來要做的就是在secondViewController聲明一個@property NSString * 類型,名稱爲data的字符串,然後在其.m文件中的-(void) viewDidLoad方法中寫入如下代碼://08
注意:發送數據時,[send setValue:msg forKey:@"data"]; 這個"data"名稱一定要與跳轉後界面的聲明的類型對象的命名一致,不然的話,跳轉後的界面是收不到傳遞的值的。
方法二,使用notification廣播實現視圖跳轉傳遞數據,繼續上面的項目展開。
廣播機制分爲:註冊----發送------------接收(接收方),具體請看一下代碼。
1,在要發送數據的視圖頁面.m文件處理髮送邏輯的方法裏註冊+發送
- - (IBAction)pressed:(id)sender {
- // [self performSegueWithIdentifier:@"second" sender:self];
- NSLog(@"send message:%@",firstField.text);
- //頁面跳轉傳值方法二:利用notification
- NSDictionary *dicts = [NSDictionary dictionaryWithObjectsAndKeys:@"one1",@"one",@"two2",@"two",@"three3",@"three", nil];
- //註冊(第一步)
- NSNotification *notification =[NSNotification notificationWithName:@"mynotification" object:firstField.text];
- //發送(第二步)
- [[NSNotificationCenter defaultCenter] postNotification:notification];
- //註冊+發送也可以一行完成(等效於以上兩行)
- [[NSNotificationCenter defaultCenter] postNotificationName:@"mynotification2" object:dicts];//發送一個字典過去
- }
2,在跳轉後,接收數據視圖頁面.m文件中處理邏輯的方法裏 接收
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view.
- //接受端:接受(第一步)
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationHandler:) name:@"mynotification" object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationHandler2:) name:@"mynotification2" object:nil];
- }
- //自定義接收信息和處理的方法(第二步)
- -(void) notificationHandler:(NSNotification *) notification{
- secondField.text = [notification object];//收到消息後在UItextField中顯示出來
- }
- //自定義接收字典信息的方法
- -(void) notificationHandler2:(NSNotification *) notification2{
- NSDictionary *dict = [notification2 object];
- NSLog(@"receive dict :%@,forkey:%@",dict,[dict objectForKey:@"one"]);
- }
注意:如果註冊的notification在目標視圖沒有收到或名稱寫錯,目標視圖的相關方法就不會執行
國外參考論壇【傳送門】http://blog.isotoma.com/2009/11/on-objective-c-delegates-and-nsnotification-objects/
方法三,通過Delegate委託傳遞數據
此方法我測試完後,感覺不是太好用,有一些侷限性,相當於自定義讀取方法:無非是在A對象裏保存了一個B對象的指針,然後在A的某個函數裏去設置B對象某個屬性的值。
具體看教程把。
1,首先add a File-- Objective-C protocol,然後聲明一個傳遞數值的方法:
- //<1>自定義一個用來傳遞數值的delegate
- @protocol ViewPassValueDelegate <NSObject>
- -(void) passValue :( NSString *) value;
- @end
2,然後在要發送數據的視圖的.h文件下聲明一個自定義的delegate
- #import <UIKit/UIKit.h>
- #import "ViewPassValueDelegate.h"
- @interface ViewController : UIViewController{
- NSObject<ViewPassValueDelegate> *delegte ;
- }
- - (IBAction)pressed:(id)sender;//主視圖button點擊出發的Action
- @property (retain, nonatomic) IBOutlet UITextField *firstField;
- @end
3,在要發送數據的視圖的事件處理方法裏聲明一個secondViewController實例,然後賦值給 delegate,同時執行協議的 passValue方法
- - (IBAction)pressed:(id)sender {
- secondViewController *secondController = [[secondViewController alloc] init];//實例化一個視圖2的對象
- delegte = secondController;
- [delegte passValue:firstField.text];
- }
4,然後在接收數據視圖(secondViewController).h文件實現自定義協議
- //<2> 視圖1實現自定義協議
- @interface secondViewController : UIViewController<ViewPassValueDelegate>
5,在接收數據視圖(secondViewController).m文件中實現協議中的passValue方法:
- //<3>實現自定義delege的方法
- -(void) passValue:(NSString *)value{
- secondField.text= value;
- NSLog(@"passValue method get Value : %@ secondField.text:%@",value,secondField.text);
- }
目前總結是,以上value只是對視圖1對象賦值時的一個指針引用,出了方法範圍,就無效了。所以在方法體內打印都是有數據的,出了方法體,就沒有持有的引用了。
具體原因有待考察。