前言:
第一次用Swift學習寫一個自定義Tabbar,不知道理的清楚不慎颗。不同的代碼敲的還有點小亂,慢慢磨吧腹泌。
目錄:
001 - 自定義TabBar大概過程
002 - 核心代碼
自定義TabBar步驟
1.創(chuàng)建一個tabBar控制器嘶卧,把他作為窗口的根控制,并顯示。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = LLTabBarViewController() window?.backgroundColor = UIColor.white window?.makeKeyAndVisible() return true }
效果圖:
2.我們自定義一個繼承于UITabBar的Tabbar類,并利用KVC將系統(tǒng)的Tabbar替換掉凉袱。
import UIKit class ZBTabBarController: UITabBarController { var TabBar = ZBTabBar() override func viewDidLoad() { super.viewDidLoad() self.creatTabBar() } func creatTabBar() { let customTabBar: ZBTabBar = ZBTabBar() self.setValue(customTabBar, forKey: "tabBar") TabBar = customTabBar } }
3.根據(jù)標題數(shù)量芥吟,便利添加子控制器侦铜,并配置其基本信息。
func setRootTaBarVc() { var Vc: UIViewController? for i in 0 ..< self.tabBarTitles.count { print(self.tabBarTitles[i]) switch i { case 0: Vc = ZBInkDropController() case 1: Vc = ZBExchangeController() case 2: Vc = ZBTreasureHuntController() case 3: Vc = ZBMineController() default: break } // 1.創(chuàng)建導航控制器 let nav = ZBRootNavController.init(rootViewController: Vc!) // 2.創(chuàng)建tabbarItem let barItem = UITabBarItem.init(title: self.tabBarTitles[i], image: UIImage.init(named: self.tabBarNormalImgs[i])?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage.init(named: self.tabBarSelectImgs[i])?.withRenderingMode(.alwaysOriginal)) // 3.更改字體顏色 barItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:RGBAlpa(128,128,128,1)], for:.normal ) barItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:RGBAlpa(0,0,0,1)], for: .selected) // 設置標題 Vc?.title = self.tabBarTitles[i] // 設置根控制器 Vc?.tabBarItem = barItem // 添加到當前控制器 self.addChild(nav) } } }
效果圖如下:
4.根據(jù)標題數(shù)量钟鸵,便利添加子控制器钉稍,并配置其基本信息
class ZBTabBar: UITabBar { // 懶加載創(chuàng)建一個中間按鈕 private lazy var addButton:UIButton = { return UIButton() }() // 視圖初始化 override init(frame: CGRect) { super.init(frame: frame) addButton.setBackgroundImage(UIImage.init(named: "tabbar_margin_img"), for: .normal) addButton.addTarget(self, action: #selector(ZBTabBar.addButtonClick), for: .touchUpInside) self.addSubview(addButton) self.backgroundImage = UIColor.creatImageWithColor(color: UIColor.white) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 點擊中間按鈕的實現(xiàn)方法 @objc func addButtonClick() { print("我點擊了中間的按鈕") } // 調用布局約束方法 override func layoutSubviews() { super.layoutSubviews() let buttonX = SCREEN_WIDTH / 5 var index = 0 for barButton in self.subviews { if barButton.isKind(of: NSClassFromString("UITabBarButton")!) { if index == 2 { /// 設置添加按鈕位置 addButton.frame.size = CGSize.init(width: (addButton.currentBackgroundImage?.size.width)!, height: (addButton.currentBackgroundImage?.size.height)!) addButton.center = CGPoint.init(x: self.center.x, y: self.frame.size.height/2 - 15) index += 1 } barButton.frame = CGRect.init(x: buttonX * CGFloat(index), y: 0, width: buttonX, height: self.frame.size.height) index += 1 } } self.bringSubviewToFront(addButton) } }
效果圖如下:
5.接下來,我們會發(fā)現(xiàn)棺耍,點擊中間按鈕超出父類的部分不能點擊贡未,所以我們做的是重寫hitTest方法,監(jiān)聽按鈕的點擊 讓凸出tabbar的部分響應點擊蒙袍。
/// 重寫hitTest方法俊卤,監(jiān)聽按鈕的點擊 讓凸出tabbar的部分響應點擊 override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // 判斷是否為根控制器 if self.isHidden { // tabbar隱藏 不在主頁 系統(tǒng)處理 return super.hitTest(point, with: event) }else { // 將單線觸摸點轉換到按鈕上生成新的點 let onButton = self.convert(point, to: self.addButton) // 判斷新的點是否在按鈕上 if self.addButton.point(inside: onButton, with: event) { return addButton }else { // 不再按鈕上 系統(tǒng)處理 return super.hitTest(point, with: event) } }
6.最后,我們創(chuàng)建一個代理事件害幅,讓按鈕的點擊由控制器去代理瘾蛋,執(zhí)行點擊事件。
protocol RootTabBarDelegate :NSObjectProtocol{ func addClick() } // 點擊中間按鈕的實現(xiàn)方法 @objc func addButtonClick() { if addDelegate != nil{ addDelegate?.addClick() } }
7.tabbar控制器矫限,設置哺哼、遵守代理就ok了。
核心代碼
ZBTabBarController.swift
class ZBTabBarController: UITabBarController,RootTabBarDelegate { // 點擊中間按鈕的方法 func addClick() { print("點擊中間按鈕的方法") } var TabBar = ZBTabBar() var tabBarNormalImgs = ["1","2","3","4"] var tabBarSelectImgs = ["1","2","3","4"] var tabBarTitles = ["墨滴","兌換","尋寶","我的"] override func viewDidLoad() { super.viewDidLoad() self.creatTabBar() } func creatTabBar() { // 替換系統(tǒng)Tabbar let customTabBar: ZBTabBar = ZBTabBar() customTabBar.addDelegate = self self.setValue(customTabBar, forKey: "tabBar") TabBar = customTabBar // 設置tabbar子控制器 self.setRootTaBarVc() } func setRootTaBarVc() { var Vc: UIViewController? for i in 0 ..< self.tabBarTitles.count { print(self.tabBarTitles[i]) switch i { case 0: Vc = ZBInkDropController() case 1: Vc = ZBExchangeController() case 2: Vc = ZBTreasureHuntController() case 3: Vc = ZBMineController() default: break } // 1.創(chuàng)建導航控制器 let nav = ZBRootNavController.init(rootViewController: Vc!) // 2.創(chuàng)建tabbarItem let barItem = UITabBarItem.init(title: self.tabBarTitles[i], image: UIImage.init(named: self.tabBarNormalImgs[i])?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage.init(named: self.tabBarSelectImgs[i])?.withRenderingMode(.alwaysOriginal)) // 3.更改字體顏色 barItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:RGBAlpa(128,128,128,1)], for:.normal ) barItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:RGBAlpa(0,0,0,1)], for: .selected) // 設置標題 Vc?.title = self.tabBarTitles[i] // 設置根控制器 Vc?.tabBarItem = barItem // 添加到當前控制器 self.addChild(nav) } } }
ZBTabBar.swift
import UIKit protocol RootTabBarDelegate :NSObjectProtocol{ func addClick() } class ZBTabBar: UITabBar { weak var addDelegate: RootTabBarDelegate? // 懶加載創(chuàng)建一個中間按鈕 private lazy var addButton:UIButton = { return UIButton() }() // 視圖初始化 override init(frame: CGRect) { super.init(frame: frame) addButton.setBackgroundImage(UIImage.init(named: "tabbar_margin_img"), for: .normal) addButton.addTarget(self, action: #selector(ZBTabBar.addButtonClick), for: .touchUpInside) self.addSubview(addButton) self.backgroundImage = UIColor.creatImageWithColor(color: UIColor.white) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 點擊中間按鈕的實現(xiàn)方法 @objc func addButtonClick() { if addDelegate != nil{ addDelegate?.addClick() } } // 調用布局約束方法 override func layoutSubviews() { super.layoutSubviews() let buttonX = SCREEN_WIDTH / 5 var index = 0 for barButton in self.subviews { if barButton.isKind(of: NSClassFromString("UITabBarButton")!) { if index == 2 { /// 設置添加按鈕位置 addButton.frame.size = CGSize.init(width: (addButton.currentBackgroundImage?.size.width)!, height: (addButton.currentBackgroundImage?.size.height)!) addButton.center = CGPoint.init(x: self.center.x, y: self.frame.size.height/2 - 15) index += 1 }
barButton.frame = CGRect.init(x: buttonX * CGFloat(index), y: 0, width: buttonX, height: self.frame.size.height) index += 1 } } self.bringSubviewToFront(addButton) } /// 重寫hitTest方法叼风,監(jiān)聽按鈕的點擊 讓凸出tabbar的部分響應點擊 override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // 判斷是否為根控制器 if self.isHidden { // tabbar隱藏 不在主頁 系統(tǒng)處理 return super.hitTest(point, with: event) }else { // 將單線觸摸點轉換到按鈕上生成新的點 let onButton = self.convert(point, to: self.addButton) // 判斷新的點是否在按鈕上 if self.addButton.point(inside: onButton, with: event) { return addButton }else { // 不再按鈕上 系統(tǒng)處理 return super.hitTest(point, with: event) } } } }