Kotlin 04.1 の高度な Android: Android Google マップ

1. 始める前に

Google マップを使用してアプリを構築すると、航空写真、地図用の堅牢な UI コントロール、位置情報追跡、位置マーカーなどの機能をアプリに追加できます。有名な釣り場や登山エリアの場所など、独自のデータセットの情報を表示することで、標準の Google マップに価値を追加できます。宝探しや拡張現実ゲームのように、プレーヤーが現実世界を探索するゲームを作成することもできます。

このレッスンでは、カスタマイズされた地図を表示し、ユーザーの現在地を表示する Wander という Google マップアプリを作成します。

前提条件

次の知識が必要です。

  • Android Studio を使用して基本的な Android アプリを作成して実行する方法。
  • 文字列などのリソースを作成して管理する方法。
  • Android Studio を使用してコードをリファクタリングし、変数の名前を変更する方法。
  • ユーザーとして Google マップを使用する方法。
  • ランタイム権限を設定する方法。

学習内容

  • Google API Console から API キーを取得してアプリに登録する方法
  • アプリに Google マップを統合する方法
  • さまざまな地図の種類を表示する方法
  • Google マップのスタイルを設定する方法
  • 地図にマーカーを追加する方法
  • ユーザーがスポット(POI)にマーカーを配置できるようにする方法
  • 位置情報の追跡を有効にする方法
  • Google マップが埋め込まれた Wander アプリを作成する方法
  • マーカーやスタイル設定など、アプリのカスタム機能を作成する方法
  • アプリで位置情報の追跡を有効にする方法

2. アプリの概要

この Codelab では、カスタム スタイルで Google マップを表示する Wander アプリを作成します。Wander アプリでは、位置にマーカーをドロップしたり、オーバーレイを追加したり、自分の位置をリアルタイムで確認したりできます。

5b12eda7f467bc2f.png

3. タスク: プロジェクトを設定して API キーを取得する

Maps SDK for Android には API キーが必要です。API キーを取得するには、[API とサービス] ページでプロジェクトを登録します。API キーは、アプリをその作成者に関連付けるデジタル証明書に関連付けられています。デジタル証明書の使用とアプリへの署名について詳しくは、アプリへの署名をご覧ください。

この Codelab では、デバッグ証明書の API キーを使用します。デバッグビルドに署名するで説明されているように、デバッグ用証明書は設計上安全ではありません。Maps SDK for Android を使用する公開済みの Android アプリには、リリース証明書のキーという 2 つ目の API キーが必要です。リリース証明書の取得について詳しくは、API キーを取得するをご覧ください。

Android Studio には、便利なテンプレート コードを生成する Google Maps Activity テンプレートが含まれています。テンプレート コードには、API キーの取得を簡素化するリンクを含む google_maps_api.xml ファイルが含まれています。

ステップ 1: 地図テンプレートを使用して Wander プロジェクトを作成する

  1. 新しい Android Studio プロジェクトを作成します。
  2. [Google Maps Activity] テンプレートを選択します。

d6b874bb19ea68cd.png

  1. プロジェクトに Wander という名前を付けます。
  2. 最小 API レベルを API 19 に設定します。言語が Kotlin になっていることを確認します。
  3. [完了] をクリックします。
  4. アプリのビルドが完了したら、プロジェクトと、Android Studio が作成した次のマップ関連ファイルを確認します。

google_maps_api.xml - この構成ファイルを使用して API キーを保持します。このテンプレートは、デバッグ用とリリース用の 2 つの google_maps_api.xml ファイルを生成します。デバッグ証明書の API キーのファイルは src/debug/res/values にあります。リリース用証明書の API キーのファイルは src/release/res/values にあります。この Codelab では、デバッグ証明書のみを使用します。

activity_maps.xml - このレイアウト ファイルには、画面全体を埋める単一のフラグメントが含まれています。SupportMapFragment クラスは Fragment クラスのサブクラスです。SupportMapFragment は、アプリに地図を配置する最も簡単な方法です。地図のビューをラップし、必要なライフサイクルを自動的に処理します。

SupportMapFragment は、ViewGroup<fragment> タグで、追加の name 属性とともにレイアウト ファイルに含めることができます。

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java - MapsActivity.kt ファイルは、onCreate() メソッドで SupportMapFragment をインスタンス化し、クラスの getMapAsync() を使用して、マップシステムとビューを自動的に初期化します。SupportMapFragment を含むアクティビティは、OnMapReadyCallback インターフェースとそのインターフェースの onMapReady() メソッドを実装する必要があります。地図が読み込まれると、onMapReady() メソッドが呼び出されます。

ステップ 2: API キーを取得する

  1. google_maps_api.xml ファイルのデバッグ バージョンを開きます。
  2. ファイルで、長い URL を含むコメントを探します。URL のパラメータには、アプリに関する具体的な情報が含まれます。
  3. URL をコピーしてブラウザに貼り付けます。
  4. プロンプトに従って、[API とサービス] ページでプロジェクトを作成します。指定された URL のパラメータにより、ページは Maps SDK for Android を自動的に有効にすることを認識します。
  5. [API キーを作成] をクリックします。
  6. 次のページで、[API キー] セクションに移動し、作成したキーをクリックします。
  7. [キーを制限] をクリックし、[Maps SDK for Android] を選択して、キーの使用を Android アプリに制限します。
  8. 生成された API キーをコピーします。「AIza"」で始まります。
  9. google_maps_api.xml ファイルで、YOUR_KEY_HERE と書かれている google_maps_key 文字列に鍵を貼り付けます。
  10. アプリを実行します。アクティビティに地図が埋め込まれ、オーストラリアのシドニーにマーカーが設定されていることが確認できます。(シドニーのマーカーはテンプレートの一部であり、後で変更します)。

34dc9dd877c90996.png

ステップ 3: mMap の名前を変更する

MapsActivity には、mMap という名前のプライベート lateinit var があります。これは GoogleMap 型です。Kotlin の命名規則に従って、mMap の名前を map に変更します。

  1. MapsActivity で、mMap を右クリックし、[Refactor] > [Rename...] をクリックします

e713ccb3384450c6.png

  1. 変数名を map に変更します。

onMapReady() 関数の mMap へのすべての参照も map に変更されます。

4. タスク: 地図タイプを追加する

Google マップには、標準、ハイブリッド、衛星、地形、なし(地図をまったく表示しない)の 5 種類の地図タイプがあります。

法線マップ

航空写真地図

ハイブリッド地図

地形地図

地図の種類ごとに、異なる種類の情報が表示されます。たとえば、車でナビゲーションに地図を使用する場合は、道路名が表示されると便利なので、[標準] オプションを使用できます。ハイキングの際は、地形図で山頂までの残り距離を確認できます。

このタスクでは、次のことを行います。

  1. ユーザーが地図の種類を変更できるオプション メニューを含むアプリバーを追加します。
  2. 地図の開始位置を自宅の位置に移動します。
  3. 地図上の単一の場所を示し、ラベルを含めることができるマーカーのサポートを追加します。

地図の種類のメニューを追加

このステップでは、ユーザーが地図の種類を変更できるオプション メニューを含むアプリバーを追加します。

  1. 新しいメニュー XML ファイルを作成するには、res ディレクトリを右クリックして、[New] > [Android Resource File] を選択します。
  2. ダイアログで、ファイル名を map_options とします。
  3. リソースタイプとして [メニュー] を選択します。
  4. [OK] をクリックします。
  5. [コード] タブで、新しいファイル内のコードを次のコードに置き換えて、地図のメニュー オプションを作成します。「なし」のマップタイプは、マップがまったく表示されないため、省略されています。このステップではエラーが発生しますが、次のステップで解決します。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never" />
</menu>
  1. strings.xml で、title 属性のリソースを追加してエラーを解決します。
<resources>
   ...
   <string name="normal_map">Normal Map</string>
   <string name="hybrid_map">Hybrid Map</string>
   <string name="satellite_map">Satellite Map</string>
   <string name="terrain_map">Terrain Map</string>
   <string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
   <string name="dropped_pin">Dropped Pin</string>
   <string name="poi">poi</string>
</resources>
  1. MapsActivity で、onCreateOptionsMenu() メソッドをオーバーライドし、map_options リソース ファイルからメニューをインフレートします。
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. MapsActivity.kt で、onOptionsItemSelected() メソッドをオーバーライドします。地図の種類定数を使用して地図の種類を変更し、ユーザーの選択を反映します。
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
   // Change the map type based on the user's selection.
   R.id.normal_map -> {
       map.mapType = GoogleMap.MAP_TYPE_NORMAL
       true
   }
   R.id.hybrid_map -> {
       map.mapType = GoogleMap.MAP_TYPE_HYBRID
       true
   }
   R.id.satellite_map -> {
       map.mapType = GoogleMap.MAP_TYPE_SATELLITE
       true
   }
   R.id.terrain_map -> {
       map.mapType = GoogleMap.MAP_TYPE_TERRAIN
       true
   }
   else -> super.onOptionsItemSelected(item)
}
  1. アプリを実行します。
  2. 428da163b831115b.png をクリックして、地図の種類を変更します。モードによって地図の外観がどのように変化するかを確認してください。

6fa42970d87f5dc7.png

5. タスク: マーカーを追加する

デフォルトでは、onMapReady() コールバックには、Google マップが作成されたオーストラリアのシドニーにマーカーを配置するコードが含まれています。デフォルトのコールバックでは、地図をアニメーションでシドニーにパンします。

このタスクでは、地図のカメラを自宅に移動し、指定したレベルまでズームして、マーカーを配置します。

ステップ 1: 自宅にズームしてマーカーを追加する

  1. MapsActivity.kt ファイルで、onMapReady() メソッドを見つけます。シドニーにマーカーを配置してカメラを移動するコードを削除します。メソッドは次のようになります。
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. こちらの手順に沿って、自宅の緯度と経度を確認します。
  2. 緯度と経度の値を作成し、その浮動小数点値を入力します。
val latitude = 37.422160
val longitude = -122.084270
  1. homeLatLng という名前の新しい LatLng オブジェクトを作成します。homeLatLng オブジェクトで、作成した値を渡します。
val homeLatLng = LatLng(latitude, longitude)
  1. 地図のズームレベルを指定する val を作成します。ズームレベル 15f を使用します。
val zoomLevel = 15f

ズームレベルは、地図の拡大率を制御します。次のリストは、各ズームレベルで表示されるおおよその詳細度を示しています。

  • 1: 世界
  • 5: 大陸
  • 10: 都市
  • 15: 通り
  • 20: 建物
  1. map オブジェクトで moveCamera() 関数を呼び出し、CameraUpdateFactory.newLatLngZoom() を使用して CameraUpdate オブジェクトを渡すことで、カメラを homeLatLng に移動します。homeLatLng オブジェクトと zoomLevel を渡します。
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. homeLatLng の地図にマーカーを追加します。
map.addMarker(MarkerOptions().position(homeLatLng))

完成したメソッドは次のようになります。

override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

   //These coordinates represent the latitude and longitude of the Googleplex.
   val latitude = 37.422160
   val longitude = -122.084270
   val zoomLevel = 15f

   val homeLatLng = LatLng(latitude, longitude)
   map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
   map.addMarker(MarkerOptions().position(homeLatLng))
}
  1. アプリを実行します。地図が自宅に移動し、目的のレベルにズームされ、自宅にマーカーが配置されます。

fc939024778ee76.png

ステップ 2: 長押しでマーカーを追加できるようにする

このステップでは、ユーザーが地図上の場所を長押ししたときにマーカーを追加します。

  1. MapsActivity に、GoogleMap を引数として受け取る setMapLongClick() というメソッド スタブを作成します。
  2. setOnMapLongClickListener リスナーを地図オブジェクトにアタッチします。
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. setOnMapLongClickListener() で、addMarker() メソッドを呼び出します。位置が渡された LatLng に設定された新しい MarkerOptions オブジェクトを渡します。
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. onMapReady() メソッドの最後で、map を使用して setMapLongClick() を呼び出します。
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. アプリを実行します。
  2. 地図を長押しして、その場所にマーカーを配置します。
  3. マーカーをタップすると、画面の中央に表示されます。

4ff8d1c1db3bca9e.png

ステップ 3: マーカーの情報ウィンドウを追加する

このステップでは、マーカーがタップされたときにマーカーの座標を表示する InfoWindow を追加します。

  1. setMapLongClick()setOnMapLongClickListener() で、snippetval を作成します。スニペットは、タイトルの後に表示される追加のテキストです。スニペットにマーカーの緯度と経度が表示されます。
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A snippet is additional text that's displayed after the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. addMarker() で、R.string.dropped_pin 文字列リソースを使用して、マーカーの title を Dropped Pin に設定します。
  2. マーカーの snippetsnippet に設定します。

完成した関数は次のようになります。

private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A Snippet is Additional text that's displayed below the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet)
              
       )
   }
}
  1. アプリを実行します。
  2. 地図を長押しして位置マーカーをドロップします。
  3. マーカーをタップして情報ウィンドウを表示します。

63f210e6e47dfa29.png

ステップ 4: POI リスナーを追加する

スポット(POI)は、対応するアイコンとともに地図にデフォルトで表示されます。POI には、公園、学校、政府機関などが含まれます。地図のタイプが normal に設定されている場合、ビジネス スポットも地図に表示されます。ビジネス スポットは、店舗、レストラン、ホテルなどのビジネスを表します。

このステップでは、地図に GoogleMap.OnPoiClickListener を追加します。このクリック リスナーは、ユーザーがスポットをクリックすると、すぐに地図上にマーカーを配置します。クリック リスナーは、POI 名を含む情報ウィンドウも表示します。

  1. MapsActivity に、GoogleMap を引数として受け取る setPoiClick() というメソッド スタブを作成します。
  2. setPoiClick() メソッドで、渡された GoogleMapOnPoiClickListener を設定します。
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. setOnPoiClickListener() で、マーカーの val poiMarker を作成します。
  2. map.addMarker() を使用してマーカーに設定し、MarkerOptionstitle を POI の名前に設定します。
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. setOnPoiClickListener() 関数で、poiMarker に対して showInfoWindow() を呼び出して、情報ウィンドウをすぐに表示します。
poiMarker.showInfoWindow()

setPoiClick() 関数の最終的なコードは次のようになります。

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. onMapReady() の最後に、setPoiClick() を呼び出して map を渡します。
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. アプリを実行し、公園やカフェなどの POI を探します。
  2. POI をタップすると、その場所にマーカーが配置され、情報ウィンドウに POI の名前が表示されます。

f4b0972c75d5fa5f.png

6. タスク: 地図のスタイルを設定する

Google マップはさまざまな方法でカスタマイズでき、地図に独自のルック アンド フィールを与えることができます。

他のフラグメントをカスタマイズする場合と同様に、使用可能な XML 属性を使用して MapFragment オブジェクトをカスタマイズできます。ただし、このステップでは、GoogleMap オブジェクトのメソッドを使用して、MapFragmentコンテンツのルック アンド フィールをカスタマイズします。

地図のカスタム スタイルを作成するには、地図内のフィーチャーの表示方法を指定する JSON ファイルを生成します。この JSON ファイルを手動で作成する必要はありません。Google は、地図のスタイルを視覚的に設定すると JSON を生成する Maps Platform スタイル ウィザードを提供しています。このタスクでは、地図をレトロなテーマでスタイル設定します。つまり、地図でビンテージ カラーを使用し、色付きの道路を追加します。

ステップ 1: 地図のスタイルを作成する

  1. ブラウザで https://mapstyle.withgoogle.com/ に移動します。
  2. [スタイルを作成] を選択します。
  3. [レトロ] を選択します。

208b3d3aeab0d9b6.png

  1. [その他のオプション] をクリックします。

4a35faaf9535ee82.png

  1. [道路] > [塗りつぶし] を選択します。
  2. 道路の色を任意の色(ピンクなど)に変更します。

92c3293749293a4c.png

  1. [完了] をクリックします。

f1bfe8585eb69480.png

  1. 結果のダイアログから JSON コードをコピーし、必要に応じて、次のステップで使用するためにプレーン テキストのメモに保存します。

3c32168b299d6420.png

ステップ 2: 地図にスタイルを追加する

  1. Android Studio の res ディレクトリに、リソース ディレクトリを作成して raw という名前を付けます。raw ディレクトリ リソースは JSON コードのように使用します。
  2. res/rawmap_style.json というファイルを作成します。
  3. 保存した JSON コードを新しいリソース ファイルに貼り付けます。
  4. MapsActivity で、onCreate() メソッドの上に TAG クラス変数を作成します。これはロギングの目的で使用されます。
private val TAG = MapsActivity::class.java.simpleName
  1. また、MapsActivity で、GoogleMap を受け取る setMapStyle() 関数を作成します。
  2. setMapStyle()try{} ブロックを追加します。
  3. try{} ブロックで、スタイルの成功を表す val success を作成します。(次の catch ブロックを追加します)。
  4. try{} ブロックで、JSON スタイルを地図に設定し、GoogleMap オブジェクトで setMapStyle() を呼び出します。JSON ファイルを読み込む MapStyleOptions オブジェクトを渡します。
  5. 結果を success に割り当てます。setMapStyle() メソッドは、スタイル設定ファイルの解析とスタイルの設定の成功ステータスを示すブール値を返します。
private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )
   }
}
  1. success が false の場合の if ステートメントを追加します。スタイリングに失敗した場合は、解析が失敗したことを示すログを出力します。
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. スタイル ファイルが見つからない状況を処理する catch{} ブロックを追加します。catch ブロックで、ファイルを読み込めない場合は、Resources.NotFoundException をスローします。
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

完成したメソッドは次のコード スニペットのようになります。

private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )

       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}
  1. 最後に、onMapReady() メソッドで setMapStyle() メソッドを呼び出し、GoogleMap オブジェクトを渡します。
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. アプリを実行します。
  2. マップを normal モードに設定すると、レトロなテーマと選択した色の道路で新しいスタイルが表示されます。

b59d6cb81f02a14f.png

ステップ 3: マーカーのスタイルを設定する

地図マーカーのスタイルを設定して、地図をさらにカスタマイズできます。このステップでは、デフォルトの赤いマーカーをより魅力的なものに変更します。

  1. onMapLongClick() メソッドで、次のコード行をコンストラクタの MarkerOptions() に追加して、デフォルトのマーカーを使用し、色を青に変更します。
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

onMapLongClickListener() は次のようになります。

map.setOnMapLongClickListener { latLng ->
   // A snippet is additional text that's displayed after the title.
   val snippet = String.format(
       Locale.getDefault(),
       "Lat: %1$.5f, Long: %2$.5f",
       latLng.latitude,
       latLng.longitude
   )
   map.addMarker(
       MarkerOptions()
           .position(latLng)
           .title(getString(R.string.dropped_pin))
           .snippet(snippet)
         .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
   )
}
  1. アプリを実行します。長押し後に表示されるマーカーが青色で表示されます。onPoiClick() メソッドにスタイルを追加していないため、POI マーカーはまだ赤色です。

b9916bca3c367e3.png

7. タスク: オーバーレイを追加する

Google マップをカスタマイズする方法の 1 つは、地図の上に描画することです。この手法は、人気の釣り場など、特定の種類の場所をハイライト表示する場合に便利です。

  • シェイプ: 地図にポリラインポリゴンを追加できます。
  • GroundOverlay オブジェクト: 地面オーバーレイは、地図に固定されている画像です。マーカーとは異なり、地面オーバーレイは画面ではなく地表面に平行に配置されます。地図を回転、傾斜、ズームすると、画像の向きが変わります。地面オーバーレイは、地図上の 1 つの領域に 1 つの画像を固定する場合に役立ちます。

ステップ: 地面オーバーレイを追加する

このタスクでは、Android の形のグラウンド オーバーレイを現在地に配置します。

  1. この Android イメージをダウンロードして、res/drawable フォルダに保存します。(ファイル名が android.png であることを確認してください)。

61fabd56a0841b44.png

  1. onMapReady() で、カメラを家の位置に移動する呼び出しの後に、GroundOverlayOptions オブジェクトを作成します。
  2. オブジェクトを androidOverlay という変数に割り当てます。
val androidOverlay = GroundOverlayOptions()
  1. BitmapDescriptorFactory.fromResource() メソッドを使用して、ダウンロードした画像リソースから BitmapDescriptor オブジェクトを作成します。
  2. 結果の BitmapDescriptor オブジェクトを GroundOverlayOptions オブジェクトの image() メソッドに渡します。
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. 目的のオーバーレイの幅(メートル単位)の float overlaySize を作成します。この例では、幅 100f が適切です。

position() メソッドを呼び出して GroundOverlayOptions オブジェクトの position プロパティを設定し、homeLatLng オブジェクトと overlaySize を渡します。

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. GoogleMap オブジェクトで addGroundOverlay() を呼び出し、GroundOverlayOptions オブジェクトを渡します。
map.addGroundOverlay(androidOverlay)
  1. アプリを実行します。
  2. zoomLevel の値を 18f に変更すると、Android の画像がオーバーレイとして表示されます。

b1b25b0acd6a9807.png

8. タスク: 位置情報の追跡を有効にする

ユーザーは現在地を確認するために Google マップをよく利用します。地図上にデバイスの位置情報を表示するには、位置情報レイヤを使用します。

位置情報レイヤは、地図に現在地アイコンを追加します。

f317f84dcb3ac3a1.png

ユーザーがボタンをタップすると、地図の中心がデバイスの位置に移動します。現在地は、デバイスが静止している場合は青い点で示され、デバイスが移動している場合は青い山形で示されます。

このタスクでは、位置情報データレイヤを有効にします。

ステップ: 位置情報の利用許可をリクエストする

Google マップで位置情報の追跡を有効にするには、1 行のコードが必要です。ただし、ユーザーが位置情報の権限を付与していることを確認する必要があります(ランタイム権限モデルを使用)。

このステップでは、位置情報の利用許可をリクエストし、位置情報の追跡を有効にします。

  1. AndroidManifest.xml ファイルで、FINE_LOCATION 権限がすでに存在することを確認します。Android Studio で Google マップ テンプレートを選択すると、この権限が挿入されます。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. MapsActivityREQUEST_LOCATION_PERMISSION クラス変数を作成します。
private val REQUEST_LOCATION_PERMISSION = 1
  1. 権限が付与されているかどうかを確認するには、MapsActivityisPermissionGranted() というメソッドを作成します。このメソッドで、ユーザーが権限を付与しているかどうかを確認します。
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. アプリで位置情報の追跡を有効にするには、引数を受け取らず何も返さない enableMyLocation() というメソッドを MapsActivity に作成します。内部で ACCESS_FINE_LOCATION 権限を確認します。権限が付与されている場合は、位置情報レイヤを有効にします。それ以外の場合は、権限をリクエストします。
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. onMapReady() コールバックから enableMyLocation() を呼び出して、位置情報レイヤを有効にします。
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. onRequestPermissionsResult() メソッドをオーバーライドします。requestCodeREQUEST_LOCATION_PERMISSION と等しいかどうかを確認します。その場合は、権限が付与されています。権限が付与されている場合は、grantResults 配列の最初のスロットに PackageManager.PERMISSION_GRANTED が含まれているかどうかも確認します。その場合は、enableMyLocation() を呼び出します。
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. アプリを実行します。デバイスの位置情報へのアクセスを求めるダイアログが表示されます。権限を許可してください。

da7e23e00ec762c1.png

地図にデバイスの現在地が青い点で表示されます。位置情報ボタンが表示されます。地図を現在地から移動させた後にこのボタンをクリックすると、地図がデバイスの現在地を中心に戻ります。

5b12eda7f467bc2f.png

9. 解答コード

完成した Codelab のコードをダウンロードします。

$  git clone https://github.com/googlecodelabs/android-kotlin-geo-maps

または、リポジトリを ZIP ファイルとしてダウンロードし、Android Studio で開くこともできます。

10. まとめ

おめでとうございます!Android Kotlin アプリに Google マップを追加し、スタイルを設定しました。

11. 関連リンク

Android デベロッパー ドキュメント:

リファレンス ドキュメント:

12. 次の Codelab

このコースの他の Codelab へのリンクについては、Kotlin を使った高度な Android 開発の Codelab のランディング ページをご覧ください。