UI:UINavigationController、界面通信
IOS中实现对控制器的管理的控制器有:UINavigationController 和 UITableBarController 两个控制器。下面是主要学习前者。
⼀、UINavigationController
⼆、定制UINavigationBar
三、界⾯间通信
一、UINavigationController
UINavigationController:导航控制器,是iOS中最常⽤的多视图控制器之⼀,它⽤来管理多个视图控制器。 导航控制器可以认为是管理控制器的控制器,主要管理有层级关系的控制器。
UINavigationController继承于UIViewController,以栈的⽅式管理所控制的视图控制器,⾄少要有⼀个被管理的视图控制器,这个控制器我们称作导航控制器的根视图控制器。 任何继承⾃UIViewController的类都可以作为根控制器。
工作方式
UINavigationController 通过栈的⽅式管理控制器的切换,控制⼊栈和出栈来展⽰各个视图控制器。
UINavigationController 的 ContentView ⾥始终显⽰栈顶控制器的view。
viewControllers 属性存储了栈中的所有被管理的控制器
navigationController 属性,⽗类中的属性,每个在栈中的控制器,都能通过此属性,获取⾃⼰所在的 UINavigationController 对象。
⼊栈和出栈
pushViewController:animated //进⼊下⼀个视图控制器
popViewControllerAnimated: //返回上⼀个视图控制器
popToViewController:animated //返回到指定的视图控制器
popToRootViewControllerAnimated //返回到根视图控制器
常⽤属性
viewControllers //所有处于栈中的控制器
topViewController //位于栈顶的控制器
visibleViewController //当前正在显⽰的控制器
navigationBar //导航条
⼆、定制UINavigationBar
UINavigationBar
navigationBar—导航条,iOS7之后默认是透明的,iOS7之前默认是不透明的。
navigationBar 在透明情况下,与 contentView 会重合⼀部分区域。
navigationBar 在不透明情况,contentView 跟在 navigationBar 的下⾯。
navigationBar 竖屏下默认⾼度44,横屏下默认⾼度32
⾃定义navigationBar
barTintColor //设置导航条的颜⾊
setBackgroundImage:forBarMetrics: //导航条加背景图⽚
管理UINavigationItem
UINavigationBar 除了能定义⾃⾝的样式外,还管理⼀组 UINavigationItem。与 UINavigationController 相似,UINavigationBar 也是以栈的⽅式管理⼀组 UINavigationItem。提供 push 和 pop 操作 item。
每个视图控制器都有⼀个navigationItem属性。navigationItem中设置的左按钮、右按钮、标题等,会随着控制器的显⽰,也显⽰到 navigationBar上
UINavigationItem
UINavigationItem属于MVC中的M。封装了要显⽰在UINavigationBar上的数据。
title //标题
titleView //标题视图 (可是Button、 UIView )
leftBarButtonItem //左按钮
rightBarButtonItem //右按钮
leftBarButtonItems //多个左按钮(这里是个数组)
rightBarButtonItems //多个右按钮
UIBarButtonItem
UIBarButtonItem属于MVC的M。定义了UINavigationItem上按钮的触
发事件,外观等
-initWithBarButtonSystemItem:target:action:
-initWithTitle:style:target:action:
-initWithImage:style:target:action:
tintColor
三、⻚⾯间通信
属性传值
第⼀个视图控制器如何获得第⼆个视图控制器的部分信息?例如:第⼀个界⾯中lable显⽰第⼆个界⾯textField中的⽂本
⻚⾯间通信
代理传值
UINavigationController 以栈的⽅式管理视图控制器。通过push和pop 控制跳转
UINavigationBar管理⼀组UINavigationItem,UINavigationItem包含了 UIBarButtonItem。
使⽤属性传值解决从前往后传值的问题
使⽤delegate解决从后往前传值的问题
代码
#import "AppDelegate.h" #import "RootViewController.h" @interface AppDelegate () @end @implementation AppDelegate -(void)dealloc{ [_window release]; [super dealloc]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; RootViewController * RootVC = [[RootViewController alloc]init]; //创建一个导航控制器 (并且制定 RootVC 为导航控制器的根视图控制器) UINavigationController * navl = [[UINavigationController alloc]initWithRootViewController:RootVC]; //指定导航控制器为窗口根视图控制器 (window -> navl -> RootVC) self.window.rootViewController = navl; [RootVC release]; return YES; } AppDelegate.m
// // RootViewController.m #import "RootViewController.h" #import "SecondViewController.h" @interface RootViewController () @end @implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor]; //设置导航栏的属性 [self commonSettings]; } /* self.navigationController 取到来管理我们当前视图控制器的导航控制器 */ -(void)commonSettings{ //1.改变导航栏的颜色 (IOS 7之后新出的属性)(导航栏 是44像素 状态条20像素) // self.navigationController.navigationBar.barTintColor = [UIColor cyanColor]; self.navigationController.navigationBar.barTintColor = [UIColor grayColor]; //2.导航条的半透明效果 (默认的是打开的) //关闭半透明的效果 self.navigationController.navigationBar.translucent = NO;//半透明效果也叫 毛玻璃效果 (**) //3.导航条是否隐藏 self.navigationController.navigationBarHidden = YES; self.navigationController.navigationBarHidden = NO; self.navigationController.navigationBar.hidden = YES; self.navigationController.navigationBar.hidden = NO; //4.导航条的标题内容的颜色 self.navigationController.navigationBar.tintColor = [UIColor whiteColor];//如果为导航条控件添加按钮(按钮上的图片会被渲染)我们要对图片进行渲染 例如Button上添加的图片后,吧图片的渲染改为原图模式 [[UIImage imageNamed:@"NavBtnBack"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] //当导航条上的控件为图片的时候,我们需要对图片进行一个渲染设置,默认的系统的渲染是渲染模板,如果需要设置为原图,则需要设置为原图渲染 //设置当前界面的导航栏的属性<当前界面的哦> [self customesizeNavigationconBar]; self.navigationController.title = @"行健 -—— 主页面"; //5.设置导航条的标题字体大小和颜色 NSDictionary * dic = @{NSFontAttributeName:[UIFont systemFontOfSize:20],NSForegroundColorAttributeName:[UIColor orangeColor]}; self.navigationController.navigationBar.titleTextAttributes = dic; //6.设置背景图片 [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"NavBar_64"] forBarMetrics:UIBarMetricsDefault]; /*不同尺寸的图片,导航条的显示效果不一样 小于 44 像素 将图片拉伸,同时铺满状态条和导航条的空间 等于 44 像素 只会显示在导航条 大于 44 像素小于 64像素 将图片平铺在状态条和导航条的空间 等于 64 像素 图片正好显示在导航条以及状态条上 */ //上面的属性设置都是一个导航控制器的公共的属性(*******) //布局一个 Button UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(50, 100, 200, 30); button.backgroundColor = [UIColor grayColor]; [button setTitle:@"进入下一界面" forState:UIControlStateNormal]; //添加点击事件 [button addTarget:self action:@selector(pushToNext:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; UISegmentedControl * segment = [[UISegmentedControl alloc]initWithItems:@[@"好友",@"电话",@"QQ"]]; self.navigationItem.titleView = segment; //IOS6.0 和 IOS7.0 导航栏的布局都是 // // UIView * uiView = [[UIView alloc]initWithFrame:CGRectMake(20, 20, 20, 20)]; // uiView.backgroundColor = [UIColor redColor]; // self.navigationItem.titleView = uiView; // [uiView release]; // segment.frame = [[UIScreen mainScreen]bounds]; //设置左边内容 UIBarButtonItem * left = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(handleLeftAction:)]; self.navigationItem.leftBarButtonItem = left; [left release]; //设置右边内容 // UIBarButtonItem * right = [[UIBarButtonItem alloc]initWithTitle:@"右边内容" style:UIBarButtonItemStylePlain target:self action:@selector(handleRightAction:)]; UIBarButtonItem * right = [[UIBarButtonItem alloc]initWithImage:[[UIImage imageNamed:@"NavBtnBack"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:segment action:@selector(handleRightAction:)]; // UIBarButtonItem * right = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(handleRightAction:)]; self.navigationItem.rightBarButtonItem = right; [right release]; } #pragma mark-------------pushToNext-- 进入下一页面--------------- -(void)pushToNext:(UIButton * )sender{ //创建第二个视图控制器 SecondViewController * SecondVC = [[SecondViewController alloc]init]; //利用当前控制器的导航控制器 去进入到下一个页面(最好改变一下要跳闸到的页面的背景颜色,不染有卡顿效果) [self.navigationController pushViewController:SecondVC animated:YES]; self.navigationItem.title = @"行健的第二页面"; //释放所有权 [SecondVC release]; } #pragma mark-------------设置当前界面的导航栏的属性<当前界面的哦>--------------- -(void)customesizeNavigationconBar{ //设置导航条的标题 self.navigationItem.title = @"行健主页面<第一页面>"; //设置导航条的标题视图 // self.navigationItem.titleView = } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; if ([self isViewLoaded]&& self.view.window == nil) { self.view = nil; } } #pragma mark-------------设置左边& 右边 按钮内容 lefttBarButton 事件--------------- -(void)handleLeftAction:(UIBarButtonItem * )leftBarButton{ NSLog(@"测试"); } -(void)handleRightAction:(UIBarButtonItem *)rightButton{ NSLog(@"测试右边按钮"); } @end RootViewController.m
#import "SecondViewController.h" @interface SecondViewController () @end @implementation SecondViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor greenColor]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end SecondViewController.m
视图的生命周期
指定的初始化方法 initWithNibName....
创建视图加载视图 loadView
视图已经加载 viewDidLoad
视图将要出现 viewWillAppear
视图确实出现 viewDidAppear
视图将要消失 viewWillDisappear
视图确实消失 viewDidDisappear
second <--> third (两个界面跳转时) 视图的出现/消失的过程
second --> third (从前到后)
前 viewWillDisappear --> 后 viewWillAppear --> 前 viewDidDisappear --> 后 viewDidAppear
second <-- third (从后到前)
后 viewWillDisappear --> 前 viewWillAppear --> 后 viewDidDisappear --> 前 viewDidAppear
页面传值
1.创建一个根视图控制器,设为服从导航控制器管理(指定导航控制器为window的根控制器)
RootViewController * RootVC = [[RootViewController alloc]init];
UINavigationController * navl = [[UINavigationController alloc]initWithRootViewController:RootVC];
self.window.rootViewController = navl;
[RootVC release];
[navl release];
总结: 在传值的时候,对于属性为 数组的 一定要记得初始化
代码
#import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; -(void)dealloc; @end AppDelete.h文件
#import "AppDelegate.h" #import "RootViewController.h" #import "FRootViewController.h" @interface AppDelegate () @end @implementation AppDelegate -(void)dealloc{ [_window release]; [super dealloc]; } //界面跳转的时刻同时传值 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; RootViewController * RootVC = [[RootViewController alloc]init]; UINavigationController * navl = [[UINavigationController alloc]initWithRootViewController:RootVC]; self.window.rootViewController = navl; [RootVC release]; [navl release]; // FRootViewController * frVC = [[FRootViewController alloc]init]; // UINavigationController * navl = [[UINavigationController alloc]initWithRootViewController:frVC]; // self.window.rootViewController = navl; // [frVC release]; // [navl release]; return YES; } AppDelete.m文件
#import <UIKit/UIKit.h> @interface RootViewController : UIViewController @property(nonatomic,retain)UITextField * tf; @property(nonatomic,retain)UILabel * lable; @end
#import "RootViewController.h" #import "FirstViewController.h" #pragma Mark 代理传值 4 前一个界面服从协议 @interface RootViewController ()<UITextFieldDelegate,PassValueDelegate> @end /*界面之间的传值 1.从前往后传值——利用属性传值 2.从后往前传值——代理传值 ——Block传值 《代理的步骤》 A.在后一个界面制定协议 B.在后一个界面设置代理属性 C.在前一个界面进入后一个界面之前设置代理对象 D.前一个界面的类服从协议 E.前一个界面实现协议方法 F.在后一个界面消失时机,把对应的数据作为协议的方法的参数传入 3.间隔几个页面的的传值(多页面之间的传值)——单例传值 */ @implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; self.tf = [[UITextField alloc]initWithFrame:CGRectMake(120, 150, 150, 30)]; _tf.layer.cornerRadius = 8; _tf.layer.borderWidth = 1; _tf.layer.borderColor = [UIColor blackColor].CGColor; _tf.delegate = self; _tf.placeholder = @"输入框"; [self.view addSubview:_tf]; [self.tf release]; self.lable = [[UILabel alloc]initWithFrame:CGRectMake(120, 200, 150, 30)]; _lable.text = @""; _lable.backgroundColor = [UIColor orangeColor]; [self.view addSubview:_lable]; [_lable release]; self.navigationController.title = @"0页面"; [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"NavBar_64"] forBarMetrics:UIBarMetricsDefault]; self.view.backgroundColor = [UIColor whiteColor]; UIButton * secondButton = [UIButton buttonWithType:UIButtonTypeSystem]; secondButton.backgroundColor = [UIColor grayColor]; [secondButton addTarget:self action:@selector(pushToNext1:) forControlEvents:UIControlEventTouchUpInside]; [secondButton setTitle:@"进入下一页面" forState:UIControlStateNormal]; secondButton.frame = CGRectMake(100, 400, 200, 30); [self.view addSubview:secondButton]; } -(void)pushToNext1:(UIButton *)sender{ FirstViewController * firstVC = [[FirstViewController alloc]init]; #pragma Mark 代理传值 3 进入到后一个界面之前 指定代理对象 firstVC.delegate = self; firstVC.text = self.tf.text;//传值 [self.navigationController pushViewController:firstVC animated:YES]; [firstVC release]; } #pragma Mark 代理传值 5 前一个页面执行协议的方法 -(void)passValue:(NSString *)text{ self.lable.text = text; } //回收键盘 -(BOOL)textFieldShouldReturn:(UITextField *)textField{ [textField resignFirstResponder]; return YES; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [self.tf resignFirstResponder]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; if ([self isViewLoaded] && !self.view.window) { self.view = nil; } } @end RootViewController.m文件
#import <UIKit/UIKit.h> #pragma Mark 代理传值 1 制定协议 @protocol PassValueDelegate <NSObject> @optional -(void)passValue:(NSString *)text; @end @interface FirstViewController : UIViewController //在后一个界面添加属性 @property(nonatomic,retain)NSString * text; @property(nonatomic,retain)UITextField * tf; #pragma Mark 代理传值 2 添加属性用来存储代理对象 @property(nonatomic,retain)id<PassValueDelegate>delegate; @end FirstViewController.h文件
#import "FirstViewController.h" #import "SecondViewController.h" @interface FirstViewController () @end @implementation FirstViewController - (void)viewDidLoad { [super viewDidLoad]; [self layoutSubViews]; } //布局 -(void)layoutSubViews{ self.tf = [[UITextField alloc]initWithFrame:CGRectMake(120, 150, 150, 30)]; _tf.layer.cornerRadius = 8; _tf.layer.borderWidth = 1; _tf.layer.borderColor = [UIColor blackColor].CGColor; _tf.placeholder = @"输入框"; [self.view addSubview:_tf]; [self.tf release]; UILabel * lable = [[UILabel alloc]initWithFrame:CGRectMake(120, 200, 150, 30)]; lable.text = self.text; lable.backgroundColor = [UIColor orangeColor]; [self.view addSubview:lable]; [lable release]; self.navigationController.title = @"1页面"; [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"NavBar_64"] forBarMetrics:UIBarMetricsDefault]; self.view.backgroundColor = [UIColor lightGrayColor]; UIButton * secondButton = [UIButton buttonWithType:UIButtonTypeSystem]; secondButton.backgroundColor = [UIColor grayColor]; [secondButton addTarget:self action:@selector(pushToNext1:) forControlEvents:UIControlEventTouchUpInside]; [secondButton setTitle:@"进入下一页面" forState:UIControlStateNormal]; secondButton.frame = CGRectMake(100, 400, 200, 30); [self.view addSubview:secondButton]; } -(void)pushToNext1:(UIButton *)sender{ SecondViewController * secondVC = [[SecondViewController alloc]init]; [self.navigationController pushViewController:secondVC animated:YES]; [secondVC release]; } //后一个页面将要消失的时机去传值 #pragma Mark 代理传值 6 后一个页面将要消失的时机去把本页面输入框的内容传值到前一个界面 对应的数据作为协议的参数 -(void)viewWillDisappear:(BOOL)animated{ //如果代理存在 并且 代理响应了方法 if (_delegate && [_delegate respondsToSelector:@selector(passValue:)]) { [self.delegate passValue:self.tf.text]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end FirstViewController.m文件
#import <UIKit/UIKit.h>
@interface SecondViewController : UIViewController
@end
#import "SecondViewController.h" @interface SecondViewController () @end @implementation SecondViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } SecondViewController.m文件