【转】【iOS】导航栏那些事儿

原文网址:http://www.jianshu.com/p/f797793d683f

参考文章

前言

本文试图阐释清楚导航栏相关的概念和用法,比如UINavigationBarUINavigationItem的区别和联系,UIBarButtonItem的用法以及在纯代码和storyboard中有什么不同。如果读者有类似的疑惑,不妨读一读本文。

本文撰写时,用的iOS8.3、Xcode6.3,因为没有仔细考证iOS各版特性的不同,可能导致出入,若读者遇到,还请指出,我及时改正。

1、UINavigationBar VS UINavigationItem

UINavigationBar继承图

文档说明:

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类提供一种对导航层级内容的控制。它是一个栏,最典型的用法就是放在屏幕顶端,包含着各级视图的导航按钮。它最首要的属性是左按钮(返回按钮)、中心标题,还有可选的右按钮。你可以单独用导航栏,或者和导航控制器一起使用。

UINavigationItem继承图

文档说明:

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 有leftBarButtonItemsrightBarButtonItems两个属性,每个属性都可以赋值一个装有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,如图:

没有添加navigation item 之前

添加navigation item 之后

  • storyboard中怎样配置leftBarButtonItemsrightBarButtonItems两个属性?

    我发现storyboard只支持左右各一个bar button item,当你拖拽一个新的bar button item到导航栏视图给它增加一个时,它只会替换,可能,如果想多个,还得用代码来实现。如图:

    storyboard只支持左右各一个

3、UIBarButtonItem VS UIButton

其实对于这两个,我没有深入总结。

UIBarButtonItem继承图

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准备的)

image

没有添加间隔

添加间隔

效果

代码用法

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;

}

效果2

这种用法只对该视图控制器的导航栏有效果,由于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;

}

相关效果图1

相关效果图2

相关效果图3

文/刘大帅(简书作者)
原文链接:http://www.jianshu.com/p/f797793d683f
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

时间: 2024-12-24 04:41:39

【转】【iOS】导航栏那些事儿的相关文章

iOS 导航栏的属性设置

iOS中设置导航栏背景.字体属性 --------------------------------------------------- 1.自定义导航控制器作为基类,在 + (void)initialize 方法中设置偏好设置,不要在 + (void)load 方法中设置 + (void)initialize { // 设置 两侧按钮 的颜色tintColor(标题除外) [[UINavigationBar appearance] setTintColor:FGCOLOR]; // FGCOL

iOS 导航栏黑线,UIImage 枚举处理方式

ios 找出导航栏下面的黑线(可隐藏,改变样式等) http://www.jianshu.com/p/effa4a48f1e3 设置UIImage的渲染模式:UIImage.renderingMode http://blog.csdn.net/djxiaoyu_haha/article/details/40949083 着色(Tint Color)是iOS7界面中的一个.设置UIImage的渲染模式:UIImage.renderingMode重大改变,你可以设置一个UIImage在渲染时是否使用

自定义iOS导航栏背景,标题和返回按钮文字颜色-----转载自gyz413977349

在iOS7下,默认导航栏背景,颜色是这样的,接下来我们就进行自定义,如果你仅仅是更改一下背景和颜色,代码会很简单,不需要很复杂的自定义View来替代leftBarItem 更改导航栏的背景和文字Color 方法一: [objc] view plaincopy //set NavigationBar 背景颜色&title 颜色 [self.navigationController.navigationBar setBarTintColor:[UIColor colorWithRed:20/255.

iOS 导航栏

最近项目里有个需求和导航栏的样式定制有关,深入之后发现之前理解的一些概念有些模糊,刚好趁着这次机会全面整理了一下. 从 iOS7 开始,苹果采用了大量的扁平化和毛玻璃风格,刚升级到 iOS7 之后会发现界面的布局多多少少有一些偏差(当然现在新建的项目没有这方面困扰,不需要经历6到7的适配),适配过程中会发现如下一些属性, - edgesForExtendedLayout - translucent - extendedLayoutIncludesOpaqueBars - automaticall

转:ios导航栏设置

原帖:http://www.cocoachina.com/industry/20131104/7287.html 本文提供的代码需要用Xcode 5来执行.如果你还在使用老版本的Xcode,那么在运行示例之前请将Xcode升级到Xcode 5. iOS 7中默认的导航栏 在开始定制之前,我们先来看看iOS 7中默认导航栏的外观.通过Xcode用Single View Controller模板创建一个工程.然后将view controller嵌入到一个navigation controller中.

&lt;iOS 导航栏&gt;第一节:导航栏透明方法实现代码

说下导航栏的透明方法: 很多应用需要导航栏随着向上滑动,逐渐从透明变成不透明,很炫酷,大部分应用都在使用导航栏渐变效果,现附上代码然后直接将实现,一会讲下如何来实现,这一部分直接上代码. 先附上代码: 方法声明: #import <UIKit/UIKit.h> @interface IDSNavBarView : UIView - (instancetype)initWithFrame:(CGRect)frame titleImg:(UIImage *)aTitleImg; - (UILabe

ios 导航栏 点击barbutton的按钮 下拉列表

环境:xocde5.0.2+ios7.0.1 1.导航栏 ----点击科目--------下拉列表 代码:NGRightTableViewViewController.h #import <UIKit/UIKit.h> @protocol PulldownMenuDelegate -(void)menuItemSelected:(NSIndexPath *)indexPath; -(void)pullDownAnimated:(BOOL)open; @end @interface NGRigh

ios 导航栏(自己定义和使用系统方式)

系统方式: //1.设置导航栏背景图片 [self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault]; self.navigationController.navigationBar.shadowImage = [[UIImage alloc]init]; [[self navigationController] setNa

IOS 导航栏颜色 标题

修改导航栏颜 1 #define COLOR_TOMATO    [UIColor colorWithRed:255/255.0f green:99/255.0f blue:71/255.0f alpha:1.0f]     /*!< 番茄色 */ 2 3 self.navigationController.navigationBar.barTintColor = COLOR_TOMATO;//修改导航栏颜色 修改导航栏标题字体(大小.颜色) 1 self.navigationControlle