myLocationOverlay change the marker

Thx @CommonsWare, you led me in the right direction. Spent quite a wile twiddling with this. The Javadoc on http://code.google.com/android/add-ons/google-apis/reference/com/google/android/maps/MyLocationOverlay.html is just wrong (or outdated) and messes with your brain where it says:

drawMyLocation

Also, if the user’s position moves near the edge of the screen, and we’ve been given a MapController in our constructor, we’ll scroll to recenter the new reading.

This is completely wrong. First, there is no such constructor in the class. Second of all, drawMyLocation only gets called when the current Location is within the viewbounds, or the screen is moved. So if you receive a new location and you don’t see the marker at this moment, it won’t be redrawn. Which is a good thing in general, but a bad thing if you want to implement mc.animateTo in the method to keep the location centered.

Third of all, you shouldn’t need to pass a MapController, to enable currentLocation, because you already have the mapView and get the controller from it..

So I ended up writing my own Class that keeps centering on the current location once the location reaches the border of the mapView or is off-screen:

public class CurrentLocationOverlay extends MyLocationOverlay {

  // TODO: use dynamic calculation?
  private final static int PADDING_ACTIVE_ZOOM     = 50;

  private MapController    mc;
  private Bitmap           marker;
  private Point            currentPoint            = new Point();

  private boolean          centerOnCurrentLocation = true;

  private int              height;
  private int              width;

  /**
   * By default this CurrentLocationOverlay will center on the current location, if the currentLocation is near the
   * edge, or off the screen. To dynamically enable/disable this, use {@link #setCenterOnCurrentLocation(boolean)}.
   *
   * @param context
   * @param mapView
   */
  public CurrentLocationOverlay(Context context, MapView mapView) {
    super(context, mapView);
    this.mc = mapView.getController();
    this.marker = BitmapFactory.decodeResource(context.getResources(), R.drawable.position);
  }

  @Override
  protected void drawMyLocation(Canvas canvas, MapView mapView, Location lastFix, GeoPoint myLocation, long when) {
    // TODO: find a better way to get height/width once the mapView is layed out correctly
    if (this.height == 0) {
      this.height = mapView.getHeight();
      this.width = mapView.getWidth();
    }
    mapView.getProjection().toPixels(myLocation, currentPoint);
    canvas.drawBitmap(marker, currentPoint.x, currentPoint.y - 40, null);
  }

  @Override
  public synchronized void onLocationChanged(Location location) {
    super.onLocationChanged(location);
    // only move to new position if enabled and we are in an border-area
    if (mc != null && centerOnCurrentLocation && inZoomActiveArea(currentPoint)) {
      mc.animateTo(getMyLocation());
    }
  }

  private boolean inZoomActiveArea(Point currentPoint) {
    if ((currentPoint.x > PADDING_ACTIVE_ZOOM && currentPoint.x < width - PADDING_ACTIVE_ZOOM)
        && (currentPoint.y > PADDING_ACTIVE_ZOOM && currentPoint.y < height - PADDING_ACTIVE_ZOOM)) {
      return false;
    }
    return true;
  }

  public void setCenterOnCurrentLocation(boolean centerOnCurrentLocation) {
    this.centerOnCurrentLocation = centerOnCurrentLocation;
  }
}

Leave a Comment