If you are interested in developing Android applications which have a mapping component, you have undoubtedly heard of
Google's mapping API. It's an incredibly usefull API, but has some holes.
For example, they haven't released code to detect if one of your
OverlayItems has been clicked by the user. Actually, they've documented that the
ItemizedOverlay class has a method called
hitTest which does not seem to work properly.
Very quickly, here's a method you can implement in your ItemizedOverlay which will check if any of your OverlayItems have been clicked. The meat of this code is the runHitTest method. Be sure to notice, however, that we've saved a copy of the defaultMarker that was passed in when the SomeItemizedOverlay class was instantiated. This is important, because we need to know what the marker's bounds are. These bounds can be changed. Take a look at
boundCenterBottom or
boundCenter, for example.
import java.util.ArrayList;
import android.app.Activity;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.Projection;
public class SomeItemizedOverlay extends ItemizedOverlay<SomeOverlay> {
private ArrayList<SomeOverlay> mOverlays = new ArrayList<SomeOverlay>();
private Activity mContext;
private Drawable mMarker;
private SomeItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
mMarker = boundCenterBottom(defaultMarker);
}
public SomeItemizedOverlay(Drawable defaultMarker, Activity ctx) {
super(boundCenterBottom(defaultMarker));
mContext = ctx;
mMarker = boundCenterBottom(defaultMarker);
}
@Override
protected SomeOverlay createItem(int i) {
return mOverlays.get(i);
}
@Override
public int size() {
return mOverlays.size();
}
public void addOverlay(SomeOverlay overlay) {
mOverlays.add(overlay);
populate();
}
public boolean onTap(GeoPoint p, MapView v) {
// Create and add an OverlayItem
}
public boolean onTouchEvent(MotionEvent e, MapView v) {
return runHitTest(e,v);
}
private boolean runHitTest(MotionEvent e, MapView v) {
if( e.getAction() != MotionEvent.ACTION_DOWN )
return false;
int x = new Float(e.getX()).intValue();
int y = new Float(e.getY()).intValue();
Projection proj = v.getProjection();
for(int i = 0; i < mOverlays.size(); i++) {
// We need to translate the geographical location
// of this particular OverlayItem to it's corresponding
// on-screen pixel location.
GeoPoint gpt = mOverlays.get(i).getPoint();
Point loc = proj.toPixels(gpt, null);
// Now we need to translate the clicked pixel (x,y)
// to this OverlayItem's coordinate frame.
int x_ovrly = x - loc.x;
int y_ovrly = y - loc.y;
// Now we need to check if the translated point is in
// the Drawable used to mark this OverlayItem.
if( mMarker.getBounds().contains(x_ovrly, y_ovrly) ) {
Log.v("MyApplication", "hit item: " + i);
return true;
}
}
return false;
}
}
I hope you find this useful!
Edit: You could alternately use this version of runHitTest(). It responds only to taps, where the other version responded to any gesture that began on an instance of SomeOverlay.
private boolean runHitTest(MotionEvent e, MapView v) {
// Only handle the event if it truly represents a tap.
if( ! (e.getAction() == MotionEvent.ACTION_UP && mInteractionState == MotionEvent.ACTION_DOWN) ) {
mInteractionState = e.getAction();
return false;
} else {
mInteractionState = e.getAction();
}
int x = new Float(e.getX()).intValue();
int y = new Float(e.getY()).intValue();
Projection proj = v.getProjection();
for(int i = 0; i < mOverlays.size(); i++) {
// We need to translate the geographical location
// of this particular OverlayItem to it's corresponding
// on-screen pixel location.
VicinityOverlay ovrly = mOverlays.get(i);
GeoPoint gpt = ovrly.getPoint();
Point loc = proj.toPixels(gpt, null);
// Now we need to translate the clicked pixel (x,y)
// to this OverlayItem's coordinate frame.
int x_ovrly = x - loc.x;
int y_ovrly = y - loc.y;
// Now we need to check if the translated point is in
// the Drawable used to mark this OverlayItem.
if( mMarker.getBounds().contains(x_ovrly, y_ovrly) ) {
Log.v("MyApplication", "hit item: " + i);
return true;
}
}
return false;
}
Where
mInteractionState is a
private int in the SomeItemizedOverlay class.