Google Maps Android API - 如何在拖动时移动标记的锚点
Posted
技术标签:
【中文标题】Google Maps Android API - 如何在拖动时移动标记的锚点【英文标题】:Google Maps Android API - How to shift anchor of marker while dragging 【发布时间】:2014-10-02 04:37:22 【问题描述】:在 android 上的 Google Maps 地图上拖动标记时,标记会显示在手指下方,因此几乎不可能在地图上精确放置标记。有没有办法简单地将标记移动一些像素到顶部以使其可见?
我尝试在onMarkerDragStart()
中移动标记,但当我继续拖动时,它立即返回到原来的位置。我还尝试不断改变onMarkerDrag()
中的标记位置。这会在停止拖动标记时产生不可预知的结果。
是否有官方方法可以在拖动标记时移动标记,或者是否有人找到了其他方法?
【问题讨论】:
【参考方案1】:我自己对这个很感兴趣,所以我尝试了很多方法。
我终于发现默认情况下 Maps API 会在开始拖动标记时将标记向右移动它的宽度。要在拖动后伪造 [1, 1] 锚点,我们需要将标记向左水平(x 轴)移动宽度,垂直向上(y 轴)移动高度。
这种方式似乎工作正常,非常整洁。
这是一个例子:
// Get marker dimensions
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.marker);
final int width = img.getWidth();
final int height = img.getHeight();
mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener()
@Override
public void onMarkerDragStart(final Marker marker)
marker.setAnchor(1, 1);
@Override
public void onMarkerDrag(Marker marker)
@Override
public void onMarkerDragEnd(final Marker marker)
Projection projection = mMap.getProjection();
// Coordinates to point (in screen pixels)
Point point = projection.toScreenLocation(marker.getPosition());
// Move to [1, 1]
point.x -= width;
point.y -= height;
// Point to coordinates
LatLng coords = projection.fromScreenLocation(point);
// Reset the anchor and use the coordinates
marker.setAnchor(0, 0);
marker.setPosition(coords);
);
// Your marker
BitmapDescriptor bitmapDescriptor =
BitmapDescriptorFactory.fromResource(R.drawable.marker);
mMap.addMarker(new MarkerOptions()
.position(mPolylines.get(0).getPoints().get(1000))
.icon(bitmapDescriptor)
.anchor(0, 0)
.draggable(true));
注意:this answer 建议您可能需要等待地图完全充气后才能使用地图的投影。您可能需要相应地进行编辑,尽管我发现没有它也可以正常工作。
【讨论】:
试过了,将锚点设置回 0,0 会使标记在地图上跳跃。我不想更改锚点(它指定标记图像中的哪个位置应该是地图上标记的实际位置),而是在拖动开始时向上移动标记,包括其锚点。 谢谢,我也试过了。你是对的,标记停留在该位置,但实际位置(纬度和经度)现在不符合预期。这是正常的,因为我们改变了锚点位置。 也许最简单的解决方案是使用一个标记符号,它的锚点不在底部中间,而是在顶部中间。这样在拖动时可能会看到它;-) @Hokascha 啊,你是对的,我的 美丽的解决方案 失败了:/ 但是你知道一旦开始拖动,API 会稍微移动标记,所以它们并不是真的那么隐形。 是的,看起来即使是谷歌也考虑到了这一点。来自 onMarkerDragStart() 文档:“可以通过 getPosition() 访问标记的位置;此位置可能与拖动开始之前的位置不同,因为标记在触摸点上方弹出。”因此,他们将其弹出了一点,但似乎无法控制标记弹出的距离。只需使用默认标记图像即可显示问题 - 除非您的手指是透明的,否则您看不到锚点。【参考方案2】:这里是基本步骤,下面是完整代码。经过测试,效果很好。
首先,假设我们使用的是标记图标位图,大小为 27 x 27 像素,并且您希望将锚点从图标的默认左下角移动到右下角。
将锚点移至右下方:marker.setAnchor(1,0);
一个图标在 x 方向的宽度是 27 DPs,但我们需要知道这是多少像素。offsetPoint.x -= MapUtils.convertDpToPx(CreateRouteActivity.this, offsetDPX);
现在我们知道屏幕上的点在哪里,所以只需从中获取 LatLng:marker.setPosition(projection.fromScreenLocation(offsetPoint));
如果您想将图标移到离手指更远的位置,只需尝试使用 ANCHOR_FACTOR 值即可。
这是我的 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));
;
以及我的 MapUtils 对象中的一些转换工具:
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;
【讨论】:
以上是关于Google Maps Android API - 如何在拖动时移动标记的锚点的主要内容,如果未能解决你的问题,请参考以下文章
Google Geolocation API 和 Google Maps Android SDK
Android:使用 Google API 获取实时方向,还是与 Google Maps 通信?
Android Manifest 未向 Google Maps 提供 API 密钥
为 Google Maps API v2 Android 发布流媒体方向