本章我們會為 Coffee Shop App 加入菜單的畫面。這畫面中,我們會使用到 TabView, ZStack, Image, 和 GeometryReader 這些新的 UI 元件。另外,還會介紹如何設定 List 的背景顏色,以及如何自訂字體和大小。
SwiftUI Coffee Shop
加入 TabView
新增一個資料夾叫 Menu,然後它下面新增一個 SwiftUI View 叫 MenuView,這會是菜單的主頁面。
回到 ContentView,在裡面加入 TabView。TabView 裡面有 ProductListView 和 MenuView 兩個頁面。這樣就有 TabBar 出現了。
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
ProductListView()
}
.tabItem {
Image("ShopIcon")
Text("Shop")
}
MenuView()
.tabItem {
Image("MenuIcon")
Text("Menu")
}
}
}
}在 .tabItem 中,我們要設定 Tab 的圖示還有 Tab 的標題。用 Image 就可以顯示圖片。Image 的參數是 Assets.xcassets 中的 Image Set 名稱。下面已經準備好這兩個 Tab 圖示,請先新增到 Assets.xcassets,並分別命名為 ShopIcon 和 MenuIcon。
然後執行一下程式,看看剛剛加入的 TabView 吧。

菜單與背景圖
現在來替 MenuView 加上背景圖,這樣整體會比較像一般紙本的 Menu。下載下面的背景圖片,新增到 Assets.xcassets,並命名為 MenuBackground。
MenuView 的 Layout 如下方程式碼。ZStack 相對於 VStack/HStack,它是前後的順序。所以會先是背景圖 MenuBackground,然後前方是商品列表。
我們對背景圖呼叫 .resizable() 讓它可以填滿畫面。這是因為背景圖的尺寸和螢幕不是很合,而我們又不希望會有留白的地方。可以試著將 .resizable() 移除,看看效果會是怎樣。
MenuView 是被 TabView 包起來。所以我們希望 MenuView 的 Heigh 是不包含 TabBar 的。為了要取得不含 TabBar Height 的 Height,就要用 GeometryReader。如果不用 GeometryReader 的話,背景圖會延伸到 TabBar 的後面去。
背景圖的上方和下方有一些圖案,我們希望商品列表不要遮蓋到,所以將列表的高度縮小。
MenuView 的建構子裡,那 4 行是為了要將 List 的背景設為透明,還有隱藏分隔線。UITableView 是 UIKit 的,而 List 是 SwiftUI 的。兩者都是用來顯示列表的,而且 List 的底層是用 UITableView 實作的。目前 List 不支援設定透明的方法,所以只好透過 UITableView 來設定。
struct MenuView: View {
@FetchRequest(entity: Product.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Product.name, ascending: false)])
var products: FetchedResults<Product>
init() {
UITableView.appearance().backgroundColor = .clear
UITableViewCell.appearance().backgroundColor = .clear
UITableView.appearance().separatorStyle = .none
}
var body: some View {
GeometryReader { proxy in
ZStack {
Image("MenuBackground")
.resizable()
List {
ForEach(self.products, id: \.id) { product in
MenuRowView(product: product)
}
}
.frame(width: proxy.size.width * 0.75, height: proxy.size.height * 0.65)
}
.frame(width: proxy.size.width, height: proxy.size.height, alignment: .topLeading)
}
}
}商品列
在 Menu 資料夾下新增 MenuRowView,並貼上以下的程式碼。整個商品列是一個 Button,所以點擊列就可以點餐,點餐的部分會在下一張講解。
商品列的左邊是商品名稱,右邊是商品價格。用 .font() 設定成 Georgia 字體,以及大小為 24。.foregroundColor() 是設定字體顏色。所新增一個叫 MenuTextColor 的 Color Set,而且顏色設為 #1A0D02。
struct MenuRowView: View {
let product: Product
var body: some View {
Button(action: {
// Add an action later
}) {
HStack {
Text(product.name ?? "")
.font(.custom("Georgia", size: 24))
.foregroundColor(Color("MenuTextColor"))
Spacer()
Text(String(format: "$ %.2f", product.price))
.font(.custom("Georgia", size: 24))
.foregroundColor(Color("MenuTextColor"))
}
}
.buttonStyle(PlainButtonStyle())
.frame(height: 36)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}
}執行一下程式,我們已經完成菜單的畫面。

結語
本章中使用了 UITableView 來設定列表的背景顏色。這表示 SwiftUI 的功能還不是那麼地完整,畢竟它還很新。所以對 UIKit 還是要有一些了解,偶爾還是需要使用到它。









