iOS 13 客製 bar 模樣的 UINavigationBarAppearance

請參考以下新版說明的連結,原本文章的內容是舊版的說明。

新版說明

舊版說明

iOS 13 的 navigation bar 多了一些新的樣式設定方法,多了方便我們客製它模樣的新類別, UINavigationBarAppearance ,接下來就讓我們好好認識它的威力吧。

預設的 navigation bar 樣式

我們先在 storyboard 上建立一個 navigation controller,串接兩個畫面,顯示伊坂幸太郎的新書,蹺蹺板怪物。

App 啟動後, navigation bar 將呈現毛玻璃的效果,隱隱約約看到背後 view 的顏色。

透明的 navigation bar

現在讓我們透過 UINavigationBarAppearance,將 navigation bar 變透明吧。

override func viewDidLoad() {
super.viewDidLoad()
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithTransparentBackground()
navigationController?.navigationBar.standardAppearance = barAppearance
}

產生 UINavigationBarAppearance 物件 barAppearance 後,呼叫 function configureWithTransparentBackground 將 bar 變透明, 然後將 barAppearance 設為目前畫面 navigationBar 的 standardAppearance。

透過同樣的方法,我們也可以讓搭配捲動畫面的 navigation bar 變透明,比方以下搭配 table view 的 navigation bar。

如下圖所示,我們將 table 的背景設為綠色,因此當 navigation bar 透明時,我們將清楚看到表格的背景色。

讓整個 App 的 navigation bar 變透明

在類別 AppDelegate 的 function application(_:didFinishLaunchingWithOptions:)裡產生 UINavigationBarAppearance 物件,然後將它設為 UINavigationBar.appearance() 的 standardAppearance。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

let barAppearance = UINavigationBarAppearance()

barAppearance.configureWithTransparentBackground()
UINavigationBar.appearance().standardAppearance = barAppearance
return true
}

指定 navigation bar 的顏色

當我們設定 UINavigationBarAppearance 的 backgroundColor 時,navigation bar 將變成完全不透明,顯示我們指定的顏色。

let barAppearance = UINavigationBarAppearance()
barAppearance.backgroundColor = .red

預設透明的放大版 navigation bar

若是放大版的 navigation bar,navigation bar 將預設變成透明的樣式。

若想讓放大版的 navigation bar 顯示毛玻璃效果,則須呼叫 function configureWithDefaultBackground,然後設定 scrollEdgeAppearance。

let barAppearance =  UINavigationBarAppearance()
barAppearance.configureWithDefaultBackground()

UINavigationBar.appearance().scrollEdgeAppearance = barAppearance

搭配捲動畫面的放大版 navigation bar

當放大版的 navigation bar 搭配捲動畫面,比方搭配 table 時,navigation bar 將預設變成透明的樣式,捲動後顯示毛玻璃的 bar。

如下圖所示, table 的背景為綠色,因此一開始 navigation bar 透明時將看到清楚的綠色。接著當 table 捲動時,它將變身成毛玻璃的樣式和背景顏色融合在一起。

我們也可以讓 navigation bar 一開始就顯示毛玻璃效果,透過呼叫 function configureWithDefaultBackground,然後設定 scrollEdgeAppearance。

let barAppearance =  UINavigationBarAppearance()
barAppearance.configureWithDefaultBackground()

UINavigationBar.appearance().scrollEdgeAppearance = barAppearance

搭配放大版的 navigation bar 時,scrollEdgeAppearance 控制一開始的 bar 樣式,standardAppearance 則控制向上捲動時的樣式,因此若是我們只設定 scrollEdgeAppearance 顯示紅色 bar,向上捲動時 bar 將變回灰色樣式。

let barAppearance =  UINavigationBarAppearance()
barAppearance.backgroundColor = .red
UINavigationBar.appearance().scrollEdgeAppearance = barAppearance

我們也可以設計兩種樣式, scrollEdgeAppearance 顯示紅色 bar,standardAppearance 顯示黃色 bar。因此一開始會顯示紅色,向上捲動時會顯示黃色。

let scrollEdgeAppearance =  UINavigationBarAppearance()
scrollEdgeAppearance.backgroundColor = .red
UINavigationBar.appearance().scrollEdgeAppearance = scrollEdgeAppearance
let standardAppearance = UINavigationBarAppearance()
standardAppearance.backgroundColor = .yellow
UINavigationBar.appearance().standardAppearance = standardAppearance

指定特定頁面的 navigation bar 樣式

我們也可以從 controller 的 navigationItem 設定UINavigationBarAppearance,如此將只影響此頁面的 bar 樣式。

let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithDefaultBackground()
navigationItem.standardAppearance = barAppearance

navigation bar 的背景圖片

UINavigationBarAppearance 的 backgroundImage 控制 navigation bar 的背景圖片。

let barAppearance =  UINavigationBarAppearance()
barAppearance.backgroundImage = UIImage(named: "bar")

navigation bar 的 shadow

let barAppearance =  UINavigationBarAppearance()   barAppearance.shadowColor = nil

我們可透過 shadowColor 設定 navigation bar 下方 shadow 的顏色,比方左下是預設的 shadow,右下是 shadowColor 設為 nil 後無 shadow 的模樣。

back button 的圖片

我們也可以改變 back button 的圖片,比方以下例子透過 function setBackIndicatorImage(_:transitionMaskImage:) 設定 back button 的圖片。

let barAppearance =  UINavigationBarAppearance()
let backIndicatorImage = UIImage(systemName: "arrowshape.turn.up.left.fill")
barAppearance.setBackIndicatorImage(backIndicatorImage, transitionMaskImage: backIndicatorImage)

setBackIndicatorImage 的宣告如下,我們通常將 backIndicatorImage & transitionMaskImage 設為一樣的圖片。

open func setBackIndicatorImage(_ backIndicatorImage: UIImage?, transitionMaskImage backIndicatorTransitionMaskImage: UIImage?)

button item 的樣式

利用 UIBarButtonItemAppearance 設定 button item 的樣式,然後將它存入 UINavigationBarAppearance 的 buttonAppearance。(也可以設定 backButtonAppearance 或 doneButtonAppearance)

let barAppearance =  UINavigationBarAppearance()barAppearance.configureWithTransparentBackground()let buttonAppearance = UIBarButtonItemAppearance(style: .plain)buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.red]barAppearance.buttonAppearance = buttonAppearance

navigation bar 的標題樣式

利用 titleTextAttributes 設定 navigation bar 的標題樣式,largeTitleTextAttributes 設定放大版 bar 的標題樣式。

let barAppearance =  UINavigationBarAppearance()
barAppearance.titleTextAttributes = [.foregroundColor: UIColor.red, .font: UIFont.systemFont(ofSize: 20)]

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com