iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
生成式 AI

iOS? AI-Yes!:用 Vide Coding 加速我的 Swift 學習曲線系列 第 28

Day 28 - 【天氣實戰 III】打造互動地圖:MapKit 應用與畫面呈現

  • 分享至 

  • xImage
  •  

昨天,我們完成了顯示天氣詳情的核心功能模組。然而,使用者還無法選擇他們想看的地區。

今天,我們就要來完主入口畫面。我們將使用 MapKit 框架,打造一個以台灣地圖為基礎的互動介面,讓使用者可以直觀地在地圖上點擊城市,進而查詢該地區的天氣資訊。

  • 困惑點:我想在 App 的主畫面加上一個地圖,並在上面標示出台灣所有主要的城市。當使用者點擊這些標示時,要如何觸發事件,並跳轉到對應城市的天氣頁面呢?

  • AI 協作

    • 我的 Prompt我希望在 App 的主畫面加上一個地圖,顯示台灣所有主要城市的大頭針。當使用者點擊大頭針時,就跳轉到該城市的天氣頁面。請問在 iOS 中,實現這個功能的核心框架是什麼?以及如何處理地圖上的點擊事件?

    AI 的回答:

    要為您的 iOS App 實現這個功能,核心框架是 MapKit


    核心框架:MapKit

    MapKit 是 Apple 提供的原生地圖框架,它允許您在應用程式中嵌入地圖,並能自由地操作地圖資料。使用 MapKit 您可以:

    • 顯示地圖,並控制其顯示區域和縮放等級。
    • 添加地圖標註 (Annotations),也就是您所說的「大頭針」,來標記特定位置。
    • 處理使用者與地圖的互動,例如點擊地圖或標註。

    如何處理地圖上的點擊事件

    處理點擊事件主要有兩個步驟:

    1. 添加地圖標註 (Annotations):首先,您需要為台灣所有主要城市建立相應的 MKPointAnnotation 物件,每個物件都包含該城市的座標。將這些物件添加到您的 MKMapView 中,App 就會在地圖上顯示出這些「大頭針」。
    2. 實作代理協定 (Delegate Protocol)MKMapView 有一個代理 (delegate) 屬性,您可以將它設定為您的視圖控制器 (view controller)。當使用者點擊任何一個地圖標註時,MapKit 會呼叫代理協定中的特定方法,例如 mapView(_:didSelect:)。在這個方法中,您可以取得使用者點擊的標註資訊,並依據其所代表的城市,執行跳轉到對應天氣頁面的邏輯。

    簡而言之,MapKit 提供了您所需的一切工具,讓您能夠輕鬆地在地圖上展示資料並處理使用者的互動。

    • 根據 AI 的建議,我把詳細的實作步驟整理如下:
      1. 建立主畫面與地圖:在 MainViewController 中,初始化一個 MKMapView,並將其設定為顯示整個台灣的視圖。
      2. 在地圖上標註城市:建立一個包含台灣所有主要縣市與其對應經緯度的字典,並使用迴圈將它們批量生成為 MKPointAnnotation 加到地圖上。
      3. 捕捉地圖點擊事件:讓 MainViewController 遵守 MKMapViewDelegate,並實作 mapView(_:didSelect:) 方法。
      4. 實現頁面跳轉與傳值:在 didSelect 方法中,呼叫一個 MapsToWeather(for:) 函式,它會建立 AreaViewController 的實例,將被點擊的城市名稱傳遞過去,並以 Modal 方式呈現。

步驟一:建立主畫面與地圖 (MainViewController)

我們的 MainViewController 將作為 App 的入口。

  1. 建立 MainViewController.swift 及其 .xib 檔案。
  2. 打開 MainViewController.xib,從元件庫拖曳一個 Map Kit View 到畫布上,並設定其 Auto Layout 約束使其填滿整個安全區域。
  3. MKMapViewMainViewController.swift 檔案連結成 IBOutlet,命名為 mapView
  4. viewDidLoad 中呼叫 setupMapView(),設定地圖的初始狀態。

檔案:Views/MainView/MainViewController.swift

import UIKit
import MapKit

class MainViewController: UIViewController {
    
    // MARK: - IBOutlet
    @IBOutlet weak var mapView: MKMapView!
    
    // MARK: - Property
    let areas = ["臺北市", "新北市", "桃園市", "臺中市", "臺南市", "高雄市", "基隆市", "新竹縣", "新竹市", "苗栗縣", "彰化縣", "南投縣", "雲林縣", "嘉義縣", "嘉義市", "屏東縣", "宜蘭縣", "花蓮縣", "臺東縣", "澎湖縣", "金門縣", "連江縣"]
    let cityCoordinates: [String: CLLocationCoordinate2D] = [
        "臺北市": CLLocationCoordinate2D(latitude: 25.0330, longitude: 121.5654),
        "新北市": CLLocationCoordinate2D(latitude: 25.0169, longitude: 121.4628),
        "桃園市": CLLocationCoordinate2D(latitude: 24.9936, longitude: 121.2908),
        "臺中市": CLLocationCoordinate2D(latitude: 24.1477, longitude: 120.6736),
        "臺南市": CLLocationCoordinate2D(latitude: 22.9997, longitude: 120.2133),
        "高雄市": CLLocationCoordinate2D(latitude: 22.6273, longitude: 120.3014),
        "基隆市": CLLocationCoordinate2D(latitude: 25.1276, longitude: 121.7392),
        "新竹縣": CLLocationCoordinate2D(latitude: 24.8423, longitude: 121.0116),
        "新竹市": CLLocationCoordinate2D(latitude: 24.8039, longitude: 120.9687),
        "苗栗縣": CLLocationCoordinate2D(latitude: 24.5602, longitude: 120.8148),
        "彰化縣": CLLocationCoordinate2D(latitude: 24.0524, longitude: 120.5161),
        "南投縣": CLLocationCoordinate2D(latitude: 23.9125, longitude: 120.9328),
        "雲林縣": CLLocationCoordinate2D(latitude: 23.7121, longitude: 120.4320),
        "嘉義縣": CLLocationCoordinate2D(latitude: 23.4500, longitude: 120.2500),
        "嘉義市": CLLocationCoordinate2D(latitude: 23.4801, longitude: 120.4491),
        "屏東縣": CLLocationCoordinate2D(latitude: 22.5513, longitude: 120.5433),
        "宜蘭縣": CLLocationCoordinate2D(latitude: 24.7021, longitude: 121.7378),
        "花蓮縣": CLLocationCoordinate2D(latitude: 23.9871, longitude: 121.6016),
        "臺東縣": CLLocationCoordinate2D(latitude: 22.7972, longitude: 121.0714),
        "澎湖縣": CLLocationCoordinate2D(latitude: 23.5701, longitude: 119.5663),
        "金門縣": CLLocationCoordinate2D(latitude: 24.4411, longitude: 118.3184),
        "連江縣": CLLocationCoordinate2D(latitude: 26.1517, longitude: 119.9575)
    ]
    
    // MARK: - LifeCycle
    override func viewDidLoad() {
        super.viewDidLoad()
        setupMapView()
        addAnnotations()
    }
    
    // MARK: - UI Setting
    func setupMapView() {
        mapView.delegate = self
        mapView.mapType = .hybrid
        let center = CLLocationCoordinate2D(latitude: 24.1477, longitude: 120.6736)
        let span = MKCoordinateSpan(latitudeDelta: 4.0, longitudeDelta: 4.0)
        let region = MKCoordinateRegion(center: center, span: span)
        mapView.setRegion(region, animated: true)
    }
    
    // MARK: - Function
    func addAnnotations() {
        for area in areas {
            if let coordinate = cityCoordinates[area] {
                let annotation = MKPointAnnotation()
                annotation.title = area
                annotation.coordinate = coordinate
                mapView.addAnnotation(annotation)
            }
        }
    }
    
    func navigateToWeather(for city: String) {
        let areaVC = AreaViewController()
        areaVC.selectedArea = city
        let navVC = UINavigationController(rootViewController: areaVC)
        self.present(navVC, animated: true, completion: nil)
    }
}

步驟二:捕捉地圖點擊事件與頁面跳轉

當使用者點擊地圖上的大頭針時,我們需要捕捉這個事件,並將使用者導向對應的 AreaViewController

檔案:Views/MainView/MainViewController.swift (Extension)

// MARK: - MKMapViewDelegate
extension MainViewController: MKMapViewDelegate {
    
    func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
        guard let cityName = view.annotation?.title, let unwrappedCityName = cityName else { return }
        navigateToWeather(for: unwrappedCityName)
        mapView.deselectAnnotation(view.annotation, animated: true)
    }
}

今日總結

今天,我們為天氣 App 打造了一個美觀且直觀的入口。透過整合 MapKit,使用者現在可以透過點擊地圖上的城市大頭針,輕鬆地查詢該地區的詳細天氣預報。

我們的天氣實戰 App 核心功能已經全部完成!從明天開始,我們將進回顧這 20 多天來的學習歷程,並展望在 AI 時代下,身為 iOS 開發者的我們,未來將會面臨哪些新的機會與挑戰。

image image

Simulator Screen Recording - iPad (A16) - 2025-07-26 at 15.25.26 Simulator Screen Recording - iPhone 16 Pro - 2025-09-02 at 14.18.29


上一篇
Day 27 - 【天氣實戰 II】導入 MVVM 架構與 UI 搭建
系列文
iOS? AI-Yes!:用 Vide Coding 加速我的 Swift 學習曲線28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言