MapView で地図の移動や拡大時のイベントを拾う


http://bricolsoftconsulting.com/2011/10/31/extending-mapview-to-add-a-change-event/

にあるように、MapView を拡張したクラスを作り、独自のonChangedListener を定義、自前で移動前後を覚えておきイベントを投げることで対応できる。
リンク先の MyMapView.java を定義し、以下のように使う

```java:MyActivity.java
public class MyMapActivity extends MapActivity
{
    // Members
    MyMapView mMapView;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map);
 
        // Populate the map member
        mMapView = (MyMapView) findViewById(R.id.theMap);
 
        // Add zoom controls
        mMapView.setBuiltInZoomControls(true);
 
        // Listener 登録
        mMapView.setOnChangeListener(new MapViewChangeListener());
    }
 
    private class MapViewChangeListener implements MyMapView.OnChangeListener
    {
 
        @Override
        public void onChange(MapView view, GeoPoint newCenter, GeoPoint oldCenter, int newZoom, int oldZoom)
        {
            // Check values
            if ((!newCenter.equals(oldCenter)) && (newZoom != oldZoom))
            {
                // ZoomとPanがされた
            }
            else if (!newCenter.equals(oldCenter))
            {
                // Pan がされた
            }
            else if (newZoom != oldZoom)
            {
                // Zoom 変更がされた
            }
        }
    }
}
```


MyMapView.java 側のポイントは

Listener の定義部

```java:MyMapView.java
    // Listener の定義
    public interface OnChangeListener
    {
        public void onChange(MapView view, GeoPoint newCenter, GeoPoint oldCenter, int newZoom, int oldZoom);
    }
```

Touchイベントをオーバーライドして、移動前後のポジションやズームレベルを比較、違っていたらListnerのメソッドをコールする部分

```java:MyMapVIew.java
    // ------------------------------------------------------------------------
    // EVENT HANDLERS
    // ------------------------------------------------------------------------
 
    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        // Set touch internal
        mIsTouched = (ev.getAction() != MotionEvent.ACTION_UP);
 
        return super.onTouchEvent(ev);
    }
 
    @Override
    public void computeScroll()
    {
        super.computeScroll();
 
        // Check for change
        if (isSpanChange() || isZoomChange())
        {
            // If computeScroll called before timer counts down we should drop it and
            // start counter over again
            resetMapChangeTimer();
        }
    }
    // ------------------------------------------------------------------------
    // TIMER RESETS
    // ------------------------------------------------------------------------
 
    private void resetMapChangeTimer()
    {
        mChangeDelayTimer.cancel();
        mChangeDelayTimer = new Timer();
        mChangeDelayTimer.schedule(new TimerTask()
        {
            @Override
            public void run()
            {
                if (mChangeListener != null) mChangeListener.onChange(mThis, getMapCenter(), mLastCenterPosition, getZoomLevel(), mLastZoomLevel);
                mLastCenterPosition = getMapCenter();
                mLastZoomLevel = getZoomLevel();
            }
        }, mEventsTimeout);
    }
 ```

Timer とスクロールイベントの組み合わせ方が、なるほどーといった感じです。