Google MapにDrawableを配置する

Last-modified: 2009-07-10 (金) 17:22:55

表示されたGoogle Mapの上に、アイコンや図形を描画する方法を紹介します。
Google Mapの表示方法はGoogle Mapを表示するを参照してください。

 

Map上にアイコンを描画する

地図上にアイコンを表示するにはItemizedOverlay<OverlayItem>の派生クラスを作成し、MapViewのOverlayに追加します。
チュートリアルとして、Map上にピンのアイコンを描画するPinItemizedOverlayクラスを作成し、
描画する場所を保持するOverlayItemクラスを継承したPinOverlayItemクラスを作成します。

 

PinItemizedOverlay.java

public class PinItemizedOverlay extends ItemizedOverlay<PinOverlayItem> {
    private List<GeoPoint> points = new ArrayList<GeoPoint>();
    public PinItemizedOverlay(Drawable defaultMarker) {
        super( boundCenterBottom(defaultMarker) );
    }
    @Override
    protected PinOverlayItem createItem(int i) {
        GeoPoint point = points.get(i);
        return new PinOverlayItem(point);
    }
    @Override
    public int size() {
        return points.size();
    }
    public void addPoint(GeoPoint point) {
        this.points.add(point);
        populate();
    }
    public void clearPoint() {
        this.points.clear();
        populate();
    }
}
 

PinOverlayItem.java

public class PinOverlayItem extends OverlayItem {
    public PinOverlayItem(GeoPoint point){
        super(point, "", "");
    }
}
 

PinItemizedOverlayのコンストラクタではアイコンとなるDrawableを受け取り、boundCenterBottomメソッドで位置の調整を行います。
ItemizedOverlay#boundCenterBottomメソッドによってDrawableの原点を画像の下部中央に位置づけます。

 

ItemizedOverlayを継承するクラスはcreateItemメソッドとsizeメソッドを実装する必要があります。
Map上にアイコンを描画するポイントがいくつあるのかをsizeメソッドで返し、そのひとつひとつに対して、生成するOverlayItemをcreateItemメソッドで返さなければなりません。
PinItemizedOverlayクラスでは、描画するポイントをGeoPointオブジェクトのListとして保持し、sizeメソッドでそのListのサイズを返すように実装します。
また、createItemメソッドでListから指定されたインデックスのGeoPointを使って生成したPinOverlayItemを返すように実装します。

 

GeoPointクラスは緯度(latitude)と、経度(longitude)をint型で保持し、Map上の座標の指定/取得に使用します。

 

描画ポイントの追加・クリアのためにaddPointメソッドとclearPointメソッドを定義し、それぞれGeoPointのListのadd・clearを呼び出しています。
描画ポイントに変更を加えた場合はpopulateメソッドを呼び出して、PinItemizedOverlayをMapViewへ貼り付けなおします。

 

作成したPinItemizedOverlayをMapViewに追加し、描画ポイントとなるGeoPointをPinItemizedOverlayに追加します。
東京駅と大阪駅の2つのGeoPointを登録し、PinItemizedOverlayのデフォルトマーカとしてpin.pngをPinItemizedOverlayのコンストラクタに渡します。
pin.pngファイルは、res/drawableディレクトリに追加します。

pin.png
 

SimpleMapActivity.java

public class SimpleMapActivity extends MapActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple_map);
        MapView map = (MapView)findViewById( R.id.map);
        map.setClickable(true);
        map.setBuiltInZoomControls(true);
        Drawable pin = getResources().getDrawable( R.drawable.pin);
        PinItemizedOverlay pinOverlay = new PinItemizedOverlay( pin);
        map.getOverlays().add( pinOverlay);
        GeoPoint tokyo = new GeoPoint( 35681396, 139766049);
        GeoPoint osaka = new GeoPoint( 34701895, 135494975);
        pinOverlay.addPoint( tokyo);
        pinOverlay.addPoint( osaka);
    }
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}
 

アクティビティを実行すると、Map上の東京駅と大阪駅にピンのアイコンが描画されているのが確認できます。

mapview_icon.jpg
 

Map上に図形を描画する

GeoPointで指定した東京駅と大阪駅の間を結ぶ線を描画します。
Androidの画面上に線を描画するには、Android標準の2DグラフィックライブラリからPathクラスを使用します。
2Dグラフィックライブラリの詳細については、Android 2Dグラフィック?を参照してください。

 

アイコン描画の場合はItemizedOverlayを継承してオーバレイを作成しましたが、MapViewのCanvasに直接描画を行うのでOverlayクラスを継承してLineOverlayクラスを作成します。

 

LineOverlay.java

public class LineOverlay extends Overlay {
    private GeoPoint geoStart;
    private GeoPoint geoEnd;
    public LineOverlay( GeoPoint geoStart, GeoPoint geoEnd) {
        this.geoStart = geoStart;
        this.geoEnd = geoEnd;
    }
    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        super.draw(canvas, mapView, shadow);
        if( !shadow ) {
            Paint paint = new Paint( Paint.ANTI_ALIAS_FLAG);
            paint.setStyle( Paint.Style.STROKE);
            paint.setAntiAlias( true);
            paint.setStrokeWidth( 3);
            paint.setColor( Color.RED);
            Path path = new Path();
            Projection projection = mapView.getProjection();
            Point pxStart = projection.toPixels( geoStart, null);
            Point pxEnd = projection.toPixels( geoEnd, null);
            path.moveTo( pxStart.x, pxStart.y);
            path.lineTo( pxEnd.x, pxEnd.y);
            canvas.drawPath(path, paint);
        }
    }
}
 

LineOverlayのコンストラクタで線の開始と終了のGeoPoint2つを指定します。
Canvasに線を描画するにあたって、開始位置と終了位置のにはスクリーン上のピクセル座標を指定しなければなりません。
Map上のGeoPointからスクリーン上のピクセル座標を取得するには、Projectionインターフェースを使います。
ProjectionインタフェースはMap上のGeoPointとスクリーン上のピクセル座標の橋渡しを行ってくれます。
MapViewのgetProjectionメソッドでProjectionを取得し、toPixcelsメソッドで開始位置と終了位置のGeoPointからそれぞれのピクセル座標を取得します。

Projection projection = mapView.getProjection();
Point pxStart = projection.toPixels( geoStart, null);
Point pxEnd = projection.toPixels( geoEnd, null);
 

LineOverlayクラスではdrawメソッドをオーバーライドして、Overlayの描画処理の後に線の描画を追加しています。
drawメソッドでは描画範囲のCanvasと、このLineOverlayを追加したMapView、影の描画フラグの3つの引数を受け取ります。
Overlayのdrawメソッドは、
・アイコンなどを配置したときの影となる部分の描画時(shadow=true)
・アイコンそのものの描画時(shadow=false)
の計2回呼び出されます。
サンプルでは、shadow=falseのときのみ描画を行っています。

 

PinItemizedOverlayと合わせて、LineOverlayもMapViewのオーバレイに追加するよう修正します。

 

SimpleMapActivity.java

public class SimpleMapActivity extends MapActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple_map);
        MapView map = (MapView)findViewById( R.id.map);
        map.setClickable(true);
        map.setBuiltInZoomControls(true);
        Drawable pin = getResources().getDrawable( R.drawable.pin);
        PinItemizedOverlay pinOverlay = new PinItemizedOverlay( pin);
        map.getOverlays().add( pinOverlay);
        GeoPoint tokyo = new GeoPoint( 35681396, 139766049);
        GeoPoint osaka = new GeoPoint( 34701895, 135494975);
        pinOverlay.addPoint( tokyo);
        pinOverlay.addPoint( osaka);
        LineOverlay lineOverlay = new LineOverlay( tokyo, osaka);
        map.getOverlays().add( lineOverlay);
    }
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}
 

アクティビティを実行すると、東京駅と大阪駅との間に線が引かれていることが確認できます。

mapview_line.jpg