一.前言
在做即时通讯类APP中,经常需要在tabBar上显示数字角标几小红点,这时系统TabBarController已经不能满足需要了,需要自定义TabBarController,OC 自定义TabBarController相信大家都很熟悉,今天笔者来聊聊Swift中自定义TabBarController的实现,笔者顺便做下封装,方便调用.
二.需求:
1.自定义TabBarController,传入
文字
图片
控制器
名称数组,实现一行代码创建. 2.能够自定义高度 3.能够显示数字角标及小红点
三.效果
四.实现
-1.创建一个类(笔者命名XHTabBar)继承UITabBarController,定义变量,并定义其初始化方法如下:
class XHTabBar:UITabBarController { //记录选中button var seleBtn: UIButton? //tabbar高度 var tabBarHeight:CGFloat = 49.0 //title数组 var titleArray = [String]() //默认图片数组 var imageArray = [String]() //选中图片数组 var selImageArray = [String]() //控制器数组 var controllerArray = [String]() /* 自定义TabBarController初始化方法- parameter controllerArray:控制器名称数组- parameter titleArray:title数组- parameter imageArray:默认图片数组- parameter selImageArray:选中图片数组- 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添加控制器方法实现
/** 添加控制器 */ private func addController(){ guard controllerArray.count > 0 else { print("error:控制器数组为nil") return } var navArray = [UIViewController]() //获取命名空间 let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String for className in controllerArray { // 将类名转化为类 let cls: AnyClass? = NSClassFromString(ns + "." + className) //Swift中如果想通过一个Class来创建一个对象, 必须告诉系统这个Class的确切类型 guard let vcCls = cls as? UIViewController.Type else { print("error:cls不能当做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方法实现
-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,及数字角标,小红点
/** 添加tabBarButton */ private func addTabBarButton() { let num = controllerArray.count for i in 0..
-3定义TabBar角标,小红点,手动切换控制器等操作
-3.1设置数字角标
/** * 设置数字角标 * * - param: num 所要显示数字 * - 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 { //隐藏角标 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设置小红点
/** * 设置小红点 * * - 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角标及小红点影藏
/** * 影藏角标及小红点 * * - 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宏定义)相关常量及方法,若需调整可直接修改下面属性的值
/** * 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)}/** * 随机色 */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默认颜色 */private let ColorTitle = UIColor.grayColor()/** * title选中颜色 */private let ColorTitleSel = ColorRGB(41,g: 167,b: 245)/** * title字体大小 */private let titleFontSize : CGFloat = 12.0/** * 数字角标直径 */private let numMarkD:CGFloat = 20.0/** * 小红点直径 */private let pointMarkD:CGFloat = 12.0/** * button 图片与文字上下占比 */private let scale:CGFloat = 0.55复制代码
五.调用
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { window = UIWindow(frame:UIScreen.mainScreen().bounds) window?.backgroundColor = UIColor.whiteColor() /* 控制器name数组 */ let controllerArray = ["MainVC","MsgVC","FriendVC","MeVC"] /* title数组 */ let titleArray = ["首页","消息","朋友","我的"] /* 默认图片数组 */ let imageArray = ["home_tabbar","msg_tabbar","friend_tabbar","me_tabbar"] /* 选中图片数组 */ let selImageArray = ["home_tabbar_sel","msg_tabbar_sel","friend_tabbar_sel","me_tabbar_sel"] /* tabbar高度, 传nil默认49 */ let height = CGFloat(49) /* 创建tabBarController */ let tabBarController = XHTabBar(controllerArray:controllerArray,titleArray: titleArray,imageArray: imageArray,selImageArray: selImageArray,height:height) /* 设为根控制器 */ window?.rootViewController = tabBarController /* 设置数字角标(可选) */ tabBarController.showBadgeMark(100, index: 1) /* 设置小红点(可选) */ tabBarController.showPointMarkIndex(2) /* 不显示小红点/数字角标(可选) */ //tabBarController.hideMarkIndex(3) /* 手动切换tabBarController 显示到指定控制器(可选) */ //tabBarController.showControllerIndex(3) window?.makeKeyAndVisible() return true }复制代码
六.注意
- 该项目通过
动态获取命名空间
+.
+类名
来创建类对象,如下:
let cls: AnyClass? = NSClassFromString(命名空间 + "." + 类名)复制代码
- 实测中发现,当命名空间中含有
-
等特殊字符时 创建类对象会为nil
- 1.项目命名空间默认为项目名称.
- 2.当碰到类名称正确 创建类对象失败(即
报error:cls不能当做UIViewController错误时
)时,你可以: - 2.1.修改项目名去掉
-
等特殊字符(不推荐,笔者推荐第二种方法) - 2.2到TARGETS -> Build Settings ->Produce Name 中修改命名空间,去掉命名空间中
-
等特殊字符:
七.小节
- 通过上面的封装可以实现传入数据源,一行代码初始化tabBarController,并且支持角标及小红点,很方便在今后项目中调用.
- 代码地址: