iOS| #20 | 使用GoogleMaps第三方API製作簡易版地圖App

Tommy
彼得潘的 Swift iOS / Flutter App 開發教室
11 min readJan 13, 2022

繼上次製作了簡易版音樂App後,這次要使用GoogleMaps第三方API做出簡易的地標搜尋App。

技術應用

  1. 串接GoogleMaps Place API
  2. Search Bar
  3. TableViewController 配合 UIActivityIndicatorView

成果展示

UI畫面

Model設計

  • class GoogleMapListController

這次主要的網路功能會寫在class GoogleMapListController裡面,未來要抓取資料時透過該物件來達成。

key:google 的 api-key,需要自己辦帳號申請。
shared:為實體化的自己,未來調用function時會透過他來執行,這樣可以省去實體化的步驟。
func fetchNearbySearch(location: , keyword: , completion: ):搜尋地標。
func fetchPlaceDetail(place_id: , completion: ):搜尋地標詳細資訊。
func getPhoto(url: , completion: ):抓圖片。

相關程式碼解說可參考iOS| #17,這邊不再贅述。

  • 根據API文件將需要的欄位宣告成struct型態,未來decode會使用到。(記得要遵從Codable,才可用於解析)

Place Search — NearbySearch

  • struct ListResponse
  • struct itemResults

Place Details — Place Details Requests

  • struct DetailResponse
  • struct InfoResults
  • struct PhotosResults
  • struct Reviews

功能解說&程式解說

  • 實作Search Bar

首先在InterFace Builder拉好Search Bar

拉好IBOutlet

指派delegate為self

遵從UISearchBarDelegate,並且實作方法:
1. func searchBar(_ searchBar: , textDidChange searchText: ):搜尋文字改變時會觸發
2. func searchBarSearchButtonClicked(_ searchBar: ):點擊search後會觸發

根據需求撰寫程式:當使用者輸入SearchBar時,上網抓取相關資料帶入。
注意:更新UI介面的程式要放到main thread執行。

  • 研究 Place API

首先要

  1. 先申請帳號取得API KEY,參考此文章
  2. 看懂Google 官方的 Place API 文件說明

Place Search — NearbySearch

透過下圖可得知:

  1. output 為想要解析的格式
  2. url 為 https://maps.googleapis.com/maps/api/place/nearbysearch/output?parameters

接下來我們需要知道要傳什麼參數進去

必輸 parameters 為:

  1. location:經緯度
  2. radius:搜索範圍的半徑,在這邊雖然被歸類為選填的parameters,但實測後要搭配location一起輸入才會搜尋到結果,因此我個人認定為必輸。
  3. key:google 的 api key

接回來JSON檔後我們再根據上述Model宣告的格式解析就可以得到我們想要的資料。

Place Details — Place Details Requests

透過下圖可得知:

  1. output 為想要解析的格式
  2. url 為 https://maps.googleapis.com/maps/api/place/details/output?parameters

接下來我們需要知道要傳什麼參數進去

必輸 parameters 為:

  1. place_id :地點的id
  2. key:google 的 api key

接回來JSON檔後我們再利用上述Model宣告的物件 class GoogleMapListController 解析就可以得到我們想要的資料。

  • 評論/圖片頁面顯示
  1. 拉好Segue,並實作@IBSegueAction

2. 在ListTableViewController選擇地標後進入下一頁,因此要實作func tableView(_ tableView: , didSelectRowAt indexPath: )

3. 到下一頁(ReviewsViewController),在viewDidLoad()抓資料,並且更新UITableView、UICollectionView。

  • TableViewController 配合 UIActivityIndicatorView

由於第一頁(ListTableViewController)是使用TableViewController,經過實測後發現沒辦在storyboard上拉一個UIActivityIndicatorView直接蓋在上面,因此在這邊使用程式碼做出一個loading中的View蓋在我們的TableViewController上。

實際作法如下:

  1. 建立一個view,裝著UIActivityIndicatorView、UILabel,並將view作為Subview加進tableView中

宣告UIView、UIActivityIndicatorView、UILabel作為屬性

實作func setActivityIndicatorView()

定義loadingView的寬高,並且將位置設定在畫面的正中間
計算 y 座標要注意扣除navigationBar的高度,這樣才能算出tableView正中間的位置

let width: CGFloat = 120let height: CGFloat = 30let x = (tableView.frame.width / 2) - (width / 2)let y = (tableView.frame.height / 2) - (height / 2) - (navigationController?.navigationBar.frame.height)!loadingView.frame = CGRect(x: x, y: y, width: width, height: height)

設定loadingLabel的字樣與位置

// Sets loading textloadingLabel.textColor = .grayloadingLabel.textAlignment = .centerloadingLabel.text = "Loading..."loadingLabel.frame = CGRect(x: 0, y: 0, width: 140, height: 30)

設定UIActivityIndicatorView的style與位置

// Sets spinneractivityIndicator.style = .mediumactivityIndicator.frame = CGRect(x: 0, y: 0, width: 30, height: 30)activityIndicator.startAnimating()

將loadingLabel、activityIndicator作為Subview加進loadingView中;
再將loadingView作為Subview加進tableView中。

// Adds text and spinner to the viewloadingView.addSubview(loadingLabel)loadingView.addSubview(activityIndicator)tableView.addSubview(loadingView)

完整程式碼:

以上程式碼在viewDidLoad()中呼叫

2. 當搜尋時才要顯示loading的view,搜尋完畢就隱藏

因為是搜尋時才要顯示,所以換句話說是在SearchBar的值有變動時func searchBar(_ searchBar: , textDidChange searchText: )要做事

func showActivityIndicatorView() { loadingView.isHidden = false }func hideActivityIndicatorView() { loadingView.isHidden = true }

3. 一開始進來畫面因為還沒搜尋,所以預設隱藏

若內容有誤煩請指教,感謝收看。

--

--