SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

速習! Androidアプリケーション開発

地図描画と方位センサーの利用
~速習! Androidアプリケーション開発(6)~

第6回 アクティビティの実装その2

  • X ポスト
  • このエントリーをはてなブックマークに追加

マップ上への描画処理

 ここまでの作業で、表示すべき座標が特定できたので、描画処理を実装しましょう。マップ上に何らかの描画を行う場合は、下記のようなイメージでOverlayというレイヤーを追加していきます。

 目的値には画鋲のイメージを使用し、目的地の位置にピンの先端がくるように描画します。

 Overlayを継承したDistinationOverlayをMapActivityのインナークラスとして作成し、draw()に描画処理を記述します。描画位置は、現在のマップの表示位置と目的地の座標から計算し、画像のサイズに合わせて描画位置を調整しています。そのままの位置に描画すると、指定したポイントに画像の左上が来るように描画されてしまうので注意してください。

/**
 * 目的地描画用Overlay
 */
public class DistinationOverlay extends Overlay {
	
	// 描画するイメージ
	private Bitmap bmp;
	// 描画する座標
	private GeoPoint geoPoint;
	
	/**
	 * コンストラクタ
	 * @param bmp 描画するイメージ
	 */
	public DistinationOverlay( Bitmap bmp) {
		this.bmp = bmp;
	}

	/**
	 * 描画する座標の取得
	 * @return 描画する座標
	 */
	public GeoPoint getGeoPoint() {
		return geoPoint;
	}

	/**
	 * 描画する座標の設定 
	 * @param geoPoint 描画する座標
	 */
	public void setGeoPoint(GeoPoint geoPoint) {
		this.geoPoint = geoPoint;
	}

	@Override
	public void draw(Canvas canvas, MapView mapView, boolean shadow) {
		// shadow = true,falseで2回呼び出される
		if( !shadow){
			// Mapの表示位置と座標から画面の描画位置を算出
			Projection pro = mapView.getProjection();
			Point p = pro.toPixels(geoPoint, null);
			
			// 描画(目的地がピンの先に来るようにy座標を調整)
			int centerX = p.x;
			int centerY = p.y - bmp.getHeight();
			// 画像の描画
			canvas.drawBitmap(bmp, centerX, centerY, null);
		}
	}
}

 次に、作成したOverlayをMapViewに設定します。

OverlayはMapView.getOverLays()で取得したList<Overlay>に追加します。
// デフォルトのズーム値
protected int defaultZoom = 17; 

// 目的地表示Overlay
protected DistinationOverlay distLocationOverlay = null;

/**
 * 目的地を設定する
 * 
 * @param address 住所
 */
protected void setDist( Address address){
	// AddressからGeoPointに変換
	int latitude = (int)(address.getLatitude() * 1E6);
	int longitude = (int)(address.getLongitude() * 1E6);
	GeoPoint distPoint = new GeoPoint( latitude, longitude);

	// 目的地をマップの中心にする。
	controller.animateTo( distPoint);
	// ズームをデフォルト設定
	controller.setZoom( defaultZoom);

	// 目標値の座標にイメージを描画
	if( distLocationOverlay == null){
		// 初回はOverlayを作成
		Bitmap bmp = BitmapFactory.decodeResource( getResources(), R.drawable.pushpin);
		distLocationOverlay = new DistinationOverlay(bmp);
		distLocationOverlay.setGeoPoint( distPoint);
		// Overlayの追加
		map.getOverlays().add( distLocationOverlay);
	}
	else{
		// 2回目以降はOverlayを再利用
		distLocationOverlay.setGeoPoint( distPoint);
		// 無効にして再描画
		map.invalidate();
	}
}

 以上で目的地の描画が完成です。

目的地の描画
目的地の描画

 現時点でのソースコードは、次のようになります。

package sample.bizcard;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import sample.bizcard.db.BizCard;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.RadioGroup.OnCheckedChangeListener;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

/**
 * 地図表示アクティビティ
 * MapViewを扱うアクティビティはcom.google.android.maps.MapActivityを継承する必要がある
 */
public class MapActivity extends com.google.android.maps.MapActivity implements OnCheckedChangeListener{
    
    // UI部品
    private MapView map = null;
    private RadioGroup radioGroup = null;
    private RadioButton normalMapRadio = null;
    private ToggleButton currentLocationToggle = null;
    
    // Mapのコントローラ
    private MapController controller = null;    
    
    // デフォルトのズーム値
    protected int defaultZoom = 17; 
    
    // 目的地表示Overlay
    protected DistinationOverlay distLocationOverlay = null;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map);
        
        // UI部品の取得
        map = (MapView) findViewById(R.id.map);
        normalMapRadio = (RadioButton)findViewById(R.id.normalMapRadio);
        // デフォルトでマップを選択
        normalMapRadio.setChecked( true);
        radioGroup = (RadioGroup)findViewById( R.id.mapRadioGroup);
        // 衛星写真選択時のリスナ追加
        radioGroup.setOnCheckedChangeListener( this);
        currentLocationToggle = (ToggleButton)findViewById( R.id.currentLocationToggle);
        
        // コントローラの取得
        controller = map.getController();
        // ZoomControlの利用
        map.setBuiltInZoomControls( true);
        // 衛星写真OFF
        map.setSatellite( false);
        map.setClickable(true);
        map.setEnabled(true);
        
        // 座標取得用のGeocoder取得
        Geocoder geocoder = new Geocoder( this, Locale.getDefault());
    
        // インテントから住所の文字列を取得
        Intent intent = getIntent();
        String strAddress = intent.getStringExtra( BizCard.COLUMN_ADDRESS);

        try {
            // 住所からAddressへ変換
            List<Address> addressList = geocoder.getFromLocationName(strAddress, 10);
            
            Address address = null;
            if( addressList.size() == 1){
                address = addressList.get( 0);
            }
            else if( addressList.size() != 0){
                // 複数のアドレスが見つかった場合はダイアログで対象を選択する
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder( this);
                alertDialogBuilder.setTitle( R.string.select_target);
                
                // ダイアログ表示用の文字列の生成
                List<String> strAddressList = new ArrayList<String>();
                for( Address element: addressList){
                    int maxAddressLineIdx = element.getMaxAddressLineIndex();
                    strAddressList.add( element.getAddressLine( maxAddressLineIdx));
                }

                // ダイアログに表示するリストの生成
                AddressSelectionListener listener = new AddressSelectionListener( addressList);
                ListView listView = new ListView( this);
                ArrayAdapter<String> listAdaptor = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strAddressList);
                listView.setAdapter(listAdaptor);
                listView.setOnItemClickListener( listener);
                
                // ダイアログにリストを生成
                alertDialogBuilder.setView( listView);
                
                // ダイアログの表示
                AlertDialog dialog = alertDialogBuilder.create();
                listener.setDialog( dialog);
                dialog.show();
            }
            
            if( address != null){
                setDist(address);
            }
        } catch (IOException e) {
            Toast toast = Toast.makeText(this, R.string.cannot_get_address, Toast.LENGTH_SHORT);
            toast.show();
        }
    }

    /**
     * ラジオボタンの選択変更時にマップを切り替える
     */
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if( checkedId == R.id.normalMapRadio){
            // 衛星写真OFF
            map.setSatellite( false);
        }
        else if( checkedId == R.id.satelliteMapRadio){
            // 衛星写真ON
            map.setSatellite( true);
        }
    }
    
     /**
     * 目的地を設定する
     * 
     * @param address 住所
     */
    protected void setDist( Address address){
        // AddressからGeoPointに変換
        int latitude = (int)(address.getLatitude() * 1E6);
        int longitude = (int)(address.getLongitude() * 1E6);
        GeoPoint distPoint = new GeoPoint( latitude, longitude);
        
        // 目的地をマップの中心にする。
        controller.animateTo( distPoint);
        // ズームをデフォルト設定
        controller.setZoom( defaultZoom);
        
        // 目標値の座標にイメージを描画
        if( distLocationOverlay == null){
            // 初回はOverlayを作成
            Bitmap bmp = BitmapFactory.decodeResource( getResources(), R.drawable.pushpin);
            distLocationOverlay = new DistinationOverlay(bmp);
            distLocationOverlay.setGeoPoint( distPoint);
            // Overlayの追加
            map.getOverlays().add( distLocationOverlay);
        }
        else{
            // 2回目以降はOverlayを再利用
            distLocationOverlay.setGeoPoint( distPoint);
            // 無効にして再描画
            map.invalidate();
        }
    }
    
    /**
     * 目的地描画用Overlay
     */
    public class DistinationOverlay extends Overlay {
        
        // 描画するイメージ
        private Bitmap bmp;
        // 描画する座標
        private GeoPoint geoPoint;
        
        /**
         * コンストラクタ
         * @param bmp 描画するイメージ
         */
        public DistinationOverlay( Bitmap bmp) {
            this.bmp = bmp;
        }

        /**
         * 描画する座標の取得
         * @return 描画する座標
         */
        public GeoPoint getGeoPoint() {
            return geoPoint;
        }

        /**
         * 描画する座標の設定 
         * @param geoPoint 描画する座標
         */
        public void setGeoPoint(GeoPoint geoPoint) {
            this.geoPoint = geoPoint;
        }

        @Override
        public void draw(Canvas canvas, MapView mapView, boolean shadow) {
            // shadow = true,falseで2回呼び出される
            if( !shadow){
                // Mapの表示位置と座標から画面の描画位置を算出
                Projection pro = mapView.getProjection();
                Point p = pro.toPixels(geoPoint, null);
                
                // 描画(目的地がピンの先に来るようにy座標を調整)
                int centerX = p.x;
                int centerY = p.y - bmp.getHeight();
                // 画像の描画
                canvas.drawBitmap(bmp, centerX, centerY, null);
            }
        }
    }
    
    /**
     * 住所の候補が複数あった場合にリストで選択された住所を表示するリスナ
     */
    class AddressSelectionListener implements OnItemClickListener{
        
        private List<Address> listAddress = null;
        
        private AlertDialog dialog = null;
        
        private AddressSelectionListener( List<Address> listAddress){
            this.listAddress = listAddress;
        }
        
        public AlertDialog getDialog() {
            return dialog;
        }

        public void setDialog(AlertDialog dialog) {
            this.dialog = dialog;
        }

        public void onItemClick(AdapterView<?> parent, View view, int position,    long id) {
            // 選択された住所を目的地として設定
            Address address = listAddress.get( position);
            setDist( address);
            // ダイアログを閉じる
            dialog.dismiss();
        }
    }
    
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}

次のページ
GPS機能を利用した現在地の描画

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
速習! Androidアプリケーション開発連載記事一覧

もっと読む

この記事の著者

横井 朗(ヨコイ アキラ)

株式会社ビーブレイクシステムズにて業務システムのパッケージソフト(MA-EYES)の製品開発から導入までを手掛けるとともに、オープンソースソフトウェア(ExCella)の開発リーダも務める。オープンソース関連について多くの執筆経験を持つ。  

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4878 2010/02/08 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング