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. 將 MKMapView 與 MainViewController.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 搭建
下一篇
Day 29 - 【完賽前回顧】AI 時代下,身為 iOS 開發者的變與不變
系列文
iOS? AI-Yes!:用 Vide Coding 加速我的 Swift 學習曲線 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言