NavigationController已經洗乾淨了,就等你來

si1ence發表於2017-12-14

2016.12.04

好久沒有更新部落格了,近日把專案中遇到的NavigationController 相關技術點梳理一下,與大家共同分享

首先來點基礎的屬性

一. 基本屬性

  • 設定顏色 如果專案中 Navigation 都是統一的,而你又懶得單獨抽取一個BaseNavigationController,可以直接在 [appDelegate didFinishLaunchingWithOptions]方法中寫
//設定NavigationBar背景顏色
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];

// 通過富文字設定title 樣式(這裡也可以通過自定義Label,然後設定 titleView 來實現)
[[UINavigationBar appearance] setTitleTextAttributes:@{
                    NSForegroundColorAttributeName : [UIColor whiteColor]
                                                           }];

// 設定狀態列格式,如果 NavigationBar 為深色調,就設定為 UIBarStyleBlack,則狀態列顯示為白色
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
複製程式碼
  • 實現 NavigationBar 透明效果 實現透明可能大家第一個想到的是 設定 alpha 值,但是由於設定了作為父控制元件的 NavigationBar 的透明度後,其子控制元件 BarButtonItem 也會隨之改變,因此想要實現導航欄透明,但是 BarButtonItem 正常顯示(類似 手機QQ 的好友動態頁),可以採用下面的方法
// 設定一個空的圖片背景圖片,就能實現導航欄透明但是 BarButtonItem 正常顯示
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
                                                forBarMetrics:UIBarMetricsDefault];
複製程式碼

然而設定之後乍一看沒問題,可仔細一看你會發現NavigationBar下面還有一條細線,這個細線就是shadow

快看那條淡淡的細線!
層級關係圖

可通過以下程式碼來去掉

// 設定一個空的 shadowImage 來實現
self.navigationController.navigationBar.shadowImage = [UIImage new];
複製程式碼

那麼有同學可能要問了,一直透明的可以通過上述方法來實現,那如果想要隨著 上拉距離的改變,實現其透明度動態變化要怎麼做?

// 這個就要監聽 scrollView 的 offset
// 然後獲取到 NavigationBar複合檢視 的顯示子控制元件,動態改變其透明度
[[self.navigationController.navigationBar subviews] objectAtIndex:0].alpha = 0;
複製程式碼

既然講到這裡了就說下來回 push 或 pop,以及使用手勢來返回的時候,上下層級之間 NavigationBar 隱藏與否的設定,因為如果這裡沒處理好的話,會有一個黑條,或者直接顯示下一層級的檢視,體驗特別差,這時候就需要通過動畫的方式的在下一層級進行設定

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // 當前 VC 需要顯示 navigationBar 就設定為 NO,需要隱藏就設定為 YES
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}
複製程式碼
  • 側滑手勢相關 很多時候,leftBarButtonItem需要自定義,因為預設的顯示上一層級的title不一定是我們想要的,但是自定義改變之後,會發現側滑返回的手勢不好使了
    NavigationController已經洗乾淨了,就等你來
#warning 這時候就需要在當前 VC 中設定手勢代理了
self.interactivePopGestureRecognizer.delegate = self;

// 實現代理方法:返回 YES,則手勢有效
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    //當導航控制器的子控制器個數 大於1 手勢才有效
    return self.childViewControllers.count > 1;
}
複製程式碼
  • 由於專案中同一個 VC,有時候是 modal 出來的,有時候是 push 出來的,那麼在這個VC中就要判斷進行處理
NSArray *viewcontrollers=self.navigationController.viewControllers;
if (viewcontrollers.count > 1) {
    if ([viewcontrollers objectAtIndex:viewcontrollers.count - 1] == self) {
        // push方式
        [self.navigationController popViewControllerAnimated:YES];
    }
} else {    
    // present方式    
    [self dismissViewControllerAnimated:YES completion:nil];
}
複製程式碼
  • 如果要實現如下效果的導航欄,設定 leftBarButtonItems 和 rightBarButtonItems 即可

    喂!焦點在 NavigationBar,老看 tableView 幹啥!

  • 關於 rootVC 的 offset,先來看幾個 ViewController 的屬性

    NavigationController已經洗乾淨了,就等你來

  • iOS7以後預設設定是 UIRectEdgeAll,translucent 的預設值是 true,這個組合會使 rootView 的佈局從 (0, 0) 開始,就會造成 rootView 被 NavigationBar 遮擋住一部分,將 edgesForExtendedLayout 設定為 UIRectEdgeNone 即可解決問題

  • automaticallyAdjustsScrollViewInsets 預設值是 YES,表示在全屏下會自動將 第一個新增到 rootVC 的 ScrollView 的 contentInset 設定為 (64, 0, 0, 0),這樣 scrollView 就不會被導航欄遮擋住了

二. 來回跳轉

專案中有個需求是A push 到 B, B push 到 C, C pop 到 D,D 再 pop到 A,就好比這樣:

類似這種交叉跳轉的感覺

  • 首先 A push 到 B,直接使用
[self.navigationController pushViewController:B animated:YES];
// 此時 self.navigationController.childViewControllers = [A, B];
複製程式碼
  • 然後 B push 到 C,同理
[self.navigationController pushViewController:C animated:YES];
// 此時 self.navigationController.childViewControllers = [A, B, C];
複製程式碼
  • 現在要實現 C pop 到 D,由於 navigationController.childViewControllers 是隻讀的,因此不能直接對其進行操作
    navigationController.childViewControllers 是隻讀的
// 建立可變拷貝物件,然後進行替換操作
NSMutableArray *navChildMArr = [self.navigationController.childViewControllers mutableCopy];
[navChildMArr replaceObjectAtIndex:1 withObject:D];

// 當然,最後再將替換後的陣列賦值回去不要忘了
[self.navigationController setViewControllers:navChildMArr animated:YES];

#warning 至於寫上面這串程式碼的時機:寫在 B push C 之後可以,寫在 C 的 viewDidLoad() 方法中也可以
複製程式碼

最後的效果如圖

對,效果如圖

就四這麼簡單!

如果有其他問題,可以在留言處寫下來,不定期更新

相關文章