IOS-UINavigationController详解

(一)UINavigationController及其相关控件之间的关系

@interface UINavigationController : UIViewController
@property(nonatomic,readonly) UINavigationBar *navigationBar;

@interface UIViewController (UINavigationControllerItem)
@property(nonatomic,readonly,strong) UINavigationItem *navigationItem;

@interface UINavigationBar : UIView
@property(nullable, nonatomic,readonly,strong) UINavigationItem *topItem;
@property(nullable, nonatomic,readonly,strong) UINavigationItem *backItem;
@property(nullable,nonatomic,copy) NSArray<UINavigationItem *> *items;

@interface UINavigationItem : NSObject
@property(nullable,nonatomic,strong) UIBarButtonItem *backBarButtonItem
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *leftBarButtonItems;
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *rightBarButtonItems;
@property(nullable, nonatomic,strong) UIBarButtonItem *leftBarButtonItem;
@property(nullable, nonatomic,strong) UIBarButtonItem *rightBarButtonItem;

@interface UIBarButtonItem : UIBarItem
@property(nullable, nonatomic)         SEL                  action; 

@interface UIBarItem : NSObject
@property(nullable, nonatomic,copy)             NSString    *title;
@property(nullable, nonatomic,strong)           UIImage     *image;

通过对上述几个类的属性的罗列,我们可以做个总结

基本介绍
  • UIBarItem
    一个可以放置在Bar之上的所有小控件类的抽象类,可以设置标题,图片等
  • UIBarButtonItem
    继承UIBarItem,增加了动作以及目标等button的属性。相当于放在UIToolBar或者UINavigationBar上的特殊的button。
  • UINavigationItem
    包含了title,prompt,titleView,leftBarButtonItem,rightBarButtonItem,backBarButonItem等当前页面上所有的信息
  • UINavigationBar
    NavigaitonBar就是导航栏 主要对UINavigationItem进行栈管理 展示导航栏的外观背景
  • UINavigationController
    包含了viewcontrollers、navigationbar、toolbar
关系综述
  • UINavigationController是一个容器类,对ViewController进行栈管理,包含navigationBar。
  • UINavigationBar 即UINavigationController顶部的导航栏,主要负责外观背景的展示,并对navigationItem进行栈管理
  • UINavigationItem是导航栏上显示的具体的元素的一个抽象类,UINavigationController 通过Category的方法为ViewController添加了一个navigationItem,把UINavigationItem交由ViewController管理

// Created on-demand so that a view controller may customize its navigation appearance.

这里引用叶落寒的一段介绍,更加的通俗易懂

通俗地说就是,UINavigationController是个容器,里面可以装很多UIViewController。装这么多UIViewController让用户怎么控制它们呢?总得有个工具吧,这个工具就是UINavigationBar。一个容器就这么一个bar,相当于控制台吧。但是管理那么多UIViewController,控制台上得按钮啊、标题啊,都千篇一律是不是看起来太无聊了。为了解决这个问题,UINavigationController为每个UIViewController生成一个UINavigationItem,通过这个UINavigationItem可以改变控制台“上面”的按钮和标题。如果你不自定义UINavigationItem,UINavigationController会使用默认的;

(二)UINavigationController及其相关控件的属性和方法

1. UIBarButtonItem

//初始化方法
- (instancetype)init;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;
- (instancetype)initWithImage:(nullable UIImage *)image landscapeImagePhone:(nullable     UIImage *)landscapeImagePhone style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;
- (instancetype)initWithTitle:(nullable NSString *)title style:(UIBarButtonItemStyle)style target:(nullable id)target action:(nullable SEL)action;
- (instancetype)initWithBarButtonSystemItem:(UIBarButtonSystemItem)systemItem target:(nullable id)target action:(nullable SEL)action;
- (instancetype)initWithCustomView:(UIView *)customView;

@property(nonatomic)         UIBarButtonItemStyle style;  //类型
@property(nonatomic)         CGFloat              width;
@property(nullable, nonatomic,copy)    NSSet<NSString *>   *possibleTitles;
@property(nullable, nonatomic,strong)  __kindof UIView     *customView;
@property(nullable, nonatomic)         SEL                  action;
@property(nullable, nonatomic,weak)    id                   target;
@property(nullable, nonatomic,strong) UIColor *tintColor

//为任意style的button设置背景图片
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics
- (nullable UIImage *)backgroundImageForState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics

//为特定style的button设置背景图片
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forState:(UIControlState)state style:(UIBarButtonItemStyle)style barMetrics:(UIBarMetrics)barMetrics
- (nullable UIImage *)backgroundImageForState:(UIControlState)state style:(UIBarButtonItemStyle)style barMetrics:(UIBarMetrics)barMetrics


//设置背景图片垂直方向的偏移量
- (void)setBackgroundVerticalPositionAdjustment:(CGFloat)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (CGFloat)backgroundVerticalPositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics

//设置标题的偏移量
- (void)setTitlePositionAdjustment:(UIOffset)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (nullable UIImage *)backButtonBackgroundImageForState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics

//设置返回按钮标题偏移量
- (void)setBackButtonTitlePositionAdjustment:(UIOffset)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (UIOffset)backButtonTitlePositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics

//设置返回按钮背景图片在垂直方向上的偏移量
- (void)setBackButtonBackgroundVerticalPositionAdjustment:(CGFloat)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (CGFloat)backButtonBackgroundVerticalPositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics
typedef NS_ENUM(NSInteger, UIBarButtonSystemItem) {
    UIBarButtonSystemItemDone,//显示完成
    UIBarButtonSystemItemCancel,//显示取消
    UIBarButtonSystemItemEdit,  //显示编辑
    UIBarButtonSystemItemSave, //显示保存 
    UIBarButtonSystemItemAdd,//显示加号
    UIBarButtonSystemItemFlexibleSpace,//什么都不显示,占位一个空间位置
    UIBarButtonSystemItemFixedSpace,//和上一个类似
    UIBarButtonSystemItemCompose,//显示写入按钮
    UIBarButtonSystemItemReply,//显示循环按钮
    UIBarButtonSystemItemAction,//显示活动按钮
    UIBarButtonSystemItemOrganize,//显示组合按钮
    UIBarButtonSystemItemBookmarks,//显示图书按钮
    UIBarButtonSystemItemSearch,//显示查找按钮
    UIBarButtonSystemItemRefresh,//显示刷新按钮
    UIBarButtonSystemItemStop,//显示停止按钮
    UIBarButtonSystemItemCamera,//显示相机按钮
    UIBarButtonSystemItemTrash,//显示移除按钮
    UIBarButtonSystemItemPlay,//显示播放按钮
    UIBarButtonSystemItemPause,//显示暂停按钮
    UIBarButtonSystemItemRewind,//显示退后按钮
    UIBarButtonSystemItemFastForward,//显示前进按钮
    UIBarButtonSystemItemUndo,//显示消除按钮
    UIBarButtonSystemItemRedo ,//显示重做按钮
    UIBarButtonSystemItemPageCurl ,//在tool上有效
};

2.UINavigationItem

NS_CLASS_AVAILABLE_IOS(2_0) @interface UINavigationItem : NSObject <NSCoding>
//初始化
- (instancetype)initWithTitle:(NSString *)title NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

//设置导航栏中间的内容标题
@property(nullable, nonatomic,copy)   NSString        *title;         
//设置导航栏中间的内容视图    
@property(nullable, nonatomic,strong) UIView          *titleView;        
//提示
@property(nullable,nonatomic,copy)   NSString *prompt;      
//返回
@property(nullable,nonatomic,strong) UIBarButtonItem *backBarButtonItem; 
//是否隐藏返回Button
@property(nonatomic,assign) BOOL hidesBackButton;
- (void)setHidesBackButton:(BOOL)hidesBackButton animated:(BOOL)animated;

//左边数组Item
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *leftBarButtonItems NS_AVAILABLE_IOS(5_0);
//右边数组Item
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *rightBarButtonItems NS_AVAILABLE_IOS(5_0);
- (void)setLeftBarButtonItems:(nullable NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated NS_AVAILABLE_IOS(5_0);
- (void)setRightBarButtonItems:(nullable NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated NS_AVAILABLE_IOS(5_0);

//通过指定该属性为YES,可以让leftBarButtonItem和backBarButtonItem同时显示,其中leftBarButtonItem显示在backBarButtonItem的右边 默认值为NO
@property(nonatomic) BOOL leftItemsSupplementBackButton NS_AVAILABLE_IOS(5_0);

//左边Item
@property(nullable, nonatomic,strong) UIBarButtonItem *leftBarButtonItem;
//右边Item
@property(nullable, nonatomic,strong) UIBarButtonItem *rightBarButtonItem;
- (void)setLeftBarButtonItem:(nullable UIBarButtonItem *)item animated:(BOOL)animated;
- (void)setRightBarButtonItem:(nullable UIBarButtonItem *)item animated:(BOOL)animated;
@end

prompt 是一个NSString类型描述,注意添加该描述以后NavigationBar的高度会增加30,总的高度会变成74(不管当前方向是Portrait还是Landscape,此模式下navgationbar都使用高度44加上prompt30的方式进行显示)。

如:

self.navigationItem.prompt=@"这是什么?";
self.title=@"HAH";
prompt.png

3.UINavigationBar

NS_CLASS_AVAILABLE_IOS(2_0) @interface UINavigationBar : UIView <NSCoding, UIBarPositioning> 

//UIBarStyleDefault  灰色背景 白色文字 UIBarStyleBlack    纯黑色背景 白色文字
@property(nonatomic,assign) UIBarStyle barStyle;
@property(nullable,nonatomic,weak) id<UINavigationBarDelegate> delegate;
//Translucent设置成透明度,设置成YES会有一种模糊效果
@property(nonatomic,assign,getter=isTranslucent) BOOL translucent NS_AVAILABLE_IOS(3_0) UI_APPEARANCE_SELECTOR; 
//UINavigationBar上面不只是简单的显示标题,它也将标题进行了堆栈的管理,每一个标题抽象为的对象在iOS系统中是UINavigationItem对象,我们可以通过push与pop操作管理item组。
//向栈中添加一个item,上一个item会被推向导航栏的左侧,变为pop按钮,会有一个动画效果
- (void)pushNavigationItem:(UINavigationItem *)item animated:(BOOL)animated;
//pop一个item
- (nullable UINavigationItem *)popNavigationItemAnimated:(BOOL)animated; 
//当前push到最上层的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *topItem;
//仅次于最上层的item,一般式被推向导航栏左侧的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *backItem;
//获取堆栈中所有item的数组
@property(nullable,nonatomic,copy) NSArray<UINavigationItem *> *items;
//设置一组item
- (void)setItems:(nullable NSArray<UINavigationItem *> *)items animated:(BOOL)animated; 

//系统类型按钮文字颜色
@property(null_resettable, nonatomic,strong) UIColor *tintColor;

//通过barTintColor来设置背景色
@property(nullable, nonatomic,strong) UIColor *barTintColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;  

//设置工具栏背景和阴影图案
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarPosition:(UIBarPosition)barPosition barMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;
- (nullable UIImage *)backgroundImageForBarPosition:(UIBarPosition)barPosition barMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;

//通过背景图片来设置导航栏的外观
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
- (nullable UIImage *)backgroundImageForBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;

//背景阴影图片 - 即分割线
@property(nullable, nonatomic,strong) UIImage *shadowImage NS_AVAILABLE_IOS(6_0) UI_APPEARANCE_SELECTOR;

//标题的富文本
@property(nullable,nonatomic,copy) NSDictionary<NSString *,id> *titleTextAttributes NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;

//标题垂直偏移
- (void)setTitleVerticalPositionAdjustment:(CGFloat)adjustment forBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
- (CGFloat)titleVerticalPositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;

//设置返回按钮的图片
@property(nullable,nonatomic,strong) UIImage *backIndicatorImage NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;
@property(nullable,nonatomic,strong) UIImage *backIndicatorTransitionMaskImage NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;
@end

4.UINavigationController

NS_CLASS_AVAILABLE_IOS(2_0) @interface UINavigationController : UIViewController

//UINavigationController初始化,自定义NavigationBar,自定义toolbar
- (instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass NS_AVAILABLE_IOS(5_0);

//UINavigationController初始化,导航控制器的根控制器
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;

//压栈:将目标控制器压入栈中
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; 

//弹栈:将栈顶控制器从栈中弹出
- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;

//弹栈:弹到指定的目标控制器
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated; 

//弹栈:弹到根控制器
- (nullable NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated;
//导航栈的栈顶视图 只读 就是某个导航栈的栈顶视图,和导航息息相关
@property(nullable, nonatomic,readonly,strong) UIViewController *topViewController; 
//当前显示的控制器 只读 visibleViewController和哪个导航栈没有关系,只是当前显示的控制器,也就是说任意一个导航的visibleViewController所返回的值应该是一样的
@property(nullable, nonatomic,readonly,strong) UIViewController *visibleViewController;

//栈里的视图控制器数组
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;

//替换栈中的视图控制器数组
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated NS_AVAILABLE_IOS(3_0); 

//是否隐藏导航栏
@property(nonatomic,getter=isNavigationBarHidden) BOOL navigationBarHidden;

//设置导航栏隐藏 是否有动画
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated; 

//导航栏
@property(nonatomic,readonly) UINavigationBar *navigationBar; 

//toolbar是否隐藏
@property(nonatomic,getter=isToolbarHidden) BOOL toolbarHidden NS_AVAILABLE_IOS(3_0);

//toolbar是否隐藏 是否有动画
- (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated NS_AVAILABLE_IOS(3_0); 

//toolbar对象
@property(null_resettable,nonatomic,readonly) UIToolbar *toolbar NS_AVAILABLE_IOS(3_0); 

//委托
@property(nullable, nonatomic, weak) id<UINavigationControllerDelegate> delegate;

//边缘侧滑返回手势
@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer NS_AVAILABLE_IOS(7_0);

//展示视图控制器
- (void)showViewController:(UIViewController *)vc sender:(nullable id)sender NS_AVAILABLE_IOS(8_0); // Interpreted as pushViewController:animated:

//输入键盘出现时将导航栏隐藏 IOS8特性
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenKeyboardAppears NS_AVAILABLE_IOS(8_0);

//滚动页面时隐藏Bar  IOS8特性
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnSwipe NS_AVAILABLE_IOS(8_0);

//获取能够隐藏navigationBar的滑动手势 只读
@property (nonatomic, readonly, strong) UIPanGestureRecognizer *barHideOnSwipeGestureRecognizer NS_AVAILABLE_IOS(8_0);

//当设置为true时,横向方向时隐藏NavigationBar
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenVerticallyCompact NS_AVAILABLE_IOS(8_0);

//当设置为true时,如果有没处理的点击手势就会隐藏和现实navigationBar 
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnTap NS_AVAILABLE_IOS(8_0);

//获取能够隐藏navigationBar的点击手势 只读
@property (nonatomic, readonly, assign) UITapGestureRecognizer *barHideOnTapGestureRecognizer NS_AVAILABLE_IOS(8_0);

@end
@interface UIViewController (UINavigationControllerItem)
//导航栏上面用户自定义视图
@property(nonatomic,readonly,strong) UINavigationItem *navigationItem; 
//推送时隐藏bottom
@property(nonatomic) BOOL hidesBottomBarWhenPushed;
//下级视图的导航控制器
@property(nullable, nonatomic,readonly,strong) UINavigationController *navigationController; 
@end
@interface UIViewController (UINavigationControllerContextualToolbarItems)
//属性设置工具条中包含的按钮
@property (nullable, nonatomic, strong) NSArray<__kindof UIBarButtonItem *> *toolbarItems NS_AVAILABLE_IOS(3_0);
- (void)setToolbarItems:(nullable NSArray<UIBarButtonItem *> *)toolbarItems animated:(BOOL)animated NS_AVAILABLE_IOS(3_0);
@end

(三)实际开发过程中的一些问题

1.UINavigationBar的背景颜色

-(void)changeNavigationBarBackgroundColor {
    //背景色
    self.navigationBar.barTintColor = [UIColor blueColor];

    //title字体
    //[self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor lightGrayColor],NSFontAttributeName:[UIFont systemFontOfSize:17]}];

    //修改UIBarButtonItem 图片 title颜色
    self.navigationBar.tintColor = [UIColor greenColor];

    //是否半透明 当为YES时 设置的导航栏背景颜色会和实际rgb值有误差
    self.navigationBar.translucent = NO;

    //如果想要半透明效果 颜色没有色差 可以通过设置背景图片的方法 背景图片会覆盖barTintColor
    //- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics
}

2.UINavigationBar底部的shadowImage

Apple官方对shadowImage有这样的介绍:

/* Default is nil. When non-nil, a custom shadow image to show instead of the default shadow image. For a custom shadow to be shown, a custom background image must also be set with -setBackgroundImage:forBarMetrics: (if the default background image is used, the default shadow image will be used).
*/

设置shadowImage必须先setBackgroundImage,否则无法实现效果

-(void)changeNavigationBarBottonLine {
    //设置底部line颜色时需要同时设置backgroundImage即导航栏的背景图片 否则没有效果
    [self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    [self.navigationBar setShadowImage:[self imageWithColor:[UIColor redColor]]];
    //此处设置透明颜色的image,底部line即可隐藏,但此种方法隐藏,没有办法再显示 下面方法通过找到该view 控制其hidden属性
    //[self reducibilityHiddenNavogationBarLine];
}

找到该imageView设置起Hidden为YES

-(void)reducibilityHiddenNavogationBarLine {
    UIImageView * imageView = [self findLineImageViewUnder:self.navigationBar];
    if (imageView) {
       imageView.hidden = YES;
    }
}

找到该imageView

-(UIImageView *)findLineImageViewUnder:(UIView *)view {
    if ([view isKindOfClass:[UIImageView class]] && view.bounds.size.height <= 1.0) {
        return (UIImageView *)view;
    }
    for (UIView * subView in view.subviews) {
        UIImageView * imageView = [self findLineImageViewUnder:subView];
        if (imageView) {
            return imageView;
        }
    }
    return nil;
}

3.自定义导航栏的返回按钮

@property(nonatomic,readonly) UINavigationBar *navigationBar;// The navigation bar managed by the controller. Pushing, popping or setting navigation items on a managed navigation bar is not supported.

受controller管理的navigationBar 不支持对navigation items操作,所以此处对返回按钮的操作是在ViewController完成的,以下代码中self表示ViewController

Apple官方对setBackIndicatorImage和setBackIndicatorTransitionMaskImage做了如下解释,必须同时设置才能生效

/*
 The back indicator image is shown beside the back button.
 The back indicator transition mask image is used as a mask for content during push and pop transitions
 Note: These properties must both be set if you want to customize the back indicator image.
 */

1.自定义文字+图片

-(void)createCustomBackBarItem {
    
    //修改图片文字颜色
    self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
    
    //替换图片
    [self.navigationController.navigationBar setBackIndicatorImage:[UIImage imageNamed:@"erwema"]];
    [self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"erwema"]];
    
    //设置文字
    UIBarButtonItem * backBarItem = [[UIBarButtonItem alloc]initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];
    self.navigationItem.backBarButtonItem = backBarItem;
}

注意:
对backBarButtonItem的修改是在当前viewController前一个页面完成的,在当前页面修改针对下一个viewController的navigationItem生效

2.不显示文字
设置Title在Y方向上的偏移量,使其移除屏幕,该方法在第一次进入时会有个文字移动的动画效果,效果不好,不推荐使用

[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -100) forBarMetrics:UIBarMetricsDefault];

3.使用leftBarButtonItem替代backBarButtonItem
使用这种方法,不能使用边缘滑动返回手势,且不能同时设置图片和标题

-(void)setLeftBarItemBack
{
    UIBarButtonItem *leftBarBtnItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"back"] style:UIBarButtonItemStylePlain target:self action:@selector(clickLeftBarBtnItem:)];
    [self.navigationItem setLeftBarButtonItem:leftBarBtnItem animated:YES];
    self.navigationItem.leftBarButtonItem.tintColor = NavigationLeftBackColor;
}

/**
 *  导航条leftBarBtn事件
 */
- (void)clickLeftBarBtnItem:(UIBarButtonItem *)sender {
    [self.navigationController popViewControllerAnimated:YES];
}

4.使用CustomView的方法
此方法不适于backBarButtonItem,只能用于leftBarButtonItem

注意:
1.如果B视图有一个自定义的左侧按钮(leftBarButtonItem),则会显示这个自定义按钮;
2.如果B没有自定义按钮,但是A视图的backBarButtonItem属性有自定义项,则显示这个自定义项;
3.如果前2条都没有,则默认显示一个后退按钮,后退按钮的标题是A视图的标题;


此处注意:
5.0中新增加了一个属性leftItemsSupplementBackButton,通过指定该属性为YES,可以让leftBarButtonItem和backBarButtonItem同时显示,其中leftBarButtonItem显示在backBarButtonItem的右边。

使用3、4方法,边缘返回会失效,此时加上这句代码依然可以实现边缘滑动返回

    self.navigationController.interactivePopGestureRecognizer.delegate = self;

这里推荐使用FDFullscreenPopGesture 全屏滑动手势返回,减少工作量。

4.navigationBar偶尔显示上一个页面的navigationBar

一般情况下都是正常的。但是在偶然情况下,会出现在进入新界面后,新界面的navigationBar会突然消失,出现的还是上一个界面的 navigationBar。从此以后,navigationBar 全乱了, kill 掉重新进,恢复正常。
原因:
一般我们会打点调用navigationBarHidden的属性来设置导航栏是否隐藏,这种方法是不带动画效果的。这样偶尔就会导致错乱,这应该是一个系统的bug,所以应尽量使用

[self.navigationController setNavigationBarHidden:YES animated:YES];

来设置navigationBar的Hidden属性。

5.修改系统navigationBar的高度

UINavigationBar * navigatioBar = self.navigationController.navigationBar;
CGFloat navBarHeight = 100.f;
CGRect frame = CGRectMake(0.0f, 0.0f, 320.0f, navBarHeight);
[navigatioBar setFrame:frame];

此种方法经测试只有在非rootViewController中才能生效,这样在第一次进入根视图的时候navigationBar并不会变高,不知有没有人知道该如何解决,欢迎赐教。

6.易混淆知识点

1.self.title、self.navigationItem.title、self.tabBarItem.title之间的关系

一目了然

self.navigationItem.title = @"my title"; //sets navigation bar title.
self.tabBarItem.title = @"my title"; //sets tab bar title.
self.title = @"my title"; //sets both of these.
  1. 如果当前VC通过 self.navigationItem.titleView指定了自定义的titleView,系统将会显示指定的titleView,设置self.title、self.navigationItem.title不会改变导航栏的标题。
  1. 如果当前VC没有指定titleView,系统则会根据当前VC的title或者当前VC的navigationItem.title的内容创建一个UILabel并显示。
  2. self.title会重写navigationItem和tabBarItem的title。

2.self.navigationItem,self.navigationController.navigationItem的关系

navigationItem是UIViewController的一个属性,navigationController继承UIViewController,自然会继承viewControoler的navigationItem属性。此处self.navigationController.navigationItem是应该被忽视的。navigationItem直接由viewController管理。

3.UIBarMetrics和UIBarPosition

typedef NS_ENUM(NSInteger, UIBarMetrics) {
    UIBarMetricsDefault, //横屏
    UIBarMetricsCompact,//竖屏
    UIBarMetricsDefaultPrompt = 101, //横屏且设置了prompt属性  Applicable only in bars with the prompt property, such as UINavigationBar and UISearchBar
    UIBarMetricsCompactPrompt, //竖屏且设置了prompt属性
};

typedef NS_ENUM(NSInteger, UIBarPosition) {
    UIBarPositionAny = 0, //Bar在任何位置
    UIBarPositionBottom = 1, //Bar在底部
    UIBarPositionTop = 2, //Bar在顶部
    UIBarPositionTopAttached = 3, //Bar在顶部,且他的背景扩展到statusBar的区域
} NS_ENUM_AVAILABLE_IOS(7_0);

不正之处,还望多多指教!

参考文章
你真的了解UINavigationController吗?
UINavigationItem UINavigationBar 关系分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容