一.前言
在做即時(shí)通訊類APP中,經(jīng)常需要在tabBar上顯示數(shù)字角標(biāo)幾小紅點(diǎn),這時(shí)系統(tǒng)TabBarController已經(jīng)不能滿足需要了,需要自定義TabBarController,OC 自定義TabBarController相信大家都很熟悉,今天筆者來聊聊Swift中自定義TabBarController的實(shí)現(xiàn),筆者順便做下封裝,方便調(diào)用.
二.需求:
1.自定義TabBarController,傳入
文字
圖片
控制器
名稱數(shù)組,實(shí)現(xiàn)一行代碼創(chuàng)建.
2.能夠自定義高度
3.能夠顯示數(shù)字角標(biāo)及小紅點(diǎn)
三.效果
四.實(shí)現(xiàn)
-1.創(chuàng)建一個(gè)類(筆者命名XHTabBar)繼承UITabBarController,定義變量,并定義其初始化方法如下:
class XHTabBar:UITabBarController {
//記錄選中button
var seleBtn: UIButton?
//tabbar高度
var tabBarHeight:CGFloat = 49.0
//title數(shù)組
var titleArray = [String]()
//默認(rèn)圖片數(shù)組
var imageArray = [String]()
//選中圖片數(shù)組
var selImageArray = [String]()
//控制器數(shù)組
var controllerArray = [String]()
/*
自定義TabBarController初始化方法
- parameter controllerArray:控制器名稱數(shù)組
- parameter titleArray:title數(shù)組
- parameter imageArray:默認(rèn)圖片數(shù)組
- parameter selImageArray:選中圖片數(shù)組
- parameter height:TabBar高度
*/
init(controllerArray: [String], titleArray: [String],imageArray: [String],selImageArray: [String],height: CGFloat?) {
self.controllerArray = controllerArray
self.titleArray = titleArray
self.imageArray = imageArray
self.selImageArray = selImageArray
if let tempHeight = height
{
tabBarHeight = tempHeight;
}
if tabBarHeight < 49.0
{
tabBarHeight = 49.0
}
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
-2.在viewDidLoad初始化自定義TabBar,代碼如下
override func viewDidLoad() {
super.viewDidLoad()
//2.1添控制器
addController()
//2.2添加自定義TabBarView
self.tabBar.addSubview(cusTabbar)
//2.3添加TabBarButton
addTabBarButton()
//2.4處理高度大于49,TabBar頂部橫線
setupTabbarLine()
}
-2.1添加控制器方法實(shí)現(xiàn)
/**
添加控制器
*/
private func addController(){
guard controllerArray.count > 0 else
{
print("error:控制器數(shù)組為nil")
return
}
var navArray = [UIViewController]()
//獲取命名空間
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
for className in controllerArray {
// 將類名轉(zhuǎn)化為類
let cls: AnyClass? = NSClassFromString(ns + "." + className)
//Swift中如果想通過一個(gè)Class來創(chuàng)建一個(gè)對象, 必須告訴系統(tǒng)這個(gè)Class的確切類型
guard let vcCls = cls as? UIViewController.Type else
{
print("error:cls不能當(dāng)做UIViewController")
return
}
let vc = vcCls.init()
let nav = UINavigationController(rootViewController:vc)
navArray.append(nav)
}
self.viewControllers = navArray;
}
-2.2添加自定義cusTabbar懶加載
//MARK: - cusTabbar懶加載
private lazy var cusTabbar: UIView = {
let x = CGFloat(0)
let y = 49.0 - self.tabBarHeight
let width = MWIDTH
let height = self.tabBarHeight
let view = UIView(frame:CGRectMake(x,y,width,height))
view.backgroundColor = ColorTabBar
return view
}()
-2.3添加tabBarButton方法實(shí)現(xiàn)
-2.3.1先自定義tabBarButton,使Button圖片及文字呈上下布局
/*
自定義tabBarButton
*/
class XHTabBarButton:UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
imageView?.contentMode = UIViewContentMode.ScaleAspectFit
titleLabel?.textAlignment = NSTextAlignment.Center
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//重定義image位置
override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
let newX:CGFloat = 0.0
let newY:CGFloat = 5.0
let newWidth:CGFloat = CGFloat(contentRect.size.width)
let newHeight:CGFloat = CGFloat(contentRect.size.height)*scale-newY
return CGRectMake(newX, newY, newWidth, newHeight)
}
//重定義title位置
override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
let newX: CGFloat = 0
let newY: CGFloat = contentRect.size.height*scale
let newWidth: CGFloat = contentRect.size.width
let newHeight: CGFloat = contentRect.size.height-contentRect.size.height*scale
return CGRectMake(newX, newY, newWidth, newHeight)
}
}
-2.3.2添加tabBarButton,及數(shù)字角標(biāo),小紅點(diǎn)
/**
添加tabBarButton
*/
private func addTabBarButton()
{
let num = controllerArray.count
for i in 0..<num {
let width = UIScreen.mainScreen().bounds.size.width
let x = CGFloat(width/CGFloat(num)*CGFloat(i))
let y:CGFloat = 0.0
let w = width/CGFloat(num)
let h = tabBarHeight
let button = XHTabBarButton(frame:CGRectMake(x,y,w,h))
button.tag = 1000+i
button.setTitleColor(ColorTitle, forState: UIControlState.Normal)
button.setTitleColor(ColorTitleSel, forState: UIControlState.Selected)
button.titleLabel?.font = UIFont.systemFontOfSize(titleFontSize)
button.setImage(UIImage.init(named:self.imageArray[i]), forState: UIControlState.Normal)
button.setImage(UIImage.init(named: self.selImageArray[i]), forState: UIControlState.Selected)
button.setTitle(self.titleArray[i], forState: UIControlState.Normal)
button.addTarget(self, action:#selector(buttonAction(_:)), forControlEvents: UIControlEvents.TouchUpInside)
cusTabbar.addSubview(button)
//默認(rèn)選中
if i == 0 {
button.selected = true
self.seleBtn = button
}
//添加角標(biāo)
let numLabel = UILabel(frame: CGRectMake(button.frame.size.width/2.0+6, 3, numMarkD, numMarkD))
numLabel.layer.masksToBounds = true
numLabel.layer.cornerRadius = 10
numLabel.backgroundColor = UIColor.redColor()
numLabel.textColor = UIColor.whiteColor()
numLabel.textAlignment = NSTextAlignment.Center
numLabel.font = UIFont.systemFontOfSize(13)
numLabel.tag = 1020+i
numLabel.hidden = true
button.addSubview(numLabel)
}
}
//MARK: - TabBar Action
@objc private func buttonAction(button: UIButton) {
let index: Int = button.tag-1000
self.showControllerIndex(index)
}
-3定義TabBar角標(biāo),小紅點(diǎn),手動切換控制器等操作
-3.1設(shè)置數(shù)字角標(biāo)
/**
* 設(shè)置數(shù)字角標(biāo)
*
* - param: num 所要顯示數(shù)字
* - param: index 位置
*/
func showBadgeMark(badge: Int, index: Int) {
guard index < controllerArray.count else
{
print("error:index="+"\\(index)"+"超出范圍")
return;
}
let numLabel = (cusTabbar.viewWithTag(1020+index) as? UILabel)!
numLabel.hidden = false
var nFrame = numLabel.frame
if badge <= 0 {
//隱藏角標(biāo)
self.hideMarkIndex(index)
} else {
if badge > 0 && badge <= 9 {
nFrame.size.width = numMarkD
} else if badge > 9 && badge <= 19 {
nFrame.size.width = numMarkD+5
} else {
nFrame.size.width = numMarkD+10
}
nFrame.size.height = numMarkD
numLabel.frame = nFrame
numLabel.layer.cornerRadius = numMarkD/2.0
numLabel.text = "\\(badge)"
if badge > 99 {
numLabel.text = "99+"
}
}
}
-3.2設(shè)置小紅點(diǎn)
/**
* 設(shè)置小紅點(diǎn)
*
* - param: index 位置
*/
func showPointMarkIndex(index: Int) {
guard index < controllerArray.count else
{
print("error:index="+"\\(index)"+"超出范圍")
return;
}
let numLabel = (cusTabbar.viewWithTag(1020+index) as? UILabel)!
numLabel.hidden = false
var nFrame = numLabel.frame
nFrame.size.height = pointMarkD
nFrame.size.width = pointMarkD
numLabel.frame = nFrame
numLabel.layer.cornerRadius = pointMarkD/2.0
numLabel.text = ""
}
-3.3角標(biāo)及小紅點(diǎn)影藏
/**
* 影藏角標(biāo)及小紅點(diǎn)
*
* - param: index 位置
*/
func hideMarkIndex(index: Int) {
guard index < controllerArray.count else
{
print("error:index="+"\\(index)"+"超出范圍")
return;
}
let numLabel = (cusTabbar.viewWithTag(1020+index) as? UILabel)!
numLabel.hidden = true
}
-3.4手動切換TabBar要顯示的控制器
/**
* 手動切換要顯示的控制器
*
* - param: index 位置
*/
func showControllerIndex(index: Int) {
guard index < controllerArray.count else
{
print("error:index="+"\\(index)"+"超出范圍")
return;
}
self.seleBtn!.selected = false
let button = (cusTabbar.viewWithTag(1000+index) as? UIButton)!
button.selected = true
self.seleBtn = button
self.selectedIndex = index
}
-3.5 影藏TabBarController
let controller = UIViewController.init()
//隱藏TabBarController
controller.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(controller, animated: true)
-4.貼出上面用到的(類似OC宏定義)相關(guān)常量及方法,若需調(diào)整可直接修改下面屬性的值
/**
* RGBA顏色
*/
func ColorRGBA(r:CGFloat,g:CGFloat,b:CGFloat,a:CGFloat) -> UIColor {
return UIColor(red:r/255.0,green:g/255.0,blue:b/255.0,alpha:a)
}
/**
* RGB顏色
*/
func ColorRGB(r:CGFloat,g:CGFloat,b:CGFloat) -> UIColor {
return ColorRGBA(r, g: g, b: b, a: 1.0)
}
/**
* 隨機(jī)色
*/
func ColorRandom() -> UIColor {
return ColorRGB(CGFloat(arc4random()%255), g: CGFloat(arc4random()%255), b: CGFloat(arc4random()%255))
}
/**
* 屏幕寬度
*/
let MWIDTH = UIScreen.mainScreen().bounds.size.width
/**
* 屏幕高度
*/
let MHEIGHT = UIScreen.mainScreen().bounds.size.height
/**
* tabbar背景色
*/
private let ColorTabBar = UIColor.whiteColor()
/**
* title默認(rèn)顏色
*/
private let ColorTitle = UIColor.grayColor()
/**
* title選中顏色
*/
private let ColorTitleSel = ColorRGB(41,g: 167,b: 245)
/**
* title字體大小
*/
private let titleFontSize : CGFloat = 12.0
/**
* 數(shù)字角標(biāo)直徑
*/
private let numMarkD:CGFloat = 20.0
/**
* 小紅點(diǎn)直徑
*/
private let pointMarkD:CGFloat = 12.0
/**
* button 圖片與文字上下占比
*/
private let scale:CGFloat = 0.55
五.調(diào)用
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame:UIScreen.mainScreen().bounds)
window?.backgroundColor = UIColor.whiteColor()
/*
控制器name數(shù)組
*/
let controllerArray = ["MainVC","MsgVC","FriendVC","MeVC"]
/*
title數(shù)組
*/
let titleArray = ["首頁","消息","朋友","我的"]
/*
默認(rèn)圖片數(shù)組
*/
let imageArray = ["home_tabbar","msg_tabbar","friend_tabbar","me_tabbar"]
/*
選中圖片數(shù)組
*/
let selImageArray = ["home_tabbar_sel","msg_tabbar_sel","friend_tabbar_sel","me_tabbar_sel"]
/*
tabbar高度, 傳nil默認(rèn)49
*/
let height = CGFloat(49)
/*
創(chuàng)建tabBarController
*/
let tabBarController = XHTabBar(controllerArray:controllerArray,titleArray: titleArray,imageArray: imageArray,selImageArray: selImageArray,height:height)
/*
設(shè)為根控制器
*/
window?.rootViewController = tabBarController
/*
設(shè)置數(shù)字角標(biāo)(可選)
*/
tabBarController.showBadgeMark(100, index: 1)
/*
設(shè)置小紅點(diǎn)(可選)
*/
tabBarController.showPointMarkIndex(2)
/*
不顯示小紅點(diǎn)/數(shù)字角標(biāo)(可選)
*/
//tabBarController.hideMarkIndex(3)
/*
手動切換tabBarController 顯示到指定控制器(可選)
*/
//tabBarController.showControllerIndex(3)
window?.makeKeyAndVisible()
return true
}
六.注意
- 該項(xiàng)目通過
動態(tài)獲取命名空間
+.
+類名
來創(chuàng)建類對象,如下:
let cls: AnyClass? = NSClassFromString(命名空間 + "." + 類名)
- 實(shí)測中發(fā)現(xiàn),當(dāng)命名空間中含有
-
等特殊字符時(shí) 創(chuàng)建類對象會為nil
- 1.項(xiàng)目命名空間默認(rèn)為項(xiàng)目名稱.
- 2.當(dāng)碰到類名稱正確 創(chuàng)建類對象失敗(即
報(bào)error:cls不能當(dāng)做UIViewController錯(cuò)誤時(shí)
)時(shí),你可以: - 2.1.修改項(xiàng)目名去掉
-
等特殊字符(不推薦,筆者推薦第二種方法) - 2.2到TARGETS -> Build Settings ->Produce Name 中修改命名空間,去掉命名空間中
-
等特殊字符:
七.小節(jié)
- 通過上面的封裝可以實(shí)現(xiàn)傳入數(shù)據(jù)源,一行代碼初始化tabBarController,并且支持角標(biāo)及小紅點(diǎn),很方便在今后項(xiàng)目中調(diào)用.
- 代碼地址:https://github.com/CoderZhuXH/XHTabBarSwift