AndroidでGoogle Maps APIを使って地図をヘディングアップ表示する方法.電子コンパスに合わせて地図が回転するというものです.(android sdk 1.5)
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をオーバーライドするという方法)は,以下のページがとても参考になりました.