iOS 自定义导航栏笔记

一、UINavigationBar的结构

导航栏几乎是每个页面都会碰到的问题,一般两种处理方式:1.隐藏掉不显示 2.自定义

1. 添加导航栏

TestViewController * mainVC = [[TestViewController alloc] init];
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:mainVC];
    self.window.rootViewController = nav;

2. 隐藏导航栏

在的TestViewController.m文件中,使用以下代码:

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.navigationController setNavigationBarHidden:YES];
    //self.navigationController.navigationBar.hidden = YES;
}

说明:通过属性直接设置之所以能成功,是因为虽然navigationBar是readonly,但是hidden是默认的(readwrite)。建议使用第一个,通过发送消息来设置。

3. 修改导航栏背景色

由于系统自带的导航栏已经不能满足用户的审美需求,因此开发中导航栏或多或少都被自定义了;即便只是修改了背景色或是字体颜色。

  • 方式一:通过代理来设置

    [[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];

    效果图

说明:为什么能修改所有导航栏的背景色?

  1. 查看UINavigationBar发送的消息appearance,是一个名为UIAppearance协议。根据官网解释:UIAppearance是一个外观协议(装饰模式)。要想改变外观需要实现此协议,因此UINavigationBar内部肯定实现了此协议。
  2. 查看头文件UIAppearance协议里面有4个方法,但是根据官网文档,iOS9以后有两个方法被废弃。因此只有下面两个可用,都返回的是类的对象,因此可以给此类发送修改外观的消息.比如:setBarTintColor。其实这里拿到对象后可以任意修改。
+ (instancetype)appearance;
+ (instancetype)appearanceForTraitCollection:(UITraitCollection *)trait
  • 方式二、直接通过属性设置,或发送消息来设置

在的TestViewController.m文件中,使用以下代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    // 无效果
    self.navigationController.navigationBar.backgroundColor = [UIColor redColor];
    // 可行
    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav.png"] forBarMetrics:UIBarMetricsDefault];
}

说明:

  1. 下面代码为什么无效果,其实看一下结构图就明白了。
self.navigationController.navigationBar.backgroundColor = [UIColor redColor];

UINavgationBar结构图

没错:这样修改的是navigationBar的背景色,而navigationBar里面添加了UIView和UIImageView,UILabel等控件,覆盖了navigationBar。

  1. 那么如何来修改?
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"yao_1"] forBarMetrics:UIBarMetricsDefault];

通过添加背景图,使用默认的模式。
注意:这里会出现状态栏背景色也变化的问题,其实这是由于在navigationBar添加的控件自动延伸到边界造成的。如果只是修改导航栏的背景色,完全没必要再给navigationBar添加控件了,给navigationBar堆太多的无用控件,不能忍。

// 设置透明
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"yao_1"] forBarMetrics:UIBarMetricsCompact];
// 修改navigationBar的背景色
self.navigationController.navigationBar.backgroundColor = [UIColor redColor];

这样修改navigationBar背景色,才有种很舒畅的感觉,有木有。因为我就只是要修改navigationBar的背景色而已么。效果图:

UINavgationBar效果图

为什么要这样

[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];

或者为什么要这样

[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"yao_1"] forBarMetrics:UIBarMetricsDefault];

UINavigationBar和UINavigationController、UIViewController关系

1.导航栏类名:UINavigationBar,是导航控制器(UINavgationController)下得一个属性,一般给一个视图控制器(TestViewController)添加导航栏,也就是把它添加为导航控制器(UINavgationController)的根视图控制器。

2.在此视图控制器中为什么可以直接操作导航控制器,因为TestViewController类是自定义的继承自UIViewController类的。而UIViewController类中有一个类别,声明了UINavgationController类的一个属性。在第一步的时候,把这个属性设置为上面导航控制器的对象。

UIController分类

3.UINavigationBar对照图如下:

UINavigationBar对照图

UINavgationBar结构图说明:

  • 从图中的对照关系可以看到,UINavigationBar包含一个:UINavigationBarBackground控件(已经延伸到边界,覆盖掉了导航栏),另一个UINavigationBarBackIndicatorView(其实就是那个蓝色的返回按钮,当push进来一个ViewController才会显示)
  • UINavigationBarBackground控件里面包含:UIBackdropView(UIBackdropEffectView标识阴影视图),UIImageView

总结:

可以看到,UINavigationBarBackIndicatorView(返回按钮只占了左边一部分区域,并且在push新的视图控制器时才显示。因此,显示在最上面的是UIImageView)。所以,这才是通过代码

self.navigationController.navigationBar.backgroundColor = [UIColor redColor];

*修改背景色,老是被遮住的根本原因。解决方法,因此掉UIImageView控件,或者干脆给UIImageView设置一张你想要的背景色的图片。*

二、UINavigationBar的自定义

1. 自定义

一般自定义分三种情况:左侧、右侧和中间视图

  • 自定义左侧按钮
- (void)viewDidLoad {
    [super viewDidLoad];
    // 自定义导航栏左侧按钮
    UIButton * leftBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    leftBtn.frame = CGRectMake(0, 7, 83, 30);
    leftBtn.backgroundColor = [UIColor orangeColor];
    [leftBtn addTarget:self action:@selector(onTap) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem * leftItem = [[UIBarButtonItem alloc] initWithCustomView:leftBtn];
    self.navigationItem.leftBarButtonItem = leftItem;
}

// 点击事件处理
- (void)onTap {
    NSLog(@"点击了导航栏左侧按钮");
}
  • 自定义右侧按钮

    和自定义左侧按钮方法类似,差别如下:

    self.navigationItem.rightBarButtonItem = rightItem;
  • 自定义中间视图
    UIView * centerView = [[UIView alloc] initWithFrame:CGRectMake(0, 7, 110, 30)];
    centerView.backgroundColor = [UIColor greenColor];
    self.navigationItem.titleView = centerView;

    2. 结构分析

从自定义的代码看到,自定义都是在修改navigationItem里面的东西。查看头文件可知,TestViewController之所以可以操作navigationItem,和上面UINavigationController实现方式一样。

UINavigationBar类中有一个items集合,存储navigationItem和其他相关内容。UINavigationItem类里面存储leftBarButtonItems、rightBarButtonItems等集合。同时也会有leftBarButtonItem、rightBarButtonItem控件,根据集合是否为空来决定是否创建和显示这些控件。

因此,当不设置内容时,默认集合为空,所有控件也就不显示。

3. 手写代码技巧

对于导航栏的自定义,大部分app都是左侧为"返回",右侧为"地图",“扫码”等按钮,中间除显示标题外,可能会自定义个分段按钮,选择菜单等。而对于这些自定义的按钮和视图,尺寸都是根据图片尺寸和导航栏的宽高凭感觉设置的(总之,我以前是这样>.<)。
今天在测试iOS7的布局使用了SB,发现控件拖上去它会自适应系统给定的尺寸。然后我绑定控件获取了这些控件的尺寸。测试了iPhone4s和iPhone6,获取到的左侧和右侧按钮尺寸:frame = {0,7,83,30},中间的视图尺寸:frame = {0,7,110,30}。
这样,以后导航栏按钮没有什么特殊要求,就可以都按这个尺寸设置了。

原文链接:http://www.jianshu.com/p/b7818eba288c

时间: 2024-12-26 16:29:31

iOS 自定义导航栏笔记的相关文章

IOS 自定义导航栏标题和返回按钮标题

IOS中自定义导航栏标题: UILabel *titleText = [[UILabel alloc] initWithFrame: CGRectMake(160, 0, 120, 50)]; titleText.backgroundColor = [UIColor clearColor]; titleText.textColor=[UIColor whiteColor]; [titleText setFont:[UIFont systemFontOfSize:17.0]]; [titleTex

ios 自定义导航栏和分割线

自定义导航栏: // CustomNaviBarView.h #import <UIKit/UIKit.h> @interface CustomNaviBarView : UIView { @private /** * 左侧按钮 */ UIButton* _leftButton; /** * 右侧按钮 */ UIButton* _rightButton; /** * 中部标签 */ UILabel* _navTitle; } @property(nonatomic,strong)UIButto

ios 自定义导航栏,开启侧滑返回手势

自定义一个常用ListViewController .h文件 1 #import <UIKit/UIKit.h> 2 3 @interface ListViewController : UIViewController 4 5 -(void)diquButtonClick; 6 7 @end .m文件 1 // 2 // ListViewController.m 3 // OuLianWang 4 // 5 // Created by allenariel on 15/6/24. 6 // C

IOS 自定义导航栏

我们自己新建一个View,来自定义导航栏,如下代码: #import <UIKit/UIKit.h> @interface CustomNavigation : UIView typedef enum { customEventClickLBtn1 ,//点击了最左边的按钮 customEventClickRBtn1 , //最右边的按钮 customEventClickLBtn2 ,//点击了左边第二个按钮 customEventClickRBtn2 //点击了右边最靠左的按钮 }Custo

IOS 自定义导航栏背景

//- (void)setBackgroundImage:(UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; -(id)init { self=[super init]; if(self) { UINavigationBar *navBar=[self navigationBar]; if([navBar respondsTo

iOS 自定义导航栏的返回按钮

UIBarButtonItem * item  =    [UIBarButtonItem appearance]; UIImage* image = [UIImage imageNamed:@"back_icon"]; [item setBackButtonBackgroundImage:[image resizableImageWithCapInsets:UIEdgeInsetsMake(0, image.size.width, 0, 0)] forState:UIControlS

iOS 为导航栏自定义按钮图案Button Image 运行出来的颜色与原本颜色不一样 -解决方案

为相机制作闪光灯,在导航栏自定义了"闪光"图案,希望点击时变换图片,但是一直没有改变,原来是因为设置了Global Tint的颜色,所以系统会自动把图片的颜色改为Global Tint的颜色. 解决方案,设置图片时,添加:imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal 源码: - (void) setFlashOn:(BOOL)isOn { if (self.captureDevice.hasFlash) { UIIm

一些关于iOS系统导航栏与自定义导航栏的事情

关于系统导航栏是真的让人又爱又恨,爱的是苹果本身对这个控件的封装已经是很完美了,包括内存.美化.渐变动画等等,一般来说,基本上所有需求都可以满足的.但是你要知道什么东西到了中国,就会发生翻天覆地的变化,例如后台的数据并发.在国内奇葩的产品设计之下,导航栏也是面目全非,反正我看了比较著名的APP,发现他们的导航栏基本都是自定义,其中牵扯最大的问题就是导航栏自身的隐藏.颜色渐变. 其实通过APP运行时,你可以看到系统NavigationBar的分层.一个navigationBar是分很多层的,并非我

实际iOS编程中遇到的自定义导航栏按钮,导致手势返回失效的解决方法

1\在实际编程过程中往往需要自定义导航栏上面的按钮,也就用: - (instancetype)initWithCustomView:(UIView *)customView; 但用了这个方法后可能会导致iOS7,8的手势返回失效,解决方法就是在自定义的导航栏的viewDidLoad方法中添加如下代码 注意:只有用系统的导航栏,或者继承于系统的导航栏才可以用Push方法,并且自带返回手势. - (void)viewDidLoad { [super viewDidLoad]; __weak type