父子控制器中的自定義導航欄


提到自定義導航欄,大家首先想到的就是自己寫個自定義導航控制器,然后設置自己的導航控制器的主題。再把包裝着自己控制器的導航控制器的class填上自己寫的自定義nav如果遇到個別控制器的導航欄想與眾不同,就再寫個自定義nav然后再弄個新的導航控制器包裹自己。

 

可是,如果一個項目中用到了 父子控制器,上面的這種做法就會沒有效果。原因就是取不到導航欄

比如我做的大概架構是一個collectionView的循環引用,讓一個個tableview都是包裝在我的collectionViewcell里面的,然后里面的的tableview的cell點擊之后會push一個新的界面。這時候不管你把這個push的新界面怎么設置導航欄樣式 在程序中都是看不見的,因為只能看到最上層,就是collectionViewController的導航欄。

(這里暫時就沒截圖了,因為好多種結果,截太麻煩了,相信大家能理解文字的意思)

而且就算設置導航欄的主題大家也都知道,這段代碼也都是寫在首次調用本類時方法里

+ (void)initialize
{
    // 設置導航欄的主題
    UINavigationBar *navBar = [UINavigationBar appearance];
    [navBar setBarTintColor:[UIColor redColor]];
}

 

 

 

之后再想在動態修改,導航欄的背景色或是背景圖片都是改不了了,只有在一加載時就寫好。我曾試過在push出新的控制器和pop彈棧之后發出通知在這里更改樣式,但是都是無效的,改不了。

 

 

 

 

 

如圖,這個里面控制器是兩個scrollView,一個是標題欄scrollView,一個是下面的內容也是一個scrollView。 (之所以用scrollview是為了每個頁面懶加載,性能更好),然后在scrollView中嵌套了一個個tableViewController。 是把tableViewController的view加到 scrollView的subViews里。

scrollView是主控制器view的subView 那這個tableViewController的view就是主控制器的 subView的subView。

這里要說一下關於父子控制器的注意點就是:如果把A的view加到了B的view的subViews里 那這個A的控制器也必須加到這個B的控制器的childControllers里。

不然view過去了控制器卻沒有 他不就是沒人管了?

上面這個效果 主要用到了一個方法就是導航欄的隱藏方法

當然在設置界面的時候,上面的箭頭和跟帖都是要自己自定義的一個普通的view不是導航欄,可以把他當作導航欄來使用。(董鉑然博客園原創)點擊返回會把棧頂控制器彈棧,點擊跟帖會再push一個評論控制器。

然后再這個詳情控制器將要顯示時把導航欄隱藏,再在這個詳情頁將要彈棧時設置導航欄顯示就好。

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (IBAction)backBtnClick:(id)sender {
    [self.navigationController popViewControllerAnimated:YES];
    [self.navigationController setNavigationBarHidden:NO animated:YES];
}

 

這里還有個注意點就是 要把導航欄隱藏寫在合適的方法里,如果寫在將要跳轉的方法prepareForSegue里就會有抽搐的bug

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[SXDetailController class]]) {
        
        NSInteger x = self.tableView.indexPathForSelectedRow.row;
        SXDetailController *dc = segue.destinationViewController;
        dc.newsModel = self.arrayList[x];
        [self.navigationController setNavigationBarHidden:YES animated:YES];
    }else{
        NSInteger x = self.tableView.indexPathForSelectedRow.row;
        SXPhotoSetController *pc = segue.destinationViewController;
        pc.newsModel = self.arrayList[x];
        [self.navigationController setNavigationBarHidden:YES animated:YES];
    }
    
}

 

如圖這個是反面教材,仔細看導航欄有個抽搐的bug

 

 

 

 

有的人可能會嘗試干脆直接不用導航控制器了 自己設置按鈕控制push和pop

但是這樣系統是不允許的 會報錯,報錯的大概意思就是 你不能給一個沒有導航控制器的控制器添加push操作。

我上面用的方法是雖然把導航控制器隱藏了,但他的功能還在。

 

隱藏導航欄非常好用,可是會遇到一個問題,就是隱藏了導航欄之后,push出的界面無法向左滑動返回。

這個問題類似於: 在導航欄的左上角自定義了一個返回按鈕把原本的返回按鈕給覆蓋了。導致無法實現滑動返回

解決方案是這樣,再將控制器push的代碼之后 或者在prepareForSegue 方法里面加上這行代碼

 if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
            self.navigationController.interactivePopGestureRecognizer.delegate = nil;
        }

 

因為你覆蓋了系統的返回按鈕,(董鉑然博客園原創)系統將會通過代理禁用這個滑動返回功能,你提前把代理給踢了,這樣滑動返回功能就能報住了。

為了安全起見 最好把主控制器的即將顯示加上這行代碼

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:NO animated:YES];
}

 

如果不加這行代碼 可能你一push再拉回來導航欄還是隱藏着的。因為剛才我們只在返回按鈕觸發時設置了導航欄顯示對吧。

最終效果可以達到這樣如圖

 

哪里覺得不對勁或者哪里覺得看不懂 歡迎與我交流 歡迎關注我


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM