🗺️

iOSアプリでのGoogleマップ活用[基本編](ポリライン・ポリゴン・マーカー・現在地表示・地図種類の変更など)

2024/12/10に公開

はじめに

  • GoogleマップをiOSアプリで表示させる方法については、前回の記事に記載しているのそちらを参照してくだいさい。この記事はその続きからとなっています。
  • 全ては網羅することはできていませんが、よく使う設定や機能などを紹介させていただきます。
  • 記事の途中ではソースコードは抜粋となっておりますが、最後に全てのコードをまとめたものを貼り付けています。
  • 本記事を作成した時点では紹介している機能を利用するだけであれば、無料で行うことができましたが、今後も無料で使用できるとは限りませんので、必ず公式ドキュメントや利用規約をご確認いただき、ご自身の責任で適切に設定・管理を行ってください。
  • 本記事内で紹介するサービスや機能の利用に伴う料金の発生や、その他の損害については一切の責任を負いかねます。

筆者の利用・実行環境

  • macOS Sonoma 14.6
  • Xcode 16.1
  • Maps SDK 9.2.0
  • Swift 5
  • UIKit
    ※StoryboardとSwiftUIは使用しません。

オプションの説明

地図の種類

地図の種類については4種類変更が可能です。

デフォルトの地図ビュー

mapView.mapType = .normal

衛星写真を表示

mapView.mapType = .satellite

地形を強調した地図

mapView.mapType = .terrain

山がある方が分かりやすいため、参考画像を一枚追加してあります。

衛星写真と道路名を組み合わせた地図

mapView.mapType = .hybrid

UI要素のカスタマイズ

現在地ボタン

現在地の表示する方法については、後述しますが、SDK側で現在地ボタンが提供されています。
ONにすると、右下にボタンが表示されます。

mapView.settings.myLocationButton = true

コンパス表示

通常時はコンパスは表示されないのですが、マップを回転させるとコンパスが右上に表示されます。コンパスをタップすると、北が上になるようにマップが回転します。

mapView.settings.compassButton = true 

階数ピッカー表示

階数が取得できる場所に移動すると階数ピッカーが右下に表示されます。
OFFにすると、表示されなくなります。

mapView.settings.indoorPicker = true

データ表示

リアルタイムの交通情報表示

mapView.isTrafficEnabled = true

建物の2D/3D表示

mapView.isBuildingsEnabled = true //3D表示

mapView.isBuildingsEnabled = false //2D表示

初期カメラの位置

初期カメラの位置は「中心点の緯度」「中心点の経度」「ズームレベル」の三つの情報を指定することで可能になります。
例えば今回は東京駅を中心にズームレベル15を設定してマップ表示をしてみたいと思います。

let options = GMSMapViewOptions()
//「緯度」「経度」「ズームレベル」を指定
options.camera = GMSCameraPosition.camera(withLatitude: 35.681236, longitude: 139.767125, zoom: 15) 
options.frame = self.view.bounds
let mapView = GMSMapView(options: options) //GoogleMapViewのインスタンスを生成
view.addSubview(mapView) // マップビューを画面に追加

マップ上への描画

今度はマップ上にマーカー・ポリライン・ポリゴンを表示する方法コードを紹介したいと思います。
参考画像はまとめて一つにさせていただきます。
マーカー:東京駅にピンを表示(タップ時に詳細情報表示)
ポリライン:東京駅から大手町駅に線を引く
ポリゴン:東京駅と有楽町駅と東銀座を結ぶ

マーカー(ピン)

let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: 35.681236, longitude: 139.767125) // 東京駅
marker.title = "東京駅"
marker.snippet = "東京都千代田区丸の内"
marker.map = mapView

ポリライン(線)

let polylinePath = GMSMutablePath()
polylinePath.add(CLLocationCoordinate2D(latitude: 35.681236, longitude: 139.767125)) // 東京駅
polylinePath.add(CLLocationCoordinate2D(latitude: 35.685410, longitude: 139.763267)) // 大手町駅

let polyline = GMSPolyline(path: polylinePath)
polyline.strokeColor = .blue // ポリラインの色
polyline.strokeWidth = 5.0 // ポリラインの太さ
polyline.map = mapView

ポリゴン

let polygonPath = GMSMutablePath()
polygonPath.add(CLLocationCoordinate2D(latitude: 35.681236, longitude: 139.767125)) // 東京駅
polygonPath.add(CLLocationCoordinate2D(latitude: 35.669825, longitude: 139.767162)) // 東銀座駅
polygonPath.add(CLLocationCoordinate2D(latitude: 35.675177, longitude: 139.763039)) // 有楽町駅
 
let polygon = GMSPolygon(path: polygonPath)
polygon.fillColor = UIColor.red.withAlphaComponent(0.3) // ポリゴン内部の色
polygon.strokeColor = .red // ポリゴンの境界線の色
polygon.strokeWidth = 2.0 // ポリゴンの線の太さ
polygon.map = mapView

現在地表示

マップ上に現在地を表示するための設定変更を行います。
TARGETSのInfo.plistに「Privacy - Location When In Use Usage Description」を追加します。現在地取得をして良いかの確認アラートに表示されるメッセージがこちらに設定されたものになります。

import UIKit
import GoogleMaps

class ViewController: UIViewController,CLLocationManagerDelegate {
    
    private var mapView: GMSMapView!
    private var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let options = GMSMapViewOptions()
        options.camera = GMSCameraPosition.camera(withLatitude: 35.681236, longitude: 139.767125, zoom: 15)
        options.frame = self.view.bounds
        mapView = GMSMapView(options: options) //GoogleMapViewのインスタンスを生成
        /* ---- 省略 ---- */
        
       /* 現在地 */
        mapView.isMyLocationEnabled = true // 現在地表示を有効化
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization() // アクセス許可をリクエスト
        locationManager.startUpdatingLocation() // 現在地の更新を開始
    }
    
    // 現在地が更新されたときに呼ばれる
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return } // 最後の位置情報を取得
        mapView.animate(toLocation: location.coordinate) // カメラを現在地に移動
    }

    // 位置情報の許可が変更されたときに呼ばれる
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.startUpdatingLocation()
        case .denied, .restricted:
            print("位置情報の使用が許可されていません")
        default:
            break
        }
    }
}

※コードのポイント※
「CLLocationManagerDelegate」をプロトコルに追加します。
現在地を取得するための、LocationManagerで、Delegateで処理を行うため、「locationManager.delegate = self」の記述を忘れないようにします。(これを書いておかないとDelegateメソッドが呼び出されません。)

マップ表示時に現在地取得の確認アラートが表示されます。

許可すると現在地にカメラが移動します。(「didUpdateLocations」にて、現在地が変更されたタイミングでカメラを移動するようにしたため。設定していないと、カメラは移動しません。)

※Simulatorでの位置情報の変更は「Features > Location > Custom Location...」より可能です。

タップイベントの取得

タップした箇所にピンを表示する

タップイベントを検知するために、プロトコルに「GMSMapViewDelegate」を追加します。

class ViewController: UIViewController,CLLocationManagerDelegate,GMSMapViewDelegate {

delegateメソッドを使用するため、mapViewに以下の記述を追加します。

mapView.delegate = self // デリゲートを設定

タップイベントの定義を行います。今回はタップした位置にピンを表示し、タップした箇所の緯度経度を確認できるようにしました。

// 地図をタップしたときに呼ばれるデリゲートメソッド
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
    // タップされた位置にマーカーを追加
    let marker = GMSMarker(position: coordinate)
    marker.title = "緯度: \(coordinate.latitude)"
    marker.snippet = "経度: \(coordinate.longitude)"
    marker.map = mapView
}

実行結果は以下です。タップするたびにピンが増え、緯度と経度を確認することができています。

ポリラインをタップする

ポリラインをタップして、タップしたポリラインに対して特定の操作を行いたいと思います、
まずは、ポリラインのタップを有効化する必要があります。

polyline.isTappable = true // タップ可能に設定

ポリラインのタップイベントを定義します。タップしたら線の色を赤色に変更するようにしています。

// ポリラインがタップされたときに呼ばれるデリゲートメソッド
func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
    if let tappedPolyline = overlay as? GMSPolyline {
        tappedPolyline.strokeColor = .red // ポリラインの色を変更
    }
}

タップ前

タップ後

まとめ

以上が、iOSアプリでのGoogleマップ活用の基本編でした。
SDKにて、様々な機能が用意されているため、簡単に色んなことを実現することがでいました。
次回はルート検索やストリートビューなど応用編の記事を作成しようと思っています。
更新楽しみにしていてください!

プログラム

※「AppDelegate.swift」と「SceneDelegate.swift」は前回の記事と同じです。

ViewController.swift

import UIKit
import GoogleMaps

class ViewController: UIViewController,CLLocationManagerDelegate,GMSMapViewDelegate {
    
    private var mapView: GMSMapView!
    private var locationManager: CLLocationManager!
    private var selectPolyline: GMSPolyline!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let options = GMSMapViewOptions()
        options.camera = GMSCameraPosition.camera(withLatitude: 35.681236, longitude: 139.767125, zoom: 15)
        options.frame = self.view.bounds
        mapView = GMSMapView(options: options) //GoogleMapViewのインスタンスを生成
        mapView.delegate = self // デリゲートを設定
        
        /* 地図の種類 */
        mapView.mapType = .normal //デフォルトの地図ビュー。
//        mapView.mapType = .satellite //衛星写真を表示。
//        mapView.mapType = .terrain //地形を強調した地図。
//        mapView.mapType = .hybrid //衛星写真と道路名を組み合わせた地図。
        
        /* UI要素のカスタマイズ */
        mapView.settings.myLocationButton = true //現在地ボタン表示
        mapView.settings.compassButton = true //コンパス表示
        mapView.settings.indoorPicker = true //階数ピッカーの表示
        
        /* データ表示 */
        mapView.isTrafficEnabled = true //リアルタイムの交通情報を表示。
        mapView.isBuildingsEnabled = false //建物の3D表示
        
        view.addSubview(mapView) // マップビューを画面に追加
        
        /* マーカー(ピン表示) */
        let marker = GMSMarker()
        marker.position = CLLocationCoordinate2D(latitude: 35.681236, longitude: 139.767125) // 東京駅
        marker.title = "東京駅"
        marker.snippet = "東京都千代田区丸の内"
        marker.map = mapView
         
        /* ポリライン(線表示) */
        let polylinePath = GMSMutablePath()
        polylinePath.add(CLLocationCoordinate2D(latitude: 35.681236, longitude: 139.767125)) // 東京駅
        polylinePath.add(CLLocationCoordinate2D(latitude: 35.685410, longitude: 139.763267)) // 大手町駅

        let polyline = GMSPolyline(path: polylinePath)
        polyline.strokeColor = .blue // ポリラインの色
        polyline.strokeWidth = 5.0 // ポリラインの太さ
        polyline.isTappable = true // タップ可能に設定
        polyline.map = mapView
         
        /* ポリゴン */
        let polygonPath = GMSMutablePath()
        polygonPath.add(CLLocationCoordinate2D(latitude: 35.681236, longitude: 139.767125)) // 東京駅
        polygonPath.add(CLLocationCoordinate2D(latitude: 35.669825, longitude: 139.767162)) // 東銀座駅
        polygonPath.add(CLLocationCoordinate2D(latitude: 35.675177, longitude: 139.763039)) // 有楽町駅
         
        let polygon = GMSPolygon(path: polygonPath)
        polygon.fillColor = UIColor.red.withAlphaComponent(0.3) // ポリゴン内部の色
        polygon.strokeColor = .red // ポリゴンの境界線の色
        polygon.strokeWidth = 2.0
        polygon.map = mapView
        
        /* 現在地表示 */
        mapView.isMyLocationEnabled = true // 現在地表示を有効化
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization() // アクセス許可をリクエスト
        locationManager.startUpdatingLocation() // 現在地の更新を開始
    }
    
    // 地図をタップしたときに呼ばれるデリゲートメソッド
    func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
        if selectPolyline == nil {
            // タップされた位置にマーカーを追加
            let marker = GMSMarker(position: coordinate)
            marker.title = "緯度: \(coordinate.latitude)"
            marker.snippet = "経度: \(coordinate.longitude)"
            marker.map = mapView
        } else {
            // ポリラインを選択中だった場合は、ピンを増やさずポリラインの色を元に戻す
            selectPolyline.strokeColor = .blue
            selectPolyline = nil
        }
    }
    
    // ポリラインがタップされたときに呼ばれるデリゲートメソッド
    func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
        if let tappedPolyline = overlay as? GMSPolyline {
            tappedPolyline.strokeColor = .red // ポリラインの色を変更
            selectPolyline = tappedPolyline // 選択中のポリラインを設定
        }
    }
    
    // 現在地が更新されたときに呼ばれる
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        /* 初期位置が東京駅では無くなってしまうので、コメントアウトしています。
        guard let location = locations.last else { return } // 最後の位置情報を取得
        mapView.animate(toLocation: location.coordinate) // カメラを現在地に移動
        locationManager.stopUpdatingLocation()
         */
    }

    // 位置情報の許可が変更されたときに呼ばれる
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.startUpdatingLocation()
        case .denied, .restricted:
            print("位置情報の使用が許可されていません")
        default:
            break
        }
    }
}

Discussion