Swift
protocol CNCustomTabBarDelegate: NSObjectProtocol {
func tabShouldSelectIndex(index: Int) -> Bool
func tabBarDidClickAtIndex(index: Int)
func centerButtonDidClick()
}
class CNCustomTabBar: UITabBar {
static let HEIGHT: CGFloat = TAB_HEIGHT + CNScreen.safeAreaBottom
// MARK: 不能设置小数, 否则tableView 分页滚动会有问题
static let TAB_HEIGHT: CGFloat = 56
weak var myDelegate: CNCustomTabBarDelegate?
let TAG_NUM: Int = 100000
var currentIndex: Int = 0 {
willSet {
if currentIndex >= 0 && currentIndex < CNTabItem.items.count {
guard self.currentIndex != newValue else {
return
}
self.currentIndex = newValue
updateTabBar()
}
}
}
var isDark: Bool {
currentIndex == CNTabItem.hot.tabIndex
}
lazy var bgView: UIView = {
let tmpView = UIView()
tmpView.backgroundColor = .white
return tmpView
}()
// MARK: 关键代码改变UITabBar 高度, 不重写sizeThatFits只是bgView 的高度改变
override open func sizeThatFits(_ size: CGSize) -> CGSize {
super.sizeThatFits(size)
var sizeThatFits = super.sizeThatFits(size)
sizeThatFits.height = CNCustomTabBar.HEIGHT
return sizeThatFits
}
override init(frame: CGRect) {
super.init(frame: .init(x: 0, y: 0, width: CNScreen.width, height: CNCustomTabBar.HEIGHT))
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
let cl: AnyClass? = NSClassFromString("UITabBarButton")
if let cl {
for item in subviews {
if item.isKind(of: cl) {
item.removeFromSuperview()
}
}
}
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard !self.isHidden else {
return nil
}
for i in 0..<CNTabItem.items.count {
let btn = self.bgView.viewWithTag(TAG_NUM+i)
if let btn, btn.bounds.contains(btn.convert(point, from: self)) && btn.isHidden == false && btn.alpha == 1 {
return btn
}
}
return nil
}
}
extension CNCustomTabBar {
func setupUI() {
bgView.frame = bounds
bgView.roundCorners([.topLeft, .topRight], radius: 16)
addSubview(bgView)
//去除黑线
let tabbarAppearance = self.standardAppearance
tabbarAppearance.backgroundEffect = nil
tabbarAppearance.backgroundImage = UIColor.clear.toImage()
tabbarAppearance.shadowImage = UIColor.clear.toImage()
self.standardAppearance = tabbarAppearance
let itemW = CNScreen.width / CGFloat(CNTabItem.items.count)
for (i, item) in CNTabItem.items.enumerated() {
let tabBtn = setupTabButton(tabItem: item)
tabBtn.addTarget(self, action: #selector(tabarBtnClick), for: .touchUpInside)
bgView.addSubview(tabBtn)
tabBtn.frame = CGRect(x: CGFloat(i) * itemW, y: 0, width: itemW, height: Self.TAB_HEIGHT)
}
updateTabBar()
}
@objc func tabarBtnClick(_ button: UIButton) {
let index = button.tag - TAG_NUM
let isShould = myDelegate?.tabShouldSelectIndex(index: index) ?? true
if isShould {
myDelegate?.tabBarDidClickAtIndex(index: index)
} else {
}
}
func updateTabBar() {
bgView.backgroundColor = isDark ? .black : .white
for (i, tabItem) in CNTabItem.items.enumerated() {
let isSelected = currentIndex == i
if let btn = self.bgView.viewWithTag(TAG_NUM+i) as? UIButton {
var updateConfig = btn.configuration
if isSelected {
updateConfig?.image = UIImage(named: tabItem.selImage)
} else {
updateConfig?.image = UIImage(named: tabItem.norImage(isDark: isDark))
}
var titleColor = UIColor.hex("#A6ABB7")!
if isDark && isSelected {
titleColor = UIColor.hex("#FFDA33")!
} else if isDark {
titleColor = UIColor.hex("#CCCCCC")!
} else if isSelected {
titleColor = UIColor.hex("#010101")!
}
let titleAttributes = AttributeContainer([
.font: UIFont.systemFont(ofSize: 10, weight: .medium),
.foregroundColor: titleColor
])
let title = AttributedString(tabItem.title, attributes: titleAttributes)
updateConfig?.attributedTitle = title
btn.configuration = updateConfig
}
}
}
private func setupTabButton(tabItem: CNTabItem) -> UIButton {
let button = UIButton()
button.tag = TAG_NUM + tabItem.tabIndex
var config = UIButton.Configuration.plain()
config.baseBackgroundColor = .clear
config.background.backgroundColor = .clear
config.image = UIImage(named: tabItem.norImage(isDark: false))
config.imagePlacement = .top
config.imagePadding = 3
let titleAttributes = AttributeContainer([
.font: UIFont.systemFont(ofSize: 10, weight: .medium),
.foregroundColor: UIColor.hex("#A6ABB7")!
])
var title = AttributedString(tabItem.title, attributes: titleAttributes)
config.attributedTitle = title
button.configuration = config
button.backgroundColor = .clear
return button
}
}
继承自UITabBar 自定义TabBar 时,遇到两个问题:
-
在 tabBarController 中 setValue(self.customTabBar, forKey: "tabBar") 设置self.customTabBar 后,tabBarController 的 viewControllers 高度 为屏幕高度,正常应该为 屏幕高度 - tabBar - 底部安全区高度,在设置tabBar.isTranslucent = false 后就莫名奇妙解决了。
-
项目中所有的高度使用了屏幕宽度等比缩放,即 h * w_scale,使用zfplayer 时, tableView 设置isPageEnable = true分页,如果cell 高度为小数,则会出现bug, 视频画面不能正常切换。这是因为自定义 TabBar 的高度一开始使用了等比缩放 56 * w_scale,修改为整数 56 后。恢复正常