导航视图控制器是一个特殊的容器视图控制器,它可以维护有明确层次关系的视图之间的切换。我们可以打开模拟器或者你的iPhone看看设置功能,这里就是一个典型的对导航视图控制器的应用,如下图所示。很明显,导航视图控制器维护了一个栈结构,这是一种先进后出(FILO)的结构,我们将一个一个的视图压入栈中,当我们想返回的时候就可以依次出栈。
可以通过UINavigationController的viewControllers属性获得其栈中保存的所有视图控制器;topViewController可以获得栈顶的视图控制器。
一个导航视图控制器通常是由以下几个部分构成的:
导航视图控制器会维持一个导航条(UINavigationBar),这个导航条被所有的视图控制器共享,可以通过UINavigationController对象navigationBar属性获得导航条,再通过下面的属性设置其半透明效果,注意对导航条的设置将对所有的视图控制器生效。
说明:UIBarPostion和UIBarMetrics都是枚举类型,前者表示导航栏的位置;后者表示导航栏的外观。前者可能的取值包括:UIBarPositionAny(不指定位置)、UIBarPositionBottom(位于视图底部)、UIBarPositionTop(位于视图顶部)和UIBarPositionTopAttached(位于屏幕顶部同时也在其视图的顶部);后者可能的取值包括:UIBarMetricsDefault(设备默认的外观)、UIBarMetricsCompact(手机尺寸的外观)等。
通过视图控制器的navigationItem属性可以获得和视图控制器对应的导航栏项,该属性是只读的,但是通过它的子属性可以对UINavigationItem进行定制。可以定制的内容包括:
说明:由于navigationItem是每个视图持有自己的navigationItem,因此可以为每个视图定制不同的导航项。
如果当前视图控制器通过navigationItem设置了leftBarButtonItem,则显示当前视图控制器设置好的leftBarButtonItem;如果当前视图控制器没有设置leftBarButtonItem,且当前视图控制器不是根视图控制器,显示上一层的backBarButtonItem;如果上一层没有指定backBarButtonItem,系统将根据上一层视图控制器的标题自动生成一个返回按钮;如果当前视图控制器没有设置leftBarButtonItem且当前视图控制器是根视图控制器,则左边不显示任何东西。
如果当前视图控制器通过navigationItem属性定制了titleView,那么将会显示自定义的titleView,titleView的高度不应该超过导航条的高度;如果当前视图控制器没有定制titleView,系统会根据当前视图控制器的标题或者navigationItem的标题创建一个UILabel来显示此标题;navigationItem的标题优于视图控制器的标题。
强调:UINavigationController本身并不显示无需定制,UINavigationBar属于导航控制器(子对象),它使被多个视图共享的,当你切换视图控制器时,导航栏并没有切换,如果需要定制导航视图控制器就需要定制导航栏以及导航栏上的项目UINavigationItem。我们可以让每个视图控制器都有自己的UINavigationItem,并按照自己的意愿来创建它。
下面通过代码对上述内容加以展示。
// 重设rightBarButtonItem
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStyleDone target:self action:@selector(onClick:)];
//重设leftBarButtonItem
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"itemImage1"] landscapeImagePhone:[UIImage imageNamed:@"itemImage2"] style:UIBarButtonItemStyleBordered target:nil action:nil];
UIBarButtonItem * item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:nil action:nil];
UIBarButtonItem * item2 = [[UIBarButtonItem alloc] initWithTitle:@"OK" style:UIBarButtonItemStylePlain target:nil action:nil];
// 使用自定义视图,创建barButtonItem
UISwitch * sw = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[sw addTarget:self action:@selector(pushNextViewController) forControlEvents:UIControlEventValueChanged];
// barButton官方推荐大小是20*20
UIBarButtonItem * item3 = [[UIBarButtonItem alloc] initWithCustomView:sw];
// 将多个item添加到右侧
self.navigationItem.rightBarButtonItems = @[item1, item2, item3];
UIButton *goBackButton = [UIButton buttonWithType:UIButtonTypeSystem];
goBackButton.frame = CGRectMake(10, 10, 60, 40);
[goBackButton addTarget:self action:@selector(goBackButtonClicked) forControlEvents:UIControlEventTouchUpInside];
[goBackButton setTitle:@"滚蛋" forState:UIControlStateNormal];
UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:goBackButton];
self.navigationItem.leftBarButtonItem = barItem;
每个导航控制器,还配备了工具条(44坐标高),默认隐藏,可以通过将导航视图控制器的toolBarHidden属性设置为NO使其显示。工具条属于UINavigationController,一个导航控制器,只有一个工具条。工具条上的toolBarItem属于每个视图控制器,每个视图控制器可以单独定制工具条上的每个项。
self.navigationController.toolbarHidden = NO;
UIImage *bgImage = [UIImage imageNamed:@"toolBar"];
[navigationController.toolbar setBackgroundImage:bgImage forToolbarPosition:UIBarPositionBottom barMetrics:UIBarMetricsDefault];
[self.navigationController.toolbar setTintColor:[UIColor whiteColor]];
UIBarButtonItem * item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:nil action:nil];
UIBarButtonItem * item2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:nil action:nil];
UIBarButtonItem * item3 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:nil action:nil];
UIBarButtonItem * spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
self.toolbarItems = @[item1, spaceItem, item2, spaceItem, item3];
从iOS 5开始,UIKit中提供了一个叫做UIAppearance的协议,通过该协议可以轻松的统一你的界面,它提供如下两个方法:
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setBackgroundImage:myNavBarButtonBackgroundImage forState:state barMetrics:metrics];
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], [UIPopoverController class], nil] setBackgroundImage:myPopoverNavBarButtonBackgroundImage forState:state barMetrics:metrics];
[[UIBarButtonItem appearanceWhenContainedIn:[UIToolbar class], nil]
setBackgroundImage:myToolbarButtonBackgroundImage forState:state barMetrics:metrics];
[[UIBarButtonItem appearanceWhenContainedIn:[UIToolbar class], [UIPopoverController class], nil] setBackgroundImage:myPopoverToolbarButtonBackgroundImage forState:state barMetrics:metrics];