09 Swift 教學10 所有文章

[Swift 教學] Swift 訂飲料App (附程式碼)

swiftOrderApp

最近參加了彼得潘的iOS App程式設計入門,此篇將會利用Firebase Database串接Swift來打造訂飲料App,如果對Swift開發有興趣的朋友,推薦參加Peter的課程唷!

此次的相關代碼放置於:https://github.com/hsuanchi/Swift_Demo/tree/master/orderAppExample

一. 最終App畫面:

二. 架構:

可以分成三個Scene,分別是Menu、訂購飲料和訂單資料

  • Menu Scene
    • ViewController
    • MenuListTableViewCell
  • 訂購飲料 Scene
    • OrderMaxTableViewController
  • 訂單資料 Scene
    • ShowOrderTableViewController

頁面一:Menu Scene

1.首先用struct來定義Menu頁內清單的型別

struct DrinkData {
    var image: String?
    var name: String?
    var price: String?
    var content: String?
    var eng_content: String?
}

2.因為UIViewController中無法拉Label,所以建立UITableViewCell來針對介面中的Label設定Outlet,並寫了update func來更新表單中的資料,詳細設定如下:

class MenuListTableViewCell: UITableViewCell {
    @IBOutlet weak var name: UILabel!
    @IBOutlet weak var price: UILabel!
    @IBOutlet weak var content: UILabel!
    @IBOutlet weak var detail: UILabel!
    @IBOutlet weak var img: UIImageView!
    
    func update(with cellData: DrinkData) {
        name.text = cellData.name
        content.text = cellData.content
        detail.text = cellData.eng_content
        price.text = cellData.price
        img.image = UIImage(named: cellData.image!)
    }
}

3.設定UIViewController內Sections和Cell行數,以及Cell要傳入的資料

// 設定Sections
    func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
// 設定cell有幾行
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellContent.count
    }
    
// 設定cell內資料
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath) as! MenuListTableViewCell
        
        let cellData = cellContent[indexPath.row]
        cell.update(with: cellData)
        
        return cell
    }

4.最後用prepare將所選到的cell資料傳遞到下個頁面

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let controller = segue.destination as? OrderMaxTableViewController, let _ = menuTableView.indexPathForSelectedRow?.section, let row = menuTableView.indexPathForSelectedRow?.row {
            controller.cellData = cellContent[row]
        }
    }

頁面二:訂購飲料 Scene

訂購飲料
訂購飲料

1.利用setCellData(with: cellData!)來接收上一頁傳遞來的資料,並用cellData.名稱來取得細項

var cellData: DrinkData?

override func viewDidLoad() {
        super.viewDidLoad()
        setCellData(with: cellData!)
    }

    func setCellData(with cellData: DrinkData) {
        nameLabel.text = cellData.name
        priceLabel.text = cellData.price
        contentLabel.text = cellData.content
        detailLabel.text = cellData.eng_content
        imgLabel.image = UIImage(named: cellData.image!)
    }

2.當使用者點擊送出訂單按鈕時,先判斷是否都有填入資料,如果判斷成功將會把資料送到Firebase Database,然後再利用self.performSegue(withIdentifier: “sendOrderDB”, sender: nil)來將畫面跳轉至下一個頁面

    @IBAction func orderSend(_ sender: Any) {
        
        if orderNameLabel.text == ""{
            print("[name] == empty")
        }else{
            db.collection("orders").addDocument(data: [
                "name": orderNameLabel.text ?? "",
                "drink": nameLabel.text ?? "",
                "price": priceLabel.text ?? "",
                "size": orderSizeLabel.titleForSegment( at: orderSizeLabel.selectedSegmentIndex) ?? "",
                "sugar": orderSugerLabel.titleForSegment( at: orderSugerLabel.selectedSegmentIndex) ?? "",
                "code": orderCodeLabel.titleForSegment( at: orderCodeLabel.selectedSegmentIndex) ?? ""
            ]) { (error) in
                if let error = error {
                    print(error)
                }
            }
        self.performSegue(withIdentifier: "sendOrderDB", sender: nil)
        }
    }

頁面三:訂單資料 Scene

1.從Firebase中撈取過去下單資料,並append進list中,再撈完資料後利用DispatchQueue.main.async{self.tableView.reloadData()}來讓tableView reload,這樣就可以顯示出所有訂單的資料囉!

 var documentId:[String] = []
 var nameList:[String] = []
 var drinkList:[String] = []
 var sizeList:[String] = []
 var sugarList:[String] = []
 var codeList:[String] = []
 var priceList:[String] = []
    
    func readData(){
        
    db.collection("orders").getDocuments { (querySnapshot, error) in
            if let querySnapshot = querySnapshot {
                for document in querySnapshot.documents {
                    self.documentId.append(document.documentID)
                    self.nameList.append(document.data()["name"] as! String)
                    self.drinkList.append(document.data()["drink"] as! String)
                    self.sizeList.append(document.data()["size"] as! String)
                    self.sugarList.append(document.data()["sugar"] as! String)
                    self.codeList.append(document.data()["code"] as! String)
                    self.priceList.append(document.data()["price"] as! String)
                }
            }
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }

        }
    }

2.讓使用者點擊cell後,可以移除此筆訂單;可以看到alert這邊是在定義待會跳出來的視窗畫面,而addAction裡面刪除db資料庫資料和刪除List 內資料,是在使用者按下確認後開始進行的動作

// 點選 cell 後執行的動作
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        let alert = UIAlertController(title: "取消此筆訂單", message: "", preferredStyle: .alert)
        
        alert.addAction(UIAlertAction(title: "再考慮一下", style: .cancel, handler: nil))
        alert.addAction(UIAlertAction(title: "確定取消 ", style: .default, handler: { _ in
            let id = self.documentId[indexPath.row]
            
            // 刪除資料庫內資料
            self.db.collection("orders").document(id).delete() { err in
                if let err = err {
                    print("Error removing document: \(err)")
                } else {
                    print("Document successfully removed!")
                }
            }
            
            // 刪除 List 內資料
            self.documentId.remove(at: indexPath.row)
            self.nameList.remove(at: indexPath.row)
            self.drinkList.remove(at: indexPath.row)
            self.sizeList.remove(at: indexPath.row)
            self.sugarList.remove(at: indexPath.row)
            self.codeList.remove(at: indexPath.row)
            self.priceList.remove(at: indexPath.row)
            self.showTableview.deleteRows(at: [indexPath], with: .automatic)
        }))
        self.present(alert, animated: true, completion: nil)
    }

相關延伸閱讀:

[Swift 教學] Swift 訂飲料App 結束囉,感謝收看,有關Max行銷誌的最新文章,都會發佈在Max的Facebook粉絲專頁,如果想看最新更新,還請您按讚或是追蹤唷!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *