【转】【iOS】导航栏那些事儿
原文网址:http://www.jianshu.com/p/f797793d683f
参考文章
前言
本文试图阐释清楚导航栏相关的概念和用法,比如UINavigationBar
和UINavigationItem
的区别和联系,UIBarButtonItem
的用法以及在纯代码和storyboard中有什么不同。如果读者有类似的疑惑,不妨读一读本文。
本文撰写时,用的iOS8.3、Xcode6.3,因为没有仔细考证iOS各版特性的不同,可能导致出入,若读者遇到,还请指出,我及时改正。
1、UINavigationBar VS UINavigationItem

文档说明:
The UINavigationBar class provides a control for navigating hierarchical content. It’s a bar, typically displayed at the top of the screen, containing buttons for navigating within a hierarchy of screens. The primary properties are a left (back) button, a center title, and an optional right button. You can use a navigation bar as a standalone object or in conjunction with a navigation controller object.
翻译:
UINavigationBar类提供一种对导航层级内容的控制。它是一个栏,最典型的用法就是放在屏幕顶端,包含着各级视图的导航按钮。它最首要的属性是左按钮(返回按钮)、中心标题,还有可选的右按钮。你可以单独用导航栏,或者和导航控制器一起使用。

文档说明:
A UINavigationItem object manages the buttons and views to be displayed in a UINavigationBar object. When building a navigation interface, each view controller pushed onto the navigation stack must have a UINavigationItem object that contains the buttons and views it wants displayed in the navigation bar. The managing UINavigationController object uses the navigation items of the topmost two view controllers to populate the navigation bar with content.
翻译:
一个UINavigationItem对象管理展示在导航栏上的按钮和视图。当创建一个导航界面的时候,每个压入导航栈中的视图控制器都需要一个navigation item,它包含了展示在导航栏上的按钮和视图。导航控制器利用最顶层的两个视图控制器的navigation item来提供导航栏的内容。
在纯代码操作UINavigationBar和UINavigationItem的实例中,我们会觉得不舒服,或者说疑惑的地方

事实上,UINavigationController并没有navigationItem
这样一个直接的属性,由于UINavigationController继承于UIViewController,而UIViewController是有navigationItem
这个属性的,所以才会出现如图所示的情况,如果你这样用:
self.navigationController.navigationItem.title = @"刘大帅";
是没有任何效果的。这当然是由于UINavigationController是个特殊的视图控制器,它是视图控制器的容器(另外两个容器是UITabBarController和UISplitViewController),你不应该把它当一般的UIViewController来使用.
另外,让人觉得不爽的地方如下:
self.navigationItem.title = @"刘大帅";
self.navigationController.navigationBar.barTintColor = [UIColor purpleColor];
效果如下:

这里让人迷惑的地方在于,同样是对导航栏的操作,怎么一个在第一层级(UIViewController),另外一个在其属性navigationController的层级。
如前所说,navigationItem
是UIViewController的一个属性,开发者文档是这样描述这个属性的:
This is a unique instance of UINavigationItem created to represent the view controller when it is pushed onto a navigation controller. The first time the property is accessed, the UINavigationItem object is created. Therefore, you should not access this property if you are not using a navigation controller to display the view controller. To ensure the navigation item is configured, you can either override this property and add code to create the bar button items when first accessed or create the items in your view controller's initialization code.
Avoid tying the creation of bar button items in your navigation item to the creation of your view controller's view. The navigation item of a view controller may be retrieved independently of the view controller's view. For example, when pushing two view controllers onto a navigation stack, the topmost view controller becomes visible, but the other view controller's navigation item may be retrieved in order to present its back button.
The default behavior is to create a navigation item that displays the view controller's title.
翻译一下:
它是UINavigationItem一个独特的实例。当视图控制器被推到导航控制器中时,它来代表这个视图控制器。当第一次访问这个属性的时候,它会被创建。因此,如果你并没有用导航控制器来管理视图控制器,那你不应该访问这个属性。为确保navigation item 已经配置,你可以在视图控制器初始化时,重写这个属性、创建bar button item。
要避免在创建视图控制器的视图时,创建bar button item。视图控制器的这个属性——navigationItem,它的恢复(生命周期——作者注),可能独立于视图控制器的视图。为什么会这样?举例来说,当把两个视图控制器压到导航栈中,最顶层的视图控制器是可见的,但另一个视图控制器的navigation item 可能是活跃状态(此时,隐藏的视图控制器的视图肯定是不活跃的,所以,这个时候navigation item 是独立于视图控制器的视图的——作者注),因为它要呈现其返回按钮。
缺省行为是创建一个navigation item 来展示视图控制器的标题。
我们来总结一下,如果把导航控制器比作一个剧院,那导航栏就相当于舞台,舞台必然是属于剧院的,所以,导航栏是导航控制器的一个属性。视图控制器(UIViewController)就相当于一个个剧团,而导航项(navigation item)就相当于每个剧团的负责人,负责与剧院的人接洽沟通。显然,导航项应该是视图控制器的一个属性。虽然导航栏和导航项都在做与导航相关的事情,但是它们的从属是不同的。
我想,这个类比应该能解决以上的疑惑吧。导航栏相当于负责剧院舞台的布景配置,导航项则相当于协调每个在舞台上表演的演员(bar button item,title 等等),每个视图控制器的导航项可能都是不同的,可能一个右边有一个选择照片的bar button item,而另一个视图控制器的右边有两个bar button item。
2、关于UINavigationItem一些测试
我们知道navigation item 有
leftBarButtonItems
和rightBarButtonItems
两个属性,每个属性都可以赋值一个装有UIBarButtonItem
对象的数组,有没有想过,如果数组装有很多UIBarButtonItem
对象,超过了导航栏展现的极限,会怎样?如下图:导航栏被撑爆...代码:
NSMutableArray* array = [NSMutableArray array];
for (int i =0; i<7; i++) {
UIBarButtonItem* item = [[UIBarButtonItem alloc]initWithTitle:[NSString stringWithFormat:@"item%d",i+1] style:UIBarButtonItemStylePlain target:nil action:nil];
[array addObject:item];
}
self.navigationItem.leftBarButtonItems = array;
self.navigationItem.rightBarButtonItems = array;
其实,这在开发文档中已经说的很清楚了,拿leftBarButtonItems
来说:
This array can contain 0 or more bar items to display on the left side of the navigation bar. Items can include fixed-width and flexible-width spaces. If the leftItemsSupplementBackButton property is YES, the items are displayed to the right of the back button, otherwise the items replace the back button and start at the left edge of the bar. Items are displayed left-to-right in the same order as they appear in the array.
If there is not enough room to display all of the items in the array, those that would overlap the title view (if present) or the buttons on the right side of the bar are not displayed.
The first item in the array can also be set using the leftBarButtonItem property.
前面说过,用代码的时候,当你首次访问视图控制器中的navigation item的时候,它会自动创建,在storyboard中是怎样的呢?
答案是,你需要给导航栏中的scene添加navigation item,如图:


storyboard中怎样配置
leftBarButtonItems
和rightBarButtonItems
两个属性?我发现storyboard只支持左右各一个bar button item,当你拖拽一个新的bar button item到导航栏视图给它增加一个时,它只会替换,可能,如果想多个,还得用代码来实现。如图:
storyboard只支持左右各一个
3、UIBarButtonItem VS UIButton
其实对于这两个,我没有深入总结。


通过这两个图,我们知道这两个家伙没什么血缘关系,有点像生物界的趋同进化,比如小熊猫和浣熊

(例子不太恰当,其实这俩动物区别挺大的……)。
我尝试过用UIButton当UIBarButtonItem使用(通过storyboard将UIButton拖拽到导航栏上,并写了响应事件),button倒是能显示出来,只是点击没反应。这倒不出乎意料,如果能当UIBarButtonItem使用,才应该出乎意料,毕竟它们除了长的样子和交互方式类似,其他并不同。
其实,我们知道UIBarButtonItem是专门给UIToolBar和UINavigationBar定制的类似button的类就好了。将来有更深的体会,我会及时更新。
4、UIToolBar VS UITabBar
这个也没什么较深的体会,先占个位置……
这里之所以提一句,是因为导航控制器带有一个toolBar的属性,在storyboard中,如果你没有给scene添加navigation item,就往scene上拖拽bar button item,它是不会落到导航栏上,而是落到toolBar上,toolBar默认是隐藏的,但在scene上它是显示出来的。
接下来,挂羊头卖狗肉,在这里结合UIToolBar,讲一个UIBarButtonItem的用法——为相邻bar button item添加间隔,通过观察,这个只在UIToolBar中有效果(在storyboard中使用的话,只能给UIToolBar添加,storyboard的对象库,也说明这是为UIToolBar准备的)

。




5、导航栏一般用法集锦
对于导航栏的操作有两种方法:
- [UINavigationBar appearance]类方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[UINavigationBar appearance].tintColor = [UIColor orangeColor];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"m_nav64"] forBarMetrics:UIBarMetricsDefault];
return YES;
}

这显然是因为UINavigationBar遵从了UIAppearance
协议的缘故。这个方法在AppDelegate中有效,在特定的视图控制器中是无效的。它应该是对所有导航栏生效的。
- self.navigationController.navigationBar 实例方法
- (void)viewDidLoad
{
self.navigationItem.title = @"刘大帅";
self.navigationController.navigationBar.tintColor = [UIColor orangeColor];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"m_nav"] forBarMetrics:UIBarMetricsDefault];
self.navigationController.toolbarHidden = NO;
}

这种用法只对该视图控制器的导航栏有效果,由于viewDidLoad:在application: didFinishLaunchingWithOptions:之后执行,所以它会覆盖上一种方法带来的效果。假设这样一种场景,用UITabBarController作为最外层视图控制器容器,每一个tab都有自己的一个导航栈。我们可以用第一种方法做整体效果的设计,用第二种方法作特定tab中的导航栏的设计。
注意:两个效果之所以有区别,是因为我用了不同的图片,以示区别。
下面我们以第二种方法为例来介绍导航栏的一般用法
- (void)viewDidLoad
{
//默认背景色上传到简书不理想,所以换一种背景色
self.view.backgroundColor = [UIColor orangeColor];
//*****************navigationItem*********************************
//navigationItem控制导航栏标题(title)、promt、标题视图(titleView)、以及按钮(barButtonItem)的添加和数量
self.navigationItem.title = @"刘大帅";
//我表示我不喜欢promt...
// self.navigationItem.prompt = @"promt";
//修改导航栏标题为图片
self.navigationItem.titleView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"m_hot60"]];
//添加多个按钮
UIBarButtonItem* item1 = [[UIBarButtonItem alloc]initWithTitle:@"item1" style:UIBarButtonItemStylePlain target:nil action:nil];
UIBarButtonItem* item2 = [[UIBarButtonItem alloc]initWithTitle:@"item2" style:UIBarButtonItemStylePlain target:nil action:nil];
NSArray* array = @[item1,item2];
self.navigationItem.leftBarButtonItems = array;
self.navigationItem.rightBarButtonItems = array;
//*****************navigationBar**********************************
//navigationBar控制导航栏背景色(barTintColor)、背景图片(backgroundImage)、按钮字体颜色(tintColor),标题文本属性(titleTextAttributes)
//调整导航栏背景色
self.navigationController.navigationBar.barTintColor = [UIColor orangeColor];
//半透明开关
self.navigationController.navigationBar.translucent = NO;
//为导航栏添加背景图片,图片如果是44高,那么不覆盖状态栏,如果是64高就会覆盖状态栏
//UIBarMetricsDefault 缺省值 UIBarMetricsCompact 横屏样式 UIBarMetricsDefaultPrompt和UIBarMetricsCompactPrompt是有promt的两种样式
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"m_nav64"] forBarMetrics:UIBarMetricsDefault];
//
self.navigationController.navigationBar.tintColor = [UIColor purpleColor];
//定制返回按钮,这两个要一起用,为啥这么用,苹果言语不详
self.navigationController.navigationBar.backIndicatorImage = [UIImage imageNamed:@"m_ios"];
self.navigationController.navigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"m_ios"];
//修改导航栏标题的字体
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
shadow.shadowOffset = CGSizeMake(0, 1);
//字典中放入你想修改的键值对,原来的UITextAttributeFont、UITextAttributeTextColor、UITextAttributeTextShadowColor、UITextAttributeTextShadowOffset已弃用
self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName:[UIColor colorWithRed:245.0/255.0 green:245.0/255.0 blue:245.0/255.0 alpha:1.0],
NSShadowAttributeName:shadow,
NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-CondensedBlack" size:21.0]
};
//导航栏toolBar隐藏开关
self.navigationController.toolbarHidden = NO;
}



原文链接:http://www.jianshu.com/p/f797793d683f
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
【转】【iOS】导航栏那些事儿的更多相关文章
- IOS 导航栏属性设置
IOS 7 以上系统导航栏: [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]]; // 返回按钮颜色 [UINaviga ...
- 【Swift】iOS导航栏错乱的原因
#iOS开发高级技巧#导航栏错乱,也就是导航栏的显示效果与内容区不匹配,引发原因很多,其中最重要的有两个原因: 1.在viewwillappear,viewwilldisappear两个函数中,设置导 ...
- 转:ios导航栏设置
原帖:http://www.cocoachina.com/industry/20131104/7287.html 本文提供的代码需要用Xcode 5来执行.如果你还在使用老版本的Xcode,那么在运行 ...
- iOS导航栏背景,标题和返回按钮文字颜色
在iOS7下,默认导航栏背景,颜色是这样的,接下来我们就进行自定义,如果你仅仅是更改一下背景和颜色,代码会很简单,不需要很复杂的自定义View来替代leftBarItem 更改导航栏的背景和文字Col ...
- iOS 导航栏黑线,UIImage 枚举处理方式
ios 找出导航栏下面的黑线(可隐藏,改变样式等) http://www.jianshu.com/p/effa4a48f1e3 设置UIImage的渲染模式:UIImage.renderi ...
- ios 导航栏的显示和隐藏切换
从简单的一个没有导航栏的界面A push到另一个有导航栏的界面 B,在界面A的逻辑中加入下面逻辑: 屏幕快照 2016-03-30 上午10.35.24.png 这样完美的处理了这个场景变换需求.引起 ...
- iOS导航栏的正确隐藏方式【转】
简介:在项目中经常碰到首页顶部是无限轮播,需要靠最上面显示.有的设置导航栏为透明等一系列的方法,这个可以借助第三方.或者干脆简单粗暴的直接隐藏掉导航栏.可是push到下一个页面的时候是需要导航栏的,如 ...
- IOS导航栏颜色渐变与常用属性
(转:http://www.cnblogs.com/Lingchen-start/archive/2015/10/23/4904361.html) 今年很忙,忙的写日志的时间都很少. 少的可怜. 自 ...
- iOS 导航栏实现总结
目标: 在UI界面中实现 整体效果的导航栏, 比如1 首页无导航条,次页有导航条, 2 导航条中不包含下方不包含黑边 3 导航条包含多个筛选项 等等 问题: 用系统带的NavigateBar 来实现时 ...
随机推荐
- JS和JSP的区别
最近很多同学在纠结于名词缩写之间的相似性,因此本人也来写一篇,讲讲JS和JSP的区别. SUN首先发展出SERVLET,其功能比较强劲,体系设计也很先进,只是,它输出HTML语句还是采用了老的CGI方 ...
- 关于Simple.Data.PostgreSql的ExecuteReader没实现非常坑爹的问题
https://github.com/ChrisMH/Simple.Data.PostgreSql/issues/3 github上有个issues...默认从nuget上下载的Simple.Data ...
- ORA-19809: 超出了恢复文件数的限制
实验环境:Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod 实验背景:向tough.t中插入40万条记录,然后rollb ...
- php源代码安装常见错误与解决办法分享
错误:configure: error: libevent >= 1.4.11 could not be found 解决:yum -y install libevent libevent-de ...
- Truncating HTML attribute value in SharePoint DataFormWebPart
<xsl:value-ofdisable-output-escaping="yes"select="@Body"/>
- ParentChildTest.java
public class ParentChildTest { public static void main(String[] args) { Parent parent=new Parent(); ...
- 一个好用且方便的FastCgi C++库 - FastCgi++
不知道你是不是曾经发愁过使用FastCgi库来使用C++开发Fastcgi程序繁琐而且会与C++ STL代码产生冲突的地方,或者你还是习惯了cout而不是pringf,那这篇文章就可以了解到一个使用的 ...
- React Native Android配置部署踩坑日记
万事开头难 作为一只进入ECMAScript世界不久的菜鸟,已经被React Native的名气惊到了,开源一周数万星勾起了我浓烈的兴趣.新年新气象,来个HellWorld压压惊吧^_^(故意少打个' ...
- no appropriate service handler found The Connection descriptor used by the client was: localhost:1521:myorcl
参考网址:http://www.2cto.com/database/201205/133542.html http://www.cnblogs.com/kerrycode/p/4244493.html ...
- What the hell is Rotate?