iOS導航欄使用總結

主要內容:

一、設置導航欄樣式
二、自定義導航欄返回按鈕后側滑不可用問題
三、隱藏導航欄底部的分割線
四、導航欄引起的布局問題

相關文章:iOS狀態(tài)欄的使用總結

一、設置導航欄樣式

設置導航欄的樣式可分為全局設置與局部設置;

1.全局設置

全局設置一般的都是在AppDelegate中設置,這樣整個app都會生效,相關的代碼與效果圖如下:

//1.設置導航欄背景顏色
[[UINavigationBar appearance] setBarTintColor:[UIColor orangeColor]];
    
//2.設置導航欄背景圖片
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"navigationBarImg"] forBarMetrics:UIBarMetricsDefault];
    
//3.設置導航欄標題樣式
[[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
                                                           [UIColor purpleColor], NSForegroundColorAttributeName,
                                                           [UIFont boldSystemFontOfSize:25], NSFontAttributeName, nil]];
    
//4.設置導航欄返回按鈕的顏色
[[UINavigationBar appearance] setTintColor:[UIColor greenColor]];

//5.設置導航欄隱藏
[[UINavigationBar appearance] setHidden:YES];
設置導航欄樣式效果圖

2.局部設置:

全局設置后,如果只有其中幾個頁面導航欄樣式不同,那么我們可以使用局部設置。
注意1:局部設置與全局設置方法相同,但調用方法的對象變成了"self.navigationController.navigationBar"

注意2:局部設置必須遵循一個原則:"進入頁面時修改,離開頁面時還原”。
比如我們進入一個頁面,需要設置當前導航欄的背景色為灰色,使用如下方法:

//進入頁面時設置顏色:灰色
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.navigationController.navigationBar setBarTintColor:[UIColor grayColor]];
}

//離開頁面時還原為全局設置:橙色
- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.navigationController.navigationBar setBarTintColor:[UIColor orangeColor]];
}

二、解決自定義導航欄返回按鈕后側滑不可用問題

iOS導航欄自帶的返回按鈕形式單一,所以大多情況下,我們都需要自定義導航欄返回按鈕。但是此時我們卻發(fā)現(xiàn)頁面的側滑返回功能不可用了。為了解決這個問題,我們需要在App中使用我們自定義的導航控制控制器,示例代碼如下:

#import "BaseNavigationController.h"
//第一步:設置自定義導航控制器使用UIGestureRecognizerDelegate
@interface BaseNavigationController ()<UIGestureRecognizerDelegate>
@end

@implementation BaseNavigationController
- (void)viewDidLoad {
    [super viewDidLoad];
    //第二步:設置自定義導航控制器的側滑手勢的代理
    self.interactivePopGestureRecognizer.delegate = self;
}
 

//第三步:實現(xiàn)代理方法
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if (self.childViewControllers.count == 1) {
        // 表示用戶在根控制器界面,就不需要觸發(fā)滑動手勢,
        return NO;
    }
    return YES;
}
@end

三、隱藏導航欄底部的分割線

隱藏導航底部分割線也是我們偶爾會遇到的開發(fā)需求,下面介紹兩種實現(xiàn)方法:

方法1:使用shadowImage

使用shadowImage,我們可以設置導航欄分割線的隱藏,在使用這個屬性之前,我們首先來看一下Xcode文檔中對它的介紹:

/* 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).
 */
@property(nullable, nonatomic,strong) UIImage *shadowImage NS_AVAILABLE_IOS(6_0) UI_APPEARANCE_SELECTO

根據(jù)文檔中的說明,使用shadowImage屬性的時候,我們也需要自定義導航欄的backfround image屬性。那么,具體的代碼示例如下:

//進入頁面隱藏分割線
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    //1.隱藏導航底部分割線,使用了一個UIImage對象
    UIImage *shadowImage = [UIImage new];
    //2.設置導航欄底部分割線顏色,使用帶顏色的圖片
    //UIImage *shadowImage = [self imageWithColor:[UIColor purpleColor] withRect:CGRectMake(0, 0, 1.0, 1.0)];
    self.navigationController.navigationBar.shadowImage = shadowImage;
    
    //必須調用setBackgroundImage設置導航欄背景,否則shadowImage無法生效
    UIImage *backgroundImg = [self imageWithColor:[UIColor whiteColor] withRect:CGRectMake(0, 0, 1.0, 1.0)];
    [self.navigationController.navigationBar setBackgroundImage:backgroundImg forBarMetrics:UIBarMetricsDefault];
}

//離開頁面時顯示分割線
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    //再次修改導航欄底部分割線樣式,恢復原樣(lightGrayColor只是為了測試方便,并不準確)
    self.navigationController.navigationBar.shadowImage = [self imageWithColor:[UIColor lightGrayColor] withRect:CGRectMake(0, 0, 1.0, 1.0)];
}

//自定義通過顏色生成圖片的方法,可當做一個工具類方法使用
-(UIImage*)imageWithColor:(UIColor*) color withRect:(CGRect)rect{
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return theImage;
}

方法2:識別UIImageView對象并隱藏

首先我們可以通過Xcode的Debug View Hierarchy功能查看導航欄的視圖結構,效果如下:

導航欄視圖層級圖

從圖中可以看出,導航欄的底部分割線是一個UIImageView對象,而且高度只有0.5,所以我們可以據(jù)此獲取到導航欄的底部分割線對象,在一個視圖控制器中實現(xiàn)此需求,代碼如下:

#import "TestViewController.h"
@interface TestViewController ()
//第一步:設置一個屬性,存放導航欄底部分割線對象
@property (nonatomic, strong) UIImageView *navBarBottomImage;
@end

@implementation TestViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    ////第三步:獲取導航欄底部分割線對象
    UIImageView *navBarBottomImage = [self findNavBarBottomImage:self.navigationController.navigationBar];
    self.navBarBottomImage = navBarBottomImage;
 }

//第四步:設置分割線的顯示或隱藏
//進入頁面隱藏分割線
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
        self.navBarBottomImage.hidden = YES;
}
//離開頁面時顯示分割線
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    self.navBarBottomImage.hidden = NO;
}

//第二步:添加用于獲取導航欄分割線的方法
//導航欄底部分割線是一個UIImageView,且高度不超過1.0個高度,可據(jù)此查找此對象
-(UIImageView *)findNavBarBottomImage:(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 findNavBarBottomImage:subview];
        if (imageView) {
            return imageView;
        }
    }
    return nil;
}

四、導航欄引起的布局問題

1.內容偏移屬性:automaticallyAdjustsScrollViewInsets

automaticallyAdjustsScrollViewInsets是視圖控制器的一個屬性,默認為YES,用于優(yōu)化滑動類視圖(繼承于UIScrollView的視圖)在視圖控制里的顯示:

iOS系統(tǒng)的導航欄UINavigationBar與標簽欄UITabBar默認都是半透明模糊效果,在這種情況下系統(tǒng)會對視圖控制器的UI布局進行優(yōu)化:視圖控制器里面第一個被添加進去的視圖是滑動類視圖,并且其Frame是整個屏幕大小時,系統(tǒng)會自動調整其contenInset,以保證滑動視圖里的內容不被UINavigationBar與UITabBar遮擋

但是對于普通的視圖,此時我們仍然需要注意:非滑動視圖的布局仍然要考慮導航欄和標簽欄高度,注意不被遮擋,比如布局的時候加上導航欄高度,以免內容被導航欄遮擋。

我們可以通過一段代碼來測試一下效果,在默認導航欄(半透明)的視圖控制器里添加如下代碼:

//UITextView是滑動視圖,內容自動向下偏移,不會被導航欄覆蓋
UITextView *leftTextView = [[UITextView alloc] init];
leftTextView.frame = CGRectMake(0, 0,100, kDeviceHeight); //
leftTextView.backgroundColor = [UIColor lightGrayColor];
leftTextView.text = @"君不見,黃河之水天上來,奔流到海不復回。君不見,高堂明鏡悲白發(fā),朝如青絲暮成雪。人生得意須盡歡,莫使金樽空對月。天生我材必有用,千金散盡還復來。";
leftTextView.font = [UIFont systemFontOfSize:18];
leftTextView.editable = NO;
[self.view addSubview:leftTextView];
    
//UIView是非滑動視圖,內容被導航欄部分覆蓋
UIView *rightView= [[UIView alloc] initWithFrame:CGRectMake(150, 0, 100, 100)];
rightView.backgroundColor = [UIColor redColor];
[self.view addSubview:rightView];
導航欄透明情況下,滑動視圖自動偏移,普通視圖被遮擋

其實,這種系統(tǒng)的優(yōu)化也是可以控制關閉的,關閉優(yōu)化之后,滑動視圖就會和普通視圖一樣,如果還設置其布局的原點是(0,0),其內容就會被導航欄所覆蓋,關鍵代碼如下:

//automaticallyAdjustsScrollViewInsets在11.0后失效,所以需要判斷
if (@available(iOS 11.0,*)) {
       scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}else{
       //automaticallyAdjustsScrollViewIn,關閉自動偏移的系統(tǒng)優(yōu)化
       self.automaticallyAdjustsScrollViewInsets = NO;
}

2.邊緣延伸屬性:edgesForExtendedLayout

edgesForExtendedLayout也是視圖控制器的布局屬性,默認值是UIRectEdgeAll,即:當前視圖控制器里各種UI控件會忽略導航欄和標簽的存在,布局時若設置其原點設置為(0,0),視圖會延伸顯示到導航欄的下面被覆蓋。

所以我們可以設置self.edgesForExtendedLayout=UIRectEdgeNone,此時視圖控制器里內容就會避開導航欄和標簽欄了,依然是上面的leftTextView和rightView,設置了UIRectEdgeNone之后的效果圖如下:

self.edgesForExtendedLayout=UIRectEdgeNone

3.導航欄透明屬性translucent

上述兩種屬性都是在解決導航欄半透明情況下的布局問題,但是如果我們的需求就是導航欄不透明,那么視圖控制器里的控件就會默認從(0,64)開始布局了,設置導航欄不透明的方法如下:

self.navigationController.navigationBar.translucent= NO;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

推薦閱讀更多精彩內容

  • 大頭在離公司不遠的地方租了個房子,房子很老很舊,可是房租很便宜。同事們知道了都勸大頭別租,說那房子不干凈,有點那個...
    驢哈哈閱讀 274評論 0 3
  • 冬天是一個必須穿打底褲打底裙的季節(jié),你都準備好了?選擇打底裙的時候你參考了哪些標準呢?這期寶寶為大家找了幾款hin...
    穿搭風格派閱讀 752評論 0 0
  • 一座偌大的孤島 海水放棄了澎湃 悄無聲息 接納他的只有依舊藍的天空 盛綠的山 難掩頹廢 知了 ...
    止語靜默閱讀 367評論 25 30
  • 2017年2月15日,22:58,北大光華MBA西安招生群里,招生老師說: “今晚對很多同學來說是不眠之夜,建議大...
    蜜絲趙閱讀 2,743評論 29 66