#6 期末App-Hw4-咖啡廳網美

游傑如
海大 SwiftUI iOS / Flutter App 程式設計
14 min readJun 23, 2019

現在不管去哪裡,用IG記錄東西就是最常需要的啊顆顆

而網美們又最喜歡去咖啡廳, 因為可以防曬又可以拍得美美derrrrr

1. App 操作畫面

咖啡廳選單
記錄頁面

2.GitHub

btw 我試過很多方法想要正常的source control,但我都修正不了 QQ,不管是用terminal設權限或網路上的方法們…. 他仍給我一堆error,於是先讓我傳個壓縮檔吧嗚嗚嗚

3. 特製截圖

咖啡廳的列表 — 旁邊的小圖示可以顯示有沒有插座或是有沒有站的桌子
顯示地址 營業時間 與用圖表顯示各項咖啡廳擁有設施的良好程度
類 IG 介面

4.文字說明 — 以彼得潘所需的必備功能順序描述

(1.)使用 table view,搭配 UITableViewDataSource 設定 cell 內容,cell 必須使用自己定義的 cell 類別。

設定cell內容

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {let cell = tableView.dequeueReusableCell(withIdentifier: "cafeCell", for: indexPath) as! CafeListTableViewCell// Configure the cell...let node = cafes[indexPath.row]cell.storeName.text = node.namecell.storeAddress.text = node.addressif(node.open_time != "no" ){cell.storeTime.text = node.open_time}if (node.socket == "no"){cell.socket.isHidden = true}if(node.standing_desk=="no"){cell.standingDesk.isHidden = true}return cell}

cell 為自定義類別

import UIKitclass CafeListTableViewCell: UITableViewCell {@IBOutlet var socket: UIImageView!@IBOutlet var standingDesk: UIImageView!@IBOutlet weak var storeName: UILabel!@IBOutlet weak var storeAddress: UILabel!@IBOutlet weak var storeTime: UILabel!override func awakeFromNib() {super.awakeFromNib()// Initialization code}override func setSelected(_ selected: Bool, animated: Bool) {super.setSelected(selected, animated: animated)// Configure the view for the selected state}}

(2.)使用 collection view,搭配 UICollectionviewDataSource 設定 cell 內容,cell 必須使用自己定義的 cell 類別。

以一個 viewController 內拉入一個 collectionView來實作

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return records.count}func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! imageCollectionViewCellcell.image?.kf.indicatorType = .activitycell.image.kf.setImage(with: records[indexPath.row].url)/*let tmp = UIImage(named: "test")?.crop(ratio: 1.0)cell.image?.image = tmp*/return cell}func numberOfSections(in collectionView: UICollectionView) -> Int {return 1}

自定義類別

import UIKitclass MyPhotoCollectionViewCell: UICollectionViewCell {var cellimage:UIImageView?override init(frame: CGRect){super.init(frame:frame)let width = (UIScreen.main.bounds.size.width)cellimage = UIImageView(frame: CGRect(x: 0, y: 0, width: width/3-30.0, height: width/3-30.0))self.addSubview(cellimage!)}required init?(coder aDecoder: NSCoder) {super.init(coder:aDecoder)}}

(3). 點選 table view cell 或 collection view cell 可顯示明細頁面,搭配資料傳遞的功能

在 table view cell 的部分靠著連結segue並用prepare來傳遞資料

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {if let row = tableView.indexPathForSelectedRow?.row{let controller = segue.destination as? CafeDetailViewControllercontroller?.cafe = cafes[row]}}

collection view cell 則是點到會顯示裡面存的文字訊息

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {des.text = records[indexPath.row].description}

(4). 使用 tab bar controller 和 navigation controller。

(5). 串接後台的 API 顯示資料

選擇要串接哪個API就花了很多時間,因為幾乎決定了主題

選擇的是咖啡廳列表的API: https://cafenomad.tw/api/v1.2/cafes/

串接程式如下:

var cafes = [Cafe]()var search : String?
func displayTable(){if let s = search{let urlString = "https://cafenomad.tw/api/v1.2/cafes/" + sif let url = URL(string: urlString) {let task = URLSession.shared.dataTask(with: url) { (data, response, error) inif let data = data{do{let cafeResult = try JSONDecoder().decode(Array<Cafe>.self,from:data)for cafe in cafeResult{self.cafes.append(cafe)}DispatchQueue.main.async{self.tableView.reloadData()}}catch{print(error)}}}task.resume()}}}

Cafe :

internal struct Cafe : Codable{internal var id: Stringinternal var name: Stringinternal var wifi: Doubleinternal var seat: Doubleinternal var quiet: Doubleinternal var tasty: Doubleinternal var cheap: Doubleinternal var music: Doubleinternal var url: Stringinternal var address: Stringinternal var latitude: Stringinternal var longitude: Stringinternal var limited_time: Stringinternal var socket: Stringinternal var standing_desk: Stringinternal var mrt: Stringinternal var open_time: String}

(6). 使用 UIImagePickerController 選照片

在這邊選擇用來選大頭貼,原本想要用FB登入後取大頭貼的圖片來作為本APP的大頭貼,但閃退問題等未改善完全

@IBAction func editBtn(_ sender: Any) {let controller = UIAlertController(title: "ImagePick", message: "選擇照片上傳", preferredStyle: .actionSheet)let albumAction = UIAlertAction(title: "相簿選取", style: .default,handler: {(action) inself.imagePicker.sourceType = .photoLibraryself.imagePicker.allowsEditing = trueself.present(self.imagePicker,animated: true)})let cameraAction = UIAlertAction(title: "照相", style: .default,handler:nil)let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)controller.addAction(albumAction)controller.addAction(cameraAction)controller.addAction(cancelAction)present(controller, animated: true, completion: nil)}

再實作 imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any])

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]){let image = info[.originalImage] as? UIImageself.selfPhoto.image = image!.crop(ratio:1.0)imagePicker.dismiss(animated: true, completion: nil)}

(7).使用 Cocoapods 加入第三方套件。

加入的有

Charts — 圖表
GoogleMaps — Google地圖
GooglePlaces — Google地圖位置
Kingfisher — 抓圖

(8.)SheetDB

原先想使用FireBase Storage 和 DataBase 來實作照片存檔與讀檔,但申請時一直連線失敗,沒有辦法驗證通過(可能當時網路太弱了嗚嗚 因為我之後居然傳成功了…. 等我之後再改吧QQQQQ)

存東西格式

struct Record : Codable{internal var id: Stringinternal var url: URLinternal var description: String}

上傳

func post(record: Record){let url = URL(string: self.sheetDBAPI)var urlRequest = URLRequest(url: url!)urlRequest.httpMethod = "POST"urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")let recordData = RecordData(data: record)let jsonEncoder = JSONEncoder()if let data = try? jsonEncoder.encode(recordData){let task = URLSession.shared.uploadTask(with: urlRequest, from: data){(rdata,response,error) inif (error != nil){print(error)}}task.resume()}else{print("Post failed!!!!!!!!!!!!!!!!!")}}

讀取所有資料

func fetchAllData(){//https://sheetdb.io/api/v1/diogbl0jdu7zylet urlS = "https://sheetdb.io/api/v1/diogbl0jdu7zy"if let url = URL(string: urlS){let task = URLSession.shared.dataTask(with: url){(data,res,error) inif let data = data{do{let recList = try JSONDecoder().decode(Array<Record>.self,from:data)for rec in recList{self.records.append(rec)}DispatchQueue.main.async {self.collectionView.reloadData()}}catch{print(error)}}}task.resume()}}

在 viewWillAppear 重抓

override func viewWillAppear(_ animated: Bool) {records = [Record]()fetchAllData()}

5.心得

遇到很多問題讓我整個心很累….像是我想要FB登入但是閃退啊什麼的問題都有嗚嗚嗚,還有網路問題害我一整個停擺,因為宿舍裡收不太到我的網路訊號我哭….所以沒有真的完成我原先心裡所預想的 Orzzzzzz

有機會再讓我改改吧 Orzzzzzz

6. 之後想要再完成

(1)打卡功能

(2) FireBase (Storage, DataBase)

(3) FB Login

--

--