掌握
控制器以及view的多种创建方式
UINavigationController的简单使用:添加\移除子控制器
UINavigationBar内容的设置
控制器的生命周期方法
Segue的使用
控制器之间数据的传递
三种方式创建一个控制器的方法
控制器常见的创建方式有以下几种
通过storyboard创建
直接创建
HMViewController *hm =[[HMViewController alloc] init];
指定xib文件来创建
HMViewController *hm =[[HMViewController alloc] initWithNibName:@”HMViewController" bundle:nil];
通过storyboard创建控制器
先加载storyboard文件(Test是storyboard的文件名)
UIStoryboard *storyboard= [UIStoryboard storyboardWithName:@"Test" bundle:nil];
接着初始化storyboard中的控制器
初始化“初始控制器”(箭头所指的控制器)
HMViewController *hm =[storyboard instantiateInitialViewController];
通过一个标识初始化对应的控制器
HMViewController *hm =[storyboard instantiateViewControllerWithIdentifier:@”hm"];
通过storyboard加载控制器
# -通过storyboard加载控制器
一.UIStoryboard:帮你加载storyboard文件
UIStoryboard : 帮你加载storyboard文件
加载storyboard文件
name:storyboard文件名,不需要后缀名
UIStoryboard*storyboard = [UIStoryboard storyboardWithName:@"Main"bundle:nil];
创建storyboard描述的控制器
instantiateInitialViewController帮你加载箭头指向的控制器
UIViewController *vc = [storyboardinstantiateInitialViewController];
根据标识符创建storyboard描述的控制器
UIViewController*vc = [storyboard instantiateViewControllerWithIdentifier:@"org"];
例:
1.设置窗口
self.window = [[UIWindow alloc]initWithFrame:[UIScreenmainScreen].bounds];
2.加载Main不需要后缀
UIStoryboard *ui = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
3.意识是箭头指向的那个控制器
UIViewController *baby = [ui instantiateInitialViewController];
self.window.rootViewController = baby;
[self.window makeKeyAndVisible];
注意:storyboard只能加载系统自己的,自己自定义的只能用xib的方式去加载,因为类型不匹配!
通过xib创建控制器(掌握)
# -通过xib创建控制器(掌握)
一.通过xib创建控制器原因:
是想通过Xib描述控制器的view
如何通过xib创建控制器.
1.创建Xib文件
2.xib文件要有一个view描述控制器
3.连线,告诉xib描述哪个控制器,设置文件拥有者为控制器
4.调用initWithNibName创建控制器
什么时候使用xib创建控制器的view
当控制器的view界面是固定的时候
为什么想要用xib或者storyboard创建控制器,其实就是想要使用它们来描述我们控制器的view
1.创建窗口
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
2.设置窗口的根控制器
XMGViewController *vc= [[XMGViewController alloc] init];
self.window.rootViewController = vc;
4.显示窗口
[self.window makeKeyAndVisible];
控制器的view创建
# -控制器的view创建
一.loadView
什么时候调用:当第一次使用控制器的view的时候就会调用
作用:加载控制器的view,自定义控制器的view
注意:
1.只要重写loadView,必须自己手动创建控制器的view(因为重写此方法会直接会把系统提供的给覆盖掉)
2.在没给_view赋值之前,不能调用self.view;
二.loadView加载流程
三.xib加载控制器的view
init底层会调用initWithNibName:bundle:
通过xib创建XMGViewController控制器的view
1.判断下nibName有没有值,如果有值,就会去加载nibName指定的xib
2.如果nibName为空,会先去查找有没有XMGView.xib,如果有就去加载
3.如果没有XMGView.xib,就会去加载根类名同名的xib:XMGViewController.xib
4.如果还没有找到,就生成一个空的view
注意:init底层调用initWithNibName
initWithNibName:底层做了一些事情
1.判断有没有指定nibName,指定了,就会加载
2.判断下有没有跟控制器类名同名的xib但是不带controller,如果有,就直接加载
3.判断下有没有跟控制器类名同名的xib,如果有,就直接加载
延迟加载:
控制器的view加载完成的时候调用
- (void)viewDidLoad {
[super viewDidLoad];
UIView *baby = [[UIView alloc]init];
baby.backgroundColor = [UIColor blueColor];
[self.view addSubview:baby];
}
延迟加载原理:在主线程自己创建了一个蓝色的view最后在控制器显示的下面红色的view,最后它会调用下面的这个代理方法,所以显示的是红色的view而不是蓝色的view
当应用程序启动完成的时候,系统会自动调用代理这个方法(自己创建的一个控制器)
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
ViewController *baby = [[ViewController alloc]init];
baby.view.backgroundColor = [UIColor redColor];
self.window.rootViewController = baby;
[self.window makeKeyAndVisible];
return YES;
}
五.控制器view默认的是几乎透明的
控制器view的延迟加载(懒加载)
控制器的view是延迟加载的:用到时再加载
可以用isViewLoaded方法判断一个UIViewController的view是否已经被加载
控制器的view加载完毕就会调用viewDidLoad方法
多控制器
一个iOS的app很少只由一个控制器组成,除非这个app极其简单
当app中有多个控制器的时候,我们就需要对这些控制器进行管理
有多个view时,可以用一个大的view去管理1个或者多个小view
控制器也是如此,用1个控制器去管理其他多个控制器
比如,用一个控制器A去管理3个控制器B、C、D
控制器A被称为控制器B、C、D的“父控制器”
控制器B、C、D的被称为控制器A的“子控制器”
为了便于管理控制器,iOS提供了2个比较特殊的控制器
UINavigationController
UITabBarController
UINavigationController的简单使用
UINavigationController的使用步骤
创建初始化UINavigationController
设置UIWindow的rootViewController为UINavigationController
根据具体情况,通过push方法添加对应个数的子控制器
UINavigationController的子控制器
UINavigationController以栈的形式保存子控制器
@property(nonatomic,copy) NSArray*viewControllers;
@property(nonatomic,readonly) NSArray*childViewControllers;
使用push方法能将某个控制器压入栈
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
使用pop方法可以移除控制器
将栈顶的控制器移除
-(UIViewController*)popViewControllerAnimated:(BOOL)animated;
回到指定的子控制器
-(NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
回到根控制器(栈底控制器)
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;
注意:导航条的标志就是导航条,其高度是44,Y值是20(它有两个子控件)
#导航控制器
1.导航控制器永远显示的是栈顶控制器的view
2.导航控制器中做界面之间的跳转必须拿到导航控制器
3.调用pop方法并不会马上销毁当前控制器,记住!
4.popToViewController使用注意点,传入进去的控制器必须是导航控制器栈里面的控制器
5.导航条的内容由栈顶控制器决定,一个导航控制器只有一个导航条,因此只能由一个控制器决定,谁先显示在最外面,谁就是栈顶控制器.
6.在iOS7之后,默认会把导航条上的按钮的图片渲染成蓝色.
7.导航条上的子控件位置不需要我们管理,只需要管理尺寸
8.UINavigationItem:是一个模型,决定导航条的内容(左边内容,中间,右边内容)
9. UIBarButtonItem:是一个模型,决定导航条上按钮的内容
10.以后只要看到item,通常都是苹果提供的模型,只要改模型就能修改苹果的某些控件.
控制器view的生命周期
# -控制器view的生命周期
1. 控制器的view的生命周期方法都是以view开头
viewDidLoad-> viewWillAppear -> viewWillLayoutSubviews ->viewDidLayoutSubviews -> viewDidAppear -> viewWillDisappear ->viewDidDisappear
控制器的view加载完成的时候调用
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%s",__func__);
}
view完全显示的时候调用
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"%s",__func__);
}
view完全消失的时候调用
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSLog(@"%s",__func__);
}
view布局子控件完成的时候调用
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
NSLog(@"%s",__func__);
}
view即将显示的时候调用
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"%s",__func__);
}
view即将消失的时候调用
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
NSLog(@"%s",__func__);
}
view即将布局子控件的时候调用
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
NSLog(@"%s",__func__);
}
#pragma mark - 非ARC
在接收到内存警告的时候有可能会调用
view即将销毁的时候调用
- (void)viewWillUnload
{
}
view完全销毁的时候调用
- (void)viewDidUnload
{
//清空数据
self.datas = nil;
}
三、导航控制器
1.介绍多控制器管理PPT演示 2.典型例子:设置界面 3.UINavgationViewController的基本使用(空项目)
3.0> 学一个新的控制器,先学他内部的结构和他的作用
•UINavgationViewController的内部结构(导航条,导航控制器的
view,存放导航控制器子控制器的view)
3.1> 怎么添加导航控制器的子控制器,push,或者一创建的时候就给一个 根控制器,默认第一个子控制器叫根控制器。
3.2> 怎么管理很多子控制器?push很多控制器就OK了,不要一下子push很多子控制器,跳转控制器的权利应该交给用户,由用户决定进入那个界 面。
3.3> 通常开发中是给某个控制器添加导航功能,是点击某个控制器中的 控件,导航到另外一个控制器
• 因此一开始只需要显示导航控制器的根控制器就好,具体需不需要 导航,由用户决定,如果需要导航,就点击跟控制器的按钮。
• 导航控制器的作用:用来做导航功能,一个控制器如果想拥有导航 功能,就包装成导航控制器。
4>UINavgationViewController子控制器管理原理
4.1> 导航控制器是通过栈管理子控制器,PPT分析,栈是先进后出 4.2> push把控制器压入栈,然后创建控制器的view,把控制器的view在 添加到导航控制器上
4.3> 什么是栈顶和栈底控制器,栈底也叫导航控制器的根控制器。
4.4> 显示到导航控制器的永远是栈顶控制器的view,栈底控制器的view 不会被销毁,只是移除父视图。 4.5>点击返回,移除栈顶控制器,移除的控制器会被销毁
5.导航控制器出栈操作
• 首先了解topViewController和viewControllers和childViewControllers,出栈
的时候可能用到。
5.0. topViewController获取栈顶控制器。
5.1viewControllers和childViewControllers:压入栈的控制器都会作为导航 控制器的子控制器。
5.2 通过pop手动出栈,之前都是点击back自动出栈。
5.3 主动出栈,要求出栈的控制器必须是栈里面的控制器,不能自己创建 一个控制器出栈,会报出栈的控制器不存在的错误,这时候可以用
viewControllers或者childViewControllers拿到根控制器。
5.4 pop控制器,不会马上销毁栈顶控制器,而是告诉导航控制器需要把 栈顶控制器出栈,等到恰当的时间就会把栈顶控制器出栈,并且销
5.2 通过pop手动出栈,之前都是点击back自动出栈。
5.3 主动出栈,要求出栈的控制器必须是栈里面的控制器,不能自己创建 一个控制器出栈,会报出栈的控制器不存在的错误,这时候可以用
viewControllers或者childViewControllers拿到根控制器。
5.4 pop控制器,不会马上销毁栈顶控制器,而是告诉导航控制器需要把 栈顶控制器出栈,等到恰当的时间就会把栈顶控制器出栈,并且销 毁。(断点演示)
6.设置导航条的内容
6.1> 一个导航控制器只有一个导航条,子控制器共用一个导航条。 6.2>如何设置导航条的内容,导航条的内容由栈顶控制器的 navigationItem决定,因此导航控制器必须要有一个根控制器,本身不具 备完整的显示功能,因为他的导航条他自己不能决定。
6.3> 设置one控制器的导航条标题,显示one的时候,one就是栈顶控制器,直接拿到navigationItem设置title.
6.4 设置navigationItem的titleView为UISegmentedControl,不需要设置位置,只需要设置尺寸。
6.5 设置导航条左右两边按钮,按钮必须是 UIBarButtonItem.leftBarButtonItem,rightBarButtonItem,rightBarButtonItems
6.6 导航条上的返回按钮由上一个控制器决定。
1> 如果上一个控制器没有设置标题,默认back
2> 如果上一个控制器设置标题,并且没有超过12个字符,默认返 回标题和上一个控制器一致,如果超过12个字符,就会变成back。 3> 还可以主动直接设置下一个界面的返回按钮,设置上一个控制 器的backBarButtonItem属性
7.验证导航条的frame和导航控制器的内部结构,用一个UIView的分类。
1> 导航条的的高度是44
2> 利用UIView的分类,生成导航控制器view的内部结构的xml,写入桌面。
3>ios6和ios7导航控制器的区别。
8.导航控制器-利用storyboard创建
8.1> 程序一启动,就加载导航控制器,设置storyboard箭头指向导航控制器
8.2> 设置导航控制器的根控制器为UIViewController
8.3> 设置导航条的内容,还有下一个控制器的返回按钮
8.4> 利用storyboard做跳转,选中按钮拖线
8.5> 利用按钮,回到上一个控制器,不能回拖,会新创建一个控制器, 只能通过代码。
.在非ARC中viewDidUnload系统方法,经常用来清空界面上的数据
如何修改导航栏的内容
导航栏的内容由栈顶控制器的navigationItem属性决定
UINavigationItem有以下属性影响着导航栏的内容
左上角的返回按钮
@property(nonatomic,retain) UIBarButtonItem*backBarButtonItem;
中间的标题视图
@property(nonatomic,retain) UIView *titleView;
中间的标题文字
@property(nonatomic,copy) NSString *title;
左上角的视图
@property(nonatomic,retain) UIBarButtonItem*leftBarButtonItem;
右上角的视图
@property(nonatomic,retain) UIBarButtonItem*rightBarButtonItem;
会自动根据按钮的图片或者文字计算按钮的尺寸
[cusBtnsizeToFit];
UIBarButtonItem*item = [[UIBarButtonItem alloc] initWithCustomView:cusBtn];
self.navigationItem.rightBarButtonItem = item;
以后只要看到以item结尾都是苹果提供的模型
UINavigationItem:决定导航条上的内容(左边,中间,右边)
UIBarButtonItem:决定导航条上按钮的内容
UINavigationController的注意细节
创建窗口
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
设置窗口的根控制器
创建导航控制器的根控制器
ViewController *vc =[[ViewController alloc] init];
一个view属于哪个控制器的view,这个view还是交给哪个控制器管理
创建导航控制器(要把需要实现在view上的控制器作为导航控制器的子控件,这样就可以实现)
UINavigationController*nav = [[UINavigationController alloc] initWithRootViewController:vc];
[nav pushViewController:vc animated:YES];initWithRootViewController底层调用pushViewController会把导航控制器的view添加到导航控制器专门存放子控制器的view
导航控制器永远显示栈顶控制器的view
self.window.rootViewController = nav;
显示窗口
[self.window makeKeyAndVisible];
跳转功能在导航控制器中跳转,只能拿到导航控制器才能跳转
1.ViewController是导航控制器根控制器,ViewController其实也是导航控制器的子控制器,而且是第一个子控制器.
2.只要是导航控制器的子控制器都可以拿到当前导航控制器
3. 在iOS7之后默认会把导航条上的按钮的图片渲染成蓝色
4.如果想不要渲染,1.修改图片的渲染模式 2.通过代码
5.导航条上的控件的位置由苹果自己决定,不能自己决定
6. 一般系统自带控件中子控件的位置一般由系统决定,我们只能决定尺寸.
Segue的类型
根据Segue的执行(跳转)时刻,Segue可以分为2大类型
自动型:点击某个控件后(比如按钮),自动执行Segue,自动完成界面跳转
手动型:需要通过写代码手动执行Segue,才能完成界面跳转
调用sourceViewController的下面方法,做一些跳转前的准备工作并且传入创建好的Segue对象
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
// 这个sender是当初performSegueWithIdentifier:sender:中传入的sender
调用Segue对象的- (void)perform;方法开始执行界面跳转操作
取得sourceViewController所在的UINavigationController
调用UINavigationController的push方法将destinationViewController压入栈中,完成跳转
UITabBarController
跟UINavigationController类似,UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换,典型例子就是QQ、微信等应用
UITabBarController的简单使用
UITabBarController的使用步骤
初始化UITabBarController
设置UIWindow的rootViewController为UITabBarController
根据具体情况,通过addChildViewController方法添加对应个数的子控制器
UITabBarController的子控制器
UITabBarController的使用步骤
初始化UITabBarController
设置UIWindow的rootViewController为UITabBarController
根据具体情况,通过addChildViewController方法添加对应个数的子控制器
UITabBar
Modal
除了push之外,还有另外一种控制器的切换方式,那就是Modal(m模态窗口)
任何控制器都能通过Modal的形式展示出来,只要是继承UIController都是控制器
Modal的默认效果:新控制器从屏幕的最底部往上钻,直到盖住之前的控制器为止
以Modal的形式展示控制器(一般Modal出来的都是导航控制器)
-(void)presentViewController:(UIViewController *)viewControllerToPresentanimated: (BOOL)flag completion:(void (^)(void))completion
关闭当初Modal出来的控制器
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void(^)(void))completion;
注意:presentingViewController这个属性一直在引用被移除的View所以不会被销毁
四、控制器的生命周期方法
1.控制器的生命周期方法
• 控制器的view什么时候创建,什么时候销毁,用导航控制器比较好讲
解。
1> 演示导航控制器根控制器View的生命周期(viewDidLoad这些view开头的,称为生命周期方法)
• 通过view的生命周期方法,就知道控制器的view是懒加载的,导航控制器有2个子控制器,先会加载第一个子控制器的view,当Push第二个的时候,才去加载第二个控制器的view
2>didReceiveMemoryWarning,当控制器接收内存警告的时候调用 3>内存警告传递过程:手机内存不足产生事件->通知应用程序->调用应 用程序代理方法->把事件传递给窗口->窗口传给控制器->调用控制器 内存警告的方法。
4> 当控制器接收内容警告,会销毁没有显示的控制器的view。
5> 调用viewWillUnload,viewDidUnload,销毁控制器的view
6>viewDidUnload里面一般清空显示在view里面的数据,演示非arc开发
• 为什么要清空显示view的数据:展示数据的view都不存在了,这些 数据也就没有用处了,因为数据主要是用来展示在view上的。
• 建议使用nil,清空数据,在非arc和arc都通用。arc是不能使用release,而且非arc,self.datas = nil;做的事情更多。
7>didReceiveMemoryWarning会导致viewDidLoad重新调用。PPT分析
○ 当收到内存警告,导航控制器的子控制器的view有可能被干掉,他
如果没有显示的话,当下次使用这个控制器的时候就会调用。 8> 回顾控制器view的生命周期方法。
/**
* view加载完毕
*/
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%@-viewDidLoad", self.class);
}
/**
* view即将显示到window上
*
*/
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"%@-viewWillAppear", self.class);
}
/**
* view显示完毕(已经显示到窗口)
*/
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"%@-viewDidAppear", self.class);
}
/**
* view即将从window上移除(即将看不见)
*
*/
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
NSLog(@"%@-viewWillDisappear", self.class);
}
/**
* view从window上完全移除(完全看不见)
*
*/
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSLog(@"%@-viewDidDisappear", self.class);
}