主要知识点:
**************** 今天的主要知识点 ****************
1. 控制器及View的多种创建方式
2. 多控制器管理。
**************** 今天的主要知识点 ****************
一、复习。
* 四个对象的关系:
1> UIApplication
2> AppDelegate
3> UIWindow
4> UIViewController
* 复习一下程序启动的过程。
* UIWindow相关:
* 新建一个"空项目"。
1. 自己手动创建UIWindow, 设置背景色, 运行看效果。
2. 为AppDelegate代理对象再加一个window2属性, 再创建一个window对象, 设置不同的颜色、大小, 并调用makeKeyAndVisible方法。
** 注意: 当多个UIWindow对象都调用了makeKeyAndVisible方法, 那么最后一个调用该方法的Window将会成为主窗口。
** 注意: 一个应用程序同时只能有一个"Key Window"。在iOS 6下只有Key Window上的文本框才能输入内容。
/** 参考代码: 创建两个UIWindow, 同时显示。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 创建一个UIWindow
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor blueColor];
[self.window makeKeyAndVisible];
// 创建第2个UIWindow
self.window2 = [[UIWindow alloc] initWithFrame:CGRectMake(50, 150, 300, 300)];
self.window2.backgroundColor = [UIColor redColor];
[self.window2 makeKeyAndVisible];
// 输出当前总的UIWindow
// NSLog(@"个数: %ld", [UIApplication sharedApplication].windows.count);
UIApplication *app = [UIApplication sharedApplication];
// 输出每个UIWindow的地址
NSLog(@"%p---%p", self.window, self.window2);
// 输出当前"主Window的地址"
NSLog(@"%p",app.keyWindow);
// 输出所有的UIWindow
NSLog(@"=====%@=======", app.windows);
return YES;
}
*/
* 通过调用[UIApplication sharedApplication].keyWindow来获取当前的"主窗口"。
* [self.window makeKeyWindow]; // 设置当前self.window为主窗口。默认只有一个window, 但是可以创建多个window对象。
* [self.window makeKeyAndVisible]; // 设置当前self.window为主窗口, 并且显示当前窗口。
* [UIApplication sharedApplication].windows, 获取所有的window。
* 平时输入内容的键盘, 就在一个独立的window中。
* 动态创建一个按钮, 当单机按钮的时候, 打印一下[UIApplication sharedApplication].windows的个数, 观察有几个Window。
** 注意: 因为键盘在一个独立的UIWindow中, 所以当我们要获取键盘上的按钮的时候, 要首先获取键盘所在的UIWindow对象。
/** 参考代码: 弹出键盘后, 再观察当前的总的UIWindow的个数。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 创建一个UIWindow
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor blueColor];
[self.window makeKeyAndVisible];
// 创建第2个UIWindow
self.window2 = [[UIWindow alloc] initWithFrame:CGRectMake(50, 150, 300, 300)];
self.window2.backgroundColor = [UIColor redColor];
[self.window2 makeKeyAndVisible];
NSLog(@"个数: %ld", [UIApplication sharedApplication].windows.count);
// 动态创建一个文本框
UITextField *txt = [[UITextField alloc] initWithFrame:CGRectMake(20, 20, 100, 20)];
txt.borderStyle = UITextBorderStyleRoundedRect;
[self.window2 addSubview:txt];
// 动态创建一个按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
[btn setTitle:@"点我一下" forState:UIControlStateNormal];
btn.frame = CGRectMake(150, 5, 100, 30);
[btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
[self.window2 addSubview:btn];
NSLog(@"个数: %ld", [UIApplication sharedApplication].windows.count);
return YES;
}
- (void)btnClick
{
// 输出当前总的UIWindow
NSLog(@"个数: %ld", [UIApplication sharedApplication].windows.count);
NSLog(@"%@", [UIApplication sharedApplication].windows);
}
*/
二、 **** 控制器以及view的多种创建方式 ****(重点掌握)
** 了解创建控制器的多种不同方式, 目的是为了后续学习"多控制器管理"打基础。先知道了如何通过多种不同的方式来创建控制器, 然后再进行多控制器的管理。
1. 控制器(ViewController)管理 (全部创建一个空项目来演示)
* 创建控制器, 主要有3中方式:
1> 直接通过alloc + init的方式创建。 然后设置self.window.rootViewController为这个控制器
/** 参考代码:
思路:
1> 创建一个"Single View Application", 删除默认控制器、Main.storyboard、Main Interface设置为空。
2> 创建一个自定义的控制器, FirstViewController。
3> 在AppDelegate的application: didFinishLaunchingWithOptions:方法中:
3.1 创建UIWindow对象。
3.2 通过alloc + init的方式创建该控制器的对象, 并设置该控制器View的背景色。
3.2 设置UIWindow的根控制器为该控制器对象。
=============================== 代码 ======================================
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 创建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 创建控制器
SteveZFirstViewController *vc1 = [[SteveZFirstViewController alloc] init];
vc1.view.backgroundColor = [UIColor blueColor];
// 设置控制器为UIWindow对象的根控制器"rootViewController"
self.window.rootViewController = vc1;
// 显示UIWindow对象
[self.window makeKeyAndVisible];
return YES;
}
=============================== 代码 ======================================
*/
2> 通过加载storyboard文件,来创建一个控制器。
** 回忆: 之前有Main.storyboard文件, 并设置Main Interface为Main的时候, 是系统在程序启动之后, 主动加载Main.storyboard文件, 并创建对应的控制器、UIView然后显示到界面上的。
** 现在: 我们删除了Main.storyboard文件, 也清空了Main Interface的配置。那么现在就需要我们自己创建一个新的storyboard文件(Two.storyboard), 然后自己写代码来加载Two.storyboard文件, 这就是手动通过storyboard文件创建控制器的方式。
* 自己新建一个storyboard文件,然后拖一个控制器上去。在AppDelegate中主动去加载该storyboard。
* 具体步骤如下:
1. UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"storyboard的文件名(无需写后缀)" bundle:nil]; // 第二个参数传nil, 表示是mainBundle。
2. [storyboard instantiateInitialViewController]; // 创建storyboard中的 initial view controller。
3. 然后设置self.window.rootViewController为这个控制器
4. 当storyboard中有多个控制器的时候, 根据控制器的Storyboard ID来创建:
[storyboard instantiateViewControllerWithIdentifier:@"vmid"];
*** 演示有Main.storyboard文件, 但是没有设置Main Interface, 自己在application:didFinishLaunchingWithOptions:方法中写代码加载Main.storyboard, 并且创建其中的"初始化控制器(Is Initial View Controller)"
*** 当要监听控制器中的view中的某个控件的时候, 需要自定义一个控制器类与该控制器相关联, 然后拖线。
/** 参考代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 0. 创建UIWindow对象
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// ==========================================================================
// 1. 加载对应的storyboard文件
UIStoryboard *myStoryboard = [UIStoryboard storyboardWithName:@"My" bundle:nil];
// 2. 创建该storyboard中的被设置为"初始化控制器"(箭头所指向的控制器)的对象。
// UIViewController *vc2 = [myStoryboard instantiateInitialViewController];
//根据storyboard中的控制器的storyboard ID来创建对应的控制器
UIViewController *vc2 = [myStoryboard instantiateViewControllerWithIdentifier:@"redVwController"];
// ==========================================================================
// 设置控制器为UIWindow对象的根控制器"rootViewController"
self.window.rootViewController = vc2;
// 显示UIWindow对象
[self.window makeKeyAndVisible];
return YES;
}
-------------------------------演示手动加载Main.storyboard-----------------------------------
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 0. 创建UIWindow对象
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// ==========================================================================
// 1. 加载Main.storyboard文件
UIStoryboard *myStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 2. 创建该storyboard中的被设置为"初始化控制器"(箭头所指向的控制器)的对象。
UIViewController *vc2 = [myStoryboard instantiateInitialViewController];
// ==========================================================================
// 设置控制器为UIWindow对象的根控制器"rootViewController"
self.window.rootViewController = vc2;
// 显示UIWindow对象
[self.window makeKeyAndVisible];
return YES;
}
*/
3> 通过指定的xib文件来创建控制器
**** 遇到的问题, 直接通过alloc + init 的方式创建控制器, 那么该控制器的view都是空的, 需要完全的自定义(自己通过代码生生View中的所有控件)。这样太麻烦。
**** 解决: 自己定义一个xib文件, 创建控制器的时候,通过alloc + initWithNibName来创建。这样创建好的控制器, 就可以使用xib中的view了。
**** 注意: 通过xib创建控制器的时候, 必须对xib进行设置, 设置如下:
/**
// ================ 这两步可以暂时先不设置, 先运行看效果 =======================
* 选中xib文件中的"File's Owner", 在属性中设置对应的类(Class)是我们自己建的控制器类。
*** "File's Owner"可以理解为, 当前的xib文件是为谁服务的。
* 然后选中"File's Owner" -> "右击"选中"view" -> 拖线到对应的View上。(设置该xib文件中哪个视图是控制器默认要创建的视图)
// ================ 这两步可以暂时先不设置, 先运行看效果 =======================
*/
* 创建一个自己的控制器类
* 创建一个xib文件(注意这个xib文件的名字暂时不要与控制器的名字一样)"Empty.xib"
* 在xib文件中拽一个UIView, 设置view的背景色(便于等会观察)
// ================ 这两步可以暂时先不设置, 先运行看效果 =======================
* 选中xib文件中的"File's Owner", 在属性中设置对应的类(Class)是我们自己建的控制器类。
*** "File's Owner"可以理解为, 当前的xib文件是为谁服务的。
* 然后选中"File's Owner" -> "右击"选中"view" -> 拖线到对应的View上。(设置该xib文件中哪个视图是控制器默认要创建的视图)
// ================ 这两步可以暂时先不设置, 先运行看效果 =======================
* 通过alloc + initWithNibName来创建。
/** 参考代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 创建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 通过xib文件, 创建控制器
SteveZFirstViewController *vc1 = [[SteveZFirstViewController alloc] initWithNibName:@"Empty" bundle:nil];
// 设置控制器为UIWindow对象的根控制器"rootViewController"
self.window.rootViewController = vc1;
// 显示UIWindow对象
[self.window makeKeyAndVisible];
return YES;
}
*/
2. 创建控制器中的UIView(参见PPT中的图, 非常重要)
/**
控制器创建好以后, 控制器所管理的View是如何创建的?
1> 控制器的View是通过调用控制器的loadView方法来创建的。这个方法是UIViewController中的一个方法。
** 只要控制器的loadView方法被调用了, 那么证明控制器的View创建好了。
2> 当调用完毕控制器的loadView方法以后, 从这时开始, 才创建好了控制器的view
3> 当控制器的View被创建好以后, 紧接着就调用控制器的viewDidLoad方法
4> 控制器的View采用了懒加载的方式, 也就是说, 在需要的使用(在用到的时候)才会创建(调用loadView方法)。
** 注意: 无论控制器是如何创建的, 只要在控制器中, 重写了("实现了")loadView方法, 并且没有调用[super loadView]方法, 那么最终控制器的View就必须完全在loadView方法中自己来创建了。所以loadView方法可以用来自定义View。
*/
** 控制器中的View的几种创建方式:
1. 先介绍self.view是通过loadView来加载的。
/*
/ 当第一次从self.view中获取view的时候(第一次使用self.view的时候),
// 控制器会调用它自己的loadView方法先创建一个view, 并且把这个新创建的view设置给self.view, 然后我们就能够通过self.view获取控制器的view了
// 控制器的view, 是通过哪个方法创建出来的。
// 控制器的view也是通过"懒汉式"来加载的。(控制器的view也是采用懒加载模式)
@property(nonatomic,retain) UIView *view; // The getter first invokes [self loadView] if the view hasn't been set yet. Subclasses must call super if they override the setter or getter.
- (void)loadView; // This is where subclasses should create their custom view hierarchy if they aren't using a nib. Should never be called directly.
*/
/*
//- (void)loadView
//{
// if (如果是直接通过alloc + init方法直接创建的控制器) {
// self.view = [[UIView alloc] init];
// } else if (如果是通过storyboard创建的控制器) {
// // 加载storyboard中的控制器, 并把storyboard中的控制器设置给self.view
// } else if (通过xib创建的控制器) {
// // 加载xib中的view, 并把xib中的view设置给self.view
// }
//}
- (void)loadView
{
//[super loadView];
// 如果希望完全自定义一个控制器的view, 那么就重写loadView方法, 同时一定不要调用父类的loadView方法。只要调用了父类的loadView方法, 那么就会执行默认的创建控制器的view的行为。
self.view = [[UIView alloc] init];
}
*/
1. 通过storyboard创建, 创建完控制器后, 自动调用loadView方法,创建控制器的view。
** 此时自定义的控制器, 因为没有"重写"("实现")loadView方法, 所以loadView方法内部就是根据storyboard文件中的view来创建View的。
2. 通过xib文件创建, 创建完控制器后, 自动调用loadView创建控制器的view。
** 此时自定义的控制器, 因为没有"重写"("实现")loadView方法, 所以loadView方法内部就是根据storyboard文件中的view来创建View的。
** 通过xib文件创建控制器的时候, 注意xib文件的名字
1> 如果创建控制器的时候, 通过initWithNibName指定了xib的名字, 那么就根据该xib创建view
2> 如果创建控制器的时候, 没有指定任何xib文件, 也没有相应的storyboard文件, 那么会尝试查找"与控制器名字相同的, 但是去除Controller的文件名的xib文件"。比如: 控制器叫做"CZViewController", 就会查找"CZView.xib"文件, 如果有, 则使用该xib文件创建view(无需手动指定, 系统自动查找)。
3> 如果创建控制器的时候, 没有指定任何xib文件, 也没有相应的storyboard文件, 也没有"CZView.xib", 那么会尝试查找与控制器名字完全相同的xib文件。比如: 控制器叫做"CZViewController", 就会查找"CZViewController.xib"文件, 如果有, 则使用该xib文件创建view(无需手动指定, 系统自动查找)。
** 建议: 如果要使用某个xib文件名自动匹配的方式创建view, 建议名字与控制器相同。
3. 通过重写(实现)UIViewController的loadView方法重写。(自己通过代码来创建控制器的View)
*** 控制器的loadView方法就是用来自定义View的。
** 如果要为控制器自定义View, 要写在loadView中, 不要写在viewDidLoad中。
*** 如果重写(实现)loadView方法中调用了[super loadView], 那么依然会使用默认的方式来加载。
*** 重写ViewController的loadView方法,用来自定义View。
/** 参考代码:
// 重写控制器的loadView方法:
- (void)loadView
{
// [super loadView];
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor purpleColor];
}
*/
/*
通过xib创建view的时候, 如果重写loadView返回的是一个透明的view,不是xib中的view
- (void)loadView
{
[super loadView];
NSLog(@"loadView");
//self.view.backgroundColor = [UIColor blueColor];
}
*/
** 注意:无论是通过加载xib创建view、storyboard创建view, 最终都依赖于loadView方法。
** 注意:修改了项目文件(比如:xxx.xib等,要先Product -> Clean, 然后把软件从模拟器中卸载, 然后再运行。)
** 如果除非手动指定了xib文件名,则按照该文件来加载,否则如果没有指定任何文件名字,则按照对应的xib文件的命名规则来找对应的xib文件。
** 控制器的loadView方法什么时候调用?
** 在需要用到控制器的view的时候才调用(当调用UIWindow对象的makeKeyAndVisible方法时,就需要显示该view了, 此时就表示用到View了。), 这个就叫做"延迟加载"。
** 比如当使用self.view.backgroundColor , 要设置控制器的view的背景色时(这时需要用到view了), 那么此时才会开始创建该控制器的view, 也就是说要调用loadView方法了。所以, 如果在loadView方法内部调用self.view.backgroundColor, 就发生死循环了。
** 可以通过调用控制器的self.isViewLoaded 方法来判断当前控制器的view是否已经加载完毕了。
** 并且当控制器的view加载完毕后, 会调用viewDidLoad方法。
** 演示控制器中的View的延迟加载效果(用到的时候才加载。)演示在loadView方法内部使用view,比如self.view.backgroundColor来设置背景色, 此时会发生死循环。
** 在loadView方法, viewDidLoad方法中输出内容。调试看在调用UIWindow的makeKeyAndVisible方法之前,是否会调用这些方法。
** 当需要访问view的时候, 调用loadView, 然后调用viewDidLoad方法, 然后才开始使用view。
=====================================UIView复习(所有控件的复习)==================================
0. 画一个控件的继承关系图。
1. 凡是继承自UIControl的控件,只要调用addTarget方法就可以监听事件, 无需代理。
2. UIView的常见属性:
@interface UIView : UIResponder<NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem>
/**
* 通过一个frame来初始化一个UI控件
*/
- (id)initWithFrame:(CGRect)frame;
// YES:能够跟用户进行交互
@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled; // default is YES
// 控件的一个标记(父控件可以通过tag找到对应的子控件)
@property(nonatomic) NSInteger tag; // default is 0
// 图层(可以用来设置圆角效果\阴影效果)
@property(nonatomic,readonly,retain) CALayer *layer;
@end
@interface UIView(UIViewGeometry)
// 位置和尺寸(以父控件的左上角为坐标原点(0, 0))
@property(nonatomic) CGRect frame;
// 位置和尺寸(以自己的左上角为坐标原点(0, 0))
@property(nonatomic) CGRect bounds;
// 中点(以父控件的左上角为坐标原点(0, 0))
@property(nonatomic) CGPoint center;
// 形变属性(平移\缩放\旋转)
@property(nonatomic) CGAffineTransform transform; // default is CGAffineTransformIdentity
// YES:支持多点触摸
@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled; // default is NO
@end
@interface UIView(UIViewHierarchy)
// 父控件
@property(nonatomic,readonly) UIView *superview;
// 子控件(新添加的控件默认都在subviews数组的后面, 新添加的控件默认都显示在最上面\最顶部)
@property(nonatomic,readonly,copy) NSArray *subviews;
// 获得当前控件所在的window
@property(nonatomic,readonly) UIWindow *window;
// 从父控件中移除一个控件
- (void)removeFromSuperview;
// 添加一个子控件(可以将子控件插入到subviews数组中index这个位置)
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
// 交换subviews数组中所存放子控件的位置
- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;
// 添加一个子控件(新添加的控件默认都在subviews数组的后面, 新添加的控件默认都显示在最上面\最顶部)
- (void)addSubview:(UIView *)view;
// 添加一个子控件view(被挡在siblingSubview的下面)
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;
// 添加一个子控件view(盖在siblingSubview的上面)
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;
// 将某个子控件拉到最上面(最顶部)来显示
- (void)bringSubviewToFront:(UIView *)view;
// 将某个子控件拉到最下面(最底部)来显示
- (void)sendSubviewToBack:(UIView *)view;
/**系统自动调用(留给子类去实现), 这些方法就可以叫做"事件方法", 由系统调用。**/
- (void)didAddSubview:(UIView *)subview;
- (void)willRemoveSubview:(UIView *)subview;
- (void)willMoveToSuperview:(UIView *)newSuperview;
- (void)didMoveToSuperview;
- (void)willMoveToWindow:(UIWindow *)newWindow;
- (void)didMoveToWindow;
/**系统自动调用**/
// 是不是view的子控件或者子控件的子控件(是否为view的后代)
- (BOOL)isDescendantOfView:(UIView *)view; // returns YES for self.
// 通过tag获得对应的子控件(也可以或者子控件的子控件)
- (UIView *)viewWithTag:(NSInteger)tag; // recursive search. includes self
/**系统自动调用(留给子类去实现)**/
// 控件的frame发生改变的时候就会调用,一般在这里重写布局子控件的位置和尺寸
// 重写了这个写方法后,一定调用[super layoutSubviews];
- (void)layoutSubviews;
@end
@interface UIView(UIViewRendering)
// YES : 超出控件边框范围的内容都剪掉
@property(nonatomic) BOOL clipsToBounds;
// 背景色
@property(nonatomic,copy) UIColor *backgroundColor; // default is nil
// 透明度(0.0~1.0)
@property(nonatomic) CGFloat alpha; // default is 1.0
// YES:不透明 NO:透明
@property(nonatomic,getter=isOpaque) BOOL opaque; // default is YES
// YES : 隐藏 NO : 显示
@property(nonatomic,getter=isHidden) BOOL hidden;
// 内容模式
@property(nonatomic) UIViewContentMode contentMode; // default is UIViewContentModeScaleToFill
@end
@interface UIView(UIViewAnimationWithBlocks)
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;
@end
三、 多控制器管理。
1. 多控制器的管理的思路: 使用一个控制器来管理所有其他控制器。
** 类似于, 使用一个UIView管理其他的的子UIView。
2. 父控制器(管理其他控制器的控制器, 就可以看做是"父控制器") 、 子控制器(被管理的控制器就是子控制器)。
3. iOS提供了两个比较特殊的控制器(用来管理"控制器"的控制器。):
* UINavigationController(导航控制器), 轻松管理多个控制器, 并且控制不同控制器之间的跳转和切换。(案例:模拟器中的"设置")
** 使用步骤:
1> 创建、初始化一个导航控制器: UINavigationController.
2> 设置UIWindow的rootViewController为UINavigationController.
3> 通过调用push方法添加子控制器到UINavigationController。
** 注意:谁是最后一个push进来的,当前显示的就是哪个ViewController。
/**
演示 :
1. 创建完毕UIWindow以后, 创建导航控制器, 然后创建多个普通控制器, push到导航控制器中。调用导航控制器的pushViewController
2. 创建完毕UIWindow以后, 创建导航控制器, 然后创建1个普通控制器, push到导航控制器中。在该控制器的View中增加一个按钮, 当点击按钮的时候, 在创建另外一个控制器, 然后将新控制器push到导航控制器中。
** 通过当前控制器的navigationController获取当前控制器所在的导航控制器。self.navigationController
// 参考代码:
- (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 purpleColor];
//==============创建导航控制器=========================
UINavigationController *nav = [[UINavigationController alloc] init];
nav.view.backgroundColor = [UIColor greenColor];
self.window.rootViewController = nav;
//==============创建导航控制器=========================
UIViewController *item =[[UIViewController alloc] init];
item.view.backgroundColor = [UIColor yellowColor];
[nav pushViewController:item animated:YES];
UIViewController *item1 =[[UIViewController alloc] init];
item1.view.backgroundColor = [UIColor blueColor];
[nav pushViewController:item1 animated:YES];
UIViewController *item2 =[[UIViewController alloc] init];
item2.view.backgroundColor = [UIColor redColor];
[nav pushViewController:item2 animated:YES];
[self.window makeKeyAndVisible];
return YES;
}
*/
** 注意: 导航控制器的导航栏是从Y坐标20开始的, 高度是44。前面的20高度是"状态栏"。
** 注意: 通过导航控制器UINavigationController切换不同的界面的时候后台做了什么? 点击导航控制器中得Back的时候后台做了什么?
** 添加到导航控制器中的自控制器的View是占满整个屏幕的。
** 参考ppt第10 - 18页。
** 点击BACK的时候自动移除栈顶控制器(被移除的控制器会被销毁, 该控制器的view也会被销毁)。
** 导航控制器始终只显示栈顶控制器。
** 栈,先进后出(First-In/Last-Out)。
* UINavigationController(导航控制器)的其他属性、方法:
1. viewControllers 、 childViewControllers都表示子控制器。(存放所有子控制器的"栈")
** childViewControllers属性是readonly的, 不能直接@[]赋值。
2. 向UINavigationController(导航控制器)中增加控制器的若干方法:
* 调用 addChildViewController:方法(不会自动跳转)
* 调用 pushViewController:animated:方法
* 直接设置viewControllers = @[vc, vc1]; 属性
* 在创建导航控制器的同时, 通过initWithRootViewController直接指定"栈底"控制器。
3. topViewController获取当前栈顶的控制器。
4. 自己写代码实现回到上一个控制器, 回到第一个控制器。
* popViewControllerAnimated:方法, 移除栈顶的控制器。
* popToViweController:vc1 animated:YES 方法表示, 从栈顶不断的移除控制器,直到看到vc1控制器为止(回到指定的控制器)。
* popToRootViewControllerAnimated:YES 移除所有的控制器, 直到显示根控制器为止(回到栈底控制器)。
* 设置导航栏的内容(导航栏高度44):
1. 一个导航控制器, 只有一个导航栏。push、pop只是更换导航控制器中的子控制器而已。导航栏始终使用的都是同一个
2. 导航栏中显示的内容, 取决于栈顶的控制器的navigationItem属性。
* 通过设置对应控制器的navigationItem的title来改变标题。
3. 在每个控制器的viewDidLoad方法中设置当前控制器的navigationItem属性。
4. navigationItem属性的具体内容:
* title属性
* titleView属性
* leftBarButtonItem // 只能设置左上角的一个按钮
* leftBarButtonItems // 可以设置左上角有多个按钮
* rightBarButtonItem // 只能设置右上角的一个按钮
* rightBarButtonItems // 可以设置右上角有多个按钮
* backBarButtonItem // 设置下一个控制器, 左上角的按钮。默认情况下,该按钮文字与上一个控制器的title文字相同。
5. 通过storyboard创建导航控制器。
6. 通过调用导航控制器的navigationBar, 可以获取导航控制器的"导航栏"。
* 在代理方法的DidBecomeActive事件中,输出导航栏的大小、位置
/** 参考代码:
UINavigationController *nav = self.window.rootViewController;
CGRect rect = nav.navigationBar.frame;
NSLog(@"%@",NSStringFromCGRect(rect));
** DidBecomeActive事件含义:程序获得焦点。与"程序进入前台"的区别: 先"进入前台", 然后才"获得焦点", 程序"获得焦点"意味着所有控件都可以开始监听事件了。
"先进入前台" 再 "获得焦点"
"先失去焦点" 再 "进入后台"
*/
* UITabBarController