你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS開發系列--視圖切換

iOS開發系列--視圖切換

編輯:IOS開發綜合

具體代碼:https://github.com/wwpeter/WW-ViewTransition.git

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

UITabBarControllerUINavigationController模態窗口

UITabBarController

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

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.其次創建兩個子視圖,在這兩個子視圖控制器中設置對應的名稱、圖標等信息。

KCWebChatViewController.m

//
//  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的根控制器。

AppDelegate.m

//
//  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

運行效果:

KCWebChatViewControllerKCContactViewController

對於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開發中常用的參數傳遞有以下幾種方法:

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

今天我們主要采用第一種方式進行數據傳遞,這在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 


#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 (){
    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 
@protocol KCMainDelegate;

@interface KCLoginViewController : UIViewController

#pragma mark 定義代理
@property (nonatomic,strong) id 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 (){
    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 

@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


  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved