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になります。ふぅ〜、やれやれだぜ。