TabBarController是项目主要框架结构, 一般来说系统自带的TabBarController已足够使用, 但是要实现一些产品的需求,有时候就需要我们自定义一个TabBarController,本篇文章将为您讲述如何使用Swift自定义TabBarController.顺便附上Demo地址
github.com/15395401361/LFTabBarContoller
首先:定制TabBar上面的按钮。
//
// LFCustomButtonItem.swift
// LFTabBarDemo
//
// Created by 吴林丰 on 2017/3/20.
// Copyright © 2017年 吴林丰. All rights reserved.
//
import UIKit
class LFCustomButtonItem: UIButton {
// MARK: - 页面所用属性
private let itemWH = 40 //item的大小
private let itemTitleColor = UIColor.colorWithHexString(hex: "7b7b7b") //item 中默认的字体颜色
private let selectedItemTitleColor = UIColor.colorWithHexString(hex: "e2231a") //item中被选中是字体的颜色
private let itemTitleFont = UIFont.systemFont(ofSize: 10) //item中字体的大小
private let badgeValueViewImageName = "badge_one@2x.png" //提醒背景图片
private let badgeValueViewImageNameMore = "badge_more@2x.png" //更多背景提醒
private let badgeValueFont = UIFont.systemFont(ofSize: 12)
private let badgeValueColor = UIColor.white
private var badgeValueViewWH:CGFloat{
get{
// return CGFloat(itemWH) * 0.15 //如果只是红点提示,则返回此大小
return CGFloat(itemWH) * 0.45 //如果显示数字,则返回这个大小
}
}
private let KSImageScale:CGFloat = 1
// MARK: - 懒加载红点
lazy var badgeValueView:UIButton = {
let x:CGFloat = self.frame.size.width/2+10
let y:CGFloat = 5
// let x:CGFloat = self.frame.size.width/2+5
// let y:CGFloat = 3 只是小红点提示的时候,常量值为这个
let badgeValueView:UIButton = UIButton.init(frame: CGRect.init(origin: CGPoint.init(x: x, y: y), size: CGSize.init(width: self.badgeValueViewWH, height: self.badgeValueViewWH)))
badgeValueView.setBackgroundImage(UIImage.init(named: self.badgeValueViewImageName), for: .normal)
badgeValueView.setTitleColor(self.badgeValueColor, for: UIControlState.normal)
badgeValueView.adjustsImageWhenHighlighted = false
badgeValueView.isHidden = true
badgeValueView.titleLabel?.font = UIFont.systemFont(ofSize: 12)
return badgeValueView
}()
// MARK: - 初始化self
init(_ frame: CGRect,_ norImage:String,_ selectImage:String,_ titile:String) {
super.init(frame: frame)
//顶部图片
self.imageView?.contentMode = .center
self.setImage(UIImage.init(named: norImage), for: .normal)
self.setImage(UIImage.init(named: selectImage), for: .selected)
self.setImage(UIImage.init(named: norImage), for: .highlighted)
//设置文字
self.titleLabel?.textAlignment = .center
self.setTitle(titile, for: .normal)
self.setTitleColor(itemTitleColor, for: .normal)
self.setTitleColor(itemTitleColor, for: .highlighted)
self.setTitleColor(selectedItemTitleColor, for: .selected)
self.titleLabel?.font = itemTitleFont
self.addSubview(self.badgeValueView)
}
// MARK: - 设置提醒小红点的数量
func setItemBadgeNumber(_ number:Int){
if number != 0 {
if self.badgeValueView.isHidden == true {
self.badgeValueView.isHidden = false
}
/**
实现红点及数字提醒
*/
let tabBadgeNum:String = number > 99 ? "...":"\(number)"
self.badgeValueView.setTitle(tabBadgeNum, for: .normal)
let tabBadgeStr:String = "\(number)"
let longImage:UIImage = UIImage.resizableImage(imageName: badgeValueViewImageName)
self.badgeValueView.setBackgroundImage(longImage, for: .normal)
var newframe:CGRect = self.badgeValueView.frame
if (tabBadgeStr as NSString).length > 1 {
newframe.size.width = badgeValueViewWH + 4
self.badgeValueView.frame = newframe
}else{
newframe.size.width = badgeValueViewWH
self.badgeValueView.frame = newframe
}
/**
只实现红点提醒,不实现数字提醒
同上方的方法二者选一
*/
// self.badgeValueView.setBackgroundImage(UIImage.init(named: "TabBarEdgeImage"), for: .normal)
}else{
self.badgeValueView.isHidden = true
}
}
//重写系统方法,设置按钮内部图片和文字的位置
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let W:CGFloat = contentRect.size.width
let H:CGFloat = contentRect.size.height * KSImageScale
return CGRect.init(x: 0, y: -5, width: W, height: H)
}
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let W:CGFloat = contentRect.size.width
let H:CGFloat = contentRect.size.height * KSImageScale
let Y:CGFloat = contentRect.size.height - H
return CGRect.init(x: 0, y: Y+15, width: W, height: H)
}
//这个是用于Storyboard 的。苹果由于主推SB,所以要求必须实现此方法
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
第二步,继承TabBarController,开始定制自己项目的TabBarController,并编写项目中所要用到的方法。
//
// LFCustomTabBarController.swift
// LFTabBarDemo
//
// Created by 吴林丰 on 2017/3/20.
// Copyright © 2017年 吴林丰. All rights reserved.
//
import UIKit
class LFCustomTabBarController: UITabBarController {
var currentSelectedIndex:NSInteger? //当前选中的button的index
var buttons = [LFCustomButtonItem]()
let ScreenWidth = kScreenWidth
lazy var objectNavis:[UINavigationController] = {
var navis = [UINavigationController]()
navis = self.viewControllers as! [UINavigationController]
return navis
}()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.customTabBar()
}
func customTabBar(){
//初始化TabBar上的Item数量和Item上的标题,图片等等
let normalImageArr = NSArray.init(array: ["out-call","patientsNormal","personalCenterNormal"])
let selectedImageArray = NSArray.init(array: ["out-callSelected","patientsSelected","personalCenterSelected"])
let titleArr = NSArray.init(array: ["首页","联系人","个人中心"])
let viewCount:Int = (self.viewControllers?.count)! > 5 ? 5:(self.viewControllers?.count)!
let _width:CGFloat = kScreenWidth / CGFloat(viewCount)
let _height:CGFloat = self.tabBar.frame.size.height
for i in 0 ..< (self.viewControllers?.count)!{
let btn:LFCustomButtonItem = LFCustomButtonItem.init(CGRect.init(x: CGFloat(i) * _width, y: 0, width: _width, height: _height), normalImageArr[i] as! String, selectedImageArray[i] as! String, titleArr[i] as! String)
btn.addTarget(self, action: #selector(selectedTab(_:)), for: UIControlEvents.touchUpInside)
btn.tag = i
self.buttons.append(btn)
self.tabBar.addSubview(btn)
}
//默认选中第一个页面
if self.buttons.count > 0 {
self.buttons[0].isSelected = true
self.selectedTab(self.buttons[0])
}
}
// MARK - 设置消息数量
//设置消息数
func setBadgeNumber(_ number:NSInteger,_ index:NSInteger){
let buttonItem:LFCustomButtonItem = self.buttons[index]
buttonItem.setItemBadgeNumber(number)
}
func pushToHome(){
for bt in self.buttons {
if bt.tag == 0 {
bt.isSelected = true
}else{
bt.isSelected = false
}
}
self.selectedIndex = 0
let nav:UINavigationController = self.objectNavis[0]
nav.popToRootViewController(animated: true)
}
//其他页面调用选择按钮
func selectedTab(_ button:UIButton){
if self.currentSelectedIndex == button.tag{
return
}
for bt in self.buttons{
if bt == button {
bt.isSelected = true
}else{
bt.isSelected = false
}
}
self.currentSelectedIndex = button.tag
self.selectedIndex = self.currentSelectedIndex!
//选中一级界面
if self.selectedIndex != 0 && (self.viewControllers?.count)! > self.selectedIndex {
/**
注意此处的跳转
由于系统的TabBarController上的viewCoutrollers 默认为继承的是UIViewController
所以,如果使用自定义的导航栏去加载ViewControllers作为TabBarControlelr的viewCoutrollers时
此处需要进行类型转换,从而顺利进行跳转。
*/
if self.objectNavis.count > 0{
//此处需要将其转为具有导航功能的navigationController
(self.selectedViewController as! UINavigationController).popToRootViewController(animated: true)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
1. 如何进行页面切换
自定义的TabBarController继承自系统, 所以还是直接用系统的selectedIndex属性来实现,
2. 自定义的几个Button如何只选中一个, 以及选中状态的切换?
定义一个currentSelectedIndex,标示表示选中的button按钮。
3.如何使用
通过上面的封装可以实现传入数据源,初始化tabBarController,并且支持角标及小红点,很方便在今后项目中调用.喜欢的话,给个星星,你们的支持就是我们笔者的动力。谢谢。✨