本章我們會為 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 還是要有一些了解,偶爾還是需要使用到它。