先說結論:
通過對一些第三方庫一些調研, 在 github 之上 , 筆者沒有找到特別高質量且低耦合的第三方 自定義 tabbar 庫, 且通過查看第三方庫的源碼, 筆者發現了一些之前忽視的自定義 tabbar 的相關參數, 可以更加的去自定義一些UI
而且筆者通過調研一些app (比如微信), 發現這些 app 也在使用原生控件, 所以筆者認為原生控件可以滿足大多數的 app 的需求, 所以筆者認為, 在不是必須的情況下, 沒有必要一定全部重寫 tabbar
那么問題來了, 我們如何很好的自定義原生 tabbar 呢?
目前可以自定義的UI
首先我們要清楚, 系統提供了哪些接口來自定義 tabbar, 我們能做什么
tabbar 高度
tabbar 默認/選中 圖片
tabbar 默認/選中 文字以及文字屬性
tabbar 默認/選中 文字以及文字屬性
tabbar 整體的背景圖片/顏色
tabbar 整體的陰影
tabbar 選中時候的背景圖片(如果想要純色, 請設置為純色圖片)
tabbarItem 的一些 button 的寬度
tabbar title/image 的偏移
我們不能做什么
tabbar 上 Button 上的 UI 以及相關動畫/布局
tabbar 紅點的樣式, 但是 iOS 10 添加了一些相關的新接口
tabar 整體的背景
自定義樣式的按鈕/或者不規則的按鈕
但是這上邊的事情我們真的就不能解決了嗎, 當然不是
對于背景, 雖然系統沒有提供接口, 但是 UIView 上的問題往往通過下面三個步驟都能解決
1.遍歷子視圖
2.插入視圖
3.調整視圖層級
而紅點樣式, 同理 我們可以找到 對應的 Button 然后向上面添加 特殊 tag 的 view, 這樣就可以自定義樣式了, 起碼微信就是這么做的.
至于自定義按鈕的話, 我會在下面講解 CYLTabBarController 的時候進行說明
CYLTabBarController
目前發現的 github 上標星最多的 自定義 tabbarViewController 第三方框架
這個庫的主要作用是添加一個 PLUS 按鍵
實現類似如下的效果
優點:
實在 UITabViewController 與 UITabBar 的基礎之上進行的再次封裝, 低耦合,接入基本上沒有什么特別大的成本
缺點:
1 它目前截獲了 tabbarController 的 delegate, (可以進行優化)
2 它的 tabbarItem 使用的是 navgationController 的, 沒有使用導航控制器的根控制器 (可以進行優化)
3 由于是在原生控件基礎之上的封裝, 所以對 UI 的可定制和原生相比提升不大
4 tabbarButton 的布局只能是均與分布, 在 iPad 上表現不佳(可以優化)
就我上面說的優缺點, 我來進行一下解釋:
首先這個庫的自定義按鈕所對應的其實是一個操作,而不是對應到相應的控制器, 所以應用場景更適合類似中間提供 分享/發狀態/拍照 等功能.
缺點中我在后面添加了很多(可以進行優化)的標識, 有興趣的同學可以和我討論一下或者自己去看一下如何優化.
CYLTabBarController 實現
TabbtController
使用自定義的 tabbar, 通過初始化方法 得到 viewControllers 與 configs, 然后逐條設置并且添加到 tabViewController
Tabbar
先注冊一個 plus button, 然后遍歷 tabbar 的所有子view, 然后把 button 重新布局,
plusbutton 一般高于 tabbar , 使用
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
來判斷是否點擊了 plus button
總結起來很簡單, 就只在上邊加一個按鈕, 再把其他東西重新布局, 所以說及時看起來不是原生的, 其實我們動動腦子也是可以的
但是每個公司不一樣, 交互一不一樣, 原生的畢竟有各種限制
那么問題來了, 如果我就是要完全重寫 Tabbar, 有哪些要注意的
如果完全重寫 TabbarVC 的關鍵點
- 為了實現原生的效果 要監聽 viewcontroller 的 tabarItem 的各種參數的變化
- 自定義的 tabbar 要自己定制布局規則 (iPad 的上尤為重要)
- 為了響應 hidesBottomBarWhenPushed, 需要與 navigationController 配合, 在執行動畫的時候改變 Tabar 的層級, 實現類似原生的效果
- 如果想完全解耦, 還想遷移完全無成本,可能需要把接口定制為與原生控件相同, 需要研究原生的所有規則
當然, 我上邊羅列的點,其實也有問題,就是我仍然想使用系統提供的參數接口, 比如是 controller 的一些類似 tabbarItem 的參數, 因為我個人是不希望因為某一個控件的自定義, 而造成其他所有代碼都要為之而發生變化.
但是要說的是, 如果真的有需要, 怎么寫都可以,實現了效果才是最重要的