MapActivityを継承したアクティビティで、ダブルタップしても地図がズームインしないので、これはGoogleMapの仕様に合わせたいなぁと試行錯誤した結果を記します。正直、しんどかった。
まぁ、似たようなことを考えている人は世の中にもおられるもので、そこを参考にさせてもらいました。
まぁ上記のサイトにも書かれているのですが、OnGestureListenerをimplementsしただけでは、MapActivityはタップイベントを拾ってくれません。理由はMapViewが先に拾っちゃうからです。原因がわかったとしても、じゃあどうすればいいか。それがなかなかわからなかったんですが、上記のサイトでヒントを書いてくれてるので、それを参考にします(上記のサイトのは俺がいうのも何だけど、完璧ではなかった…)
下のソースは実際に使ってるものの、処理をかなりパッサリと落として抽出したものです。
public class Place extends MapActivity implements LocationListener,
OnGestureListener,
OnDoubleTapListener{
private boolean mZoom = false;
private boolean mDoubleTap = false;
private boolean mSingleTap = true;
private MapView mMapView;
private MapController mMapController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.place);
mGDetector = new GestureDetector(this, this);
mMapView = (MapView)findViewById(R.id.mapview);
mMapView.setBuiltInZoomControls(true);
ZoomButtonsController zbc = mMapView.getZoomButtonsController();
zbc.setOnZoomListener(new OnZoomListener() {
@Override
public void onZoom(boolean zoomIn) {
mZoom = true;
if(zoomIn){
mMapController.zoomIn();
} else {
mMapController.zoomOut();
}
}
@Override
public void onVisibilityChanged(boolean visible) {
}
});
// ...略
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return onTouchEvent(ev);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mDoubleTap = true;
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent event) {
if (mDoubleTap) {
mDoubleTap = false;
GeoPoint gp = getGeoPointByPoint((int)event.getX(), (int)event.getY());
GeoPoint cgp = mMapView.getMapCenter();
GeoPoint point = new GeoPoint(
(gp.getLatitudeE6() + cgp.getLatitudeE6()) / 2,
(gp.getLongitudeE6() + cgp.getLongitudeE6()) / 2);
if (mMapController.zoomIn()) {
mMapController.setCenter(point);
}
}
return false;
}
@Override
public boolean onDown(MotionEvent event) {
mSingleTap = false;
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
mSingleTap = true;
if (mZoom) {
// zoomIn, zoomOutしていたら、処理をしない
mZoom = false;
} else {
GeoPoint gp = getGeoPointByPoint((int)event.getX(), (int)event.getY());
mMapController.animateTo(gp);
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGDetector.onTouchEvent(event)) {
return true;
}
return super.onTouchEvent(event);
}
private GeoPoint getGeoPointByPoint(int x, int y) {
Projection projection = mMapView.getProjection();
return projection.fromPixels(x, y);
}
}
まず、イベントを全部横取りするために、dispatchTouchEventメソッドを設定します。最初にMapActivityが持っているイベント類を全て実行させるために、super.dispatchTouchEventを実行します。その後、実行したいthis.onTouchEventにイベントを渡します。
this.onTouchEventの中で、GestureDetector.onTouchEventをやっておきます。
重要になるのが、onSingleTapConfirmedメソッド。これは簡単にいうと、シングルタップイベントに該当します。シングルタップで実行したい処理をここに書いてしまいます。これでシングルタップイベントは完成っぽく見えるけど、実は違います。あとで書きますが、罠が潜んでます。
次に、onDoubleTapEvent。これはダブルタップイベントという名前だけあって、そういうイベントなんですが、何故かonDoubleTapメソッドの後に数回コールされてしまうので、onDoubleTap内で現在ダブルタップ中というフラグを立てて、onDoubleTapEventでフラグが経っていたら処理するというふうにします。これで、ダブルタップイベントは完成。
これで、GoogleMapをダブルタップしたら、地図は拡大。シングルタップしたところが画面中央に来てハッピーかと思いきや、なんと、ZoomControlをクリックしたら、シングルタップイベントが走ってしまい、ズームコントロールを押した場所が画面中央に来てしまいます。これはどげんかせんといけませんな。
で、onCreateの中でやっているんですが、ZoomButtonsControllerのインスタンスを生成して、ズームボタンを押したときのイベントを自分で定義します。setOnZoomListenerというやつですね。ここで、onZoomイベントに来たら、現在ズーム処理中のフラグを立てます。あとは拡大・縮小の処理を実行します。
onSingleTapConfirmedメソッドで、ズーム中のフラグが立っていたら、処理をしないようにします。そうすれば、シングルタップOK, ダブルタップOK, ズームコントロールOKになります。ふぅ〜、やれやれだぜ。
