iOS-自定義導航欄

前言ide

蘋果自IOS7以後,navigationBar增長了barTintColor屬性,使得咱們更加方便的設置導航欄的背景色,可是導航欄是一個比較複雜的系統控件,朋友們常常遇到設置透明不成功的問題,因爲UINavigationBar是一個複合控件,所以沒法像其餘控件同樣設置backgroundColor和alpha屬性,控制導航欄的背景色和透明度,最關鍵的是系統導航控制器的導航欄是多個ViewController共有的,致使不一樣控制器導航欄不一樣背景色或者不一樣樣式很差控制,正由於如此,在開發中須要自定義導航欄。佈局

 

(一)導航控制器自帶導航欄ui

(1)全部的視圖控制器共用導航欄,所以存在的問題就是在當前控制器設置的導航欄屬性會影響到以後的控制器,切換過程當中須要不斷的設置導航欄控件的屬性;atom

(2)push控制器,導航欄會漸變;code

可是,你會發現市場上不少應用導航欄在切換的過程當中並無漸變,背景色也是各類各樣,所以惟有自定義導航欄能比較方便的進行相關操做,後面我會作相應的闡述。繼承

 

(二)自定義導航欄開發

(1)經過UIView構建相似導航欄結構的視圖,包括左右按鈕以及titleView子視圖;it

(2)隱藏系統導航控制器的navigationBar,而後在ViewController控制器中建立UINavigationBar控件,並將自定義navigationItem加入建立的navigationBar中,而後經過定製navigationItem達到自定義導航欄的目的。io

顯然,市場上的應用大多數偏向第二種方案,緣由是UINavigationBar能夠很方便的設置titleView、leftButton以及rightButton。class

 

(三)關鍵的兩個控制器

(1)XPQBaseViewController負責統一建立navigationBar和navigationItem,子類經過繼承XPQBaseViewController進行導航欄的相關配置(好比添加返回按鈕或者是titleView),設置導航欄透明度方法[self.navBar.subviews objectAtIndex:0].alpha = 1 - flAlpha;

#import <UIKit/UIKit.h>

@interface XPQBaseViewController : UIViewController

@property (strong, nonatomic, readonly) UINavigationBar *navBar;

- (void)configTitleView:(UIView *)titleView;

@end


#import "XPQBaseViewController.h"

@interface XPQBaseViewController ()
@property (strong, nonatomic) UINavigationBar *navBar;
@property (strong, nonatomic) UINavigationItem *navItem;
@end

@implementation XPQBaseViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64.f)];
    self.navItem = [[UINavigationItem alloc] init];
    
    [_navBar pushNavigationItem:_navItem animated:NO];
    
    [self.view addSubview:_navBar];
}

- (void)configTitleView:(UIView *)titleView {
    
    _navItem.titleView = titleView;
}

@end

 

(2)XPQNavigationViewController負責隱藏系統自帶導航欄,且自定義導航欄側滑手勢會失效,所以須要開啓側滑手勢。

#import <UIKit/UIKit.h>

@interface XPQNavigationViewController : UINavigationController

@end


#import "XPQNavigationViewController.h"

@interface XPQNavigationViewController () <UIGestureRecognizerDelegate, UINavigationControllerDelegate>

@end

@implementation XPQNavigationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setNavigationBarHidden:YES animated:NO];
    __weak XPQNavigationViewController *weakSelf = self;
    
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = weakSelf;
        self.delegate = weakSelf;
    }
}

- (UIViewController *)childViewControllerForStatusBarStyle {
    
    return self.topViewController;
}

// 當push控制器時,禁止側滑手勢。
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = NO;
    }
    
    if (self.viewControllers.count > 0) {
        viewController.hidesBottomBarWhenPushed = YES;
    }
    
    [super pushViewController:viewController animated:animated];
}

// 當新的控制器徹底顯示時,開啓側滑手勢。
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = YES;
    }
}

// 解決當控制器子視圖爲根視圖時側滑返回致使的界面卡死問題。
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    
    if (self.viewControllers.count == 1) {
        return NO;
    }
    return YES;
}

// ViewController同時接受多個手勢。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    
    return YES;
}

// ViewController 中的 UIScrollView(UITableView、UIWebView等滾動視圖)會跟着一塊兒滾動,並非原始的滑動返回效果,所以經過代碼設置側滑返回只識別UIScreenEdgePanGestureRecognizer,其餘手勢將會識別失敗。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    
    return [gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]];
}

@end

 

總結

本文XPQBaseViewController控制器只是爲了說明問題,實際應用中導航欄通常都有左右按鈕以及titleView,須要提供相應的屬性或者是方法以便子控制器定製導航欄,在子控制器佈局界面時也要考慮子視圖是否遮蓋自定義的navigationBar。

相關文章
相關標籤/搜索