IOS-UINavigationController詳解

(一)UINavigationController及其相關(guān)控件之間的關(guān)系

@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;

通過對(duì)上述幾個(gè)類的屬性的羅列,我們可以做個(gè)總結(jié)

基本介紹
  • UIBarItem
    一個(gè)可以放置在Bar之上的所有小控件類的抽象類,可以設(shè)置標(biāo)題,圖片等
  • UIBarButtonItem
    繼承UIBarItem,增加了動(dòng)作以及目標(biāo)等button的屬性。相當(dāng)于放在UIToolBar或者UINavigationBar上的特殊的button。
  • UINavigationItem
    包含了title,prompt,titleView,leftBarButtonItem,rightBarButtonItem,backBarButonItem等當(dāng)前頁(yè)面上所有的信息
  • UINavigationBar
    NavigaitonBar就是導(dǎo)航欄 主要對(duì)UINavigationItem進(jìn)行棧管理 展示導(dǎo)航欄的外觀背景
  • UINavigationController
    包含了viewcontrollers、navigationbar、toolbar
關(guān)系綜述
  • UINavigationController是一個(gè)容器類,對(duì)ViewController進(jìn)行棧管理,包含navigationBar。
  • UINavigationBar 即UINavigationController頂部的導(dǎo)航欄,主要負(fù)責(zé)外觀背景的展示,并對(duì)navigationItem進(jìn)行棧管理
  • UINavigationItem是導(dǎo)航欄上顯示的具體的元素的一個(gè)抽象類,UINavigationController 通過Category的方法為ViewController添加了一個(gè)navigationItem,把UINavigationItem交由ViewController管理

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

這里引用葉落寒的一段介紹,更加的通俗易懂

通俗地說就是,UINavigationController是個(gè)容器,里面可以裝很多UIViewController。裝這么多UIViewController讓用戶怎么控制它們呢?總得有個(gè)工具吧,這個(gè)工具就是UINavigationBar。一個(gè)容器就這么一個(gè)bar,相當(dāng)于控制臺(tái)吧。但是管理那么多UIViewController,控制臺(tái)上得按鈕啊、標(biāo)題啊,都千篇一律是不是看起來太無聊了。為了解決這個(gè)問題,UINavigationController為每個(gè)UIViewController生成一個(gè)UINavigationItem,通過這個(gè)UINavigationItem可以改變控制臺(tái)“上面”的按鈕和標(biāo)題。如果你不自定義UINavigationItem,UINavigationController會(huì)使用默認(rèn)的;

(二)UINavigationController及其相關(guān)控件的屬性和方法

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設(shè)置背景圖片
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics
- (nullable UIImage *)backgroundImageForState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics

//為特定style的button設(shè)置背景圖片
- (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


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

//設(shè)置標(biāo)題的偏移量
- (void)setTitlePositionAdjustment:(UIOffset)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (nullable UIImage *)backButtonBackgroundImageForState:(UIControlState)state barMetrics:(UIBarMetrics)barMetrics

//設(shè)置返回按鈕標(biāo)題偏移量
- (void)setBackButtonTitlePositionAdjustment:(UIOffset)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (UIOffset)backButtonTitlePositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics

//設(shè)置返回按鈕背景圖片在垂直方向上的偏移量
- (void)setBackButtonBackgroundVerticalPositionAdjustment:(CGFloat)adjustment forBarMetrics:(UIBarMetrics)barMetrics
- (CGFloat)backButtonBackgroundVerticalPositionAdjustmentForBarMetrics:(UIBarMetrics)barMetrics
typedef NS_ENUM(NSInteger, UIBarButtonSystemItem) {
    UIBarButtonSystemItemDone,//顯示完成
    UIBarButtonSystemItemCancel,//顯示取消
    UIBarButtonSystemItemEdit,  //顯示編輯
    UIBarButtonSystemItemSave, //顯示保存 
    UIBarButtonSystemItemAdd,//顯示加號(hào)
    UIBarButtonSystemItemFlexibleSpace,//什么都不顯示,占位一個(gè)空間位置
    UIBarButtonSystemItemFixedSpace,//和上一個(gè)類似
    UIBarButtonSystemItemCompose,//顯示寫入按鈕
    UIBarButtonSystemItemReply,//顯示循環(huán)按鈕
    UIBarButtonSystemItemAction,//顯示活動(dòng)按鈕
    UIBarButtonSystemItemOrganize,//顯示組合按鈕
    UIBarButtonSystemItemBookmarks,//顯示圖書按鈕
    UIBarButtonSystemItemSearch,//顯示查找按鈕
    UIBarButtonSystemItemRefresh,//顯示刷新按鈕
    UIBarButtonSystemItemStop,//顯示停止按鈕
    UIBarButtonSystemItemCamera,//顯示相機(jī)按鈕
    UIBarButtonSystemItemTrash,//顯示移除按鈕
    UIBarButtonSystemItemPlay,//顯示播放按鈕
    UIBarButtonSystemItemPause,//顯示暫停按鈕
    UIBarButtonSystemItemRewind,//顯示退后按鈕
    UIBarButtonSystemItemFastForward,//顯示前進(jìn)按鈕
    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;

//設(shè)置導(dǎo)航欄中間的內(nèi)容標(biāo)題
@property(nullable, nonatomic,copy)   NSString        *title;         
//設(shè)置導(dǎo)航欄中間的內(nèi)容視圖    
@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;

//左邊數(shù)組Item
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *leftBarButtonItems NS_AVAILABLE_IOS(5_0);
//右邊數(shù)組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同時(shí)顯示,其中l(wèi)eftBarButtonItem顯示在backBarButtonItem的右邊 默認(rèn)值為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 是一個(gè)NSString類型描述,注意添加該描述以后NavigationBar的高度會(huì)增加30,總的高度會(huì)變成74(不管當(dāng)前方向是Portrait還是Landscape,此模式下navgationbar都使用高度44加上prompt30的方式進(jìn)行顯示)。

如:

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設(shè)置成透明度,設(shè)置成YES會(huì)有一種模糊效果
@property(nonatomic,assign,getter=isTranslucent) BOOL translucent NS_AVAILABLE_IOS(3_0) UI_APPEARANCE_SELECTOR; 
//UINavigationBar上面不只是簡(jiǎn)單的顯示標(biāo)題,它也將標(biāo)題進(jìn)行了堆棧的管理,每一個(gè)標(biāo)題抽象為的對(duì)象在iOS系統(tǒng)中是UINavigationItem對(duì)象,我們可以通過push與pop操作管理item組。
//向棧中添加一個(gè)item,上一個(gè)item會(huì)被推向?qū)Ш綑诘淖髠?cè),變?yōu)閜op按鈕,會(huì)有一個(gè)動(dòng)畫效果
- (void)pushNavigationItem:(UINavigationItem *)item animated:(BOOL)animated;
//pop一個(gè)item
- (nullable UINavigationItem *)popNavigationItemAnimated:(BOOL)animated; 
//當(dāng)前push到最上層的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *topItem;
//僅次于最上層的item,一般式被推向?qū)Ш綑谧髠?cè)的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *backItem;
//獲取堆棧中所有item的數(shù)組
@property(nullable,nonatomic,copy) NSArray<UINavigationItem *> *items;
//設(shè)置一組item
- (void)setItems:(nullable NSArray<UINavigationItem *> *)items animated:(BOOL)animated; 

//系統(tǒng)類型按鈕文字顏色
@property(null_resettable, nonatomic,strong) UIColor *tintColor;

//通過barTintColor來設(shè)置背景色
@property(nullable, nonatomic,strong) UIColor *barTintColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;  

//設(shè)置工具欄背景和陰影圖案
- (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;

//通過背景圖片來設(shè)置導(dǎo)航欄的外觀
- (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;

//標(biāo)題的富文本
@property(nullable,nonatomic,copy) NSDictionary<NSString *,id> *titleTextAttributes NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;

//標(biāo)題垂直偏移
- (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;

//設(shè)置返回按鈕的圖片
@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初始化,導(dǎo)航控制器的根控制器
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;

//壓棧:將目標(biāo)控制器壓入棧中
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; 

//彈棧:將棧頂控制器從棧中彈出
- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;

//彈棧:彈到指定的目標(biāo)控制器
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated; 

//彈棧:彈到根控制器
- (nullable NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated;
//導(dǎo)航棧的棧頂視圖 只讀 就是某個(gè)導(dǎo)航棧的棧頂視圖,和導(dǎo)航息息相關(guān)
@property(nullable, nonatomic,readonly,strong) UIViewController *topViewController; 
//當(dāng)前顯示的控制器 只讀 visibleViewController和哪個(gè)導(dǎo)航棧沒有關(guān)系,只是當(dāng)前顯示的控制器,也就是說任意一個(gè)導(dǎo)航的visibleViewController所返回的值應(yīng)該是一樣的
@property(nullable, nonatomic,readonly,strong) UIViewController *visibleViewController;

//棧里的視圖控制器數(shù)組
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;

//替換棧中的視圖控制器數(shù)組
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated NS_AVAILABLE_IOS(3_0); 

//是否隱藏導(dǎo)航欄
@property(nonatomic,getter=isNavigationBarHidden) BOOL navigationBarHidden;

//設(shè)置導(dǎo)航欄隱藏 是否有動(dòng)畫
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated; 

//導(dǎo)航欄
@property(nonatomic,readonly) UINavigationBar *navigationBar; 

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

//toolbar是否隱藏 是否有動(dòng)畫
- (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated NS_AVAILABLE_IOS(3_0); 

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

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

//邊緣側(cè)滑返回手勢(shì)
@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:

//輸入鍵盤出現(xiàn)時(shí)將導(dǎo)航欄隱藏 IOS8特性
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenKeyboardAppears NS_AVAILABLE_IOS(8_0);

//滾動(dòng)頁(yè)面時(shí)隱藏Bar  IOS8特性
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnSwipe NS_AVAILABLE_IOS(8_0);

//獲取能夠隱藏navigationBar的滑動(dòng)手勢(shì) 只讀
@property (nonatomic, readonly, strong) UIPanGestureRecognizer *barHideOnSwipeGestureRecognizer NS_AVAILABLE_IOS(8_0);

//當(dāng)設(shè)置為true時(shí),橫向方向時(shí)隱藏NavigationBar
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenVerticallyCompact NS_AVAILABLE_IOS(8_0);

//當(dāng)設(shè)置為true時(shí),如果有沒處理的點(diǎn)擊手勢(shì)就會(huì)隱藏和現(xiàn)實(shí)navigationBar 
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnTap NS_AVAILABLE_IOS(8_0);

//獲取能夠隱藏navigationBar的點(diǎn)擊手勢(shì) 只讀
@property (nonatomic, readonly, assign) UITapGestureRecognizer *barHideOnTapGestureRecognizer NS_AVAILABLE_IOS(8_0);

@end
@interface UIViewController (UINavigationControllerItem)
//導(dǎo)航欄上面用戶自定義視圖
@property(nonatomic,readonly,strong) UINavigationItem *navigationItem; 
//推送時(shí)隱藏bottom
@property(nonatomic) BOOL hidesBottomBarWhenPushed;
//下級(jí)視圖的導(dǎo)航控制器
@property(nullable, nonatomic,readonly,strong) UINavigationController *navigationController; 
@end
@interface UIViewController (UINavigationControllerContextualToolbarItems)
//屬性設(shè)置工具條中包含的按鈕
@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

(三)實(shí)際開發(fā)過程中的一些問題

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];

    //是否半透明 當(dāng)為YES時(shí) 設(shè)置的導(dǎo)航欄背景顏色會(huì)和實(shí)際rgb值有誤差
    self.navigationBar.translucent = NO;

    //如果想要半透明效果 顏色沒有色差 可以通過設(shè)置背景圖片的方法 背景圖片會(huì)覆蓋barTintColor
    //- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics
}

2.UINavigationBar底部的shadowImage

Apple官方對(duì)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).
*/

設(shè)置shadowImage必須先setBackgroundImage,否則無法實(shí)現(xiàn)效果

-(void)changeNavigationBarBottonLine {
    //設(shè)置底部line顏色時(shí)需要同時(shí)設(shè)置backgroundImage即導(dǎo)航欄的背景圖片 否則沒有效果
    [self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    [self.navigationBar setShadowImage:[self imageWithColor:[UIColor redColor]]];
    //此處設(shè)置透明顏色的image,底部line即可隱藏,但此種方法隱藏,沒有辦法再顯示 下面方法通過找到該view 控制其hidden屬性
    //[self reducibilityHiddenNavogationBarLine];
}

找到該imageView設(shè)置起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.自定義導(dǎo)航欄的返回按鈕

@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 不支持對(duì)navigation items操作,所以此處對(duì)返回按鈕的操作是在ViewController完成的,以下代碼中self表示ViewController

Apple官方對(duì)setBackIndicatorImage和setBackIndicatorTransitionMaskImage做了如下解釋,必須同時(shí)設(shè)置才能生效

/*
 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"]];
    
    //設(shè)置文字
    UIBarButtonItem * backBarItem = [[UIBarButtonItem alloc]initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];
    self.navigationItem.backBarButtonItem = backBarItem;
}

注意:
對(duì)backBarButtonItem的修改是在當(dāng)前viewController前一個(gè)頁(yè)面完成的,在當(dāng)前頁(yè)面修改針對(duì)下一個(gè)viewController的navigationItem生效

2.不顯示文字
設(shè)置Title在Y方向上的偏移量,使其移除屏幕,該方法在第一次進(jìn)入時(shí)會(huì)有個(gè)文字移動(dòng)的動(dòng)畫效果,效果不好,不推薦使用

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

3.使用leftBarButtonItem替代backBarButtonItem
使用這種方法,不能使用邊緣滑動(dòng)返回手勢(shì),且不能同時(shí)設(shè)置圖片和標(biāo)題

-(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;
}

/**
 *  導(dǎo)航條leftBarBtn事件
 */
- (void)clickLeftBarBtnItem:(UIBarButtonItem *)sender {
    [self.navigationController popViewControllerAnimated:YES];
}

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

注意:
1.如果B視圖有一個(gè)自定義的左側(cè)按鈕(leftBarButtonItem),則會(huì)顯示這個(gè)自定義按鈕;
2.如果B沒有自定義按鈕,但是A視圖的backBarButtonItem屬性有自定義項(xiàng),則顯示這個(gè)自定義項(xiàng);
3.如果前2條都沒有,則默認(rèn)顯示一個(gè)后退按鈕,后退按鈕的標(biāo)題是A視圖的標(biāo)題;


此處注意:
5.0中新增加了一個(gè)屬性leftItemsSupplementBackButton,通過指定該屬性為YES,可以讓leftBarButtonItem和backBarButtonItem同時(shí)顯示,其中l(wèi)eftBarButtonItem顯示在backBarButtonItem的右邊。

使用3、4方法,邊緣返回會(huì)失效,此時(shí)加上這句代碼依然可以實(shí)現(xiàn)邊緣滑動(dòng)返回

    self.navigationController.interactivePopGestureRecognizer.delegate = self;

這里推薦使用FDFullscreenPopGesture 全屏滑動(dòng)手勢(shì)返回,減少工作量。

4.navigationBar偶爾顯示上一個(gè)頁(yè)面的navigationBar

一般情況下都是正常的。但是在偶然情況下,會(huì)出現(xiàn)在進(jìn)入新界面后,新界面的navigationBar會(huì)突然消失,出現(xiàn)的還是上一個(gè)界面的 navigationBar。從此以后,navigationBar 全亂了, kill 掉重新進(jìn),恢復(fù)正常。
原因:
一般我們會(huì)打點(diǎn)調(diào)用navigationBarHidden的屬性來設(shè)置導(dǎo)航欄是否隱藏,這種方法是不帶動(dòng)畫效果的。這樣偶爾就會(huì)導(dǎo)致錯(cuò)亂,這應(yīng)該是一個(gè)系統(tǒng)的bug,所以應(yīng)盡量使用

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

來設(shè)置navigationBar的Hidden屬性。

5.修改系統(tǒng)navigationBar的高度

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

此種方法經(jīng)測(cè)試只有在非rootViewController中才能生效,這樣在第一次進(jìn)入根視圖的時(shí)候navigationBar并不會(huì)變高,不知有沒有人知道該如何解決,歡迎賜教。

6.易混淆知識(shí)點(diǎn)

1.self.title、self.navigationItem.title、self.tabBarItem.title之間的關(guān)系

一目了然

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. 如果當(dāng)前VC通過 self.navigationItem.titleView指定了自定義的titleView,系統(tǒng)將會(huì)顯示指定的titleView,設(shè)置self.title、self.navigationItem.title不會(huì)改變導(dǎo)航欄的標(biāo)題。
  1. 如果當(dāng)前VC沒有指定titleView,系統(tǒng)則會(huì)根據(jù)當(dāng)前VC的title或者當(dāng)前VC的navigationItem.title的內(nèi)容創(chuàng)建一個(gè)UILabel并顯示。
  2. self.title會(huì)重寫navigationItem和tabBarItem的title。

2.self.navigationItem,self.navigationController.navigationItem的關(guān)系

navigationItem是UIViewController的一個(gè)屬性,navigationController繼承UIViewController,自然會(huì)繼承viewControoler的navigationItem屬性。此處self.navigationController.navigationItem是應(yīng)該被忽視的。navigationItem直接由viewController管理。

3.UIBarMetrics和UIBarPosition

typedef NS_ENUM(NSInteger, UIBarMetrics) {
    UIBarMetricsDefault, //橫屏
    UIBarMetricsCompact,//豎屏
    UIBarMetricsDefaultPrompt = 101, //橫屏且設(shè)置了prompt屬性  Applicable only in bars with the prompt property, such as UINavigationBar and UISearchBar
    UIBarMetricsCompactPrompt, //豎屏且設(shè)置了prompt屬性
};

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

不正之處,還望多多指教!

參考文章
你真的了解UINavigationController嗎?
UINavigationItem UINavigationBar 關(guān)系分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容