UIWindow
- 程序启动完成时加载窗口
// 程序启动完成的时候
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 1.创建窗口,注意窗口必须要有尺寸,尺寸跟屏幕一样大的尺寸,窗口不要被释放
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor redColor];
// 2.创建窗口的根控制器
UIViewController *vc = [[UIViewController alloc] init];
vc.view.backgroundColor = [UIColor yellowColor];
[vc.view addSubview:[UIButton buttonWithType:UIButtonTypeContactAdd]];
// 如果设置窗口的根控制器,默认就会把控制器的view添加到窗口上
// 设置窗口的根控制器,默认就有旋转功能
self.window.rootViewController = vc;
// [self.window addSubview:vc.view];
// 3.显示窗口
[self.window makeKeyAndVisible];
return YES;
}
- 窗口有层级关系
- UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert
// 设置窗口的层级关系
self.window1.windowLevel = UIWindowLevelStatusBar;
- 键盘也是窗口,状态栏也是
// 判断下键盘是不是窗口
// NSLog(@"%@",application.windows);
// 如何才能弹出键盘
// 如果需要看到键盘,必须要把textField添加到一个View上面
UITextField *textField = [[UITextField alloc] init];
_textField = textField;// 必须强引用
[textField becomeFirstResponder];// 打开键盘
[self.window addSubview:textField];
// NSLog(@"%@",application.windows);
// 显示窗口
[self.window makeKeyAndVisible];
-
// application.windows:只要一给delegate的window属性赋值,就会添加到windows数组。
// NSLog(@"%@",application.windows);
// 2.显示窗口
// makeKeyAndVisible:成为app的主窗口并且显示
[self.window makeKeyAndVisible];
// NSLog(@"%@",application.windows);
// self.window.hidden = NO;
NSLog(@"%@",self.window);
- 通过storyboard创建控制器
- 1、加载storyboard
- 2、实例化控制器
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// 创建窗口
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 创建窗口的跟控制器
// 加载storyboard
// storyboard文件名,不需要带后缀
// nil: [NSBundle mainBundle]
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 通过storyboard创建控制器
// instantiateInitialViewController:加载箭头指向的控制器
// UIViewController *vc = [storyboard instantiateInitialViewController];
// 根据storyboard的中控制器的标示加载
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"green"];
NSLog(@"%@",[vc class]);
self.window.rootViewController = vc;
// 显示窗口
[self.window makeKeyAndVisible];
return YES;
}
- 通过xib创建控制器
- 一定要描述xib的文件拥有者是控制器,也就是说这个xib是用来描述控制器
// 通过xib创建控制器
ViewController *vc = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
loadView方法
loadView作用:自定义控制器的view
loadView什么时候调用:第一次使用控制器的view的时候调用
注意:在这个方法中如果没有自定义view,就不能获取控制器的view
一旦重写了这个方法,就不要调用[super loadView]
如果重写了这个方法,就不会去加载storyboard描述的控制器的View
- (void)loadView
{
// 创建控制器view
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 这里设置颜色不靠谱,因为最终会返回到程序启动完成时
self.view.backgroundColor = [UIColor purpleColor];
}
- 系统内部的实现原理
- (UIView *)view
{
if (_view == nil) {
[self loadView];
[self viewDidLoad];
}
// 最终会将view返回到外界,属性应由外面设置
return _view;
}
- 错误写法
#pragma mark - 直接不实现就是系统默认的做法
- (void)loadView
{
// super -> UIViewController
// 系统默认的做法,一定不要这样写
[super loadView];
}
通过xib创建控制器的view
- 默认loadView可以加载storyboard和xib描述的控制器的view
// 加载跟类名相同的xib
// 如果描述控制器View的xib跟控制器的类名相同,就会去加载
// 只有控制器的init方法底层会调用initWithNibName:bundle:
// 只要通过initWithNibName:bundle:初始化控制器,并且nibName为nil,就会执行以下几步。
// XMGViewController类型
// 1.寻找有没有跟控制器类名同名但是不带Controller的xib,如果有就会去加载(XMGView.xib)
// 2.寻找有没有跟控制器类名同名的xib,如果有就会去加载(XMGViewController.xib)
// 3.如果都没有找到,创建空的view,
UIViewController *vc = [[ViewController alloc] initWithNibName:@"VC" bundle:nil];
self.window.rootViewController = vc;
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
NSLog(@"%s",__func__);
return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}
创建UIViewController控制器,控制器的view并没有创建
- 控制器的view懒加载:第一次使用的时候才会去加载,并不是创建UIViewController控制器的时候去加载
可以用isViewLoaded方法判断一个UIViewController的view是否已经被加载
控制器的view加载完毕就会调用viewDidLoad方法
UIViewController *vc = [[ViewController alloc] init];
// 只有用到时才会加载
vc.view.backgroundColor = [UIColor redColor]
- 默认控制器的view:几乎透明
- 可以显示后面的控件并使用 alpha > 0
- 如果控制器是窗口的根控制器就可以不用设置尺寸
- 默认就是窗口的尺寸
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectZero];
self.view.backgroundColor = [UIColor yellowColor];
}
- 在viewDidLoad中打印控制器的尺寸不准确,通常在viewDidAppear
#pragma mark - view完全显示的时候调用
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"%@",NSStringFromCGRect(self.view.bounds));
}
> 1.控制器view的创建(空项目) 2.研究控制器view的加载,首先需要自定义控制器view,作为根控制器。 3.证明控制器的view是透明的:直接通过alloc,init创建的控制器的view默认是透明的 4.通过storyboard加载的控制器view,和storyboard描述的一样。 5.重写控制器的loadView,不会去加载storyboard. 6.解释loadView方法 1> loadView作用:一般用来创建自定义的view 2> loadView什么时候调用:当控制器的view没有创建的时候,就会调用loadView 去创建控制器的view. 3> loadView使用注意:如果重写loadView里面没有创建控制器的view,就不能使 用self.view,会造成死循环。 7.通过xib加载控制器的view 1> 取一个CZViewController123的xib描述控制器的view,通过这个xib加载控制器的 view 2> 取一个CZViewController的xib描述控制器的view,通过这个xib加载控制器的 view,不用告诉控制器去加载哪个xib,会自动去加载CZViewController这个xib。 3> 取一个CZView的xib描述控制器的view,通过这个xib加载控制器的view,不用告 诉控制器去加载哪个xib,优先去加载CZView这个xib。 8.PPT演示LoadView的默认做法。 8.1> 控制器View的决定权:重写LoadView>storyboard>nibName>xib 9.控制器的view是延迟加载的。 9.1> 验证控制器的view延迟加载,只有在窗口显示的时候,才会调用loadView 方法。 9.2> 用到控制器view的时候才会加载控制器的view,设置控制器view的背景颜色 9.3> 通过设置控制器view的颜色,引出两个疑问。 1> 重写loadView,不是不会加载xib了吗,控制器的view由loadView决定, loadView显示什么颜色,就是什么颜色。 2> loadView只是创建控制器View,并不能决定控制器的view的颜色。 3> 理解loadView的调用时刻:第一次调用self.view,底层会调用LoadView 方法,创建控制器的view,这时候的view是LoadView的颜色,但是 vc.view.backgroundColor,是拿到控制器的view又设置一次颜色,把 LoadView设置的颜色给覆盖了。 4> 在viewDidLoad也设置颜色,还是vc.view.backgroundColor决定,因为 vc.view就是获取控制器的view,只有控制器的view加载完成之后,才能获取 到,因此先调用viewDidLoad。 10.如何快速生成一个xib描述控制器的view,之前还要在xib拖视图,设置xib描述哪个 控制器,很麻烦。 1> 定义新的控制器的时候,勾选xib,会自动搞一个xib描述控制器的view. 2> 会自动生成一个和控制器同名的xib,并且里面设置好了。 学习方法:学习原理,不要一开始就用最快的方式创建xib,开发的时候才使用最快的方 式。