Android Tips #26 Google Maps Android API v2 のマーカーをカスタマイズする
はじめに
前回の記事でご紹介したマーカーのカスタマイズ方法について、もう少し詳細に解説してみたいと思います。以下のようなマーカーを作ることができます!
マーカーを追加するには
マップ上にマーカーを追加するには GoogleMap#addMarker() メソッドを使います。引数には MarkerOption クラスのインスタンスを渡し、 MarkerOption でマーカーのタイトルやスニペットなどを設定します。
// マーカーを貼る緯度・経度 LatLng location = new LatLng(35.697261, 139.774728); // マーカーの設定 MarkerOptions options = new MarkerOptions(); options.position(location); options.title("クラスメソッド株式会社"); options.snippet(location.toString()); // マップにマーカーを追加 mMarker = mMap.addMarker(options);
アイコンをカスタマイズする
マップ上に表示されるアイコンをカスタマイズしてみます。アイコンを変更するには MarkerOption#icon() メソッドを使います。引数には BitmapDescriptor という GoogleMap ライブラリ独自の Bitmap クラスを使います。BitmapDescriptorFactory クラスを使って BitmapDescriptor を生成することができ、 マーカー用のアイコンを作る defaultMarker() メソッドを使うと色違いのデフォルトアイコンを作れたりします。以下では BitmapDescriptorFactory#defaultMarker() を使い、青色のデフォルトアイコンを設定してみました。
// 紫色のアイコン BitmapDescriptor icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE); options.icon(icon);
defaultMarker() で作成できるデフォルトアイコンのカラーバリエーションは下図の通りです。
ちなみに defaultMarker() で渡す引数は float 型で Hue (色相) を直接指定することもできました。RED の 0f から始まり 360f まで自由に指定できます。 180f は RED の補色である CYAN になります。
また BitmapDescriptor#fromResource() を使うとリソース内の Drawable をアイコンに指定できます。
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.ic_logo); options.icon(icon);
InfoWindow をカスタマイズする
次に InfoWindow (マーカーをタップしたときに表示されるウインドウ) をカスタマイズしてみます。InfoWindow の表示を制御するには、まず InfoWindowAdapter インターフェースを実装したカスタムアダプタークラスを作ります。InfoWindowAdapter を実装すると以下のようになるはずです。
private class CustomInfoAdapter implements InfoWindowAdapter { public CustomInfoAdapter() { } @Override public View getInfoWindow(Marker marker) { return null; } @Override public View getInfoContents(Marker marker) { return null; } }
実装メソッド getInfoWindow() と getContents() の中でカスタムViewの生成を行います。つまり View であれば何でも良い!ということになります。自由にカスタマイズできますね。getInfoWindow() と getContents() メソッドでは Marker インスタンスが渡されるので、そこでどの Marker がタップされたか判別し、プロパティの情報を View に反映します (今回は getInfoWindow() のときのみで実装しました)。
/** * InfoAdapter のカスタムクラス. */ private class CustomInfoAdapter implements InfoWindowAdapter { /** Window の View. */ private final View mWindow; /** * コンストラクタ. */ public CustomInfoAdapter() { mWindow = getLayoutInflater().inflate(R.layout.custom_info_window, null); } @Override public View getInfoWindow(Marker marker) { render(marker, mWindow); return mWindow; } @Override public View getInfoContents(Marker marker) { return null; } /** * InfoWindow を表示する. * @param marker {@link Marker} * @param view {@link View} */ private void render(Marker marker, View view) { // ここでどの Marker がタップされたか判別する if (marker.equals(mMarker)) { // 画像 ImageView badge = (ImageView) view.findViewById(R.id.badge); badge.setImageResource(R.drawable.ic_logo); } TextView title = (TextView) view.findViewById(R.id.title); TextView snippet = (TextView) view.findViewById(R.id.snippet); title.setText(marker.getTitle()); snippet.setText(marker.getSnippet()); } }
あとはこのカスタムアダプターをインスタンス化し、 GoogleMap#setInfoWindowAdapter() でセットして完成です!
mMap.setInfoWindowAdapter(new CustomInfoAdapter());
ソースコード
今回のサンプルプロジェクトを github に公開しました!ぜひ Pull してみてください。AndroidManifest.xml の application タグ内の meta-data の value を自身の Google API Key に変更しないと動かないのでご了承ください。詳しくはこちらに載っているのでご参照ください!
suwa-yuki/GoogleMapMarkerSample
まとめ
InfoWindow は View であれば何でも良い、というところが自由度高くて良い感じですね。微妙なところは Adapter の Marker の判別処理ですね。 Marker に Id などセットできれば解消できそうなんですが…。現状は ArrayList など使って自分で作っていくしかなさそうです。