Xamarin逆引きTips

Xamarin逆引きTips

Xamarin.Androidで地図を操作するには?(Google Maps使用)

2014年10月1日

「Google Maps Android API v2」を使って、Xamarin.Androidアプリで地図の表示位置や種類を変更する方法、ジェスチャの有効/無効を切り替える方法などを説明する。

奥山 裕紳(@amay077
  • このエントリーをはてなブックマークに追加

 前回に引き続き、Xamarin.AndroidアプリでGoogle Maps Android API v2(以下、「GoogleMapAPI」と表記)を使用する。今回は、地図の位置の変更や、地図種類の変更などの各種設定について解説する。

 「Tips:Xamarin.Androidで地図を表示するには?(Google Maps使用)」の続きとして解説するので、プロジェクトの準備は前回を参照してほしい。

1. 地図の位置を変更する

 GoogleMapAPIで地図を指定の位置に移動させるには、以下のような方法がある。

  • 中心位置(緯度経度)を指定
  • 範囲(南西と北東の緯度経度)を指定
  • カメラ(緯度経度、方位、傾き)を指定

 それぞれを試すために、まずは画面にボタンを3つ用意する。

 前回終了時点で、Main.axmlファイルを開くと、以下のようになっているはずだ。

AXML
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/map"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:name="com.google.android.gms.maps.MapFragment" />
前回終了時点のUIデザイン内容(Main.axml)

 これを、以下のように修正する。

AXML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
1
12
13
14
15
16
17
2
19
20
21
22
23
24
3
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <fragment
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.google.android.gms.maps.MapFragment" />
  <Button
    android:id="@+id/buttonCenter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentBottom="true"
    android:text="Center" />
  <Button
    android:id="@+id/buttonBounds" 
    android:layout_toRightOf="@+id/buttonCenter"
    android:layout_alignTop="@+id/buttonCenter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Bounds" />
  <Button
    android:id="@+id/buttonCamera" 
    android:layout_toRightOf="@+id/buttonBounds"
    android:layout_alignTop="@+id/buttonCenter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Camera" />
</RelativeLayout>
今回のUIデザイン内容(Main.axml)

 これをUIデザイナーで確認すると、図1のようになる。

図1 ボタンを貼り付けたMain.axml

 前回は画面いっぱいに地図を配置しただけだったが、今回はそれに加えてボタンを配置するため、全体をRelativeLayoutで囲み、その全体にMapFragmentを配置し、13で、それぞれ[Center][Bounds][Camera]ボタンを配置している。

【コラム】レイアウト変更後にアプリケーションが落ちる場合

 筆者の経験による事象だが、上記のようなFragmentを含むレイアウトXMLを変更し、アプリケーションをビルドして実行すると、エラーでアプリケーションが落ちることがあった。このような場合は、メニューバーの[ビルド]-[すべてクリーン]を実行してから再度ビルド→実行すると正しく動作する。

中心位置(緯度経度)を指定

 MainActivity.csファイルを、以下のように修正する。

C#
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
……省略……

[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);

    var mapFragment = (MapFragment)FragmentManager.FindFragmentById(Resource.Id.map);
    var map = mapFragment.Map;  // <--1

    FindViewById<Button>(Resource.Id.buttonCenter).Click += (sender, e) => 
    {
      map.AnimateCamera(CameraUpdateFactory.NewLatLng(
        new LatLng(35.68d, 139.76d)));  // 東京駅付近 <--2
    };
  }
}
[Center]ボタンを押した時に、「東京駅付近」に移動する処理を実装したコード(MainActivity.cs)

 [Center]ボタンを押した時の処理を上記のように記述する。

 1で、画面に配置したMapFragmentから、実際の「地図」を表すGoogleMapオブジェクトを取得し、変数mapに代入する。

 GoogleMapAPIでは、GoogleMapオブジェクトのAnimateCameraメソッドにCameraUpdateクラスのインスタンスを渡すことで、目的の位置へ移動する。2では、CameraUpdateFactory.NewLatLngメソッドで緯度経度からCameraUpdateオブジェクトを生成し、それを引数にmap.AnimateCameraメソッドを呼び出している。なお、AnimateCameraは、メソッド名の通りアニメーションしながら移動するが、アニメーションさせたくない場合はGoogleMapオブジェクトのMoveCameraメソッドを使用する。こちらも引数はCameraUpdateだ。

範囲(南西と北東の緯度経度)を指定

 MainActivity.csファイルを、以下のように修正する。

C#
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);

    ……省略……

    FindViewById<Button>(Resource.Id.buttonBounds).Click += (sender, e) => 
    {
      var bounds = LatLngBounds.InvokeBuilder()
        .Include(new LatLng(35.4661d,139.6227d)) // 横浜駅
        .Include(new LatLng(35.4713d,139.6274d)) // 神奈川駅
        .Build(); //<--1

      map.AnimateCamera(CameraUpdateFactory.NewLatLngBounds(bounds, 100)); //<--2
    };
  }
}
[Bounds]ボタンを押した時に、「横浜駅」~「神奈川駅」を含む範囲に移動する処理を実装したコード(MainActivity.cs)

 [Bounds]ボタンを押した時の処理を上記のように記述する。

 範囲指定でもGoogleMap.AnimateCameraメソッドを使用する。引数として渡すCameraUpdateの生成方法が異なるだけだ。あらかじめ緯度経度の範囲を示すLatLngBoundsオブジェクトを用意しておき、それを指定してCameraUpdateFactory.NewLatLngBoundsメソッドを呼び出してCameraUpdateを生成する。NewLatLngBoundsメソッドの第2引数は画面に設ける余白で、ここでは100pxを指定している。あとはCameraUpdatemap.AnimateCameraメソッドに渡すだけだ。

カメラ(緯度経度、方位、傾き)を指定

 MainActivity.csファイルを、以下のように修正する。

C#
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);

    ……省略……

    FindViewById<Button>(Resource.Id.buttonCamera).Click += (sender, e) => 
    {
      map.AnimateCamera(CameraUpdateFactory.NewCameraPosition(
        new CameraPosition(
          new LatLng(35.710063d,139.8107d), // 東京スカイツリー(中心位置)
          17f,     // ズームレベル
          45f,     // 方位
          30f)));  // 傾き
    };
  }
}
[Camera]ボタンを押した時に、「横浜駅」~「神奈川駅」を含む範囲に移動する処理を実装したコード(MainActivity.cs)

 [Camera]ボタンを押した時の処理を上記のように記述する。

 カメラを使用する際は、CameraPositionオブジェクトを生成し、それを指定してCameraUpdateFactory.NewCameraPositionメソッドを呼び出し、CameraUpdateを生成する。CameraPositionは、「中心位置」「ズームレベル(=地図の表示倍率)」「方位」「視点の傾き」を指定する。上記の例では、「東京スカイツリー」で、「時計周りに45度回転」し、「視点を30度手前に傾けた」位置となる。方位については、自分が時計回りに45度回転するので、地図上のコンパスは反時計周りに45度回転する。

 ここまでのプログラムを実行すると、それぞれ以下の画面のようになる。

図2 プログラムの実行結果(それぞれ中心位置、範囲、カメラによる移動結果)

2. 地図の種類の変更、ジェスチャの有効/無効の切り替えなど

 その他の一般的な機能をまとめて紹介する。まずはMainActivity.csファイルを、以下のように追加する。

C#
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);

    var mapFragment = (MapFragment)FragmentManager.FindFragmentById(Resource.Id.map);
    var map = mapFragment.Map;

    map.MapType = GoogleMap.MapTypeSatellite ; // 衛星画像 <--1

    map.MyLocationEnabled = true; // 現在位置を表示する <--2

    map.BuildingsEnabled = false; // 建物を3D表示しない <--3
    map.SetIndoorEnabled(false);  // インドアマップを表示しない <--4

    map.UiSettings.ScrollGesturesEnabled = false; // ジェスチャでのスクロールを許可しない <--5
    map.UiSettings.ZoomGesturesEnabled = false;   // ジェスチャでのズームを許可しない <--6
    map.UiSettings.RotateGesturesEnabled = false; // ジェスチャでの回転を許可しない <--7
    map.UiSettings.TiltGesturesEnabled = false;   // ジェスチャでの視点変更を許可しない <--8

    map.UiSettings.CompassEnabled = false;           // コンパスを表示しない <--9
    map.UiSettings.IndoorLevelPickerEnabled = false; // インドアマップの階数を表示しない <--10
    map.UiSettings.MyLocationButtonEnabled = false;  // 現在位置ボタンを表示しない <--11
    map.UiSettings.ZoomControlsEnabled = false;      // ズームボタンを表示しない <--12
  }
}
地図の種類の変更、ジェスチャの有効/無効の切り替えなど(MainActivity.cs)

地図の種類の変更

 1は、表示する地図の種類を「衛星画像(GoogleMap.MapTypeSatellite)」に変更するコードだ。他に「通常(GoogleMap.MapTypeNormal)」や「通常+衛星画像(GoogleMap.MapTypeHybrid)」、「地形図(GoogleMap.MapTypeTerrain)」が使用できる。

現在位置の表示切り替え

 2は、現在位置を表示するためのコードだ。trueを設定すると、GPSにより取得した現在の位置を、コーディングを行わなくても地図上に表示できる。

建物を3D表示に切り替え

 3は、建物を3Dで表示しないようにするコードだ。前出の東京スカイツリーなどは既定では3Dで表示されるが、これをfalseにすると2Dの表示になる。

インドアマップの有効/無効の切り替え

 GoogleMapAPIには、インドアマップと呼ばれる、建物内部の地図を表示する機能があり、主に駅などで利用できる。4は、このインドアマップを表示しないようにするコードだ(ちなみにこの項目だけプロパティでなくSetIndoorEnabledメソッドなのは、今後、修正されるのではないかと推測する)。

ジェスチャ操作の有効/無効の切り替え

 5678はそれぞれ、ジェスチャでのスクロール、ズーム、回転、視点変更を無効にするためのコードだ。

地図上のコントロールの表示切り替え

 9101112はそれぞれ、地図上に表示されているコンパス、インドアマップの階数(4が有効なときに表示される)、現在位置ボタン(2が有効なときに表示される)、ズームボタンを非表示にするためのコードだ。

 地図の種類を「衛星画像」、現在位置を「表示する」としたプログラムを実行すると、図3のようになる。

図3 プログラムの実行結果(衛星画像、現在位置を表示)

まとめ

 Xamarin.AndroidでのGoogleMapAPIの基本的な使い方を解説した。Xamarin.iOSでのMapKitの使用と同じく、AndroidネイティブのGoogleMapAPIのAPIは、ほぼそのままXamarin.Androidで使えるので、開発の際には、ネイティブのGoogleMapAPIのAPIリファレンス(英語)を参照されたい。

 また、Xamarin.Android用のGoogleMapAPIライブラリは、ネイティブのライブラリをXamarinで利用するための技術「Binding」で実現されている。ソースコードが「GitHub: mono/monodroid-bindings」で公開されているので、興味のある人は自力でビルドしてみるのもよいだろう。

 次回以降は、GoogleMapAPIで図形を描く方法や、マーカーを使用する方法について解説する予定だ。

※以下では、本稿の前後を合わせて5回分(第19回~第23回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

19. Xamarin.iOSで地図にマーカーを表示するには?(MapKit使用)

Xamarin.iOSでiOS標準の地図ライブラリ「MapKit」を使って、マーカーを追加/削除するには? また、マーカー選択時の処理や、吹き出し表示、吹き出しタップ時の処理の、基本的な実装方法を説明する。

20. Xamarin.Androidで地図を表示するには?(Google Maps使用)

Androidで最も一般的な地図API「Google Maps Android API v2」を使って、Xamarin.Androidで地図を表示する方法を解説。API利用環境の準備から、まずはGoogleマップを表示するまでの手順を説明する。

21. 【現在、表示中】≫ Xamarin.Androidで地図を操作するには?(Google Maps使用)

「Google Maps Android API v2」を使って、Xamarin.Androidアプリで地図の表示位置や種類を変更する方法、ジェスチャの有効/無効を切り替える方法などを説明する。

22. Xamarin.Androidで地図に図形を表示するには?(Google Maps使用)

「Google Maps Android API v2」を使って、Xamarin.Androidアプリで地図上にライン/ポリゴン/円などの図形を表示する方法を解説する。

23. Xamarin.Androidで地図にマーカーを表示するには?(Google Maps使用)

「Google Maps Android API v2」を使って、Xamarin.Androidアプリで地図上にマーカーや吹き出しを表示する方法を解説する。

イベント情報(メディアスポンサーです)

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • 日本マイクロソフト株式会社
  • グレープシティ株式会社