iOS導航欄樣式方案梳理

1.背景

在iOS開發中每個頁面都有可能被個性化設計,但如果頁面是以push方式進行管理,那麼多個視圖控制器共享一個導航欄,導航欄的適配顯示就是一個問題。因此需基於系統導航進一步調整和修改才能滿足需求。本文參考下面兩篇博客進行分析梳理。

2.關注點

頁面樣式自定義(包括隱藏或顯示導航欄)之後,關注點如下:

  1. 導航欄內容Title和Item容易編碼維護。
  2. 頁面過渡導航欄內容漸變動畫(參見系統導航效果)。
  3. 頁面過渡導航欄背景顏色變化不突兀。
  4. 支持滑動手勢pop。

3.導航配置

  1. 導航欄透明

    self.navigationBar.isTranslucent = true //需要開啓半透明
    self.navigationBar.setBackgroundImage(UIImage(), for: .default)
    self.navigationBar.shadowImage = UIImage()
  2. 導航欄隱藏

    // 導航欄顯示(含animated,否則頁面有無導航切換可能會突變,在手勢pop時最明顯)    
    self.navigationController?.setNavigationBarHidden(true, animated: true)
  3. 導航欄顏色

    • 導航欄半透明開啓:既然開啓半透明一般是想用模糊效果的,因此明顯應使用下列第①種:

      // ① 半透明開啓,此種方式設置顏色有明顯模糊效果,展開圖層樹UINavigatuionBar -> background視圖 -> UIVisualEffectView -> UIVisualEffectBackdropView, 發現進行UIVisualEffectBackdropView顏色變化(箭頭代表內部子視圖),但是因爲UIVisualEffectView是模糊控制視圖,因此會有模糊效果顯現出來
      self.navigationController?.navigationBar.backgroundColor = UIColor.kcRed
      // ② 半透明開啓,此種方式設置顏色沒有模糊效果,展開圖層樹UINavigationBar ->background視圖 -> imageView, 發現imageView顏色變化(箭頭代表內部子視圖)
      self.navigationController?.navigationBar.setBackgroundImage(UIImage(color:UIColor.kcRed), for: .default)
      // ③ 半透明開啓,此種方式設置顏色有輕微模糊感,但不如第一種那樣明顯,展開圖層樹UINavigatuionBar -> background視圖 -> UIVisualEffectView -> _UIVisualEffectSubview,發現_UIVisualEffectSubview顏色變化(箭頭代表內部子視圖),因爲UIVisualEffectView視模糊控制視圖,因此會有模糊效果顯現出來
      self.navigationController?.navigationBar.barTintColor = UIColor.kcRed
    • 導航欄半透明關閉:建議採用第②種

      // ① 半透明關閉,此種方式不能設置導航欄背景顏色,展開圖層樹發現設置backgroundcolor僅僅影響UINavigationBar的顏色,但是UINavigationBar有一個background子視圖(默認白色)遮蓋了設置的顏色
      self.navigationController?.navigationBar.backgroundColor = UIColor.kcRed
      // ② 半透明關閉,此種方式可以設置導航欄顏色,展開圖層樹UINavigationBar ->background視圖 -> imageView,發現imageView顏色變化(箭頭代表內部子視圖)
      self.navigationController?.navigationBar.setBackgroundImage(UIImage(color:UIColor.kcRed), for: .default)
      // ③ 半透明關閉,此種方式可以設置導航欄顏色。展開圖層樹發現是設置UINavigationBar的子視圖background的顏色,但根據API語義(barTintColor)明顯不是設置背景專屬,可能會影響內部子視圖顏色,因此一般不建議採用此種方法來設置背景色
      self.navigationController?.navigationBar.barTintColor = UIColor.kcRed
  4. 隱藏導航欄下線

        // 展開圖層樹發現黑線是一個高度爲0.33的imageView(iphoneX顯示),圖層樹UINavigationBar ->background視圖 -> imageView,顏色爲透明度0.3的黑色,
        self.navigationBar.shadowImage = UIImage()

3.方案討論

  • 方案一

    • 方案說明:用系統導航欄,且導航欄顏色控制僅僅在每個視圖控制器viewWillAppear中進行配置,透明導航欄也可以使用顏色控制。當然也可根據需要部分頁面隱藏導航欄。
    • 存在問題:此方案過於簡單,頁面過渡和手勢滑動時導航欄顏色效果變化突兀。
    • 樣例:參見KenshinCui博客的名爲原始方式的方案(見其博客代碼示例的Demo1)。
    • 關注點:不滿足關注點3,頁面過渡導航欄背景顏色變化突兀。
  • 方案二

    • 方案說明:隱藏系統導航欄,切換不同顏色的導航條則只需要隱藏用這個方法隱藏導航條然後自定義一個UINavigationBar增加到導航條的位置(添加一個假的導航條)。不過這種方式的由於隱藏了導航條,那麼側滑返回手勢也會消失。透明導航條直接隱藏導航條。
    • 存在問題:①需要自己添加UINavigationBar。②由於隱藏了系統的導航欄,造成側滑手勢丟失。解決方式是重新設置當前控制器的interactivePopGestureRecognizer.delegate=self,但是多次push、pop會出現界面錯亂操作失效的問題(解決方式就是在適當的時候禁用側滑或者禁止手勢shouldReceiveTouch)。
    • 樣例:參見KenshinCui博客的方案1(見其博客代碼示例的Demo2)。
    • 關注點:由於需要添UINavigationBar所以不滿足關注點1;此方案導航欄內容和背景隨視圖漸進平移,背景不突兀,不滿足關注點2,但滿足關注點3;對於關注點4需要控制好手勢的響應。此方案實現起來複雜,並且導航欄原生的特殊效果沒有(自適應調整滾動視圖、 iOS 11的大標題特效等),但此方案並沒有突兀點,不影響需求的話可以採用。
  • 方案三

    • 方案說明:系統導航欄透明,自定義導航欄背景視圖,將系統原有導航欄的背景設置爲透明色,同時在每個 ViewController上添加一個View或者 NavigationBar來充當我們實際看到的導航欄,每個ViewController同樣只需要關心自身的樣式即可。當然也可根據需要部分頁面隱藏導航欄。
    • 存在問題:基本上滿足需求,但和系統原生比較起來,需要自己實現半透明效果,另外可在轉場過程中通過self.transitionCoordinator?.animateAlongsideTransition設置navigationBar透明度。
    • 樣例:參見KenshinCui博客的方案2(見其博客代碼示例的Demo3)。
    • 關注點:基本滿足所列4個關注點。
  • 方案四

    • 方案說明:隱藏導航欄,每個頁面包含一個NavigationController ,每個頁面有2個ViewController和一個NavigationController,一個ViewController交給所屬導航管理頁面跳轉,且其子視圖爲NavigationController(寄宿到另一個ViewController)。我們具體細節內容佈局在導航內層那個ViewController。
    • 存在問題:視圖結構複雜,過渡時導航內容的沒動畫,手勢處理需謹慎(面臨兩個導航)。
    • 樣例:網傳網易雲音樂是這樣的
    • 關注點:看起來和方案二相似,更好的滿足關注點1。不滿足關注點2。滿足關注點3,如果手勢處理好可滿足關注點4。相對每個自身頁面而言,導航欄的原生特殊效果可以通過內層NavigationController達到。
  • 方案五

    • 方案說明:使用系統導航欄,頁面過渡添加Fake Bar在轉場的過程中隱藏原有的導航欄並添加假的 NavigationBar,當轉場結束後刪除假的 NavigationBar 並恢復原有的導航欄,這一過程可以通過 Swizzle 的方式完成,而每個 ViewController 只需要關心自身的樣式即可。當然也可根據需要部分頁面隱藏導航欄。
    • 存在問題:但在解決 Bug 的時候,Swizzle 這種方式無疑會增加解決問題的時間成本和學習成本。
    • 樣例:美團
    • 關注點:不滿足關注點2,其它滿足。

4.推薦方案

  • 優先推薦方案3,簡單易用;方案3爲避免出亂子,需要良好的團隊代碼規範和完善的技術文檔來做輔助。
  • 如果舊項目並且歷史問題較多采用方案5。
  • 方案2和方案4滿足需求的情況下也可選用,但這兩個方案較複雜。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章