Here are the basic steps and below is the full code. Tested and works great.
First, assume we are using a marker icon bitmap, size 27 pixels by 27 pixels and you want to move the anchor point from the default lower left of the icon to the lower right.
Move the anchor point to the lower right: marker.setAnchor(1,0);
One icon width in the x direction is 27 DPs, but we need to know how many pixels that is.
offsetPoint.x -= MapUtils.convertDpToPx(CreateRouteActivity.this, offsetDPX);
Now we know where the point on the screen is, so just grab the LatLng from that: marker.setPosition(projection.fromScreenLocation(offsetPoint));
If you want to move the icon even further away from your finger, just experiment with the ANCHOR_FACTOR value.
Here is my CreateRouteActivity:
private GoogleMap.OnMarkerDragListener onMarkerDragListener = new GoogleMap.OnMarkerDragListener() {
float offsetDPX;
float offsetDPY;
Projection projection;
@Override
public void onMarkerDragStart(Marker marker) {
// Save the projection every time a marker starts to drag. This keeps the anchors and drop points synced up.
// If we don't save the projection at the point the marker starts to drag and the user zooms out, the icon pixel size
// will remain the same but the LatLng distances will have way fewer pixels, messing up the drop point.
projection = gMap().getProjection();
// GoogleMap's default anchor is located at the lower left point of the marker icon.
// An ANCHOR_FACTOR of 1 will move the drag point to the lower right of the icon.
// An ANCHOR_FACTOR of 2 will move the drag point to the lower right x 2. (The icon will move from under the user's finger to 2 width's above and to the left.)
float ANCHOR_FACTOR = 1f;
// 27 is my original icon's width in pixels.
// Android increases the pixel size of the image in high-density screens, so make sure you use 27 DPs, not 27 pixels.
offsetDPX = 27*ANCHOR_FACTOR;
offsetDPY = 27*(ANCHOR_FACTOR-1);
// Always set the anchor by percentage of icon width. 0,0 is lower left. 1,0 is lower right.
marker.setAnchor(ANCHOR_FACTOR,ANCHOR_FACTOR-1);
}
@Override
public void onMarkerDrag(Marker marker) {
// If you want something to happen while you drag, put it here.
}
@Override
public void onMarkerDragEnd(Marker marker) {
// getPosition returns pixel location
Point offsetPoint = projection.toScreenLocation(marker.getPosition());
// We need to offset by the number of DPs, so convert DPs to pixels.
offsetPoint.x -= MapUtils.convertDpToPx(CreateRouteActivity.this, offsetDPX);
offsetPoint.y -= MapUtils.convertDpToPx(CreateRouteActivity.this, offsetDPY);
// set the marker's LatLng from offsetPoint (in pixels)
marker.setPosition(projection.fromScreenLocation(offsetPoint));
};
And some conversion tools in my MapUtils object:
public static float convertDpToPx(Context context, float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
public static float convertPxToDp(Context context, float px) {
return px / context.getResources().getDisplayMetrics().density;
}