雖然我之前文章大力讚美SwiftUI的tabView有多好用,無奈專案大部分都是UIKit啊~~~~要在既有專案用Tab架構只能用UITabBarController了
設計這次還出了一個超複雜的UI,陰影+圓角+客製化高度 大套餐
馬上開始吧。
重點就是subclass一個UITabController 並去更改tabBar UI
也有人會在viewWillLayoutSubviews()或viewDidLayoutSubviews()去進行。
class MyTabController: UITabBarController {
func viewDidLoad() {
super.viewDidLoad()
setupTabBarUI()
}
func setupTabBarUI() {
self.tabBar.backgroundColor = .white
self.tabBar.tintColor = .grayself.tabBar.layer.cornerRadius = 10
self.tabBar.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
self.tabBar.clipsToBounds = true
self.tabBar.layer.masksToBounds = false
self.tabBar.layer.shadowColor = UIColor.black.cgColor
self.tabBar.layer.shadowOpacity = 0.2
// 陰影要這樣畫,不然會太耗效能
self.tabBar.layer.shadowPath = UIBezierPath(roundedRect: self.tabBar.bounds, cornerRadius: 10.0).cgPath
}
}
研究的時候,發現有些人的作法是在TabBar後面墊一塊UIView當陰影。這個方法如果TabBar永恆存在的話沒問題,但有些動線需要push後隱藏Tab的話,官方提供的hidesBottomBarWhenPushed
只會幫你隱藏TabBar本身,多墊的那塊UIView就要另外再處理,我覺得很不方便,不推薦。
那如何更改高度呢?在網路上有查到2017年的答案和StackOverflow是在viewWillLayoutSubviews去更改高度,但我用已經無效了。
我的作法是建立一個CustomTabBar,改他的高度。
class CustomTabBar: UITabBar {
override func sizeThatFits(_ size: CGSize) -> CGSize {
var sizeThatFits = super.sizeThatFits(size)
sizeThatFits.height = 98
return sizeThatFits
}
然而使用自定義的Tabbar意外的困難,override tabBar屬性也沒反應(NG作法)
class MyTabController: UITabBarController {
// 沒有變高
override var tabBar: UITabBar {
return customTabBar
}
}
後來查到要使用object_setClass
在runtime時把tabBar改掉。apple真的很難搞耶🧐
class MyTabController: UITabBarController {
init() {
super.init(nibName: nil, bundle: nil)
object_setClass(self.tabBar, CustomTabBar.self)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
成品
原生提供的小紅點是有數字的
vc1.tabbarItem.badgeValue = "1"
如果設計想要純小紅點怎麼辦??
有一種邪魔歪道(?的作法是,用同上方法,但不放數字
vc1.tabbarItem.badgeValue = ""
雖然可以出現紅點,但整個大的不可思議,而且因為客製化高度,位置也跑掉。
先做一個列出所有Tab的enum
enum V2TabBarItem {
case tab1
case tab2
case tab3
// badge tag要不同,新增移除時不會互相干擾
var badgeTag: Int {
switch self {
case .tab1:
return 6543
case .tab2:
return 6542
case .tab3:
return 6541
}
}
}
增加小紅點
private func addRedDotAtTabBarItem(tab: V2TabBarItem) {
guard let index = tabs.firstIndex(of: tab) else { return }
removeRedDotAtTabBarItem(tab: tab)
let radius: CGFloat = 5
let diameter = radius * 2
let topMargin:CGFloat = 17
let tabBarItemCount = CGFloat(tabBar.items?.count ?? 0)
let screenSize = UIScreen.main.bounds
let halfItemWidth = (screenSize.width) / (tabBarItemCount * 2)
let xOffset = halfItemWidth * CGFloat(index * 2 + 1)
let imageHalfWidth: CGFloat = ((tabBar.items?[index])?.selectedImage?.size.width ?? 0) / 2
// 離tab icon距離可自行調整
let redDot = UIView(frame: CGRect(x: xOffset + imageHalfWidth/2 + 3, y: topMargin, width: diameter, height: diameter))
redDot.tag = tab.badgeTag
redDot.backgroundColor = UIColor.red
redDot.layer.cornerRadius = radius
tabBar.addSubview(redDot)
}
移除小紅點
private func removeRedDotAtTabBarItem(tab: V2TabBarItem) {
for subview in tabBar.subviews {
if subview.tag == tab.badgeTag {
subview.removeFromSuperview()
break
}
}
}
加!!!!!
加在viewDidLoad裡會沒反應,我覺得應該是太快了tabBar UI還沒ready,我是選擇加在ViewDidAppear裡
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
addRedDotAtTabBarItem(tab: .tab1)
}
成品