1、頁面結(jié)構(gòu)
相信很多人和我一樣,開發(fā)了很多iOS頁面但是確一直沒有去詳細剖析iOS頁面中的頁面結(jié)構(gòu)。先說下常規(guī)的APP開發(fā)套路,首先我們會使用UINaviagtionController來作為一個導航控制器來管理我們APP中的導航,然后我們會向?qū)Ш娇刂破髦衟ush或者pop UIViewController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//1、創(chuàng)建窗口
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.window.backgroundColor = [UIColor whiteColor];
//2、創(chuàng)建導航控制器,并設(shè)置導航控制器的根控制器
OneViewController *rootVC = [[OneViewController alloc]init];
UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:rootVC];
//3、設(shè)置窗口的根控制器
self.window.rootViewController = navigationController;
//4、顯示窗口
[self.window makeKeyAndVisible];
return YES;
}
從代碼中我們可以發(fā)現(xiàn)我們的步驟是:
UIWindow--UINavigationController--UIViewController
通過上面的邏輯關(guān)系我們肯定會迷惑,不是應該一切能顯示的的東西都應該直接或者間接的繼承UIView嗎?這個就是蘋果處處強調(diào)的MVC設(shè)計理念了(View應該對應一個Controller來管理),其實我們在設(shè)置UINavigationController和UIViewController的時候系統(tǒng)自動會給我們添加繼承UIView的控件在UIWindows上面的。下面我們就來看看里面到底添加了哪些控件。
//遞歸顯示頁面的結(jié)構(gòu)
- (void)dumpView:(UIView *)aView atIndent:(int)indent into:(NSMutableString *)outstring
{
for (int i = 0; i < indent; i++) [outstring appendString:@"--"];
[outstring appendFormat:@"[%2d] %@\n", indent, [[aView class] description]];
for (UIView *view in [aView subviews])
[self dumpView:view atIndent:indent + 1 into:outstring];
}
- (NSString *) displayViews: (UIView *) aView
{
NSMutableString *outstring = [[NSMutableString alloc] init];
[self dumpView: [UIApplication sharedApplication].keyWindow atIndent:0 into:outstring];
return outstring;
}
輸出結(jié)果
我們抽取主要的UIView轉(zhuǎn)換為樹這樣看的更清晰
我們從圖中的層次結(jié)構(gòu)看出平時我們真正使用到的UIView和UINavigationBar不是直接添加到UIWindow里面的,而是有多個層次。并且還有些不是我們自己添加的UIView,這些是系統(tǒng)為了更好的實現(xiàn)功能而添加的,負責一些動畫布局處理。
UILayoutContainerView:這個是UINavigationController的容器View這個就想相當于UIViewController中的UIView;我們可以通過代碼,來看輸出類型。
NSLog(@"super-%@",[self.navigationController.view class]);
UINavigationTransitionView和UIViewControllerWrapperView是什么鬼
stackoverflow解釋
從里面的問答的基本意思是UINavigationTransitionView是UINaviagtionController來管理動畫的,UIViewControllerWrapperView是用來包含我們實際開發(fā)的UI的。從集成結(jié)構(gòu)我們也可以看出,UIView是包含在UIViewControllerWrapperView當中的。
通過下面的兩段代碼我們就可以得出我上圖中的劃線層次,
UINavigationController
//輸出UINavigationController中的View
NSLog(@"super-%@",[self.navigationController.view class]);
for (UIView *view in self.navigationController.view.subviews) {
NSLog(@"view-%@",[view class]);
}
輸出結(jié)果
2016-11-04 19:56:59.420 UINavigationControllerDemo[57578:4726504] super-UILayoutContainerView
2016-11-04 19:56:59.421 UINavigationControllerDemo[57578:4726504] view-UINavigationTransitionView
2016-11-04 19:56:59.421 UINavigationControllerDemo[57578:4726504] view-UINavigationBar
UIViewController
//輸出UIViewController中的View
NSLog(@"super-%@",[self.view class]);
for (UIView *view in self.view.subviews) {
NSLog(@"view-%@",[view class]);
}
輸出結(jié)果
2016-11-04 20:01:56.655 UINavigationControllerDemo[57601:4729878] super-UIView
2016-11-04 20:01:56.655 UINavigationControllerDemo[57601:4729878] view-UIButton
2、UINavigationController、UINavigationBar和NavigationItem之間的關(guān)系
1、UINavigationBar是包含在UINavigationController中的;
2、NavigationItem是用于管理UINavigationBar中的子控件的對象。
注意:雖然UINavigationBar屬于UINavigationController,但是我們卻不能通過UINavigationController的NavigationItem屬性來控制導航欄中的子控件;這個是很迷惑的地方
//通過控制器的navigationItem設(shè)置屬性
self.navigationItem.title = @"首頁";
//這樣設(shè)置無效
self.navigationController.navigationItem.title = @"無效標題";
?導航欄的內(nèi)容由棧頂控制器的navigationItem屬性決定
?
?UINavigationItem有以下屬性影響著導航欄的內(nèi)容
?左上角的返回按鈕
@property(nonatomic,retain) UIBarButtonItembackBarButtonItem;
?中間的標題視圖
@property(nonatomic,retain) UIView titleView;
?中間的標題文字
@property(nonatomic,copy) NSString title;
?左上角的視圖
@property(nonatomic,retain) UIBarButtonItemleftBarButtonItem;
?UIBarButtonItemrightBarButtonItem 右上角的視圖
@property(nonatomic,retain) UIBarButtonItemrightBarButtonItem; `