①③① 在 Tab Bar 添加自訂 Button 並使用 UITabBarAppearance 調整 Tab Bar Items 的位置

iOS App “私人書藏-PrivLibrary” 系列 I

Min
彼得潘的 Swift iOS / Flutter App 開發教室
11 min readFeb 20, 2024

--

這次預計做一個藏書管理 App,用來練習 CRUM、各種資料儲存與想要實現的 UI 物件。第一篇就從在 Tab Bar 放個特別的按鈕開始,像是智生活跟記帳城市這樣子:

左:智生活 右:記帳城市

Storyboard

先把畫面拉一下,因為希望按下自訂 Button 之後顯示新增書籍的頁面 Add A Book Controller,新增完一本書之後就離開頁面,因此不用連接在 Tab Bar 旗下。

Tab Bar Controller 的 Appearances 選擇 Standard

這個選擇之後大有用處:

自定義顏色

Coolers 網站找一些配色靈感,建立一個 Colors structure:

struct Colors {
static let chiliRed = UIColor(red: 214/255, green: 73/255, blue: 51/255, alpha: 1)
static let redWood = UIColor(red: 169/255, green: 99/255, blue: 88/255, alpha: 1)
static let grey = UIColor(red: 124/255, green: 124/255, blue: 124/255, alpha: 1)
static let silver = UIColor(red: 181/255, green: 177/255, blue: 179/255, alpha: 1)
static let frenchGrey = UIColor(red: 210/255, green: 203/255, blue: 206/255, alpha: 1)
static let lavenderBlush = UIColor(red: 238/255, green: 229/255, blue: 233/255, alpha: 1)
static let lightBlue = UIColor(red: 192/255, green: 225/255, blue: 231/255, alpha: 1)
static let nonPhotoBlue = UIColor(red: 146/255, green: 220/255, blue: 229/255, alpha: 1)
static let airForceBlue = UIColor(red: 95/255, green: 134/255, blue: 144/255, alpha: 1)
static let gunMetal = UIColor(red: 43/255, green: 48/255, blue: 58/255, alpha: 1)
}

之後可直接引用:

TabBarController

建立一個 TabBarController 來設定 Tab Bar 的程式:

把 Storyboard 中的 Custom Class 也選起來:

在 Tab Bar 中宣告一個 centralButton 常數,用來自定義:

class TabBarController: UITabBarController {
// 設定自訂的 button
let centralButton = UIButton()

setButton()

設定 centralButton 的方法,因為 TabBarController 繼承 UITabBarController,因此有 tabBartabBarItem 等內建實例屬性可以使用:

    // 設定 centralButton
func setButton() {
// 設定大小為 tabBar
centralButton.frame.size = CGSize(width: 114, height: tabBar.bounds.height * 0.5)
// 設定位置在 tabBar 正中央
centralButton.center = CGPoint(x: tabBar.bounds.midX, y: tabBar.bounds.midY)
// 設定背景色
centralButton.backgroundColor = Colors.chiliRed
// 設定邊框弧度
centralButton.layer.cornerRadius = 13
// 設定文字
centralButton.setTitle("Add A Book", for: .normal)
// 設定普通情況下的文字顏色
centralButton.setTitleColor(Colors.lavenderBlush, for: .normal)
// 裁剪掉弧線邊框外的內容
centralButton.clipsToBounds = true
// 設定點擊 centralButton 觸發的動作,調用 showAddingBookViewController 方法
centralButton.addTarget(self, action: #selector(showAddingBookViewController), for: .touchDown)
// 將 centralButton 添加到 tabBar 內
tabBar.addSubview(centralButton)
}

其中 centralButton.addTarget(self, action: #selector(showAddingBookViewController), for: .touchDown)

掌管點擊 central button 後出現 AddingBookViewController 的動作,在 showAddingBookViewController 中定義轉場方式、視圖呈現方式與 present 的方法:

    // 顯示 showAddingBookViewController 的方法
@objc func showAddingBookViewController() {
// 創建一個 AddingBookViewController 實例
let addingBookViewController = AddingBookViewController()
// 設定轉場樣式
addingBookViewController.modalTransitionStyle = .flipHorizontal
// 設定 ViewController 的格式
addingBookViewController.modalPresentationStyle = .pageSheet
// 呈現 addingBookViewController
present(addingBookViewController, animated: true, completion: nil)
}

ViewDidLoad 呼喚:

    override func viewDidLoad() {
super.viewDidLoad()

setButton()
}

這當下的 Tab Bar 長這樣:

兩側的 Tab Bar Item 離按鈕太近了,這時剛剛在 Storyboard 將 Tab Bar 的 Appearances 設定為 Standard 就可以派上用場了。

stackedItemPositioning

在 Standard 模式內,於 Storyboard 中可以看到有一組 Standard Stacked Item,裡面的 Positioning 可以將 item 們設定為 Fill 或 Centered(Default 跟 Automatic 我試起來都是 Fill)。

Fill 是常見的平均分散布置,而 Centered 則是向中間靠攏。所以我們試著用 Centered,再調整控制 items 間隔的 Spacing,應該就能達到設定位置的目的。

的確可行!不過如果要適應不同的螢幕寬度,像下圖,左邊的 iPhone 15 pro Max 要使用 180 的 spacing 才有分開的感覺,但對第一代 iPhone SE 來說,這個間隔會把 item 推出去,超過它能設定的範圍,因此原地不動。看來只能透過程式設定位置。

建立一個 setTabBarAppearence() 方法,將兩個 Tab Bat Item 的間隔設為 tabBar 的百分之 45 寬:

    // 設定 Tab Bar Item 的位置
func setTabBarAppearence() {
tabBar.standardAppearance.stackedItemPositioning = .centered
tabBar.standardAppearance.stackedItemSpacing = tabBar.bounds.width * 0.45
}

ViewDidLoad 呼喚:

override func viewDidLoad() {
super.viewDidLoad()

setButton()
setTabBarAppearence()
}

這樣就比較好看了:

--

--