AndroidでGoogle Maps APIを使って地図をヘディングアップ表示する方法.電子コンパスに合わせて地図が回転するというものです.(android sdk 1.5)

gmap1.png

MainAct.java

import java.util.List;
import com.google.android.maps.MapActivity;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class MainAct extends MapActivity {
	public float[] mValues;
	private SensorManager mSensorManager;
	private SensorEventListener mSensorEventListener;
	private ViewUpdateHandler mViewUpdateHandler;
	private GoogleMapView gmapView;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
		mSensorEventListener = new SensorEventListener() {
			public void onSensorChanged(SensorEvent event) {
				int ori = getResources().getConfiguration().orientation;
				if (ori == Configuration.ORIENTATION_LANDSCAPE) {
					// 横置きの場合の角度補正
					event.values[0] += 90;
					if (event.values[0] >= 360) {
						event.values[0] -= 360;
					}
				}
				mValues = event.values;
			}
			public void onAccuracyChanged(Sensor sensor, int accuracy) {
			}
		};

		gmapView = new GoogleMapView(this, null);
		
		setContentView(gmapView);
	}

	@Override
	protected void onResume(){
		super.onResume();

		List<Sensor> sl = mSensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
		mSensorManager.registerListener(mSensorEventListener, sl.get(0), SensorManager.SENSOR_DELAY_NORMAL);

		mViewUpdateHandler = new ViewUpdateHandler();
		mViewUpdateHandler.sleep(0);
	}

	@Override
	protected void onPause(){
		super.onPause();
		mSensorManager.unregisterListener(mSensorEventListener);
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	/**
	 * Google Mapを定期的に再描画するためのハンドラ
	 */
	public class ViewUpdateHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			gmapView.invalidate();
			if (mViewUpdateHandler != null) {
				mViewUpdateHandler.sleep(100);
			}
		}
		public void sleep(long delayMillis) {
			removeMessages(0);
			sendMessageDelayed(obtainMessage(0),  delayMillis);
		}
	}	 
}

GoogleMapView.java

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;

public class GoogleMapView extends MapView {
	private MainAct mainAct;

	private int centerX;
	private int centerY;

	private boolean curDown;
	private int lastdownX;
	private int lastdownY;

	private static final String API_KEY = "[自分のAPIキー]";

	public GoogleMapView(Context context, AttributeSet attrs) {
		super(context, API_KEY);
	}

	@Override
	protected void onAttachedToWindow() {
		mainAct = (MainAct)getContext();

		setBuiltInZoomControls(true);
		setSatellite(false);

		MapController mc = getController(); 	   
		mc.setZoom(17);
		mc.setCenter(new GeoPoint((int)(35.6655 * 1E6), (int)(139.7596 * 1E6)));

		setClickable(true);
		setFocusable(true);
		setFocusableInTouchMode(true);
		requestFocus();
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		centerX = w / 2;
		centerY = h / 2;

		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction(); 	 
		int curX = (int) event.getX();
		int curY = (int) event.getY();

		if (action == MotionEvent.ACTION_DOWN) {
			lastdownX = curX;
			lastdownY = curY;
			curDown = true;
			
		} else if (action == MotionEvent.ACTION_UP) {
			curDown = false;

		} else if (curDown && action == MotionEvent.ACTION_MOVE) {
			int dx = lastdownX - curX;
			int dy = lastdownY - curY;
			lastdownX = curX;
			lastdownY = curY;
			
			scroll(dx, dy);
		}
		return true;
	}

	@Override
	public boolean onTrackballEvent(MotionEvent event) {
		int action = event.getAction(); 	 
		float curX = event.getX();
		float curY = event.getY();

		if (action == MotionEvent.ACTION_MOVE) {
			int dx = (int)(curX * 50); // 50は移動速度
			int dy = (int)(curY * 50);
			
			scroll(dx, dy);
		}
		return true;
	}

	@Override
	public void draw(Canvas canvas) {
		if (mainAct.mValues != null) {
			float r = mainAct.mValues[0];
			canvas.rotate(-r, centerX, centerY);
		}
		
		super.draw(canvas);
	}
	
	private void scroll(int dx, int dy) {
		if (dx != 0 || dy != 0) {
			// 要求された移動ベクトル
			float distance = FloatMath.sqrt(dx*dx + dy*dy);
			float rad = (float)Math.atan2(dy, dx);
			
			// 地図の回転角に合わせて,移動ベクトルを回転する
			rad = rad - (float)Math.toRadians(- mainAct.mValues[0]);

			// 回転後のベクトルをX,Yに変換する
			dx = (int)(distance * FloatMath.cos(rad));
			dy = (int)(distance * FloatMath.sin(rad));
		}

		getController().scrollBy(dx, dy);
	}
}
地図ロイドの回転プログラムもほとんどこれと同じですが,さらに磁北偏差の補正処理を入れたりしています.

GoogleMapを回転させる方法(MapViewのdrawをオーバーライドするという方法)は,以下のページがとても参考になりました.

kamolandをフォローしましょう


© 2016 KMIソフトウェア