高雄公共運輸App:Part3-Ubike

顯示Ubike站點詳細資訊以及追蹤使用者位置

Poga
彼得潘的 Swift iOS / Flutter App 開發教室
8 min readFeb 15, 2022

--

功能

  • 追蹤使用者位置以及在地圖上顯示所有的站點位置
  • 可搜尋指定行政區資料
  • 按照距離進行資料排序,由近到遠
  • 顯示每個站點的詳細資訊,內容:行政區、地址、總車位、剩餘車輛、與使用者距離、預估步行時間、剩餘車輛比例、收藏功能(尚未開放)
  • 點擊站點後地圖會跳轉到該點位置,點擊右上角圖標可以跳轉回使用者位置

作法

  • 使用CLLocationManager追蹤使用者位置
  • 使用UIPickerView顯示搜尋的行政區清單
  • 使用sorted(by:)進行資料排序
  • 串接高雄城市資料平台提供的API取得動態Ubike資訊
  • 使用UIBezierPath繪製圓餅圖

畫面製作

  • 使用ViewController
  • 加入MapView & TableView
  • 搜尋功能使用PickerView+ToolBar

API

API網址:

資料平台連結:

解析JSON格式自訂資料型別

  • updated_at:資料更新時間

這筆資料在API的JSON資料中是有底線的名稱,使用CodingKey將名稱改為我們需要的updatedAt,關於CodingKey的使用可以參考下方Peter的文章連結

CodingKey文章連結:

UbikeFetcher

負責下載Ubike資料的類別,使用ResultType定義下載結果,回傳資料或是錯誤

資料下載&資料排序

下載

  • 使用UbikeFetcher.shared.fetchUbikeData在ViewController下載資料,資料下載成功後進行資料排序,最後對TableView進行reload,如果下載失敗會提醒使用者,並讓使用者確認完網路狀態後進行重新下載

資料排序

  • 聲明一個Dictionary,這是負責接收每筆資料的順序以及每筆資料裡的站點與使用者的距離
  • 聲明一個最後接收已排序資料的Array
  • 第一個迴圈:先將每筆資料的經緯度與使用者位置的經緯度進行計算取得距離,然後資料的順序以及距離加入到Dictionary中
  • 將所有的資料加入到Dictionary後使用sorted(by:)對距離由小排到大進行排序,再存到常數內這時這個常數就是已經排序好的Dictionary
  • 第二個迴圈:從排序好的Dictionary中每筆資料,我們需要的是它的Key也就是原本那筆資料的位置,然後從我們下載下來的資料中將原位置的資歷取出並存進接受排序資料的Array中

計算經緯度距離的function

地圖-MKMapViewDelegate、CLLocationManagerDelegate

使用地圖功能都要記得import MapKit!!!

  • addUseUserLocation:生成實體的CLLocationManager(),讓ViewController成為他得delegate,(.desiredAccuracy)這個可以設定我們追蹤的精度,為了判定使用者與站點距離的精確程度這邊我設定為最高精度,然後請求使用者同意App追蹤他的位置,這邊會需要在Info裡設定個東西好面會提到,然後讓MapView去顯示使用者位置
  • addUbikeStation:使用迴圈將所有的站點的經緯度取出,並用MKPointAnnotation標記上去

請求使用者同意追蹤

  • 在Info裡加入Privacy-Location When In Use Usage Description,當使用者打開的時候會跳出Alert請求使用者同意

搜尋功能-UIPickerView、UIToolBar

按下右上角的放大鏡,PickerView跟ToolBar就會顯示出來,這邊是用isHidden去控制顯示與隱藏

聲明一個空Array裝搜尋結果

UIPickerViewDataSource

#我都不知道原來高雄市現在行政區有這麼多…😅

UIToolBar

  • 每次搜尋都先把搜尋結果的Array清空
  • 檢查行政區是否包含搜尋的行政區名,如果有就裝進搜尋結果的Array中
  • 檢查是否有搜尋到東西,如果沒有就跳出Alert通知使用者該地區沒有Ubike

站點顯示-UITableViewDataSource、UITableViewDelegate

UITableViewDataSource

  • 檢查是否有下載到資料
  • 檢查搜尋結果是否是空的,有搜尋結果就顯示搜尋結果,因為我們每次下載資料以及搜尋前都會清空搜尋結果,所以有資料代表有搜到東西,以搜尋結果顯示為主
  • section Header顯示更新時間,API裡會有我們下載的時間

UITableViewDelegate

  • 檢查是否有搜尋結果,如果有點擊後就從搜尋結果調取資料裡的經緯度
  • 如果沒有搜尋則是從排序好的資料中取出該位置的經緯度,並顯示在地圖上

返回使用者位置

有時候使用者可能左滑滑右滑滑看看附近的地標又或是去點選其他地區不是在附近的站點,這時候就能點擊右上角的圖標返回到使用者地點

遇到的問題

地圖顯示問題

在畫面一打開時,我將地圖顯示使用者位置寫在addUseUser,那這個function我在viewDidLoad的時候會呼叫,會遇到一個問題就是畫面一開始是顯示不出使用者位置與地圖的,我後來將地圖顯示改寫在viewDidAppear後這個問題就解決了

百分比圓餅圖問題

昨天文章上傳後才發現一個大大大問題,自己在試用的時候發現,TableView往下滑後一直往layer上面重複疊上新的layer造成越往下滑圓餅圖跟百分比對不上,問題找了很久後來跟Peter詢問過後才發現問題

解決方法:

在每個Cell內初始空的CAShapeLayer讓這兩個去承接傳進來的百分比所繪製的圖,然後在cellForRowAt的時候把這兩個CAShapeLayer加入到percentageView中

模擬機操作畫面

實機畫面

--

--