[iOS]UINavigationController 全屏 pop 之爲每一個控制器自定義 UINavigationBar

聲明:我爲這個框架寫了四篇文章:git

第一篇:[iOS]UINavigationController全屏pop之爲每一個控制器自定義UINavigationBargithub

第二篇:[iOS]UINavigationController全屏pop之爲每一個控制器添加底部聯動視圖架構

第三篇:[iOS]UINavigationController全屏pop之爲控制器添加左滑push框架

第四篇:[iOS]調和 pop 手勢致使 AVPlayer 播放卡頓工具

框架特性

✅ 全屏 pop 手勢支持性能

✅ 全屏 push 到綁定的控制器支持動畫

✅ 爲每一個控制器定製 UINavigationBar 支持(包括設置顏色和透明度等)3d

✅ 爲每一個控制器添加底部聯動視圖支持code

✅ 自定義 pop 手勢範圍支持(從屏幕最左側開始計算寬度)cdn

✅ 爲單個控制器關閉 pop 手勢支持

✅ 爲全部控制器關閉 pop 手勢支持

❤️ 噹噹前控制器使用 AVPlayer 播放視頻的時候, 使用自定義的 pop 動畫以保證 AVPlayer 流暢播放.

說明:有不少同窗,包括你能看到,留言欄裏也有同窗說原做者不推薦使用這個框架。而後就來問我,是否能在本身的項目裏引入這個框架。從技術的角度來講,我我的的想法是,你要嘗試本身去衡量。可能不少同窗都看到原做者不推薦,可是卻沒注意不推薦的緣由:「細節問題會比這個完善不少」。我不解釋,只把緣由單獨貼出來了。補充一點,凡是我在本身的項目中使用碰到的細節問題,都已經修復好了。
有一個同窗擔憂性能問題,他的擔憂是有依據的,由於畢竟通過包裝處理之後,之前每次只須要壓入一個控制器到棧,如今是每次壓入三個。其實碰到這種問題,我是嘗試去作循環利用的,可是因爲這裏問題的特殊性(爲何特殊?),我至今仍在思考合適的方法可以達成循環利用的效果。爲了解除這部分同窗的疑問,你可使用如下網易雲音樂,他們是這種模式的締造者,同時經過Reveal觀察,沒有跡象代表他們實現了這部分的循環利用,這就是我對性能問題的交代。若是有一天我找到了一個合適的方式來作循環利用我確定還會寫一篇文章來講明這個過程的。

As we all know,Apple 提供的導航條是用來管理窗口控制器的結構的,某個 UINavigationController 執行 Push 操做後,該導航控制器管理的 controllers 共用一個導航條,若是對該導航條進行自定義,那麼各個界面的導航條都會變成自定義之後的樣式。可是,實際開發中,咱們可能須要爲不一樣的控制器定製不一樣的導航條,就像我 demo 裏寫的同樣.

關於demo,總結一下

  • 這個 demo 的結構是這樣的,UITabBarController 做爲根控制器管理着一個導航控制器和一個 UIViewController
  • 導航控制器下面有一個 UITableViewController,爲了完整的顯示圖片,該 UITableViewController 的導航欄要求是透明的
  • push 到下一個控制器的時候,要求導航欄正常顯示
  • 再 push 下一個界面,要求導航欄的顏色是紅色
  • 最後,最重要的一點,要求全屏右滑返回的時候,導航條跟隨本身的控制器滑動

0一、原做 JNTian的思路?

用 Reveal 觀察了幾個經常使用 App,發現了這種效果的實現大體分3種:

第一種是使用自定義 navigationBar.淘寶,網易新聞,達令等使用的是這種. 第二種是用截圖的辦法,在 push 到下一個頁面時,截取屏幕,在使用 edgePanpop 時看到的就是背後的截圖,也能實現這種效果.京東,天貓等使用的是這種. 第三種是使用了一種比較特別,比較巧妙的辦法實現的,也就是網易雲音樂的實現方法,後面會分析一下這種實現.

做者用 Reveal 工具考察了實現這一效果的三種已知的方式,在對比這三個實現方式各自的優缺點之後,採用了第三種方式來實現。

0二、究竟怎麼實現的?

要探究實現,先要講清楚一個原則:

  • 在蘋果的規則裏 UINavigationControler 嵌套 UINavigationControler 的方式是不被容許的,也不能執行壓入棧 push 和出棧 pop 動做

跟我看三張圖:

窗口根結構圖.png

還記得開頭的 demo 嗎?demo 的結構就是這樣一個窗口結構圖:

  • 窗口的根控制器是 TabBarController(上圖紫色的 view
  • TabBarController 每個分支子控制器,用一個根導航控制器做爲管理者(上圖小一點的黑色 View
  • 使用 setNavigationBarHidden:將根導航控制器的導航欄完全移除

pop和push結構圖.png

  • 每當用戶設置根導航控制器的 rootViewControllerpush 入棧的時候,要先將傳進來的控制器(上圖藍色的 View)先包裝一層導航控制器(上圖白色的View
  • 上面咱們說的第二個原則,UINavigationControler 嵌套 UINavigationControler 的方式是不被容許的,也不能執行壓入棧 push 和出棧 pop 動做
  • 因此咱們要在導航控制器(上圖白色的 View)外層再包裝一層 UIViewController
  • 通過以上的包裝之後,用戶傳進來的 Controller 就擁有了一個本身專有的導航控制器,咱們能夠在對應的控制器的 .m 文件裏對該導航控制器作任何自定義(設置透明度和顏色以及漸變)
  • 並且同時也實現了,最重要的一點,要求全屏右滑返回的時候,導航條跟隨本身的控制器滑動

窗口結構圖.png

上面兩張圖,咱們分析了怎麼設定根視圖的結構,以及怎麼包裝用戶傳進來的控制器。 有了以上的基礎之後,咱們就能夠進行入棧和出棧的操做了。 注意:

  • TabBarController 每個分支子控制器的 pushpop 操做都是由根導航控制器負責
  • poppush 操做的對象都是咱們包裝事後的 WarpViewController,這樣就不會有導航控制器 pushpop 導航控制器的衝突了
  • 並且,毫無疑問,也必須設定一個開關來支持全屏右滑返回。

0三、代碼實現?

代碼實現見 GitHub。或者也能夠參見原做者的 Github地址。我只是在原做的基礎上加了註釋,並無修改代碼。 若是你對demo中圖片在tableView滾動時的視差效果感興趣,能夠參見我之前的文章 仿Airbnb的tableView頭部視圖層疊效果。 最後,謝謝Github開源做者: JNTian,大寫的感謝。

0四、更新

  • 2016.08.02: 有朋友在QQ上聯繫我說,他在實際開發中有須要在某個界面暫時關閉右滑手勢的需求。因此,加入暫時關閉右滑手勢開關,方便在某些狀況下須要暫時關閉手勢。具體更新見個人GitHub_Demo

  • 2016.08.04: 上個版本使用類工廠方法,在類工廠方法裏操做了用戶傳進來的控制器的View,因此會形成在應用啓動的時候TabBarVC的子控制器一塊兒加載,有性能問題.此次提交修復了這個問題, TabBarVC的子控制器都能遵循懶加載的原則.謝謝:袁小榮同窗(Github)的提醒.

  • 2016.08.08: 這個框架有了較大的更新。具體包括給現有的Pop手勢添加暫時關閉開關,以及自定義響應手勢範圍。在現有基礎上,框架添加了底部聯動視圖,具體實現以及思路,請前往個人文章:1行代碼爲每一個Controller自定義「TabBar」

  • 2016.09.13 添加了直接拿到根導航控制器的接口,方便使用popToViewController功能。具體見demo第三個控制器的Pop。

0五、注意

注意: tabBar 的 translucent 默認爲 YES, 使用 JPNavigationCotroller 不能修改 tabBar 的透明屬性. 這是由於 Xcode 9 之後, 蘋果對導航控制器內部作了一些修改, 一旦將 tabBar 設爲不透明, 當前架構下的 UI 就會錯亂, 設置 tabBar 的 backgroundImage 爲不透明圖片, 或者設置 backgroundColor 爲不透明的顏色值也是同樣的會出錯.

NewPan 的文章集合

下面這個連接是我全部文章的一個集合目錄。這些文章凡是涉及實現的,每篇文章中都有 Github 地址,Github 上都有源碼。

NewPan 的文章集合索引

若是你有問題,除了在文章最後留言,還能夠在微博 @盼盼_HKbuy 上給我留言,以及訪問個人 Github

相關文章
相關標籤/搜索