Xamarin逆引きTips
Xamarin.Androidで地図にマーカーを表示するには?(Google Maps使用)
「Google Maps Android API v2」を使って、Xamarin.Androidアプリで地図上にマーカーや吹き出しを表示する方法を解説する。
前回に引き続き、Xamarin.AndroidアプリでGoogle Maps Android API v2(以下、「GoogleMapAPI」と表記)を使用する。今回はマーカーや吹き出しを表示する方法を解説する。
「Tips:Xamarin.Androidで地図に図形を表示するには?(Google Maps使用)」の続きとして解説するので、プロジェクトの準備は前回を参照してほしい。
1. 画面を準備する
前回終了時点で、Main.axml
ファイルを開くと、以下のようになっているはずだ。
<?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" />
<Button
android:id="@+id/buttonLine"
android:layout_alignLeft="@+id/buttonCenter"
android:layout_above="@+id/buttonCenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Line" />
<Button
android:id="@+id/buttonPolygon"
android:layout_alignLeft="@+id/buttonBounds"
android:layout_above="@+id/buttonBounds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Polygon" />
<Button
android:id="@+id/buttonCircle"
android:layout_alignLeft="@+id/buttonCamera"
android:layout_above="@+id/buttonCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Circle" />
</RelativeLayout>
|
これを、以下のように修正してボタンを追加する。
<?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" />
<Button
android:id="@+id/buttonLine"
android:layout_alignLeft="@+id/buttonCenter"
android:layout_above="@+id/buttonCenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Line" />
<Button
android:id="@+id/buttonPolygon"
android:layout_alignLeft="@+id/buttonBounds"
android:layout_above="@+id/buttonBounds"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Polygon" />
<Button
android:id="@+id/buttonCircle"
android:layout_alignLeft="@+id/buttonCamera"
android:layout_above="@+id/buttonCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Circle" />
<!-- 追加ここから -->
<Button
android:id="@+id/buttonAddMarker"
android:layout_alignLeft="@+id/buttonLine"
android:layout_above="@+id/buttonLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Marker" />
<Button
android:id="@+id/buttonDeleteMarker"
android:layout_alignLeft="@+id/buttonCircle"
android:layout_above="@+id/buttonCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete Marker" />
<!-- 追加ここまで -->
</RelativeLayout>
|
これをUIデザイナーで確認すると、図1のようになる。
前回までの画面にある[Line][Polygon][Circle]ボタンの上に、それぞれ[Add Marker][Delete Marker]ボタンを配置している。
2. マーカーを追加する
MainActivity.cs
ファイルに、[Add Marker]ボタンを押した時に「東京スカイツリー」と「東京タワー」の場所にそれぞれマーカーを追加するコードを、以下のように記述する。
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
……省略……
Marker marker1 = null;
Marker marker2 = null;
FindViewById<Button>(Resource.Id.buttonAddMarker).Click += (sender, e) =>
{
if (marker1 == null)
{
marker1 = map.AddMarker(new MarkerOptions()
.SetTitle("東京スカイツリー")
.SetSnippet("東京都墨田区押上1−1−2")
.SetPosition(new LatLng(35.710063d, 139.8107d))
.InvokeIcon(BitmapDescriptorFactory.DefaultMarker(
BitmapDescriptorFactory.HueAzure)) //<--1
);
}
if (marker2 == null)
{
marker2 = map.AddMarker(new MarkerOptions()
.SetTitle("東京タワー")
.SetSnippet("東京都港区芝公園4−2−8")
.SetPosition(new LatLng(35.65858,139.745433))
.InvokeIcon(BitmapDescriptorFactory.DefaultMarker(
BitmapDescriptorFactory.HueOrange)) //<--2
);
}
};
}
}
|
1で、[Add Marker]ボタンを押した時に、map.AddMarker
メソッドを呼び出して、東京スカイツリーの位置に、マーカーを追加している。引数はMarkerOption
で、このオブジェクトにさまざまなパラメーターを設定する。SetTitle
メソッドとSetSnippet
メソッドで指定しているのは、後述するマーカーの吹き出しに表示されるタイトルと説明文だ。SetPosition
メソッドでマーカーの位置を、InvokeIcon
メソッドでマーカーの画像を指定する。ここではBitmapDescriptorFactory.DefaultMarker
メソッドで、既定のアイコンの色だけを変更したものを使用している。
アイコンを変更するには、BitmapDescriptorFactory.FromResource
などのメソッドを使用するが、詳細についてはここでは述べない。ネイティブのGoogleMapAPIのAPIリファレンスを参考にしてほしい。
map.AddMarker
メソッドでマーカーを追加すると、その戻り値としてMarker
オブジェクトが返却される。これは、後述するマーカーの削除やマーカーが選択された時の識別子として利用する。
2は、1と同じ方法で、東京タワーの位置にマーカーを追加している。
3. マーカーを削除する
次に、追加したマーカーを削除する方法を解説する。
[Delete Marker]ボタンを押した時に「東京スカイツリー」のマーカーのみを削除するコードを、以下のように記述する。
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
……省略……
Marker marker1 = null;
Marker marker2 = null;
……省略……
FindViewById<Button>(Resource.Id.buttonDeleteMarker).Click += (sender, e) =>
{
if (marker1 != null)
{
marker1.Remove();
marker1 = null;
}
};
}
}
|
マーカーの削除は、Polyline
やPolygon
などと同じく、Marker
オブジェクトのRemove
メソッドを呼び出すだけだ。
ここまでのプログラムを実行すると、図2のようになる。
[Add Marker]ボタンを押すと、東京スカイツリーの位置に青色のマーカーが、さらに東京タワーの位置にオレンジ色のマーカーがそれぞれ表示される。
[Delete Marker]ボタンを押すと、東京スカイツリーのマーカーが削除される。
4. マーカーが選択された時に処理を行う
続いて、マーカーをタップして選択した時に何らかの処理を行う方法を解説する。
MyActivity.cs
ファイルに以下のようにコードを追加する。
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
……省略……
Marker marker1 = null;
Marker marker2 = null;
……省略……
map.MarkerClick += (object sender, GoogleMap.MarkerClickEventArgs e) => //<--1
{
Toast.MakeText(this,
e.Marker.Title + "のマーカーがタップされました。",
ToastLength.Short).Show(); //<--2
e.Handled = false; //<--3
};
}
}
|
マーカーが選択されると、GoogleMap
オブジェクトのMarkerClick
イベントが発生する(1)。イベントパラメーターであるMarkerClickEventArgs
オブジェクトから、クリックされたMarker
オブジェクトが取得できるので、そのTitle
プロパティ値を使って「○○のマーカーがタップされました。」というToast
を表示している(2)。
最後の3は、GoogleMapAPI側でマーカーがタップされた後の処理を行うかどうかだ。マーカーを選択した際の既定の動作は、「マーカーにセンタリングし、吹き出しを表示する」だが、MarkerClickEventArgs
オブジェクトのHandled
プロパティをtrue
に設定すると、既定の動作が抑制される。MarkerClickEventArgs.Handled
プロパティの既定値はtrue
であり、明示的にfalse
を設定しないと、吹き出しの表示などが行われなくなるので注意が必要だ。
ここまでのプログラムを実行すると、図3のようになる。
マーカーを選択すると、吹き出しとToast
が表示される。
5. 吹き出しが押された時に処理を行う
最後に、マーカーの上の吹き出しがタップされた時に処理を行う方法について解説する。
MyActivity.cs
ファイルに以下のようにコードを追加する。
[Activity(Label = "GoogleMapSample", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
……省略……
Marker marker1 = null;
Marker marker2 = null;
……省略……
map.InfoWindowClick += (object sender, GoogleMap.InfoWindowClickEventArgs e) => //<--1
{
Toast.MakeText(this,
e.Marker.Title + "の吹き出しがタップされました。",
ToastLength.Short).Show(); //<--2
};
}
}
|
吹き出しをタップすると、GoogleMap
オブジェクトのInfoWindowClick
イベントが発生する(1)。イベントパラメーターであるInfoWindowClickEventArgs
オブジェクトから、クリックされたMarker
オブジェクトが取得できるので、あとはマーカーの選択と同じように、「○○の吹き出しがタップされました。」というToast
を表示している(2)。
ここまでのプログラムを実行すると、図4のようになる。
マーカーを選択すると吹き出しが表示され、吹き出しをタップすると「吹き出しがタップされました」と表示される。
まとめ
Xamarin.Androidで地図を表示するには?(Google Maps使用)から今回までの数回で、Xamarin.AndroidでのGoogleMapAPIの基本的な使用方法を解説した。
再掲になるが、Xamarin Developer Center(英語)の、
および、GoogleMapAPIのネイティブの解説である
も参考にされたい。
また、クロスプラットフォームでUIを共通化できるXamarin.Formsでは、Xamarin.iOSではMapKit、Xamarin.AndroidではGoogleMapAPI、Windows PhoneではBing Mapsと、プラットフォームごとに異なるAPIを抽象化し、共通なAPIを用意している。こちらについては別の機会に解説する予定であるが、併せて参照するとよいだろう。
※以下では、本稿の前後を合わせて5回分(第21回~第25回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
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アプリで地図上にマーカーや吹き出しを表示する方法を解説する。
24. Xamarin Studio で画面を分割するには?(ショートカットキー情報あり)[Mac&Win対応]
Xamarin Studioの新機能として、コードエディターを左右の領域に分割して表示できるようになった。マウスとショートカットキーによる操作方法を説明する。
25. Xamarin.iOS/Androidでログを出力するには?
Xamarin.AndroidでネイティブAndroidのLogクラスを使ってログ出力する方法と、Xamarin.iOS/Androidで.NET基本クラスライブラリ機能を使ってログ出力する方法を解説する。