可動態化配置的中央按鈕凸起的UITabBarController

最近快要過節了,因此項目中有一個需求,四個按鈕的image經過後臺返回的圖片來進行配置。同時中間的凸起按鈕是否展示也經過後臺來配置。git

自定義TabBar類

由於項目比較急,之前沒有中間凸起按鈕的設計,因此首先考慮實現的是新建一個繼承UITaBar的類,而後經過valueForKeyPath來替換系統的tabbar。github

自定義WWTabBar面試

class WWTabBar: UITabBar {
        var oldSafeAreaInsets = UIEdgeInsets.zero
        // tabbar高度49
        let TabbarHeight: CGFloat = 49.0
        let centerWidth: CGFloat = 62.0
        let centerHeight: CGFloat = 48.0

        // 中間按鈕
        public var centerBtn: UIButton = UIButton(type: .custom)
        // 中間按鈕圖片url
        var centerImageUrl: String? {
            didSet {
                        centerBtn.kf.setImage(with: URL(string: centerImageUrl ?? ""), for: .normal)
            }
        }

        override init(frame: CGRect) {
            super.init(frame: frame)
            centerBtn.adjustsImageWhenHighlighted = false
            addSubview(centerBtn)
        }

        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        override func layoutSubviews() {
            super.layoutSubviews()

            centerBtn.frame = CGRect(x: (UIScreen.main.bounds.size.width - centerWidth) / 2, y: -5, width: centerWidth, height: centerHeight)

            //系統自帶的按鈕類型是UITabBarButton,找出這些類型的按鈕,而後從新排布位置,空出中間的位置
            let btnWidth = self.frame.size.width / 5
            for btn in self.subviews {
                if btn.isKind(of: NSClassFromString("UITabBarButton")!.self) {
                    let label = btn.value(forKeyPath: "_label") as! UILabel

                    switch (label.text ?? "") {
                    case "首頁":
                        btn.frame = CGRect(x: 0,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)

                    case "探索":
                        btn.frame = CGRect(x: btnWidth,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)
                    case "發現":
                        btn.frame = CGRect(x: btnWidth * 3,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)


                    case "個人":
                        btn.frame = CGRect(x: btnWidth * 4,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)
                    default:
                        return
                    }


                }

            }
        }

        // 處理超出tabbar部分按鈕點擊無效的問題
        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            if !self.isHidden {
                // 轉換座標
                let tempPoint = centerBtn.convert(point, from: self)
                // 判斷點擊的點是否在按鈕區域內
                if centerBtn.bounds.contains(tempPoint) {
                    // 返回按鈕
                    return centerBtn
                }
            }
            return super.hitTest(point, with: event)
        }
    }
複製代碼

動態配置中間按鈕,自定義UITabBarController。若是配置中間按鈕,使用WWTabar替換,若不配置,使用默認TabBar。 爲了擴展性,咱們先定義一個WWTabBarControllerbash

class WWTabBarController: UITabBarController {
    var isShow = false
    var tabIcon: UIImage?
    var tabIconUrl: String?
    var toUrl: String?
    var customTabbar: WWTabBar?

    init(isShowPlus: Bool, icon: UIImage?, iconUrl: String?, uri: String?) {
        isShow = isShowPlus
        tabIcon = icon
        tabIconUrl = iconUrl
        toUrl = uri
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if isShow {
            customTabbar = WWTabBar(frame: .zero)
            setValue(customTabbar, forKeyPath: "tabBar")
            customTabbar?.centerBtn.addTarget(self, action: #selector(centerBtnAction), for: .touchUpInside)
        }
    }

    // 中間按鈕點擊
    @objc func centerBtnAction() {
//        LocalRouter.shared.open(url: toUrl ?? "")
    }
}
複製代碼

這裏有中間按鈕的圖片、跳轉連接等等,經過isShow屬性來決定是否用自定義tabbar來替換系統的。中間按鈕路徑跳轉到toUrl,這裏須要本身的路由實現。 使用時,新建類來繼承這個WWTabBarController微信

class TestTabBarController: WWTabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addChildViewControllers()
    }

    //添加子控制器
    func addChildViewControllers() {
        addChildViewController(ViewController(), title: "首頁", imageName: "tab1")
        addChildViewController(ViewController(), title: "探索", imageName: "tab2")
        addChildViewController(ViewController(), title: "發現", imageName: "tab3")
        addChildViewController(ViewController(), title: "個人", imageName: "tab4")
    }

    // 添加子vc
    func addChildViewController(_ childController: UIViewController, title: String, imageName: String) {
        childController.title = title
        if imageName.count > 0{
            childController.tabBarItem.image = UIImage(named: imageName)
            childController.tabBarItem.selectedImage = UIImage(named: imageName)
        }
        let nav = UINavigationController(rootViewController: childController)
        addChild(nav)
    }
}
複製代碼

在這裏配置四個tabbaritem和對應的頁面 使用時,從後臺拿到配置,而後進行初始化網絡

使用系統tababr

self.window?.rootViewController = TestTabBarController(isShowPlus: false, icon: nil, iconUrl: nil, uri: nil)
複製代碼

添加中間凸起按鈕

self.window?.rootViewController = TestTabBarController(isShowPlus: true, icon: image, iconUrl: "iconurl", uri: "yoururl")
複製代碼

由於可能會碰見網絡很差的狀況。因此項目一開始使用系統的TabBar,請求配置文件並保存下來。第二次再使用本地的配置文件來初始化。因此我建議不要直接使用URl來加載圖片,將圖片down下來而後設置到TabBar中。在上面的WWTabBar中我是設置的url,須要修改一下。ide

因爲咱們項目中首頁對應的TabBarItem Icon是會變化的,再滑動必定距離後,首頁Icon會變成刷新圖標,因此會再次調用layoutSubviews方法,這個layout過程會被用戶看見,因此這個方法不可行。因此嘗試自定義View,不繼承系統UITabBar。 這裏先挖個坑。若是沒有這個需求,能夠用上述方法。 github.com/FrunkPiano/…ui

最近加了一些iOS開發相關的QQ羣和微信羣,可是感受都比較水,裏面對於技術的討論比較少,因此本身建了一個iOS開發進階討論羣,歡迎對技術有熱情的同窗掃碼加入,加入之後你能夠獲得:url

  1. 技術方案的討論,會有在大廠工做的高級開發工程師儘量抽出時間給你們解答問題
  2. 每週按期會寫一些文章,而且轉發到羣裏,你們一塊兒討論,也鼓勵加入的同窗積極得寫技術文章,提高本身的技術
  3. 若是有想進大廠的同窗,裏面的高級開發工程師也能夠給你們內推,而且針對性得給出一些面試建議 羣已經滿100人了,想要加羣的小夥伴們能夠掃碼加這個微信,備註:「加羣+暱稱」,拉你進羣,謝謝了

相關文章
相關標籤/搜索