iOS開發系列--視圖切換

概述

在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程當中並不常見,除非你的應用足夠簡單。在iOS開發中經常使用的視圖切換有三種,今天咱們將一一介紹:html

  1. UITabBarController
  2. UINavigationController
  3. 模態窗口

UITabBarController

iOS三種視圖切換的原理各不相同:web

  • UITabBarController:以平行的方式管理視圖,各個視圖之間每每關係並不大,每一個加入到UITabBarController的視圖都會進行初始化即便當前不顯示在界面上,相對比較佔用內存。
  • UINavigationController:以棧的方式管理視圖,各個視圖的切換就是壓棧和出棧操做,出棧後的視圖會當即銷燬。
  • UIModalController:以模態窗口的形式管理視圖,當前視圖關閉前其餘視圖上的內容沒法操做。

UITabBarController 是Apple專門爲了利用頁籤切換視圖而設計的,在這個視圖控制器中有一個UITabBar控件,用戶經過點擊tabBar進行視圖切換。咱們知道在 UIViewController內部有一個視圖,一旦建立了UIViewController以後默認就會顯示這個視圖,可是 UITabBarController自己並不會顯示任何視圖,若是要顯示視圖則必須設置其viewControllers屬性(它默認顯示 viewControllers[0])。這個屬性是一個數組,它維護了全部UITabBarController的子視圖。爲了儘量減小視圖之間的耦 合,全部的UITabBarController的子視圖的相關標題、圖標等信息均由子視圖本身控制,UITabBarController僅僅做爲一個 容器存在。數據庫

UITabBarControllerLayout

假設如今有一個KCTabBarViewController(繼承於UITabBarController),它內部有一個KCWebChatViewController、一個KCContactViewController。數組

1.首先建立一個KCTabBarViewController繼承於UITabBarController(代碼是默認生成的,再也不貼出來)。微信

2.其次建立兩個子視圖,在這兩個子視圖控制器中設置對應的名稱、圖標等信息。app

KCWebChatViewController.mide

//
//  KCWorldClockViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCWebChatViewController.h" @interface KCWebChatViewController () @end @implementation KCWebChatViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor=[UIColor redColor]; //設置視圖控制器標題 self.title=@"Chat"; //注意經過tabBarController或者parentViewController能夠獲得其俯視圖控制器(也就是KCTabBarViewController) NSLog(@"%i",self.tabBarController==self.parentViewController);//對於當前應用兩者相等 //設置圖標、標題(tabBarItem是顯示在tabBar上的標籤) self.tabBarItem.title=@"Web Chat";//注意若是這個標題不設置默認在頁簽上顯示視圖控制器標題 self.tabBarItem.image=[UIImage imageNamed:@"tabbar_mainframe.png"];//默認圖片 self.tabBarItem.selectedImage=[UIImage imageNamed:@"tabbar_mainframeHL.png"];//選中圖片 //圖標右上角內容 self.tabBarItem.badgeValue=@"5"; } @end

KCContactViewController.m學習

//
//  KCAlarmViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCContactViewController.h" @interface KCContactViewController () @end @implementation KCContactViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor=[UIColor yellowColor]; self.tabBarItem.title=@"Contact"; self.tabBarItem.image=[UIImage imageNamed:@"tabbar_contacts.png"]; self.tabBarItem.selectedImage=[UIImage imageNamed:@"tabbar_contactsHL.png"]; } @end

3.在應用程序啓動後設置Tab bar視圖控制器的子視圖,同時將Tab bar視圖控制器做爲window的根控制器。ui

AppDelegate.mthis

//
//  AppDelegate.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "AppDelegate.h" #import "KCTabBarViewController.h" #import "KCWebChatViewController.h" #import "KCContactViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { _window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; KCTabBarViewController *tabBarController=[[KCTabBarViewController alloc]init]; KCWebChatViewController *webChatController=[[KCWebChatViewController alloc]init]; KCContactViewController *contactController=[[KCContactViewController alloc]init]; tabBarController.viewControllers=@[webChatController,contactController]; //注意默認狀況下UITabBarController在加載子視圖時是懶加載的,因此這裏調用一次contactController,不然在第一次展現時只有第一個控制器tab圖標,contactController的tab圖標不會顯示 for (UIViewController *controller in tabBarController.viewControllers) { UIViewController *view= controller.view; } _window.rootViewController=tabBarController; [_window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end

運行效果:

KCWebChatViewController      KCContactViewController

對於UITabBarController簡單總結以下:

  • UITabBarController會一次性初始化全部子控制器,可是默認只加載第一個控制器視圖,其餘視圖控制器只初始化默認不會加載,爲了 可以將其餘子控制器也正常顯示在Tab bar中咱們訪問了每一個子視圖控制器的視圖以便調用其視圖加載方法(viewDidLoad);固然,既然會調用子視圖的初始化方法,固然也能夠將視圖控 制器的tabBarItem屬性設置放到init方法中設置,如此則不用再遍歷其視圖屬性了。
  • 每一個視圖控制器都有一個tabBarController屬性,經過它能夠訪問所在的UITabBarController,並且對於UITabBarController的直接子視圖其tabBarController等於parentViewController。
  • 每一個視圖控制器都有一個tabBarItem屬性,經過它控制視圖在UITabBarController的tabBar中的顯示信息。
  • tabBarItem的image屬性必須是png格式(建議大小32*32)而且打開alpha通道不然沒法正常顯示。

注意:使用storyboard建立UITabBarController的內容今天再也不着重講解,內容比較簡單,你們能夠本身試驗。

UINavigationController

代碼方式建立導航

UINavigationController是一個導航控制器,它用來組織有層次關係的視圖,在UINavigationController中 子控制器以棧的形式存儲,只有在棧頂的控制器可以顯示在界面中,一旦一個子控制器出棧則會被銷燬。UINavigationController默認也不 會顯示任何視圖(這個控制器自身的UIView不會顯示),它必須有一個根控制器rootViewController,並且這個根控制器不會像其餘子控 制器同樣被銷燬。

UINavigationControllerLayout

下面簡單經過幾個視圖模擬一下微信添加好友的功能,假設有一個導航控制器,它的根控制器爲好友列表控制器 KCFriendViewController,經過它能夠導航到添加QQ聯繫人視圖KCQQContactViewController,在QQ聯繫人 視圖又能夠導航到公共帳號視圖KCPublicAccountViewController。

1.首先在應用代理啓動後初始化一個導航控制器並設置其根控制器爲KCFriendViewController

//
//  AppDelegate.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "AppDelegate.h" #import "KCTabBarViewController.h" #import "KCWebChatViewController.h" #import "KCContactViewController.h" #import "KCFriendViewController.h" #import "KCQQContactViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { _window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; _window.backgroundColor =[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1]; //設置全局導航條風格和顏色 [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]]; [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack]; KCFriendViewController *friendController=[[KCFriendViewController alloc]init]; UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:friendController]; _window.rootViewController=navigationController; [_window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end

2.在好友列表視圖控制器中設置導航欄左右按鈕,而且設置點擊右側按鈕導航到添加QQ聯繫人視圖

//
//  KCFriendViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCFriendViewController.h" #import "KCQQContactViewController.h" @interface KCFriendViewController () @end @implementation KCFriendViewController - (void)viewDidLoad { [super viewDidLoad]; //每次出棧都會銷燬相應的子控制器 NSLog(@"childViewControllers:%@",self.navigationController.childViewControllers); //在子視圖中能夠經過navigationController屬性訪問導航控制器, //同時對於當前子視圖來講其父控制器就是其導航控制器 NSLog(@"%i",self.navigationController==self.parentViewController); //在子視圖中(或者根視圖)有一個navigationItem用於訪問其導航信息 self.navigationItem.title=@"Friends";//或者直接設置控制器title(例如[self setTitle:@"Friends"]) //設置導航欄左側按鈕 self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"Edit" style:UIBarButtonSystemItemAdd target:nil action:nil]; //設置導航欄右側按鈕 self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"ff_IconAdd.png"] style:UIBarButtonItemStyleDone target:self action:@selector(addFriends)];  } -(void)addFriends{ //經過push導航到另一個子視圖 KCQQContactViewController *qqContactController=[[KCQQContactViewController alloc]init]; [self.navigationController pushViewController:qqContactController animated:YES]; } @end

3.在QQ聯繫人視圖右側導航中添加一個導航到公共帳號的按鈕

//
//  KCQQContactViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCQQContactViewController.h" #import "KCPublicAccountViewController.h" @interface KCQQContactViewController () @end @implementation KCQQContactViewController - (void)viewDidLoad { [super viewDidLoad]; //每次出棧都會銷燬相應的子控制器 NSLog(@"childViewControllers:%@",self.navigationController.childViewControllers); [self setTitle:@"QQ Contact"]; //self.title=@"QQ contact"; //self.navigationItem.title=@"My QQ"; UIBarButtonItem *back=[[UIBarButtonItem alloc]initWithTitle:@"QQ" style:UIBarButtonItemStyleDone target:nil action:nil]; self.navigationItem.backBarButtonItem=back; self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"Public Account" style:UIBarButtonItemStyleDone target:self action:@selector(gotoNextView)]; } -(void)gotoNextView{ KCPublicAccountViewController *publicAccountController=[[KCPublicAccountViewController alloc]init]; [self.navigationController pushViewController:publicAccountController animated:YES]; } @end

4.在公共帳號視圖中在導航欄右側設置一個按鈕用於直接返回根視圖

//
//  KCPublicNumberViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCPublicAccountViewController.h" @interface KCPublicAccountViewController () @end @implementation KCPublicAccountViewController - (void)viewDidLoad { [super viewDidLoad]; //每次出棧都會銷燬相應的子控制器 NSLog(@"childViewControllers:%@",self.navigationController.childViewControllers); self.title=@"Public Account"; self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"Add Friends" style:UIBarButtonItemStyleDone target:self action:@selector(gotoAddFriends)]; } -(void)gotoAddFriends{ //直接跳轉到根控制器,也可使用- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated; 方法 [self.navigationController popToRootViewControllerAnimated:YES]; } @end
  • UINavigationController默認顯示一個根控制器,這個根視圖必須指定(前面咱們說過 UINavigationController和UITabBarController相似僅僅做爲導航容器,自己並不會顯示視圖),經過根控制器導航到 其餘下一級子視圖。
  • 在子視圖中能夠經過navigationController訪問導航控制器,同時能夠經過navigationController的childViewControllers得到當前棧中全部的子視圖(注意每個出棧的子視圖都會被銷燬)。
  • UINavigationController導航是經過上方導航欄進行的(相似的UITabBarController是經過下方 UITabBar進行導航),每一個放到UINavigationController棧中的子視圖都會顯示一個導航欄,能夠經過子控制器(包括根控制器) 的navigationItem訪問這個導航欄,修改其左右兩邊的按鈕內容。
  • 默認狀況下除了根控制器以外的其餘子控制器左側都會在導航欄左側顯示返回按鈕,點擊能夠返回上一級視圖,同時按鈕標題默認爲上一級視圖 的標題,能夠經過backBarButtonItem修改。下一級子視圖左側返回按鈕上的標題的顯示優先級爲: 導航欄返回按鈕backBarButtonItem的標題(注意不能直接給backBarButtonItem的標題賦值,只能從新給 backBarButtonItem賦值)、導航欄navigationItem的標題,視圖控制器標題。

演示效果:

 NavigationControllerEffect

使用storyboard進行導航

鑑於不少初學者在學習UINavigationController時看到的多數是使用storyboard方式建立導航,並且storyboard中的segue不少初學者不是很瞭解,這裏簡單對storyboard方式建立導航進行介紹。

下面簡單作一個相似於iOS系統設置的導航程序,系統默認進入Settings視圖控制器,在Settings界面點擊General進行General視圖,點擊Sounds進入Sounds視圖,就那麼簡單。

1.首先在Main.storyboard中拖拽一個UINavigationController將應用啓動箭頭拖拽到新建的 UINavigationController中將其做爲默認啓動視圖,在拖拽過程當中會發現UINavigationController默認會帶一個 UITableViewController做爲其根控制器。

2.設置UITableViewController的標題爲「Settings」,同時設置UITableView爲靜態表格而且包含兩行,分別在兩個UITableViewCell中放置一個UILabel命名爲」General」和「Sounds」。

3.新建兩個UITableViewController,標題分別設置爲「General」、「Sounds」,按住Ctrl拖拽 「Settings」的第一個UITableViewCell到視圖控制器「General」,同時選擇segue爲「push」,拖拽第二個 UITableViewCell到視圖控制器「Sounds」,同時選擇segue爲「push」。

到這裏其實咱們已經能夠經過Settings視圖導航到General和Sounds視圖了,可是storyboard是如何處理導航的呢?

前面咱們看到導航的過程是經過一個名爲「Segue」鏈接建立的(前面採用的是push方式),那麼這個Segue是如何工做的呢?Segue的工做方式分爲如下幾個步驟:

1.建立目標視圖控制器(也就是前面的General、Sounds視圖控制器)

2.建立Segue對象

3.調用源視圖對象的prepareForSegue:sender:方法

4.調用Segue對象的perform方法將目標視圖控制器推送到屏幕

5.釋放Segue對象

要解釋上面的過程首先咱們定義一個KCSettingsTableViewController控制器,它繼承於 UITableViewController,而後在storyboard中設置「Settings」視圖控制器的class屬性爲 KCSettingsTableViewController。同時設置導航到「General」視圖控制器的segue的Identifier爲 「GeneralSegue」,設置導航到「Sounds」控制器的segue的Identifier爲「SoundsSegue」。

而後修改KCSettingsTableViewController.m添加以下代碼:

#pragma mark - 導航 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ //源視圖控制器 UITableViewController *settingController=segue.sourceViewController; //目標視圖控制器 UITableViewController *tableViewController=segue.destinationViewController; NSLog(@"sourceController:%@,destinationController:%@",settingController.navigationItem.title,tableViewController.navigationItem.title); }

此時運行程序導航咱們會發現此方法會被調用的同時能夠打印源視圖控制器和目標視圖控制器的信息,這一步對應上面所說的第三個步驟。

接着在」Settings」視圖控制器的導航欄左右兩側分別放一個UIBarButtonItem並添加對應事件代碼以下:

- (IBAction)toGeneral:(id)sender {
    [self performSegueWithIdentifier:@"GeneralSegue" sender:self]; } - (IBAction)toSounds:(id)sender { [self performSegueWithIdentifier:@"SoundsSegue" sender:self]; }

此時運行程序發現,使用兩個按鈕一樣能夠導航到對應的視圖控制器,這一步對應上面第四個步驟,只是默認狀況下是本身執行的,這裏咱們經過手動調用來演示了這個過程。

運行效果以下:

NavigationControllerByStoryboardEffec

模態窗口

模態窗口只是視圖控制器顯示的一種方式(在iOS中並無專門的模態窗口類),模態窗口不依賴於控制器容器(例如前兩種視圖切換一個依賴於 UITabBarController,另外一個依賴於UINavigationController),一般用於顯示獨立的內容,在模態窗口顯示的時其餘 視圖的內容沒法進行操做。

模態窗口使用起來比較容易,通常的視圖控制器只要調用- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion NS_AVAILABLE_IOS(5_0);方法那麼參數中的視圖控制器就會以模態窗口的形式展示,同時調用- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion NS_AVAILABLE_IOS(5_0);方法就會關閉模態窗口。

下面的示例中演示了一個登陸操做,點擊主界面左上方登陸按鈕以模態窗口的形式展示登陸界面,用戶點擊登陸界面中的登陸按鈕就會返回到主界面。特別強 調一點在下面的示例中導航欄是手動建立的,而不是採用UINavigationController,爲了幫助你們熟悉導航欄使用同時也瞭解了 UInavigationController中導航欄的本質。

1.首先建立一個登陸界面,在界面中只有兩個輸入框和一個登陸按鈕

//
//  KCLoginViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCLoginViewController.h" @interface KCLoginViewController () @end @implementation KCLoginViewController - (void)viewDidLoad { [super viewDidLoad]; [self addLoginForm]; } -(void)addLoginForm{ //用戶名 UILabel *lbUserName=[[UILabel alloc]initWithFrame:CGRectMake(50, 150, 100, 30)]; lbUserName.text=@"用戶名:"; [self.view addSubview:lbUserName]; UITextField *txtUserName=[[UITextField alloc]initWithFrame:CGRectMake(120, 150, 150, 30)]; txtUserName.borderStyle=UITextBorderStyleRoundedRect; [self.view addSubview:txtUserName]; //密碼 UILabel *lbPassword=[[UILabel alloc]initWithFrame:CGRectMake(50, 200, 100, 30)]; lbPassword.text=@"密碼:"; [self.view addSubview:lbPassword]; UITextField *txtPassword=[[UITextField alloc]initWithFrame:CGRectMake(120, 200, 150, 30)]; txtPassword.secureTextEntry=YES; txtPassword.borderStyle=UITextBorderStyleRoundedRect; [self.view addSubview:txtPassword]; //登陸按鈕 UIButton *btnLogin=[UIButton buttonWithType:UIButtonTypeSystem]; btnLogin.frame=CGRectMake(120, 270, 80, 30); [btnLogin setTitle:@"登陸" forState:UIControlStateNormal]; [self.view addSubview:btnLogin]; [btnLogin addTarget:self action:@selector(login) forControlEvents:UIControlEventTouchUpInside]; } #pragma mark 登陸操做 -(void)login{ [self dismissViewControllerAnimated:YES completion:nil]; } @end

2.定義主界面視圖控制器KCMainViewController,在左上角放一個登陸按鈕用於彈出登陸界面

//
//  KCMainViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMainViewController.h" #import "KCLoginViewController.h" @interface KCMainViewController () @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; [self addNavigationBar]; }  #pragma mark 添加導航欄 -(void)addNavigationBar{ //建立一個導航欄 UINavigationBar *navigationBar=[[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 44+20)]; //navigationBar.tintColor=[UIColor whiteColor]; [self.view addSubview:navigationBar]; //建立導航控件內容 UINavigationItem *navigationItem=[[UINavigationItem alloc]initWithTitle:@"Web Chat"]; //左側添加登陸按鈕 UIBarButtonItem *loginButton=[[UIBarButtonItem alloc]initWithTitle:@"登陸" style:UIBarButtonItemStyleDone target:self action:@selector(login)]; navigationItem.leftBarButtonItem=loginButton; //添加內容到導航欄 [navigationBar pushNavigationItem:navigationItem animated:NO]; } #pragma mark 登陸操做 -(void)login{ KCLoginViewController *loginController=[[KCLoginViewController alloc]init]; //調用此方法顯示模態窗口 [self presentViewController:loginController animated:YES completion:nil]; } @end

參數傳遞

假設用戶名輸入「kenshincui」,密碼輸入「123」就認爲登陸成功,不然登陸失敗。同時登陸成功以後在主視圖控制器中顯示用戶名而且登陸按鈕變成「註銷」。要實現這個功能主要的問題就是如何把登陸後的用戶名信息傳遞到主界面?由此引出一個問題:多視圖參數傳遞。

在iOS開發中經常使用的參數傳遞有如下幾種方法:

  1. 採用代理模式
  2. 採用iOS消息機制
  3. 經過NSDefault存儲(或者文件、數據庫存儲等)
  4. 經過AppDelegate定義全局變量(或者使用UIApplication、定義一個單例類等)
  5. 經過控制器屬性傳遞

今天咱們主要採用第一種方式進行數據傳遞,這在iOS開發中也是最多見的一種多視圖傳參方式。使用代理方式傳遞參數的步驟以下:

1.定義協議,協議中定義好傳參時所須要的方法

2.目標視圖控制器定義一個代理對象

3.源視圖控制器實現協議並在初始化目標控制器時指定目標控制器的代理爲其自身

4.須要傳參的時候在目標窗口調用代理的協議方法

具體代碼以下:

KCMainViewController.h

//
//  KCMainViewController.h
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <UIKit/UIKit.h> #pragma mark 定義一個協議用於參數傳遞 @protocol KCMainDelegate -(void)showUserInfoWithUserName:(NSString *)userName; @end @interface KCMainViewController : UIViewController @end

KCMainViewController.m

//
//  KCMainViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMainViewController.h" #import "KCLoginViewController.h" @interface KCMainViewController ()<KCMainDelegate,UIActionSheetDelegate>{ UILabel *_loginInfo; UIBarButtonItem *_loginButton; BOOL _isLogon; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; [self addNavigationBar]; [self addLoginInfo]; } #pragma mark 添加信息顯示 -(void)addLoginInfo{ _loginInfo =[[UILabel alloc]initWithFrame:CGRectMake(0, 100,320 ,30)]; _loginInfo.textAlignment=NSTextAlignmentCenter; [self.view addSubview:_loginInfo]; } #pragma mark 添加導航欄 -(void)addNavigationBar{ //建立一個導航欄 UINavigationBar *navigationBar=[[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 44+20)]; //navigationBar.tintColor=[UIColor whiteColor]; [self.view addSubview:navigationBar]; //建立導航控件內容 UINavigationItem *navigationItem=[[UINavigationItem alloc]initWithTitle:@"Web Chat"]; //左側添加登陸按鈕 _loginButton=[[UIBarButtonItem alloc]initWithTitle:@"登陸" style:UIBarButtonItemStyleDone target:self action:@selector(login)]; navigationItem.leftBarButtonItem=_loginButton; //添加內容到導航欄 [navigationBar pushNavigationItem:navigationItem animated:NO]; } #pragma mark 登陸操做 -(void)login{ if (!_isLogon) { KCLoginViewController *loginController=[[KCLoginViewController alloc]init]; loginController.delegate=self;//設置代理 //調用此方法顯示模態窗口 [self presentViewController:loginController animated:YES completion:nil]; }else{ //若是登陸以後則處理註銷的狀況 //注意當前視圖控制器必須實現UIActionSheet代理才能進行操做 UIActionSheet *actionSheet=[[UIActionSheet alloc]initWithTitle:@"系統信息" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"註銷" otherButtonTitles: nil]; [actionSheet showInView:self.view]; } } #pragma mark 實現代理方法 -(void)showUserInfoWithUserName:(NSString *)userName{ _isLogon=YES; //顯示登陸用戶的信息 _loginInfo.text=[NSString stringWithFormat:@"Hello,%@!",userName]; //登陸按鈕內容改成「註銷」 _loginButton.title=@"註銷"; } #pragma mark 實現註銷方法 -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{ if (buttonIndex==0) {//註銷按鈕 _isLogon=NO; _loginButton.title=@"登陸"; _loginInfo.text=@""; } } @end

KCLoginViewController.h

//
//  KCLoginViewController.h
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <UIKit/UIKit.h> @protocol KCMainDelegate; @interface KCLoginViewController : UIViewController #pragma mark 定義代理 @property (nonatomic,strong) id<KCMainDelegate> delegate; @end

KCLoginViewController.m

//
//  KCLoginViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCLoginViewController.h" #import "KCMainViewController.h" @interface KCLoginViewController (){ UITextField *_txtUserName; UITextField *_txtPassword; } @end @implementation KCLoginViewController - (void)viewDidLoad { [super viewDidLoad]; [self addLoginForm]; } -(void)addLoginForm{ //用戶名 UILabel *lbUserName=[[UILabel alloc]initWithFrame:CGRectMake(50, 150, 100, 30)]; lbUserName.text=@"用戶名:"; [self.view addSubview:lbUserName]; _txtUserName=[[UITextField alloc]initWithFrame:CGRectMake(120, 150, 150, 30)]; _txtUserName.borderStyle=UITextBorderStyleRoundedRect; [self.view addSubview:_txtUserName]; //密碼 UILabel *lbPassword=[[UILabel alloc]initWithFrame:CGRectMake(50, 200, 100, 30)]; lbPassword.text=@"密碼:"; [self.view addSubview:lbPassword]; _txtPassword=[[UITextField alloc]initWithFrame:CGRectMake(120, 200, 150, 30)]; _txtPassword.secureTextEntry=YES; _txtPassword.borderStyle=UITextBorderStyleRoundedRect; [self.view addSubview:_txtPassword]; //登陸按鈕 UIButton *btnLogin=[UIButton buttonWithType:UIButtonTypeSystem]; btnLogin.frame=CGRectMake(70, 270, 80, 30); [btnLogin setTitle:@"登陸" forState:UIControlStateNormal]; [self.view addSubview:btnLogin]; [btnLogin addTarget:self action:@selector(login) forControlEvents:UIControlEventTouchUpInside]; //取消登陸按鈕 UIButton *btnCancel=[UIButton buttonWithType:UIButtonTypeSystem]; btnCancel.frame=CGRectMake(170, 270, 80, 30); [btnCancel setTitle:@"取消" forState:UIControlStateNormal]; [self.view addSubview:btnCancel]; [btnCancel addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; } #pragma mark 登陸操做 -(void)login{ if ([_txtUserName.text isEqualToString:@"kenshincui"] && [_txtPassword.text isEqualToString:@"123"] ) { //調用代理方法傳參 [self.delegate showUserInfoWithUserName:_txtUserName.text]; [self dismissViewControllerAnimated:YES completion:nil]; } else{ //登陸失敗彈出提示信息 UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:@"系統信息" message:@"用戶名或密碼錯誤,請從新輸入!" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil]; [alertView show]; } } #pragma mark 點擊取消 -(void)cancel{ [self dismissViewControllerAnimated:YES completion:nil]; } @end

在上面的代碼中,點擊登陸能夠跳轉到登陸界面,若是用戶名、密碼輸入正確能夠回傳參數到主界面中(不正確則給出提示),同時修改主界面按鈕顯示內 容。若是已經登陸則點擊註銷會彈出提示,點擊肯定註銷則會註銷登陸信息。在代碼中咱們還用到了UIActionSheet和UIAlert,這兩個控件其 實也是模態窗口,只是沒有鋪滿全屏,你們之後的開發中會常常用到。

假設登陸以後在主視圖控制器右上角點擊「我」能夠彈出當前用戶信息如何實現呢?這個時候咱們須要從主視圖控制器傳遞參數到子視圖控制器,和前面的傳參恰好相反,這個時候咱們一般使用上面提到的第五個方法,設置目標視圖控制器的屬性。

1.首先修改一下主視圖控制器

//
//  KCMainViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMainViewController.h" #import "KCLoginViewController.h" #import "KCMeViewController.h" @interface KCMainViewController ()<KCMainDelegate,UIActionSheetDelegate>{ UILabel *_loginInfo; UIBarButtonItem *_loginButton; UIBarButtonItem *_meButton; BOOL _isLogon; } @end @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; [self addNavigationBar]; [self addLoginInfo]; } #pragma mark 添加信息顯示 -(void)addLoginInfo{ _loginInfo =[[UILabel alloc]initWithFrame:CGRectMake(0, 100,320 ,30)]; _loginInfo.textAlignment=NSTextAlignmentCenter; [self.view addSubview:_loginInfo]; } #pragma mark 添加導航欄 -(void)addNavigationBar{ //建立一個導航欄 UINavigationBar *navigationBar=[[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 44+20)]; //navigationBar.tintColor=[UIColor whiteColor]; [self.view addSubview:navigationBar]; //建立導航控件內容 UINavigationItem *navigationItem=[[UINavigationItem alloc]initWithTitle:@"Web Chat"]; //左側添加登陸按鈕 _loginButton=[[UIBarButtonItem alloc]initWithTitle:@"登陸" style:UIBarButtonItemStyleDone target:self action:@selector(login)]; navigationItem.leftBarButtonItem=_loginButton; //左側添加導航 _meButton=[[UIBarButtonItem alloc]initWithTitle:@"我" style:UIBarButtonItemStyleDone target:self action:@selector(showInfo)]; _meButton.enabled=NO; navigationItem.rightBarButtonItem=_meButton; //添加內容到導航欄 [navigationBar pushNavigationItem:navigationItem animated:NO]; } #pragma mark 登陸操做 -(void)login{ if (!_isLogon) { KCLoginViewController *loginController=[[KCLoginViewController alloc]init]; loginController.delegate=self;//設置代理 //調用此方法顯示模態窗口 [self presentViewController:loginController animated:YES completion:nil]; }else{ //若是登陸以後則處理註銷的狀況 //注意必須實現對應代理 UIActionSheet *actionSheet=[[UIActionSheet alloc]initWithTitle:@"系統信息" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"註銷" otherButtonTitles: nil]; [actionSheet showInView:self.view]; } } #pragma mark 點擊查看個人信息 -(void)showInfo{ if (_isLogon) { KCMeViewController *meController=[[KCMeViewController alloc]init]; meController.userInfo=_loginInfo.text; [self presentViewController:meController animated:YES completion:nil]; } } #pragma mark 實現代理方法 -(void)showUserInfoWithUserName:(NSString *)userName{ _isLogon=YES; //顯示登陸用戶的信息 _loginInfo.text=[NSString stringWithFormat:@"Hello,%@!",userName]; //登陸按鈕內容改成「註銷」 _loginButton.title=@"註銷"; _meButton.enabled=YES; } #pragma mark 實現註銷方法 -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{ if (buttonIndex==0) {//註銷按鈕 _isLogon=NO; _loginButton.title=@"登陸"; _loginInfo.text=@""; _meButton.enabled=NO; } } @end

2.添加展現用戶信息的控制器視圖

KCMeViewController.h

//
//  KCMeViewController.h
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import <UIKit/UIKit.h> @interface KCMeViewController : UIViewController #pragma mark 須要傳遞的屬性參數(不少時候它是一個數據模型) @property (nonatomic,copy) NSString *userInfo; @end

KCMeViewController.m

//
//  KCMeViewController.m
//  ViewTransition
//
//  Created by Kenshin Cui on 14-3-15.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "KCMeViewController.h" @interface KCMeViewController (){ UILabel *_lbUserInfo; } @end @implementation KCMeViewController - (void)viewDidLoad { [super viewDidLoad]; //信息顯示標籤 _lbUserInfo =[[UILabel alloc]initWithFrame:CGRectMake(0, 100,320 ,30)]; _lbUserInfo.textAlignment=NSTextAlignmentCenter; _lbUserInfo.textColor=[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]; [self.view addSubview:_lbUserInfo]; //關閉按鈕 UIButton *btnClose=[UIButton buttonWithType:UIButtonTypeSystem]; btnClose.frame=CGRectMake(110, 200, 100, 30); [btnClose setTitle:@"關閉" forState:UIControlStateNormal]; [btnClose addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btnClose]; //設置傳值信息 _lbUserInfo.text=_userInfo; } #pragma mark 關閉 -(void)close{ [self dismissViewControllerAnimated:YES completion:nil]; } @end

前面代碼中除了演示了模態窗口的使用還演示了兩種多視圖參數傳遞方法,其餘方法往後咱們再作介紹。最後完整展示一下整個示例程序:

ModalViewControllerEffect

相關文章
相關標籤/搜索