#40 串接 TIH API - present, shouldPerformSegue, AlertController & prepare
reviews, website & map
本篇為實作 present 呈現網頁,加入 shouldPerformSegue 決定跳出 AlertController 或執行 prepare 顯示 reviews 及 map
繼前兩篇介紹了 TIH 及其 API 及部分APP應用的實作
接下來將介紹其餘在APP上的實作部分:
顯示 reviews
利用 shouldPerformSegue 分辨不同 segue
present 跳出 AlertController
顯示自訂 Date 格式
顯示飯店 map
prepare 傳遞資料
present 呈現 website
顯示 reviews、利用 shouldPerformSegue 分辨不同 segue & present 跳出 AlertController
看到 JSON 裡有旅客對飯店的 reviews (評論),這裡也是用 function prepare 去傳遞資料,但若是有 function shouldPerformSegue 則在執行 prepare 前會先執行 shouldPerformSegue。
仔細觀察,發現有時 reviews 也會是空的!!
若是在同一頁面會傳出資料到不同頁面,注意 shouldPerformSegue 的參數 identifier,就得設定 segue 的 identifier,才可分辨是專指哪一條 segue
若 reviews 的 array 是空的則會跳出 AlertController 提醒 user;
//決定segue要不要執行
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "reviewSegue", hotel?.reviews.isEmpty == true {
let alert = UIAlertController(title: "NO REVIEW YET !", message: "To return, click on Close ", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .default))
present(alert, animated: true)
return false
}
return true
}
反之,則顯示 reviews 在 ReviewTableViewController
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return reviews.count
}
func configuration(_ cell: ReviewTableViewCell) {
cell.authorNameLabel.frame = CGRect(x: 10, y: 30, width: 150, height: 25)
cell.authorNameLabel.adjustsFontSizeToFitWidth = true
cell.ratingLabel.font = .systemFont(ofSize: 12, weight: .semibold)
cell.textTextView.backgroundColor = .systemGray6
cell.textTextView.textColor = .black
cell.textTextView.layer.cornerRadius = 10
cell.timeLabel.frame = CGRect(x: 30, y: 120, width: 130, height: 25)
cell.timeLabel.font = .systemFont(ofSize: 13, weight: .regular)
cell.timeLabel.textAlignment = .right
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "\(ReviewTableViewCell.self)", for: indexPath) as! ReviewTableViewCell
configuration(cell)
let review = reviews[indexPath.row]
cell.authorNameLabel.text = review.authorName
cell.ratingLabel.text = review.rating.description
cell.textTextView.text = review.text
//顯示時間
let newDateFormatter = DateFormatter()
newDateFormatter.dateFormat = "MMMM d, yyyy"
cell.timeLabel.text = newDateFormatter.string(from: review.time)
for star in cell.starImageViews {
star.image = nil
star.image = UIImage(systemName: "star")
star.tintColor = .systemGray5
}
let rating = review.rating
let starRagne = Int(rating)-1
if rating != 0 {
for star in 0...starRagne {
cell.starImageViews[star].tintColor = .systemYellow
cell.starImageViews[star].image = UIImage(systemName: "star.fill")
if rating - Double(Int(rating)) > 0 {
cell.starImageViews[Int(rating)].tintColor = .systemYellow
cell.starImageViews[Int(rating)].image = UIImage(systemName: "star.leadinghalf.filled")
}
}
}
return cell
}
AlertController 可參考
顯示自訂 Date 格式
在上一篇解釋如何讓程式看懂 JSON 的 Date 格式,現在要呈現出我們自己想要的時間格式。
同樣的,需要 DateFormatter() 幫忙
//顯示時間
let newFormatter = DateFormatter()
newFormatter.dateFormat = "MMMM d, yyyy"
cell.timeLabel.text = newFormatter.string(from: review.time)
一樣是用 DateFormatter() 的參數 dateFormat 去設定想要的 Date 格式。
特別注意:要顯示時間的來源,則是用 DateFormatter() 的參數 string(from: ) 去設定其來源。
結果可參考上圖右。
顯示飯店 map、prepare 傳遞資料
除了顯示 reviews 用到 function prepare ,顯示飯店 map 同樣也用到 function prepare !
所以它們的 source (起始頁面) 一樣,destination (終點頁面) 不一樣,
用 segue 的 destination 型別分辨要傳什麼資料
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destoination = segue.destination as? ReviewTableViewController {
destoination.reviews = hotel!.reviews
} else if let destination = segue.destination as? MapViewController {
destination.hotel = hotel
}
}
在 destination 頁面自訂型別並遵從 UIViewController,新增 Map Kit View 及拉好 IBOutlet,import MapKit 及宣告好要承接資料的屬性 var hotel: Hotel?
JSON 裡也有給座標,同樣解析後就可以使用了
要顯示地圖需要用到:
CLLocationCoordinate2D(latitude:, longitude:) 設定座標,
在把座標丟進 MKCoordinateRegion 設為 center 及設好範圍,
之後用 Map Kit View 的 Method setRegion() 把設好的 center 及範圍丟進去
最後,設定地圖上的註解,利用 MKPointAnnotation()
hotelMapView.frame = CGRect(x: 0, y: 0, width: 393, height: 700)
if let latitude = hotel?.location.latitude,
let longitude = hotel?.location.longitude {
//defining the coordinate via latitude and longitude
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
//defining the center and range(meter) of the map
let mapRange = MKCoordinateRegion(center: location, latitudinalMeters: 1000, longitudinalMeters:520)
//show the map
hotelMapView.setRegion(mapRange, animated: true)
let annotation = MKPointAnnotation()
//defining the coordinate of annotation
annotation.coordinate = location
annotation.title = hotel?.name
annotation.subtitle = "Hotel"
//show the annotation on the map
hotelMapView.addAnnotation(annotation)
hotelMapView.showsScale = true
}
present 呈現 website
發現 JSON 給的飯店網址有的不是很完整,少了 https:// ,以至於無法顯示,只能自己幫它補齊了
@IBAction func pressWebsiteButton(_ sender: Any) {
if hotel?.officialWebsite.contains("https://") == false {
let urlString = "https://\(hotel!.officialWebsite)"
print(urlString)
if let url = URL(string: urlString) {
let browser = SFSafariViewController(url: url)
present(browser, animated: true)
}
} else {
if let url = URL(string: hotel!.officialWebsite) {
let browser = SFSafariViewController(url: url)
present(browser, animated: true)
}
}
}