利用者が設定した情報をMapView上に表示する
基本クラスのOverlayは、地図上に重ねるオーバーレイを表します。オーバーレイは、地図上にカスタムグラフィックオブジェクトを描画して表示するために使用します。実際のコードでは、基本的にdraw()
メソッドをオーバーライドして、デフォルト位置に円を描き、キャプションを透明な角丸長方形のボックスで囲むようにします。
オーバーライドしたdraw()
メソッドのコードを次に示します。このコードでは、位置から画面座標への変換(PixelCalculatorを使用)、フォントメトリクスの計算(PaintのmeasureText()
を使用)、アンチエイリアス処理したテキストの描画(PaintのsetAntiAlias()
を使用)といった処理を行っています。
// This is used draw an overlay on the map protected class MyOverlay extends Overlay { @Override public void draw(Canvas canvas, PixelCalculator pc, boolean shadow) { super.draw(canvas, pc, shadow); if (mDefCaption.length() == 0) { return; } Paint p = new Paint(); int[] scoords = new int[2]; int sz = 5; // Convert to screen coords pc.getPointXY(mDefPoint, scoords); // Draw point caption and its bounding rectangle p.setTextSize(14); p.setAntiAlias(true); int sw = (int)(p.measureText(mDefCaption) + 0.5f); int sh = 25; int sx = scoords[0] - sw / 2 - 5; int sy = scoords[1] - sh - sz - 2; RectF rec = new RectF(sx, sy, sx + sw + 10, sy + sh); p.setStyle(Style.FILL); p.setARGB(128, 255, 0, 0); canvas.drawRoundRect(rec, 5, 5, p); p.setStyle(Style.STROKE); p.setARGB(255, 255, 255, 255); canvas.drawRoundRect(rec, 5, 5, p); canvas.drawText(mDefCaption, sx + 5, sy + sh - 8, p); // Draw point body and outer ring p.setStyle(Style.FILL); p.setARGB(88, 255, 0, 0); p.setStrokeWidth(1); RectF spot = new RectF(scoords[0] - sz, scoords[1] + sz, scoords[0] + sz, scoords[1] - sz); canvas.drawOval(spot, p); p.setARGB(255, 255, 0, 0); p.setStyle(Style.STROKE); canvas.drawCircle(scoords[0], scoords[1], sz, p); } }
作成したオーバーレイは、使用する前にMapViewのオーバーレイコントローラに追加する必要があります。オーバーレイコントローラのセットアップを行うコードを次に示します。
// Set up the overlay controller mOverlayController = mMapView.createOverlayController(); MyOverlay mo = new MyOverlay(); mOverlayController.add(mo, true);
現在のGPS位置情報と統合する
android.locationは、ロケーションプロバイダの一覧を検索して、現在位置の定期的な更新を行うための登録ができるAPIを含んだパッケージです。各ロケーションプロバイダは、/data/misc/location/<provider_name>ディレクトリ配下のファイルを随時更新します。したがって、デフォルトのダミーGPSプロバイダ「gps」の情報は、エミュレータ上では/data/misc/location/gps/に置かれます。GPSファイルの形式はプロバイダごとに異なる可能性があります。詳細な情報については、Androidのサイトを参照してください。
LocationManagerを初めてアクティブにするときは、初期化を行うために多少時間がかかりますので注意してください。その後に続く呼び出しは、すぐに応答があります。次のコードは、プロバイダからのGPS位置情報を取得して、MapViewのコントローラに送る方法を示しています。
private void centerOnGPSPosition() { String provider = "gps"; LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE); // NOTE: When LocationManager is called the first time, // lat / lon is initialized to 0. // Subsequent calls are fine and fast. Location loc = lm.getCurrentLocation(provider); mDefPoint = new Point((int)(loc.getLatitude() * 1000000), (int)(loc.getLongitude() * 1000000)); mDefCaption = "GPS location"; mMapView.getController().animateTo(mDefPoint); mMapView.getController().centerMapTo(mDefPoint, true); }
まとめ
ここまでの解説を読んで、この地図表示ソフトを試してみたい、独自の機能を追加してみたいと思った読者は多いのではないでしょうか。このソフトウェアパッケージは、本稿のダウンロードサンプルに収録されています。サンプルプロジェクトをEclipseにインポートするだけで使えます。
Androidの地図表示APIは、既に普及しているGoogleのツールに直接アクセスできるため、簡単に使えてしかも強力です。Androidとより高度なAPIが発展していくにつれて、より多くの地図表示機能がAndroidプラットフォームに移植されることになるでしょう。私が思いつくだけでも、次のようなアイデアがあります。皆さんもぜひ挑戦してみてください。
- Googleマップを頻繁に利用している方なら、地図の拡大縮小と移動をコントロールできるドラッグ可能なツールバーのスタイルをきっと気に入っているかと思います。このユーザーインターフェイスと機能性にならった機能を開発してみたらどうでしょうか。素晴らしい追加機能になると思います。
- Googleマップと同様の住所検索機能を追加するというのはどうでしょうか。この機能では、検索結果をいかに解析するかが重要なポイントとなります。
- 通常の場合、GPSは新しい場所に移動すると、初期化のために多少の時間を必要とします。この待機時間がおおむね5秒を超える場合は、ANR(アプリケーション無応答)ダイアログが表示されることがあります。システムの割り込みを生じさせずにソフトウェアをスムーズに動かすには、そのための子スレッドを作成し、その子スレッドがメッセージ処理スキームを介してメインスレッドとやり取りできるようにする必要があります。