模态窗口只是视图控制器显示的一种方式(在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开发中也是最常见的一种多视图传参方式。使用代理方式传递参数的步骤如下:
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
前面代码中除了演示了模态窗口的使用还演示了两种多视图参数传递方法,其他方法日后我们再做介绍。最后完整展现一下整个示例程序: