導航控制器管理一系列顯示層次型信息的場景。它創建一個視圖管理器"棧",棧底為根視圖控制器,用戶在場景間切換時,依次將試圖控制器壓入棧中,且當前場景的試圖控制器位於棧頂。要返回上一級,導航控制器將彈出棧頂的控制器,從而回到它下面的控制器。
導航控制器還管理一個導航欄(UINavigationBar)。導航欄類似於工具欄,但它是使用導航項(UINavigationItem)實例填充的,該實例被加入到導航控制器管理的每個場景中。默認情況下,場景的導航項包含一個標題和一個Back按鈕。Back按鈕是以欄按鈕項(UIBarButtonItem)的方式加入到導航項的。
導航項在Attributes inspector面板里有三個可設置屬性:Title、Prompt和Back Button
Title -- 導航項的標題
Prompt -- 顯示在標題上方的文本,向用戶提供使用說明
Back Button -- 下一個場景的后退按鈕的文本,假如沒有設置,默認顯示的文本是標題
在任何場景中,都可通過屬性parentViewController來獲取導航控制器。
UINavigationController分為三個部分:頂部的Navigation Bar,中間的Custom Content以及底部的Navigation toolbar。如圖所示:
代碼添加UINavigationController:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UIViewController *firstVC = [[UIViewController alloc] initWithNibName:@"FirstVC" bundle:nil]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstVC]; self.window.rootViewController = navigationController; self.window.backgroundColor = [UIColor greenColor]; [self.window makeKeyAndVisible]; SecondVC *secondVC = [[SecondVC alloc] init]; ThirdVC *thirdVC = [[ThirdVC alloc] init]; NSArray *array = @[secondVC, thirdVC]; [navigationController setViewControllers:array animated:YES]; [navigationController pushViewController:firstVC animated:YES]; return YES; }
UIViewController的navigationItem屬性
添加navigationItem是UIViewController的一個屬性,這個屬性是為UINavigationController服務的。這個屬性包含以下幾個界面元素:
leftBarButtonItem -- 左按鈕
rightBarButtonItem -- 右按鈕
backBarButtonItem -- 返回按鈕
title -- 標題
prompt -- 提示
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"LeftButton" style:UIBarButtonItemStylePlain target:self action:@selector(test1)]; firstVC.navigationItem.leftBarButtonItem = leftButton; UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"RightButton" style:UIBarButtonItemStylePlain target:self action:@selector(test1)]; firstVC.navigationItem.rightBarButtonItem = rightButton; UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"BackButton" style:UIBarButtonItemStylePlain target:self action:@selector(test1)]; firstVC.navigationItem.backBarButtonItem = backButton; firstVC.navigationItem.title = @"My Title"; //firstVC.navigationItem.titleView = [[UIView alloc] init]; firstVC.navigationItem.prompt = @"Just A Prompt";
leftBarButtonItem和rightBarButtonItem可以指定多個按鈕,backButton只能指定一個按鈕。
設定了prompt會增加NavigationBar的高度。
要進一步自定義title,可以通過titleView屬性將title設置成一個自定義的UIView。
通過設定navigationItem.leftItemsSupplementBackButton = YES可以同時顯示leftBarButtonItem和backBarButtonItem。
添加單個按鈕:
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"編輯" style:UIBarButtonItemStylePlain target:self action:@selector(test1)]; NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"TimesNewRomanPS-BoldMT" size:14.0f], NSForegroundColorAttributeName: [UIColor greenColor]}; [rightButton setTitleTextAttributes:attributes forState:UIControlStateNormal]; firstVC.navigationItem.rightBarButtonItem = rightButton;
添加多個按鈕:
UIBarButtonItem *cleanButton = [[UIBarButtonItem alloc] initWithTitle:@"清空" style:UIBarButtonItemStylePlain target:self action:@selector(cleanTextView)]; UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"保存" style:UIBarButtonItemStylePlain target:self action:@selector(saveTextView)]; firstVC.navigationItem.rightBarButtonItems = @[cleanButton, saveButton];
P.s. UIBarButtonItemStylePlain和UIBarButtonItemStyleDone的區別就是后者字體更粗而已。
利用navigationController.navigationBar.titleTextAttributes屬性修改文本外觀
NSDictionary *dict = [NSDictionary dictionaryWithObject:[UIColor greenColor] forKey:NSForegroundColorAttributeName];
navigationController.navigationBar.titleTextAttributes = dict;
UIViewController的edgesForExtendedLayout屬性與extendedLayoutIncludesOpaqueBars屬性
這也是兩個與UINavigationController有關聯的屬性:
edgesForExtendedLayout — 這個屬性屬於UIExtendedEdge類型,它指定了視圖的哪條邊需要擴展開;默認值是UIRectEdgeAll(全部擴展),也可以通過UIRectEdgeLeft|UIRectEdgeRight這種方式設定部分擴展定、或設定為UIRectEdgeNone(全部不擴展)。
假如childVC有一個Y坐標為100的子控件,當edgesForExtendedLayout包含了UIRectEdgeTop時,它是從最頂端開始計算Y坐標;否則是從Navigationbar的offsetY開始計算Y坐標。
extendedLayoutIncludesOpaqueBars — 這個屬性指定了當Navigationbar使用了不透明圖片時,視圖是否延伸至Bar所在區域,默認值時NO(不延伸)。當Navigationbar並未使用不透明圖片做背景時,該屬性無效。
當Navigationbar使用了不透明圖片當背景時,各種情況如下:
1. edgesForExtendedLayout默認值(UIRectEdgeAll) && extendedLayoutIncludesOpaqueBars默認值(NO)
雖然edgesForExtendedLayout包含了UIRectEdgeTop,但由於是不透明圖片做背景,並且extendedLayoutIncludesOpaqueBars設定了不延伸,這個時候子控件的Y坐標還是從Navigationbar的offsetY開始計算。當隱藏navigationBar時(navigationController.navigationBarHidden = YES),childVC會整體上移
2. edgesForExtendedLayout默認值(UIRectEdgeAll) && extendedLayoutIncludesOpaqueBars為YES
雖然是不透明圖片做背景,但extendedLayoutIncludesOpaqueBars設定為延伸,這個時候子控件的Y坐標是從最頂端計算。當隱藏navigationBar時childVC不會改變位置。
可以通過下面的代碼來驗證這兩個屬性的各種搭配情況:
CGSize imageSize = CGSizeMake(1, 1); UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0); [[UIColor greenColor] set]; UIBezierPath * path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, imageSize.width, imageSize.height)]; [path fill]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext (); UIGraphicsEndImageContext(); [[UINavigationBar appearance] setBackgroundImage:image forBarMetrics:UIBarMetricsDefault]; firstVC.edgesForExtendedLayout = UIRectEdgeNone; firstVC.extendedLayoutIncludesOpaqueBars = YES;
UINavigationController底部的ToolBar
UIBarButtonItem *one = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:nil action:nil]; UIBarButtonItem *two = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:nil action:nil]; UIBarButtonItem *three = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:nil action:nil]; navigationController.toolbarHidden = NO; [firstVC setToolbarItems:[NSArray arrayWithObjects:one, two, three, nil] animated:YES];
UINavigationControllerDelegate
該代理的兩個主要方法如下,主要作用是在切換前對目標ViewController進行設置:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { NSLog(@"%@",viewController); viewController.view.backgroundColor = [UIColor greenColor]; NSLog(@"willShowViewController"); } - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { NSLog(@"%@",viewController); NSLog(@"didShowViewController"); }
UINavigationController的topViewController與visibleViewController屬性
topViewController — 獲取頂層ViewController
visibleViewController — 獲取當前顯示的ViewController
絕大多數情況下,topViewController是等於visibleViewController的,對於在topViewController上通過presentViewController跳轉到一個新的ViewController情況,topViewController是不等於visibleViewController的。