Android GoogleMapの使い方メモ

## はじめに
最近プロジェクトでGoogleMapAPIを利用したので、細かな使い方を記事として残しておきます。

## プロジェクト作成〜地図の表示
AndroidStudioのプロジェクトウィザードで簡単に作れます。
<img width="800" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/83aa92ff-b06c-a7e0-4275-15e5d09069ee.png">

生成された、google_maps_api.xml を開き、`YOUR_KEY_HERE` を更新します。

<img width="800" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/45a7f260-38f9-32ca-b88a-53f359a16604.png">

キーは https://console.developers.google.com から取得します。

<img width="1029" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/99441399-a036-dee3-f0c9-aa15ba3f86c2.png">

ビルドして実行すると、このように表示されます。
<img width="400" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/12dc4500-4c96-081c-d6ed-f99294ab66b9.png">

## UIの設定
#### 移動
スワイプで地図を平行移動できます。

```kotlin:
googleMap.uiSettings.isScrollGesturesEnabled = true
```

#### ズーム
ピンチイン・アウトで縮尺を変更できます。

```kotlin:
googleMap.uiSettings.isZoomGesturesEnabled = true
```

#### 回転
ピンチからの回転で地図が回転できます。

```kotlin:
googleMap.uiSettings.isRotateGesturesEnabled = true
```

#### ズームボタン
画面右下にズーム変更ボタンが表示されます。

<img width="54" alt="10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/a829715c-ea94-9bf3-821c-f49a3671823c.png">

```kotlin:
googleMap.uiSettings.isZoomGesturesEnabled = true
```

#### ツールバー
マーカーをタップした時に、
画面の右下に表示されるGoogleMapのユーザインターフェイスです。

```kotlin:
googleMap.uiSettings.isMapToolbarEnabled = true
```
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/3702d816-66dd-2113-bed8-123593d1eec4.png)

ズームボタンと同時に表示するとこのように表示されます。

<img width="148" alt="11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/f88edf93-caf4-3d85-cb58-84c51973443b.png">

#### ティルト
2本指でスワイプで視点を傾けることができます。

```kotlin:
googleMap.uiSettings.isTiltGesturesEnabled = true
```
<img width="300" alt="6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/f667fc77-fee8-4d6f-b812-d68d6edce060.png">

#### コンパス
画面左上の表示されます。

```kotlin:
googleMap.uiSettings.isCompassEnabled = true
```

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/1f5976d5-366b-1ed5-b1ec-380bbcca194f.png)

#### 現在地表示
`ACCESS_COARSE_LOCATION` または `ACCESS_FINE_LOCATION` 
の許可を取得しておく必要があります。

```kotlin
googleMap.isMyLocationEnabled = true
```

<img width="89" alt="9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/5916f1c2-7198-f0a7-2848-24eb7c62b090.png">

#### 現在地ボタン
画面の右上に表示されます。
タップすると現在地にカメラと縮尺が調整されます。

```kotlin
googleMap.isMyLocationButtonEnabled = true
```
<img width="63" alt="8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/fb32ac8c-9973-7884-957b-5fa67a9b4f5f.png">

#### カメラの移動

```kotlin
// アニメーションなし
googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng))

// アニメーションあり
googleMap.animateCamera(CameraUpdateFactory.newLatLng(sydney))
```

#### カメラの縮尺変更

```kotlin
val zoomValue = 14.0f // 1.0f 〜 21.0f を指定
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoomValue))
```
おおよその詳細レベル

```
1: World
5: Landmass/continent
10: City
15: Streets
20: Buildings
```

ズームレベルの詳細はこちらを参考に
https://developers.google.com/maps/documentation/android-sdk/views
https://qiita.com/SnowMonkey/items/795779913be692c12a0b

#### マーカー表示

```kotlin
val sydney = LatLng(-34.0, 151.0)
googleMap.addMarker(
    MarkerOptions()
        .position(sydney)             // 地図上のマーカーの位置
        .title("Marker in Sydney")    // マーカーをタップ時に表示するテキスト文字列
        .snippet("Australian cities") // タイトルの下に表示される追加のテキスト
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)) // アイコン
)
```

<img width="144" alt="12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/646225ad-fe17-7133-9c4a-5fda35e0fbe7.png">

また、マーカーをタップしなくても吹き出しを表示することも出来る。

```kotlin
val marker = googleMap.addMarker(
    MarkerOptions()
        .position(latLng)
        .title("test")
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
)
marker.showInfoWindow() // タップした時と同じ挙動
```

## 円の描画

```kotlin
val latLng = LatLng(35.681236, 139.767125) // 東京駅
val radius = 1000 * 10.0 // 10km
googleMap.addCircle(
    CircleOptions()
        .center(latLng)          // 円の中心位置
        .radius(radius)          // 半径 (メートル単位)
        .strokeColor(Color.BLUE) // 線の色
        .strokeWidth(2f)         // 線の太さ
        .fillColor(0x400080ff)   // 円の塗りつぶし色
)
```

<img width="350" alt="13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/4d33769e-8396-1966-d845-0c8ef925ed87.png">

## 線の描画

```kotlin
googleMap.addPolyline(
    PolylineOptions()
        .add(LatLng(35.681236, 139.767125)) // 東京駅
        .add(LatLng(34.7331, 135.5002))     // 新大阪駅
        .color(Color.RED)                   // 線の色
        .width(8f)                          // 線の太さ
)
```

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/bd8ce3a1-432c-4155-44ce-c65e99808df2.png)


## ２点間に距離を計算(SphericalUtil)

距離を簡単に計算するのに必要なユーティリティライブラリを追加します。
https://developers.google.com/maps/documentation/android-sdk/utility/

```gradle:/app/build.gradle
dependencies {
  ...
  // add
  implementation 'com.google.maps.android:android-maps-utils:0.5'
}

```

検証として、`東京駅` 〜 `新大阪駅` の緯度経度を使います。

```kotlin
val latLngA = LatLng(35.681236, 139.767125)
val latLngB = LatLng(34.7331, 135.5002)

// 距離をメートル単位で返す
val distance = SphericalUtil.computeDistanceBetween(latLngA, latLngB)

println("AB: $distance m")
println("AB: ${distance / 1000} km")
```

出力

```console:
AB: 401709.92548952583 m
AB: 401.70992548952586 km
```

以下は、PCのブラウザでGoogleMapで距離を測った結果です。

<img width="853" alt="ab.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112186/aad3a108-f830-ee25-a94b-de3af318f605.png">

## ２点間に距離を計算(Location)

ユーティリティライブラリを入れなくても、`Location`クラスで２点間の距離を計算できます。
簡単に呼び出せるように以下の`Extension`を定義しておきます。

```kotlin
fun LatLng.distanceBetween(toLatLng: LatLng): Float {
    val results = FloatArray(1)
    try {
        Location.distanceBetween(
            this.latitude, this.longitude,
            toLatLng.latitude, toLatLng.longitude,
            results
        )
    } catch (e: IllegalArgumentException) {
        return -1.0f
    }
    return results[0]
}
```

呼び出し元

```kotlin
val latLngA = LatLng(35.681236, 139.767125)
val latLngB = LatLng(34.7331, 135.5002)

// 距離をメートル単位で返す
val distance = latLngA.distanceBetween(latLngB)

println("AB: ${latLngA.distanceBetween(latLngB)} m")
println("AB: ${latLngA.distanceBetween(latLngB) / 1000} km")
```

`SphericalUtil`と比較した結果、こちらは少し**誤差**が出るようです。

```console
 AB: 402483.6 m
 AB: 402.48358 km
```

## まとめ
本記事で記述しているのはGoogleMapAPIの中でもごく一部です。
忘れた頃にいちいちググりにいくのが面倒なので、ひとまずまとめておきました。

## 公式資料
https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap
http://googlemaps.github.io/android-maps-utils/javadoc/com/google/maps/android/SphericalUtil.html