I’m still playing with Android (loving it, it would be so nice if I could actually do it for living). So I was playing with the MapView and MapActivity. After playing for a while with the google maps API on JS and also with openlayers, the MapView is really missing some basic stuff.
On my simple demo the basics I needed:
- Receive zoom events
- Receive pan events
- Get the map extent (that is the bounds from the rectangle that defines your map view)
For my surprise none of those are actually defined on the MapView, but at least they can be easily added. So here’s my small contribution to those out there trying to get the same
The events
So first, two small listeners that you can use to receive notifications once a zoom or a pan has happened:
package com.furiousbob.slide.events; import com.google.android.maps.GeoPoint; public interface PanChangeListener { public void onPan(GeoPoint old, GeoPoint current); }
package com.furiousbob.slide.events; public interface ZoomChangeListener { public void onZoom(int old, int current); }
The SimpleMapView
That’s basically it, so now for the new map view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | package com.furiousbob.slide; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent; import com.furiousbob.slide.events.PanChangeListener; import com.furiousbob.slide.events.ZoomChangeListener; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; public class SimpleMapView extends MapView { private int currentZoomLevel = -1; private GeoPoint currentCenter; private List<ZoomChangeListener> zoomEvents = new ArrayList<ZoomChangeListener>(); private List<PanChangeListener> panEvents = new ArrayList<PanChangeListener>(); public SimpleMapView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public SimpleMapView(Context context, String apiKey) { super(context, apiKey); } public SimpleMapView(Context context, AttributeSet attrs) { super(context, attrs); } public int[][] getBounds() { GeoPoint center = getMapCenter(); int latitudeSpan = getLatitudeSpan(); int longtitudeSpan = getLongitudeSpan(); int[][] bounds = new int[2][2]; bounds[0][0] = center.getLatitudeE6() + (latitudeSpan / 2); bounds[0][1] = center.getLongitudeE6() + (longtitudeSpan / 2); bounds[1][0] = center.getLatitudeE6() - (latitudeSpan / 2); bounds[1][1] = center.getLongitudeE6() - (longtitudeSpan / 2); return bounds; } public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_UP) { GeoPoint centerGeoPoint = this.getMapCenter(); if (currentCenter == null || (currentCenter.getLatitudeE6() != centerGeoPoint.getLatitudeE6()) || (currentCenter.getLongitudeE6() != centerGeoPoint.getLongitudeE6()) ) { firePanEvent(currentCenter, this.getMapCenter()); } currentCenter = this.getMapCenter(); } return super.onTouchEvent(ev); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if(getZoomLevel() != currentZoomLevel){ fireZoomLevel(currentZoomLevel, getZoomLevel()); currentZoomLevel = getZoomLevel(); } } private void fireZoomLevel(int old, int current){ for(ZoomChangeListener event : zoomEvents){ event.onZoom(old, current); } } private void firePanEvent(GeoPoint old, GeoPoint current){ for(PanChangeListener event : panEvents){ event.onPan(old, current); } } public void addZoomChangeListener(ZoomChangeListener listener){ this.zoomEvents.add(listener); } public void addPanChangeListener(PanChangeListener listener){ this.panEvents.add(listener); } } |
The new stuff here is the line 35
public int[][] getBounds() {
This is the new method that will give you an array with the bounds of your latitude and longitude. You can then use this to query a spatial database for instance
Zoom events are detected at the dispatchDraw method on line 63. We have to store the old value and the new value. If the view gets to be redrawn (either by a pan or a zoom) we just check if it was a zoom and fire the event
And finally them pan. On a “finger up” event we just fire an event informing the new center of the map.
Those small methods really helped me achieving what was required for my use case. It’s a simple addition that I really don’t understand why google left out of it’s API.
Happy coding

