自定義 UITabBar 總結(一個模擬 instagram TabBar 的例子)

原文連接:自定義 UITabBar 總結(一個模擬 instagram TabBar 的例子)
項目 github 倉庫:模擬 instagramhtml

引語

我在練習 iOS 開發。ios

碰到了跟 TabBar 有關的東西,但願本身儘可能對 TabBar 的使用瞭解清楚而不是直接複製粘貼,因此總體研究一番,在此總結。git

內容主要跟 TabBar 的樣式修改有關,涉及到一點點點擊事件。文中提到的諸如比較重要的方法比較重要的屬性的重要性均是相對本文內容而言。github

要實現的結果如圖:swift

圖片

其中,點擊中間按鈕時,不激活那個 tab 頁,而是執行自定義的任務。(由於 instagram 中間那個按鈕功能就是和其餘的不同嘛。)app

相關文檔

首先,敬上四篇相關文檔:ide

UITabBarController、UITabBarControllerDelegate、UITabBar 和 UITabBarItem

先來一點沒那麼有趣的東西:D。

UITabBarController
當你使用 UITabBarController 的時候,你能夠新建一個類繼承 UITabBarController 來管理你的 TabBar 及相關事件。

UITabBarController 包含許多屬性,與本文相關的比較重要的幾個屬性是:

  • delegate:一個 UITabBarControllerDelegate 對象,用於追蹤和處理一些 TabBar 事件。

  • tabBar: 一個 UITabBar 對象,直接一點說就是你在屏幕上看到的那個 TabBar。

  • viewControllers:每一個 Tab 頁面對應的 viewController 組成的列表。能夠經過排列順序值獲取對應 viewController,好比第一個 tab 的 viewController 爲:self.viewControllers[0]。

UITabBarControllerDelegate
一個比較重要的方法:

  • override func tabBarController(_ tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool
    用於決定被選中的 tab 是否激活。當返回值是 false 時,保留在以前的 tab 頁面;當返回值是 true 時,激活當前選中的 tab 頁面。

UITabBar

幾個重要的屬性:

    • items:一個 UITabBarItem 列表,即每個 tab 按鈕對象組成的列表。

    • selectedItem:當前被選中的 TabBarItem。

    • tintColor:覆蓋被選中的 TabBarItem 圖片的顏色。(默認爲藍色。就是選中時圖標的顏色。)

    • barTintColor:整個 TabBar 的背景顏色。

    UITabBarItem

    幾個重要的方法和屬性:

    • 初始化方法(init(…))。能夠經過 init 方法新建 TabBarItem,並賦予指定初始值,好比圖片、圖片顏色、選中狀態時的圖片及顏色、tag 值等等。

    • badgeValue:看圖。經過設置這個值能夠直接獲得這個效果,我以爲挺有意思的,很省事的樣子。

    • selectedImage:TabBarItem 被選中時顯示的圖片,默認和未選中狀態圖片同樣。

    TabBar 基本樣式的設置

    我目前的見解是,能用 storyboard 解決的必定不用代碼。因此基本樣式設置所有在 storyboard 完成。

    TabBar

    選中 TabBar,打開右側的屬性面板。


    • 通常都不用修改 item Positioning,默認是居中均勻分佈,應該符合大部分需求。

    • Translucent 半透明度能夠根據須要勾選。像微博的客戶端就是半透明的,而instagram 不是。

    • 沒有特別需求的話,能夠直接在這裏設置 Image Tint。咱們這個例子在代碼裏面設置。

    • Style:系統提供了 Default 默認的白色背景和可選的 Black 黑色背景。可根據須要選擇。如圖:

    TabBarItem

    選中 tab 頁面的 viewController 底部的 tab 圖標。右側的屬性面板如圖:

    先看下面的:

    • Title:就是在圖標下顯示的文字。能夠爲空,能夠經過 Title Position 調整位置。

    • Image:圖標的圖片。

    • Tag:當前 TabBarItem 的標誌,設置一個值方便在代碼裏找到對應的 TabBarItem。

    • Enabled:沒什麼好說的:)

    而後是這些:

    • Badge:就是以前提到過的紅點。能夠在這裏設置一個初始值。

    • System Item:一些系統自帶的 Tab 圖標,根據須要自行取用。通常仍是用本身的圖吧。

    • Selected Image:tab 被選中的時候的圖片。

    • Title Postition:設置 title 的位置。
      能夠如圖設置水平偏移垂直偏移

    值得注意的是:水平偏移對圖標有影響,垂直偏移對圖標沒有影響。效果如圖,紅線是我本身加的一條中線,用於對比。

    One more thing :)

    屬性面板右邊有一個設置尺寸的面板:

    在這裏能夠設置圖標的偏移量,從而修改圖標的位置。

    由於默認圖標在 Title上面,位置偏高,就算沒有 Title 圖標也在那個位置。因此當咱們不用 Title 的時候,像 instagram,須要調整圖標的位置,讓它看起來居中一點。

    一種是直接在面板設置,一種是用代碼設置。

    tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);

    對比效果如圖:

    注意:top 和 bottom 要設置成相反數,否則點擊 tab 圖標時 image 的大小會一直改變!!!
    如圖:

    一個建議

    有時候須要調整圖標的大小,不建議用代碼修改或者視圖經過 image inset 來修改。

    建議作圖標的時候,就在圖標周圍留白。好比 75px 的圖片,其中上下左右各留白 20px,這樣圖標就小了。

    另外,根據 Apple 制定的標準,tab 圖標準備 3 個尺寸,分別是 75 px(@3x),55px(@2x)和25px。

    TabBar 個性化樣式設置要求(你們好,重點要開始了:D)

    通過以前一些簡單的步驟,你將獲得如圖效果:

    記得將五個 TabBarItem 的 tag 設置爲 0 - 5,方便之後。

    可是咱們要實現的不是這麼簡單。

    要求:

    • 選中 TabBarItem 背景顏色爲黑色。

    • 未選中 TabBarItem 背景顏色爲某種灰色。

    • 選中 TabBarItem 圖標顏色爲白色。

    • 未選中 TabBarItem 圖標顏色爲某種灰色。

    • 中間按鈕始終背景顏色爲某種藍色、圖標顏色爲白色。

    如何在 UITabBarController 中修改樣式

    新建一個 Cocoa Touch Class,取名叫MainTabBarViewController,繼承 UITabBarController。去 storyboard 把做爲入口的那個 UITabBarController 的類修改成MainTabBarViewController

    這個時候,咱們就能夠在MainTabBarViewController中對 TabBar 進行修改了。

    首先來試驗一下。

    import UIKit
    
    class MainTabBarViewController: UITabBarController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            //設置 tabBar 圖標選中時的顏色
            self.tabBar.tintColor = UIColor.whiteColor()
            //遍歷所有 tabBarItem,設置 badege 值
            for one in self.tabBar.items! {
                one.badgeValue = "100"
            }
            
        }
    }

    WOW。好酷。

    • 選中 TabBarItem 圖標顏色爲白色。 達成√!!

    • 未選中 TabBarItem 圖標顏色爲某種灰色。 達成√!!

    而後還順便嘗試了設置 badge 值。

    如何經過代碼設置單個 TabBarItem 背景顏色

    以前提到過 barTintColor 這個屬性。經過self.tabBar.barTintColor = UIColor().greyColor()就能夠把背景設置爲灰色了。可是這並無完成被選中 TabBarItem 背景顏色變爲黑色的要求。

    事實上,並無直接設置單個 TabBarItem 背景顏色的方法

    解決方案

    重寫 viewDidAppear 方法和 didSelectItem 方法。didSelectItem 是每當有 tabBarItem 被選中時執行的函數。

    import UIKit
    
    class MainTabBarViewController: UITabBarController {
    
            //定義一個用於存儲背景層 view 的列表
        var tabBarItemBgViews: [UIView] = []
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.tabBar.tintColor = UIColor.whiteColor()
            for it in self.tabBar.items! {
                it.badgeValue = "100"
            }
            
        }
        
        override func viewDidAppear(animated: Bool) {
                //初始化須要用到的尺寸數值
            let ITEM_WIDTH = self.tabBar.frame.width / 5
            let ITEM_HEIGHT = CGFloat(49)
            
            //初始化 tab bar item 背景層
            for one in self.tabBar.items! {
                let vw = UIView()
                vw.backgroundColor = UIColor(red: 37/255, green: 29/255, blue: 42/255, alpha: 1)
                vw.frame = CGRectMake(ITEM_WIDTH * CGFloat(one.tag), 0, ITEM_WIDTH, ITEM_HEIGHT)
                self.tabBarItemBgViews.append(vw)
                //將背景層插入到 index 爲 1 的位置,這樣背景層就在圖標下面。記住這個 1 就行了:)
                tabBar.insertSubview(vw, atIndex: 1)
            }
            
            //修改第一個 item 的背景色爲選中狀態顏色
            self.tabBarItemBgViews[0].backgroundColor = UIColor.blackColor()
            
            //自定義中間按鈕樣式
            self.tabBarItemBgViews[2].backgroundColor = UIColor(red: 17/255, green: 86/255, blue: 136/255, alpha: 1)
        }
        
        override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
            //當選中的 TabBarItem 不是中間那個時,改變背景顏色
            if item.tag != 2 {
                for one in tabBar.items! {
                        //將當前被選中的 TabBarItem 背景顏色設置爲黑色
                    if one.tag == item.tag {
                        self.tabBarItemBgViews[one.tag].backgroundColor = UIColor.blackColor()
                    } else {
                        //將其餘 TabBarItem 背景顏色設置爲灰色
                                self.tabBarItemBgViews[one.tag].backgroundColor = UIColor(red: 37/255, green: 29/255, blue: 42/255, alpha: 1)
                    }
                }
                
                //將中間 TabBarItem 的背景顏色重置爲藍色
                self.tabBarItemBgViews[2].backgroundColor = UIColor(red: 17/255, green: 86/255, blue: 136/255, alpha: 1)
            } 
        }
    
    }

    經過上面的代碼,獲得了:

    解釋:爲何是重寫 viewDidAppear 方法而不是 viewDidLoad

    若是把上面那段代碼寫在viewDidLoad方法中,會出現以下狀況:

    能夠看到,第一個 TabBarItem 沒有圖標,並且點擊無效。

    簡單來講,在viewDidLoad的時候,頁面的那些視圖大概還沒準備好,因此插入的時候會有錯誤。包括寫在viewWillAppear中也會出現一樣問題。

    因此記得重寫viewDiaAppear

    兩個問題

    1. 打開 app 的時候,中間按鈕圖標顏色不是白色。(固然這是由於咱們上面代碼裏面沒有設置。)

    2. 點擊中間按鈕,進入了對應的 tab 頁面,如圖。(這不是咱們但願的。)

    如何修改 TabBarItem 樣式

    初一想,在viewDidAppear結尾加上這段代碼就能夠:

    //將 tabBar 包含的 tabBarItem 中的第二個修改成自定義的一個 UITabBarItem
    //使用本來設置的圖片,本來設置的 tag 值,並將圖片設置爲使用原圖片。
    //imageWithRenderingMode(.AlwaysOriginal),稍後詳細解釋
    self.tabBar.items![2] = UITabBarItem(title: nil, image: self.tabBarItem.image?.imageWithRenderingMode(.AlwaysOriginal), tag: self.tabBarItem.tag)
    //修改偏移量,讓圖標居中
    self.tabBar.items![2].imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)

    編譯也沒有問題。可是運行的時候報錯了。

    須要注意:不能直接在 tab bar controller 裏面修改 tab bar item 的屬性

    文檔原文是這樣說的:
    」You should never access the tab bar view of a tab bar controller directly. To configure the tabs of a tab bar controller, you assign the view controllers that provide the root view for each tab to the viewControllers property.」
    這裏我以爲 tab bar view 可能說得不夠清楚,應該是 tab bar item view。

    可能有同窗會對上面咱們增長背景有疑問。那難道不是修改 tab bar item 嗎?

    並非。上面咱們實際上是給 TabBar 增長子視圖,並定位到各個 TabBarItem 背後,看起來像是在給 TabBarItem 添加背景。並無直接修改 TabBarItem。

    解決方案

    如文檔所說,咱們應該在對應的 viewController 裏面去操做。

    到咱們以前應該建立好了的ThirdViewController.swift裏面,寫一個用於修改第三個 TabBarItem 樣式的函數。

    import UIKit
    
    class ThirdViewController: UIViewController, UITabBarControllerDelegate {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
        }
    
        func initTabBarItem() {
            //將該 TabBarItem 替換爲一個新的
            self.tabBarItem = UITabBarItem(title: nil, image: self.tabBarItem.image?.imageWithRenderingMode(.AlwaysOriginal), tag: self.tabBarItem.tag)
            //設置偏移量
            self.tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
        }
    }

    而後回到MainTabBarViewController.swift。加上這兩句:

    let vc = self.viewControllers![2] as! ThirdViewController
    vc.initTabBarItem()

    viewDidAppear方法如今應該以下:

    override func viewDidAppear(animated: Bool) {
        let ITEM_WIDTH = self.tabBar.frame.width / 5
        let ITEM_HEIGHT = CGFloat(49)
        
        //初始化 tab bar item 背景層
        for one in self.tabBar.items! {
            let vw = UIView()
            vw.backgroundColor = UIColor(red: 37/255, green: 29/255, blue: 42/255, alpha: 1)
            vw.frame = CGRectMake(ITEM_WIDTH * CGFloat(one.tag), 0, ITEM_WIDTH, ITEM_HEIGHT)
            self.tabBarItemBgViews.append(vw)
            tabBar.insertSubview(vw, atIndex: 1)
        }
        
        //修改第一個 item 的背景色爲選中狀態顏色
        self.tabBarItemBgViews[0].backgroundColor = UIColor.blackColor()
        
        //自定義中間按鈕樣式
        self.tabBarItemBgViews[2].backgroundColor = UIColor(red: 17/255, green: 86/255, blue: 136/255, alpha: 1)
        //獲取第三個 TabBarItem 對應的 viewController,而後調用修改樣式函數
        let vc = self.viewControllers![2] as! ThirdViewController
        vc.initTabBarItem()
    }

    這裏咱們用到了以前提到的UITabBarControllerviewControllers屬性,經過下標獲取到對應的viewContrller,而後調用裏面的函數,完成樣式修改。

    效果如圖:

    • 中間按鈕始終背景顏色爲某種藍色、圖標顏色爲白色。 達成√!!

    可是點擊中間的按鈕仍是會進入對應的 tab 頁面。下下部分繼續解決這個問題。

    imageWithRenderingMode(稍微詳細的介紹)

    官方文檔:imageWithRenderingMode:

    UIImage 自身有一個方法是 imageWithRenderingMode()。
    有三個可選值:

    • .Automatic

    • .AlwaysOriginal:保持原樣

    • .AlwaysTemplate:留住圖片的樣板,忽略原圖顏色。(好比設置爲 tabBarItem.image 的圖片,默認是渲染模式(rendering mode)是 .AlwaysTemplate,只保留了形狀,默認是灰色。)

    若是想讓 tabBarItem.image 的顏色保持原圖顏色,就要用一個 RenderingMode 爲 .AlwaysOriginal 的圖片替換。也就是上面用到的那種方式。

    如何自定義 TabBarItem 點擊事件,UITabBarControllerDelegate

    以前提到, override func tabBarController(_ tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool,用於決定被選中的 tab 是否激活。當返回值是 false 時,保留在以前的 tab 頁面;當返回值是 true 時,激活當前選中的 tab 頁面。

    咱們要作的是,當被選中的是第三個 tab 時,保留以前的 tab 頁面。

    思路就是這樣,怎麼作呢?

    1.設置 UITabBarControllerDelegate

    class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
    
        var tabBarItemBgViews: [UIView] = []
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.tabBar.tintColor = UIColor.whiteColor()
            for it in self.tabBar.items! {
                it.badgeValue = "100"
            }
            
            self.delegate = self
            
        }

    MainTabBarViewController類添加UITabBarControllerDelegate委託,並在viewDidLoad中將本身的 delegate 設置爲本身。

    這個時候咱們就能夠在MainTabBarViewController中實現UITabBarControllerDelegate中的方法來監控和響應事件。

    重寫以下方法:

    func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
        if viewController.tabBarItem.tag == 2 {
                print(viewController.tabBarItem.tag)
            return false
        } else {
            return true
        }
    }

    當被選中 tabBarItem.tag 等於 2 時,即爲中間按鈕時,返回 false,保留以前的 tab 頁面;不然切換到新頁面。

    效果如圖:

    其中print()方法是用來演示,咱們能夠在這裏作一些其餘的事情,好比像 instagram 同樣彈出拍照頁面。具體實現能夠參考我以前的模擬微博項目。以後我也會繼續完成模擬 instagram 項目,到時候也能夠在我 github 看到。

    如圖,當點擊中間按鈕時,打印出了tag值。

    結束

    以上就是對自定義 TabBar 樣式以及一點點事件相關的總結。

    但願對你們有幫助。

    由於我也是剛開始自學 iOS 開發,遇到不少問題須要花很長時間去找答案。因此但願能寫出一些有意義的總結,和其餘初學者分享,減小你們找不到解決方案的煩惱。

    :D

    相關文章
    相關標籤/搜索