前回地図の表示を作成しましたが、地図に付加できるいろいろな機能を紹介したいと思います。
まず、地図をつかんだりできるようにする為の関数
mapview.setEnabled(true); mapview.setClickable(true);
次に拡大縮小を行う為のデフォルトのコントローラーは下記です。
mapview.setBuiltInZoomControls(true);
次にmapviewのコントローラーを作成します。(見えるものでなく、関数です。)
MapController mc=mapview.getController();
GPSで場所の指定ができます。
mc.setCenter(new GeoPoint(35609127,140113235));
またズームレベルの変更ができます。
mc.setZoom(16);
ともに値の取得に際しては、コントローラーの方ではなく、mapviewの方を利用します。
mapview.getMapCenter(); mapview.getZoomLevel();
以上で地図を作成するとほぼグーグルマップと同じ機能で地図を利用できると思います。しかし、次の機能がついてません。
・ダブルクリック
・長押し
この機能の追加に関してdispatchEventを利用する方法と、layerにイベントを追加する方法があります。
最終的にはlayerの方に追加をしたのですが、dispatchEventの方も不毛な勉強ではなかったので、ついでに記載をさせていただきます。
前提としては「MapViewではイベントを取得ができない」と言う問題がおこります。
OnDoubleTapListener,OnGestureListenerで取得をしたいのですが、どうやってもイベントがわたされません。
参照::Android: MapActivityでダブルタップする
dispatchEventを利用します。
dispatchEventは発行されるイベントを全て取得します。クリックも移動も全て取得をします。
なので、dispatchEventで取得したイベントはGestureDetectorを作成して、タッチイベントにイベントを渡す形で受け渡します。
@Override public boolean dispatchTouchEvent(MotionEvent ev) { super.dispatchTouchEvent(ev); gestureDetector.onTouchEvent(ev); return onTouchEvent(ev); }
このようにしてOnDoubleTapListener,OnGestureListenerをimplementsした関数に値を引き渡すとダブルクリックの動作も取得してくれます。
@Override public boolean onDoubleTap(MotionEvent e) { return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; }
のどちらかで実行をすればよいのだけど、このイベントの差って何だろうか。割と曖昧にしている片が多かったのですが、
onDoubleTapはダブルタップで、onDoubleTapEventはダブルタップ中のイベントらしいです。なぜか、onDoubleTapEventの中に動作を書こうとしている方が多かった印象なのですが、
@Override public boolean onDoubleTap(MotionEvent e) { mc.zoomIn(); return false; }
などで、拡大ができる形がよいかと思います。
ソース一式
package in.andante.mapView; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import android.os.Bundle; import android.view.GestureDetector; import android.view.View; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; import android.view.MotionEvent; import android.view.View.OnTouchListener; public class MapVVV extends MapActivity implements OnGestureListener,OnDoubleTapListener, OnTouchListener{ private GestureDetector gestureDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MapView map = new MapView(this, "APIキー"); map.setEnabled(true); map.setClickable(true); map.setBuiltInZoomControls(true); mc=map.getController(); mc.setCenter(new GeoPoint(35609127,140113235)); mc.setZoom(16); gestureDetector = new GestureDetector(this,this); setContentView(map); } MapController mc; @Override public boolean dispatchTouchEvent(MotionEvent ev) { super.dispatchTouchEvent(ev); gestureDetector.onTouchEvent(ev); return onTouchEvent(ev); } @Override public boolean onTouch(View v, MotionEvent event) { return false; } @Override protected boolean isRouteDisplayed() { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onDoubleTap(MotionEvent e) { mc.zoomIn(); return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; } @Override public boolean onDown(MotionEvent arg0) { return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { return false; } }
同様にしてonLongPress(長押し)の動作も設定ができるのですが、問題がひとつあって、zoomボタンの上などで、ダブルクリックをしても動作をしてしまいます
dispatchTouchEventが全てのイベントを取得してしまうが故にview上にさまざまな要素が増えれば増えただけ、修正が必要になります。
なので、次にレイヤーを利用して、ダブルクリックを取得してみましょう。
レイヤーとは、mapViewにはもともと上にレイヤーを重ねる事ができて、そこに矢印を配置したりできるのですが、そのレイヤーにイベントを持たせてあげるという方法です。
参照::特定のタップイベント時にMapViewから座標を取得する
レイヤーのクラスは下記の形になります。
class MyOverlay extends Overlay implements OnDoubleTapListener,OnGestureListener{ private GestureDetector gesture = new GestureDetector(this); private MapView parent; MyOverlay(MapView mapView){ parent = mapView; } @Override public boolean onTouchEvent(MotionEvent e, MapView mapView) { gesture.onTouchEvent(e); return super.onTouchEvent(e, mapView); } public void onLongPress(MotionEvent e) { } @Override public boolean onDown(MotionEvent e) { return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onDoubleTap(MotionEvent e) { return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { mc.zoomIn(); return false; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { return false; } }
上記のレイヤーをMapViewに追加をします。
map.getOverlays().add( new MyOverlay(map));
mapviewに重ねたレイヤー上にイベントを付加する事ができました。こちらの方法だと、今のところ、特に大きな問題もなく動作できると思います。
以上です。