地図を iOS アプリに追加する(Swift)

1. 始める前に

この Codelab では、Google Maps Platform を使って Swift で iOS アプリの作成を開始する方法について学習し、以下の機能を備えた iOS アプリを作成します。

  • Maps SDK for iOS と Maps SDK for iOS ユーティリティ ライブラリを読み込む
  • オーストラリアのシドニーが中央に配置された地図を表示する
  • シドニー周辺の 100 個のポイントを示すカスタム マーカーを表示する
  • マーカー クラスタリングを実装する
  • マーカーがタップされた際、地図上にそのマーカーを中心とする円を描画する

マーカーが表示された iOS アプリの地図

要件

  • Swift および iOS の開発に関する基本的な知識

学習する内容

  • Maps SDK for iOS と Google Maps SDK for iOS ユーティリティ ライブラリを読み込む
  • 地図を読み込む
  • マーカー、カスタム マーカー、マーカー クラスタリングを使用する
  • Maps SDK for iOS のイベント システムを使ってユーザー操作を処理する
  • 地図のカメラをプログラムで制御する
  • 地図上に図形を描画する

必要なもの

この Codelab を実行するには、次のアカウント、サービス、ツールが必要です。

  • Xcode 12.0 以降(ターゲット SDK が 12.0 以降)
  • Cocoapods がインストールされていること
  • 課金が有効になっている Google Cloud Platform アカウント(次の手順を参照)
  • Maps SDK for iOS を有効にした Cloud Console のプロジェクト(次の手順を参照)

2. 準備

以下の有効化の手順では、Maps SDK for iOS を有効にする必要があります。

Google Maps Platform を設定する

課金を有効にした Google Cloud Platform アカウントとプロジェクトをまだ作成していない場合は、Google Maps Platform スタートガイドに沿って請求先アカウントとプロジェクトを作成してください。

  1. Cloud Console で、プロジェクトのプルダウン メニューをクリックし、この Codelab に使用するプロジェクトを選択します。

  1. Google Cloud Marketplace で、この Codelab に必要な Google Maps Platform API と SDK を有効にします。詳しい手順については、こちらの動画またはドキュメントをご覧ください。
  2. Cloud Console の [認証情報] ページで API キーを生成します。詳しい手順については、こちらの動画またはドキュメントをご覧ください。Google Maps Platform へのすべてのリクエストで API キーが必要になります。

クイックスタート

できるだけ早く演習を開始できるように、この Codelab で使用できるスターター コードが用意されています。

  1. git がインストールされている場合は、リポジトリのクローンを作成します。
git clone https://github.com/googlemaps/codelab-maps-platform-101-swift.git

または、[コードをダウンロード] をクリックしてソースコードをダウンロードします。

  1. コードをダウンロードしたら、/starter ディレクトリにある StarterApp プロジェクトを開きます。このプロジェクトには、この Codelab の実行に必要な基本的なファイル構造が含まれています。作業対象のすべてのコンポーネントは /starter/StarterApp ディレクトリにあります。

ソリューション コード全体の動作を確認するには、/solution/SolutionApp ディレクトリで最終的なコードをご確認ください。

3. Maps SDK for iOS をインストールする

Maps SDK for iOS を使用する最初の手順は、必要な依存関係のインストールで、このプロセスには 2 つの手順があります。それは、CocoaPods 依存関係マネージャーから Maps SDK for iOS と Maps SDK for iOS ユーティリティ ライブラリをインストールし、SDK に API キーを提供することです。

  1. Maps SDK for iOS と Maps SDK for iOS ユーティリティ ライブラリを Podfile に追加します。

この Codelab では、Google マップのすべての主要な機能を提供する Maps SDK for iOS と、地図を強化するためのさまざまなユーティリティ(マーカー クラスタリングなど)を提供する Maps iOS ユーティリティ ライブラリの両方を使用します。

まずは、Xcode(または任意のテキスト エディタ)で Podfile を開き、ファイルを更新して、Maps SDK for iOS とユーティリティ ライブラリの依存関係を # Pods for StarterApp コメントに含めます。

pod 'GoogleMaps', '6.1.0'
pod 'Google-Maps-iOS-Utils', '3.4.0'

SDK の最新バージョンとメンテナンスに関するガイドについては、Maps SDK for iOS のバージョンに関するドキュメントをご確認ください。

Podfile は以下のようになります。

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'

target 'StarterApp' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for StarterApp
  pod 'GoogleMaps', '6.1.0'
  pod 'Google-Maps-iOS-Utils', '3.4.0'
end
  1. Maps SDK for iOS と Maps SDK for iOS ユーティリティ ライブラリの pod をインストールします。

依存関係をインストールするには、コマンドラインから /starter ディレクトリで pod install を実行します。CocoaPods では、自動的に依存関係がダウンロードされ、StarterApp.xcworkspace が作成されます。

  1. 依存関係がインストールされたら、/starter ディレクトリから open StarterApp.xcworkspace を実行して Xcode でファイルを開き、Command+R を押して iPhone シミュレータでアプリを実行します。すべてが正しく設定されると、シミュレータが起動し、画面が黒く表示されますが、まだ何も作成されていないため、これは予期されたエラーです。
  2. SDK を AppDelegate.swift にインポートします。

これで依存関係のインストールが完了しました。次に API キーを SDK に提供します。最初の手順として、import UIKit インポート文の下に以下のコードを挿入して、Maps SDK for iOS を依存関係としてインポートします。

import GoogleMaps
  1. application: didFinishLaunchingWithOptions:GMSServicesprovideAPIKey を呼び出して、API キーを iOS SDK に渡します。
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.
    GMSServices.provideAPIKey("YOUR_API_KEY")

    return true
  }

更新された AppDelegate.swift ファイルは以下のようになります。

import UIKit
import GoogleMaps

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.
    GMSServices.provideAPIKey("YOUR_API_KEY")

    return true
  }

}

YOUR_API_KEY を、Cloud Console で作成した API キーに置き換えます。

これで、依存関係のインストールと、API キーの提供が完了しました。次は、Maps SDK for iOS の呼び出しを開始します。

4. 地図を表示する

ではいよいよ地図を表示してみましょう。

Maps SDK for iOS で最も頻繁に使用されるのは GMSMapView クラスで、地図インスタンスの作成と操作を可能にする多くのメソッドが用意されています。その方法を以下に示します。

  1. ViewController.swift を開きます。

ここで、この Codelab の残りの作業を行います。ビュー コントローラの loadView および viewDidLoad のライフサイクル イベントは、すでにスタブアウトされています。

  1. ファイルの先頭に以下のコードを追加して、Maps SDK for iOS をインポートします。
import GoogleMaps
  1. ViewController インスタンス変数を宣言して GMSMapView を格納します。

GMSMapView のインスタンスは、この Codelab 全体をとおして主に使用するオブジェクトで、ビュー コントローラのさまざまなライフサイクル メソッドから参照や操作を行う対象となります。それを使用できるようにするには、ViewController の実装を更新してインスタンス変数を宣言し、格納します。

class ViewController: UIViewController {

  private var mapView: GMSMapView!

  ...
}
  1. loadView で、GMSCameraPosition のインスタンスを作成します。

GMSCameraPosition は、地図の中心に配置される場所と、表示されるズームレベルを定義します。このコードで cameraWithLatitude:longitude:zoom: のメソッドを呼び出して、オーストラリアのシドニー(緯度 -33.86、経度 151.20)を地図の中心に配置し、ズームレベルを 12 に設定します。

let camera:GMSCameraPosition = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 12)
  1. loadViewGMSMapView のインスタンスを作成して、地図をインスタンス化します。

新しい地図インスタンスを作成するには、GMSMapView(frame: CGRect, camera: GMSCameraPosition) を呼び出します。フレームは CGRect.zero に設定されます。これは iOS CGGeometry ライブラリのグローバル変数で、幅 0、高さ 0 のフレームを指定し、ビュー コントローラ内の「0,0」の位置に配置されます。カメラは、先ほど作成したカメラ位置に設定されます。

地図を表示するには、次に、ビュー コントローラのルートビューを mapView に設定します。これにより、地図が全画面表示になります。

    mapView = GMSMapView(frame: .zero, camera: camera)
    self.view = mapView
  1. GMSMapViewDelegate をビュー コントローラに設定します。

実装すると、マップビュー デリゲートにより、GMSMapView インスタンスでのユーザー操作からのイベントを処理できるようになります。これは後の手順で必要になります。

まず、GMSMapViewDelegate: のプロトコルに準拠するように ViewController のインターフェースを更新します。

class ViewController: UIViewController, GMSMapViewDelegate

次に、これを loadView 関数に追加して、GMSMapViewDelegateViewController に設定します。

    mapView.delegate = self

これで、iOS シミュレータ(Command+R)でアプリを再読み込みすると、図 1 のような地図が表示されるようになりました。

Google マップを表示している iOS アプリ

図 1. Google マップを表示している iOS アプリ

この手順では、オーストラリアのシドニーを中心に配置した地図を表示する GMSMapView のインスタンスを作成しました。

ViewController.swift ファイルは以下のようになります。

import UIKit
import GoogleMaps

class ViewController: UIViewController, GMSMapViewDelegate {

  private var mapView: GMSMapView!

  override func loadView() {

    // Load the map at set latitude/longitude and zoom level
    let camera:GMSCameraPosition = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 11)

    mapView = GMSMapView(frame: .zero, camera: camera)
    self.view = mapView
    mapView.delegate = self
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
  }

}

5. 地図のスタイルを設定する(省略可)

Cloud ベースのマップのスタイル設定によって地図のスタイルをカスタマイズすることも可能です。

マップ ID を作成する

地図スタイルを関連付けたマップ ID の作成が済んでいない場合は、マップ ID のガイドを参照して、以下を行いましょう。

  1. マップ ID を作成します。
  2. マップ ID を地図スタイルに関連付けます。

マップ ID をアプリに追加する

前の手順で作成したマップ ID を使用するには、ViewController.swift ファイルを開き、loadView メソッド内に GMSMapID オブジェクトを作成してマップ ID を指定します。次に、GMSMapID オブジェクトをパラメータとして指定して GMSMapView のインスタンス化を変更します。

ViewController.swift

  override func loadView() {

    // Load the map at set latitude/longitude and zoom level
    let camera:GMSCameraPosition = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 11)
    let mapID = GMSMapID(identifier: "YOUR_MAP_ID")

    mapView = GMSMapView(frame: .zero, mapID: mapID, camera: camera)
    self.view = mapView
    mapView.delegate = self
  }

以上が完了したら、アプリを実行してみましょう。指定したスタイルで地図が表示されるはずです。

6 地図にマーカーを追加する

Maps SDK for iOS で実行できる操作は多数ありますが、最も頻繁に使用するのは地図上にマーカーを配置する操作です。地図上の特定の地点を示すマーカーは、ユーザー操作を処理するための一般的な UI 要素です。Google マップを利用したことがあれば、図 2 の赤いピンのようなデフォルトのマーカーを見たことがあるかもしれません。

赤いマーカーが配置された地図

図 2. 赤いマーカーが配置された地図

この手順では、GMSMarker クラスを使って地図上にマーカーを配置する方法を学習します。

なお、ビュー コントローラの loadView ライフサイクル イベントの前の手順から地図が読み込まれるまではマーカーを地図に配置できないため、これらの手順は、ビュー(と地図)の読み込み後に呼び出される viewDidLoad ライフサイクル イベントで完了することになります。

  1. CLLocationCoordinate2D オブジェクトを定義します。

CLLocationCoordinate2D は、iOS の CoreLocation ライブラリによって使用可能になる構造体で、設定された緯度と経度でエリアを定義します。最初のマーカーの作成を開始するには、CLLocationCoordinate2D オブジェクトを定義し、緯度と経度を地図の中心に設定します。camera.target.latitude プロパティと camera.target.longitude プロパティを使用すると、地図表示から地図の中心の座標にアクセスできます。

    // Add a single marker with a custom icon
    let mapCenter = CLLocationCoordinate2DMake(mapView.camera.target.latitude, mapView.camera.target.longitude)
  1. GMSMarker のインスタンスを作成します。

Maps SDK for iOS には、GMSMarker クラスが用意されています。GMSMarker の各インスタンスは、地図上で個々のマーカーを示し、markerWithPosition: を呼び出してそれに CLLocationCoordinate2D オブジェクトを渡すことで作成され、地図上のどこにマーカーを配置するかを SDK に伝えます。

    let marker = GMSMarker(position: mapCenter)
  1. カスタム マーカー アイコンを設定します。

Google マップのデフォルトの赤いピンでも機能に不足はありませんが、地図をカスタマイズするのも効果的です。Maps SDK for iOS では、カスタム マーカーをとても簡単に使用できます。StarterApp プロジェクトには ‘custom_pin.png' という画像が含まれていますが、任意の画像を使用できます。

カスタム マーカーを設定するには、マーカーの icon プロパティを UIImage インスタンスに設定します。

    marker.icon = UIImage(named: "custom_pin.png")
  1. 地図にマーカーをレンダリングします。

マーカーは作成されたものの、地図上にはまだ表示されていません。これを行うには、GMSMarker インスタンスの map プロパティを GMSMapView のインスタンスに設定します。

    marker.map = mapView

アプリを再読み込みして、図 3 に示すように、マーカーが配置された最初の地図を確認してみましょう。

赤いマーカーが中央に配置された Google マップを表示している iOS アプリ

図 3. 赤いマーカーが中央に配置された Google マップを表示している iOS アプリ

このセクションでは GMSMarker クラスのインスタンスを作成し、地図表示に適用して、地図上にマーカーを表示しました。ViewController.swift 内の更新された viewDidLoad ライフサイクル イベントは、以下のようになります。

  override func viewDidLoad() {
    super.viewDidLoad()

    // Add a single marker with a custom icon
    let mapCenter = CLLocationCoordinate2DMake(mapView.camera.target.latitude, mapView.camera.target.longitude)
    let marker = GMSMarker(position: mapCenter)

    marker.icon = UIImage(named: "custom_pin.png")
    marker.map = mapView
  }

7. マーカー クラスタリングを有効にする

多数のマーカーを使用していたり、マーカーが密集したりしている場合、複数のマーカーが重なって表示され、ユーザーの利便性が低下します。たとえば、2 個のマーカーが近接している場合、図 4 のように表示される可能性があります。

2 個のマーカーが近接している

図 4. 2 個のマーカーが近接している

このような場合に効果を発揮するのがマーカー クラスタリングです。マーカー クラスタリングも広く利用されている機能で、図 5 に示すように、近接する複数のマーカーをズームレベルに応じて 1 つのアイコンにグループ化できます。

1 つのアイコンにクラスタ化されたマーカーの例

図 5. 1 つのアイコンにクラスタリングされたマーカーの例

マーカー クラスタリングのアルゴリズムは、地図の表示可能領域をグリッドに分割し、同じセル内にあるアイコンをクラスタ化します。Google Maps Platform チームが作成した Google Maps SDK for iOS ユーティリティ ライブラリと呼ばれるオープンソースの便利なユーティリティ ライブラリでは、特にマーカー クラスタリングを自動的に処理します。マーカー クラスタリングについて詳しくは、Google Maps Platform のドキュメントをご覧いただくか、GitHub で iOS ユーティリティ ライブラリのソースをご確認ください。

  1. さらに多くのマーカーを地図に追加します。

マーカー クラスタリングの動作を確認するには、地図上に多数のマーカーを配置する必要があります。これを簡単に行えるように、スターター プロジェクトの MarkerGenerator.swift には便利なマーカー生成ツールが用意されています。

指定した数のマーカーを地図に追加するには、前の手順のコードの下にあるビュー コントローラの viewDidLoad ライフサイクルで MarkerGenerator(near:count:).markerArray を呼び出します。このメソッドは、CLLocationCoordinate2D オブジェクトで指定された座標周辺の無作為な位置に、count オブジェクトで指定された数のマーカーを作成します。今回の場合は、先ほど作成した mapCenter 変数を渡します。マーカーは [GMSMarker] で返されます。

    // Generate many markers
    let markerArray = MarkerGenerator(near: mapCenter, count: 100).markerArray

この多数のマーカーがどのように表示されるかを確認するには、markerArray の定義の後に以下の行を追加してアプリを実行します。これらの行は、次の手順に進む前に必ずコメントアウトしてください。次の手順では、Marker Clusterer を代わりに使用してマーカーの表示を管理します。

    // Comment the following code out if using the marker clusterer
    // to manage markers instead.
    for marker in markerArray {
      marker.map = mapView
    }
  1. Google Maps SDK for iOS ユーティリティ ライブラリをインポートします。

Maps iOS ユーティリティ ライブラリを依存関係としてプロジェクトに追加するには、ViewController.swift の先頭の依存関係リストに以下のコードを追加します。

import GoogleMapsUtils
  1. Marker Clusterer を設定します。

Marker Clusterer を使用するには、その仕組みを設定するために、クラスタリング アルゴリズム、アイコン生成ツール、レンダラの 3 つを指定する必要があります。アルゴリズムは、同じクラスタに含めるマーカー間の距離など、マーカーをクラスタ化する仕組みの動作を決定します。アイコン生成ツールは、異なるズームレベルで使用されるクラスタ アイコンを提供します。レンダラは、地図上にあるクラスタ アイコンに対して行う実際のレンダリングを処理します。

これらはすべて、ゼロから作成することもできますが、Maps iOS ユーティリティ ライブラリには、このプロセスを簡単に行うためにデフォルトの実装が用意されており、以下のコードを追加するだけで済みます。

    // Set up the cluster manager with a supplied icon generator and renderer.
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let iconGenerator = GMUDefaultClusterIconGenerator()
    let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
  1. GMUClusterManager のインスタンスを作成します。

GMUClusterManager は、指定されたアルゴリズム、アイコン生成ツール、レンダラを使ってマーカー クラスタリングを実装するクラスです。レンダラを作成して地図表示で使用できるようにするには、まず ViewController の実装にインスタンス変数を追加して、クラスタ マネージャー インスタンスを格納します。

class ViewController: UIViewController, GMSMapViewDelegate {

  private var mapView: GMSMapView!
  private var clusterManager: GMUClusterManager!
}

次に、viewDidLoad ライフサイクル イベントで GMUClusterManager のインスタンスを作成します。

    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
  1. マーカーを追加して Marker Clusterer を実行します。

Marker Clusterer インスタンスの構成が完了したら、add(items:) を呼び出してクラスタ化するマーカーの配列をクラスタ マネージャーに渡してから、cluster を呼び出して Marker Clusterer を実行します。

    clusterManager.setMapDelegate(self)
    clusterManager.add(markerArray)
    clusterManager.cluster()

アプリを再読み込みすると、図 6 の例のように、多数のマーカーが適切にクラスタ化された状態で表示されます。ピンチ操作で地図をズームしてさまざまなズームレベルを試し、マーカーのズームインとズームアウトに合わせてマーカー クラスタが変化するのを確認してみましょう。

Google マップとクラスタ化されたマーカーが表示された iOS アプリ

図 6. Google マップとクラスタ化されたマーカーが表示された iOS アプリ

この手順では、Google Maps SDK for iOS ユーティリティ ライブラリの Marker Clusterer のインスタンスを設定し、それを使って地図上で 100 個のマーカーをクラスタ化しました。ViewController.swiftviewDidLoad ライフサイクル イベントは以下のようになります。

  override func viewDidLoad() {
    super.viewDidLoad()

    // Add a single marker with a custom icon
    let mapCenter = CLLocationCoordinate2DMake(mapView.camera.target.latitude, mapView.camera.target.longitude)
    let marker = GMSMarker(position: mapCenter)

    marker.icon = UIImage(named: "custom_pin.png")
    marker.map = mapView

    // Generate many markers
    let markerArray = MarkerGenerator(near: mapCenter, count: 100).markerArray
    // Comment the following code out if using the marker clusterer
    // to manage markers instead.
    //    for marker in markerArray {
    //      marker.map = mapView
    //    }

    // Set up the cluster manager with a supplied icon generator and renderer.
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let iconGenerator = GMUDefaultClusterIconGenerator()
    let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)

    clusterManager.setMapDelegate(self)
    clusterManager.add(markerArray)
    clusterManager.cluster()
  }

8. ユーザー操作を追加する

これで、マーカーを表示し、マーカー クラスタリングを使用する地図が完成しました。この手順では、先ほどビュー コントローラに設定した GMSMapViewDelegate を使ってさらに多くのユーザー操作を処理し、地図の利便性を高めます。

Maps SDK for iOS には、マップビュー デリゲートを介して実装される包括的なイベント システムが用意されており、さまざまなユーザー操作が発生した際にコードを実行できるようにするイベント ハンドラが含まれています。たとえば、MapView デリゲートには、地図やマーカーのクリック、地図表示のパン、ズームインやズームアウトなど、ユーザーがなんらかの操作を行った際にコードの実行をトリガーできるようにするメソッドが含まれています。

この手順では、ユーザーがタップした任意のマーカーが中央に表示されるように、プログラムで地図をパンします。

  1. マーカー タップ リスナーを実装します。

mapView(_:didTap:) は、以前に作成したマーカーのいずれか、およびマーカー クラスタ(マーカー クラスタは GMSMarker のインスタンスとして内部で実装されます)をユーザーがタップするたびに呼び出されます。

イベント リスナーを実装するには、まず右中括弧の前の ViewController.swift の下部でイベント リスナーをスタブアウトします。

  func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    return false
  }

メソッドからは false が返されます。これにより、iOS SDK はデフォルトの GMSMarker 機能を引き続き実行するように伝えられます。たとえば、情報ウィンドウが設定されている場合は、イベント ハンドラ コードの実行後、情報ウィンドウが表示されます。

  1. タップイベントを処理し、カメラの動きにアニメーションを付けて、マーカーまたはマーカー クラスタがタップされた際に地図をセンタリングし直します。

mapView(_:didTap:) を呼び出すと、タップされた GMSMarker のインスタンスが渡され、コードでそれを処理できるようになります。このインスタンスを使って、イベント ハンドラ内から地図表示で animate(toLocation:) を呼び出し、position プロパティからマーカー インスタンスの位置を渡すことにより、地図をセンタリングし直すことができます。

    // Animate to the marker
    mapView.animate(toLocation: marker.position)
  1. タップされたマーカー クラスタにズームインします。

一般的な UX パターンでは、タップされたマーカー クラスタにズームインします。クラスタはより低いズームレベルで展開されるため、ユーザーはクラスタ化されたマーカーを表示できるようになります。

前述のように、マーカー クラスタ アイコンは、実際には、カスタム アイコンを使用した GMSMarker の実装です。では、マーカーやマーカー クラスタがタップされたかどうかを判別するには、どうすればよいでしょうか。Marker Clusterer マネージャーで新しいクラスタ アイコンが作成されると、GMUCluster. というプロトコルに準拠するように GMSMarker のインスタンスが実装されます。イベント ハンドラに渡されるマーカーがこのプロトコルに準拠しているかどうかは、条件を使って確認できます。

クラスタがタップされていることをプログラムで把握したら、地図表示インスタンスで animate(toZoom:) を呼び出して、現在のズームレベルに 1 を足した値にズームを設定できます。現在のズームレベルは、camera.zoom プロパティの mapView インスタンスで確認できます。

また、以下のコードでは true が返されます。これにより、イベントの処理を完了したことと、ハンドラで追加のコードを実行してはならないことがイベント ハンドラに伝えられます。これを行う理由の 1 つは、基盤となる GMSMarker オブジェクトが、その他のデフォルト動作(クラスタ アイコンがタップされた場合にそれほど意味を持たない情報ウィンドウの表示など)を実行するのを防ぐことです。

    // If the tap was on a marker cluster, zoom in on the cluster
    if let _ = marker.userData as? GMUCluster {
      mapView.animate(toZoom: mapView.camera.zoom + 1)
      return true
    }

アプリを再読み込みし、いくつかのマーカーとマーカー クラスターをタップしてみましょう。どちらかをタップすると、タップされた要素が地図の中央にセンタリングし直されます。マーカー クラスタをタップすると、地図も 1 つ上のレベルにズームインされ、マーカー クラスタが展開されて、そこにクラスタ化されているマーカーが表示されます。

この手順では、マーカー タップ リスナーを実装し、イベントを処理して、タップされた要素が中央に表示されるようにし、その要素がマーカー クラスタ アイコンの場合はズームインされるようにしました。

mapView(_:didTap:) メソッドは以下のようになります。

  func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    // Animate to the marker
    mapView.animate(toLocation: marker.position)

    // If the tap was on a marker cluster, zoom in on the cluster
    if let _ = marker.userData as? GMUCluster {
      mapView.animate(toZoom: mapView.camera.zoom + 1)
      return true
    }

    return false
  }

9. 地図上に図形を描画する

ここまでの手順により、無作為の 100 個のポイントにマーカーを表示し、ユーザーの操作を処理できるシドニーの地図が完成しました。この Codelab の最後の手順では、Maps SDK for iOS の描画機能を使用して、地図を操作するうえで有用な機能を追加します。

この地図は、シドニー市内を探索する観光客が使用することを想定しています。クリックされたマーカーを中心とする半径を地図上に描画し、その地点から歩いて行ける範囲が一目でわかるようにしましょう。

iOS SDK には、正方形、ポリゴン、ライン、円などの図形を地図上に描画する関数が用意されています。この手順では、クリックされたマーカーを中心に、半径 800 メートル(約 0.5 マイル)の円を描画します。

  1. ViewController の実装に circle インスタンス変数を追加します。

このインスタンス変数は、最後に描画された円を保存するために使用されます。これにより、最後に描画された円は別の円が描画される前に破棄されるようになります。タップされたすべてのマーカーの周囲に円が表示された場合、ユーザーの操作性が落ち、見た目も悪くなるため、避ける必要があります。

これを行うには、ViewController の実装を以下のように更新します。

class ViewController: UIViewController, GMSMapViewDelegate {

  private var mapView: GMSMapView!
  private var clusterManager: GMUClusterManager!
  private var circle: GMSCircle? = nil
  ...
}
  1. マーカーがタップされた際に円を描画します。

mapView(_:didTap:) メソッドの下部、return false ステートメントのすぐ上に以下のコードを追加して、iOS SDK の GMSCircle クラスのインスタンスを作成し、地図をセンタリングし直した際と同じように GMSCircle(position:radius:) を呼び出して、マーカーがタップされた位置を渡し、半径 800 m の新しい円を描画します。

    // Draw a new circle around the tapped marker
    circle = GMSCircle(position: marker.position, radius: 800)
  1. 円のスタイルを設定します。

デフォルトでは、GMSCircle は黒いストロークと透明の塗りつぶしで円を描画します。これは、半径を表示するうえでは問題ありませんが、見た目が悪く、視認性にも少々劣ります。UIColor を円の fillColor プロパティに割り当てて円に塗りつぶし色を加え、スタイルを改善してみましょう。以下のコードでは、透明度 50%のグレーの塗りつぶし色を追加します。

    circle?.fillColor = UIColor(red: 0.67, green: 0.67, blue: 0.67, alpha: 0.5)
  1. 地図上に円をレンダリングします。

前の手順でマーカーを作成した際と同様、GMSCircle のインスタンスを作成しただけでは、地図上に表示されません。これを行うには、地図表示インスタンスを円の map プロパティに割り当てます。

    circle?.map = mapView
  1. 以前にレンダリングした円をすべて削除します。

前述のとおり、地図に円を追加し続けても、優れたユーザー エクスペリエンスはもたらされません。以前のタップイベントによってレンダリングされた円を削除するには、mapView(_:didTap:) の上部にある circlemap プロパティを nil に設定します。

    // Clear previous circles
    circle?.map = nil

アプリを再読み込みしてマーカーをタップしてみましょう。図 7 に示すように、マーカーがタップされ、以前にレンダリングされた円が削除されるたびに、新しく描画された円が表示されます。

タップされたマーカーの周りに描画された円

図 7. タップされたマーカーの周りに描画された円

この手順では、GMSCircle クラスを使って、マーカーがタップされるたびに円をレンダリングしました。

mapView(_:didTap:) メソッドは以下のようになります。

  func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    // Clear previous circles
    circle?.map = nil

    // Animate to the marker
    mapView.animate(toLocation: marker.position)

    // If the tap was on a marker cluster, zoom in on the cluster
    if let _ = marker.userData as? GMUCluster {
      mapView.animate(toZoom: mapView.camera.zoom + 1)
      return true
    }

    // Draw a new circle around the tapped marker
    circle = GMSCircle(position: marker.position, radius: 800)
    circle?.fillColor = UIColor(red: 0.67, green: 0.67, blue: 0.67, alpha: 0.5)
    circle?.map = mapView
    return false
  }

10. 完了

インタラクティブな Google マップを組み込んだ iOS アプリが正常に作成されました。

学習した内容

次のステップ

  • maps-sdk-for-ios-samples GitHub リポジトリのサンプルとデモを詳しく確認またはフォークします。
  • Google Maps Platform で iOS アプリをビルドするためのその他の Swift Codelab を確認します。
  • 皆様のお役に立つコンテンツをご提供できるよう、以下のアンケートにご協力ください。

他にどのような Codelab をご希望ですか。

地図上のデータの可視化 地図のスタイルのカスタマイズの詳細 地図上に 3D インタラクションを構築する

ご希望の Codelab が上記にない場合、こちらからリクエストしてください