上一章中我們完成了菜單的畫面,本章會加入點餐的動作。我們會介紹如何使用 ActionSheet 這個 UI 元件。此外,還會介紹如何在 Swift 使用 Singleton 物件。這是常常使用的技巧。
SwiftUI Coffee Shop
加入 ActionSheet
點餐的動作是,點擊商品列,會顯示 ActionSheet
,詢問是否要將此商品加入到帳單。畫面如下:
所以首先我們要加上 ActionSheet。回到 MenuRowView
,新增下方的程式碼到 Button
。
對 Button
呼叫 .actionSheet(isPresetned:)
,如果 showingActionSheet
是 true
的話,就會顯示裡面的 ActionSheet
。
ActionSheet
的第一個參數標題。第二參數是按鈕。第一個按鈕是可自訂動作的按鈕。第二個按鈕是預設的 Destructive 按鈕,它會顯示紅色的字,而且沒有任何動作。當你點擊任一個按鈕後,showingActionSheet
會自動被設為 false
。
struct MenuRowView: View { ... @State var showingActionSheet = false var body: some View { Button(action: { self.showingActionSheet = true }) { ... } ... .actionSheet(isPresented: self.$showingActionSheet) { ActionSheet(title: Text(product.name ?? ""), buttons: [ .default(Text("Add")) { OrderManager.shared.add(product: self.product) }, .destructive(Text("Cancel")), ]) } ... } }
訂單管理
剛剛的第一個按鈕中,我們會將商品加入一個叫 OrderManager
的物件中,他會紀錄所有被點的商品。
在 Model 資料夾下新增 OrderManager
和 Order
,程式碼如下方。OrderManager 會管理數筆訂單。而 Order
代表一筆訂單,它紀錄著商品的資訊和數量。OrderManager
提供 add(product:)
方法可以加入商品。如果商品的訂單已經存在,則增加數量。
我們希望 OrderManager
在整個 App 裡面只有一個實體,以便於管理,這也叫做 Singleton。它是用來管理訂單,所以不需要多於一個實體。因此,我們宣告一個靜態的 Property 叫 shared
。整個程式都會透過 shared
來存取這個唯一的 OrderManager
。
class OrderManager { static let shared = OrderManager() var orders: [Order] = [] func add(product: Product) { guard let id = product.id else { return } if let index = orders.firstIndex(where: { $0.id == id }) { orders[index] = orders[index].increased() } else { let order = Order(id: id, name: product.name ?? "", price: product.price, quantity: 1) orders.append(order) } } }
struct Order { let id: UUID let name: String let price: Double var quantity: Int func increased() -> Order { var copy = self copy.quantity += 1 return copy } }
結語
SwiftUI 將 Button 整合了 ActionSheet,使它們變為更為好用。在 UIKit 中,這兩個元件是完全獨立的,所以在使用上也就沒有這麼地方便。另外,我們還介紹了 Singleton 的使用方式。我們常常會建立一些 class,而且希望整個 App 中只會有那一個實體。這時候我們就會用 Singleton 來實作。在 Swift 中,Singleton 的物件常常會用 shared、default、instance 等這幾個來作為靜態變數的名稱。