FlutterでGoogle Mapを表示させる

##  初めに
Flutterを使っている人の中で、GoogleMapの導入を考えている人も多いのではないでしょうか。
自分も自作しているアプリの中で、GoogleMapを導入することになったので、その使い方を共有したいと思います！
なお、今回はiOSのみ行います。

##  APIキー取得
[Google Maps Platform](https://mapsplatform.google.com/)のページから以下の６つの項目を完了させてください。
* Googleアカウント作成
* Google Cloud Platform 利用開始
* 請求先アカウントの設定
* プロジェクトの作成
* API有効化
* APIキーの作成

今回はiOSに導入するため、有効化させるAPIは「Maps SDK for iOS」のみです。

## AppDelegate.swift の変更 
APIキーの取得が完了したら GoogleMap を読み込むために設定を変更する必要があります。
以下のパスにあるファイルを開いて下のコードの緑で囲まれた部分を追加してください。
ios/Runner/AppDelegate.swift

```diff_dart:AppDelegate.swift
import UIKit
import Flutter
+ import GoogleMaps 

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
+   GMSServices.provideAPIKey("YOUR KEY")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
```

``"YOUR KEY"``の部分に Google Maps Platform で取得した APIキーを記述してください。

## pubspec.yaml の変更

次に必要なパッケージを「pubspec.yaml」に記述します。
今回使用するパッケージは[google_maps_flutter](https://pub.dev/packages/google_maps_flutter)です。

```diff_dart:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
+ google_maps_flutter: ^2.1.8

```
Pub get も忘れないようにしましょう！

## Map を表示させる
これで全ての準備が完了しました。
今回は [google_maps_flutter](https://pub.dev/packages/google_maps_flutter) のサンプルを表示させてみましょう。
以下のコードを記述してください。

```diff_dart:main.dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Google Maps Demo',
      home: MapSample(),
    );
  }
}

class MapSample extends StatefulWidget {
  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  Completer<GoogleMapController> _controller = Completer();

  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  static final CameraPosition _kLake = CameraPosition(
      bearing: 192.8334901395799,
      target: LatLng(37.43296265331129, -122.08832357078792),
      tilt: 59.440717697143555,
      zoom: 19.151926040649414);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        mapType: MapType.hybrid,
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _goToTheLake,
        label: Text('To the lake!'),
        icon: Icon(Icons.directions_boat),
      ),
    );
  }

  Future<void> _goToTheLake() async {
    final GoogleMapController controller = await _controller.future;
    controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
  }
}

```
以下の画像のように Map と 「To the lake!」と書かれた FloatingActionButton が表示されました。「To the lake!」ボタンを押すと視点が入れ替わるようになっています。

<img width=300, alt="normal-map" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/c1557b64-00b8-2363-c754-6fc44123c7c4.png">

※「To the lake!」ボタンの下のレイヤーにあるのは以下のような現在地を表示するためのボタンでした。
<img width=300, alt="", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/c4bf9bf2-c7db-9ae4-9b83-ba4d64be6da0.png">

## Map を変更する
次に Map の変更をしてみましょう。以下で GoogleMap のプロパティをまとめました。この他にもありますが、今回は使用頻度が高いと思われるものをまとめました。
|プロパティ  |用途  |
|---|---|
|mapType  |Map のタイプを指定  |
|markers  |Map 上にマーカーを表示  |
|initialCameraPosition|カメラの初期値を指定 |
|polylines|２地点以上マーカーがある場合にその直線距離を結ぶ直線を表示 |

### mapType
mapType には以下の４種類があります。
|種類|説明|実際の表示|
|---|---|---|
|hybrid|normal と satellite の情報を複合した地図|<img width=200, alt="", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/38758a2d-01b9-9577-5f41-44e27843ef46.png">|
|normal|道路や建物などが表示される地図|<img width=200, alt="", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/f3b8db49-8a98-693a-58a6-0246ef35f702.png">|
|satellite|衛星写真を使った地図|<img width=200, alt="", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/3ced6766-fea6-7eeb-3851-b200abf20b1d.png">|
|terrain|地形情報を使った地図|<img width=200, alt="", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/b4f918b3-a33b-ec0b-577f-b391b69f2181.png">|

### markers
次はマーカーを表示させてみましょう。

```diff_dart:main.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class GoogleMapExample extends StatefulWidget {
  @override
  State<GoogleMapExample> createState() => GoogleMapExampleState();
}

class GoogleMapExampleState extends State<GoogleMapExample> {
  Completer<GoogleMapController> _controller = Completer();

+   static Marker _kGooglePlexMarker = Marker(
+   markerId: MarkerId("_kGooglePlex"),
+   infoWindow: InfoWindow(
+     title: "Google",
+   ),
+   icon: BitmapDescriptor.defaultMarker,
+   position: LatLng(37.42796133580664, -122.085749655962),
+ );

  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        mapType: MapType.hybrid,
+       markers: {
+         _kGooglePlexMarker,
+       },
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
    );
  }
}
```
コードを追加して実行するとマーカーが表示され、マーカーを押すと ``infoWindow`` の ``title`` に指定した「Google」というテキストが以下のように表示されます
<img width=300, alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/48f8385b-23d3-f779-9410-76243243767d.png">

タイトル以外にもアイコンを以下のように変更すると

```diff_dart:main.dart
- icon: BitmapDescriptor.defaultMarker,
+ icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue),
```
<img width=300, alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/7c91851b-a673-81e4-d4aa-9ed319979f0a.png">

ピンの色を変更できます。

他にも自分で指定した画像をピンとして使うこともできます。

### initialCameraPosition
GoogleMap が初めて読み込まれた時のカメラの位置を指定できます。
```dart: main.dart
static final CameraPosition _kGooglePlex = CameraPosition(
  target: LatLng(37.42796133580664, -122.085749655962),
  zoom: 14.4746,
);
```
このコードのように予め ``Cameraposition`` という型で指定したい地点の緯度、経度とカメラのズームの程度を指定することで初期値を決めることができます。

### polylines
``polylines`` を使うことで２地点以上を結ぶ直線を描くことができます。

```diff_dart:main.dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class GoogleMapExample extends StatefulWidget {
  @override
  State<GoogleMapExample> createState() => GoogleMapExampleState();
}

class GoogleMapExampleState extends State<GoogleMapExample> {
  Completer<GoogleMapController> _controller = Completer();

  static Marker _kGooglePlexMarker = Marker(
    markerId: MarkerId("_kGooglePlex"),
    infoWindow: InfoWindow(
      title: "Google",
    ),
    // icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue),
    icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue),
    position: LatLng(37.42796133580664, -122.085749655962),
  );

+  static final Marker _kLakeMarker = Marker(
+    markerId: MarkerId("_kLake"),
+    infoWindow: InfoWindow(
+      title: "Lake",
+    ),
+    icon: BitmapDescriptor.defaultMarker,
+    position: LatLng(37.43296265331129, -122.08832357078792),
+  );

+  static final CameraPosition _kLake = CameraPosition(
+      bearing: 192.8334901395799,
+      target: LatLng(37.43296265331129, -122.08832357078792),
+      tilt: 59.440717697143555,
+      zoom: 19.151926040649414
+  );

+  static final Polyline _kPolyline = Polyline(
+    polylineId: PolylineId("_kPolyline"),
+    points: [
+      LatLng(37.42796133580664, -122.085749655962),
+      LatLng(37.43296265331129, -122.08832357078792),
+    ],
+    width: 5,
+    color: Colors.white70,
+  );


  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        mapType: MapType.hybrid,
        markers: {
          _kGooglePlexMarker,
+         _kLakeMarker,
        },
+       polylines: {_kPolyline},
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },

      ),
    );
  }
}
```

新たに``_kLakeMarker``という地点を追加し、``_kGooglePlexMarker``と``_kLakeMarker``の二地点間をつなぐ直線を追加しました。
<img width=300, alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/4a57d870-a4e4-721c-cdf3-6a624879128b.png">
``polylines`` は直線の幅や色を変更することができます。


以上です！

## あとがき
最後まで読んでいただきありがとうございました。
参考にしていただければ幸いです。

誤っている箇所やその他のアイコンがあればご指摘いただければ幸いです。

### 参考にしたサイト
https://pub.dev/packages/google_maps_flutter