单击标记时,摄像机的默认行为是将其置于屏幕中心,但由于我通常在信息窗口中有长文本说明,因此实际更改摄像机位置以便标记打开更方便屏幕底部(使信息窗口位于屏幕中央)。我想我应该能够通过覆盖onMarkerClick函数来做到这一点(当此函数返回true时,默认行为被取消)
@Override
public boolean onMarkerClick(final Marker marker) {
// Google sample code comment : We return false to indicate that we have not
// consumed the event and that we wish
// for the default behavior to occur (which is for the camera to move
// such that the
// marker is centered and for the marker's info window to open, if it
// has one).
marker.showInfoWindow();
CameraUpdate center=
CameraUpdateFactory.newLatLng(new LatLng(XXXX,
XXXX));
mMap.moveCamera(center);//my question is how to get this center
// return false;
return true;
}
编辑:
使用接受的答案的步骤解决问题,代码如下:
@Override
public boolean onMarkerClick(final Marker marker) {
//get the map container height
LinearLayout mapContainer = (LinearLayout) findViewById(R.id.map_container);
container_height = mapContainer.getHeight();
Projection projection = mMap.getProjection();
LatLng markerLatLng = new LatLng(marker.getPosition().latitude,
marker.getPosition().longitude);
Point markerScreenPosition = projection.toScreenLocation(markerLatLng);
Point pointHalfScreenAbove = new Point(markerScreenPosition.x,
markerScreenPosition.y - (container_height / 2));
LatLng aboveMarkerLatLng = projection
.fromScreenLocation(pointHalfScreenAbove);
marker.showInfoWindow();
CameraUpdate center = CameraUpdateFactory.newLatLng(aboveMarkerLatLng);
mMap.moveCamera(center);
return true;
}
感谢您帮助^ ^
答案 0 :(得分:46)
我可能稍后会编辑这个答案以提供一些代码,但我认为可行的是:
LatLng
( LatLng M )。Projection.toScreenLocation(LatLng)
方法将 LatLng M 转换为Point
( Point M )。这将为您提供设备显示屏上标记的位置(以像素为单位)。LatLng
并将地图置于其中心。查看here我的答案,了解如何获取地图的高度。
// googleMap is a GoogleMap object
// view is a View object containing the inflated map
// marker is a Marker object
Projection projection = googleMap.getProjection();
LatLng markerPosition = marker.getPosition();
Point markerPoint = projection.toScreenLocation(markerPosition);
Point targetPoint = new Point(markerPoint.x, markerPoint.y - view.getHeight() / 2);
LatLng targetPosition = projection.fromScreenLocation(targetPoint);
googleMap.animateCamera(CameraUpdateFactory.newLatLng(targetPosition), 1000, null);
答案 1 :(得分:18)
是的,使用Projection类。更具体地说:
获取地图的预测:
Projection projection = map.getProjection();
获取标记的位置:
LatLng markerLocation = marker.getPosition();
将位置传递给Projection.toScreenLocation()方法:
Point screenPosition = projection.toScreenLocation(markerLocation);
像这样你可以相对于中心或屏幕周围移动你的标记
Point mappoint = googleMap.getProjection().toScreenLocation(new LatLng(latitude, longitude));
mappoint.set(mappoint.x, mappoint.y-30);
googleMap.animateCamera(CameraUpdateFactory.newLatLng(googleMap.getProjection().fromScreenLocation(mappoint)));
答案 2 :(得分:6)
我更喜欢Larry McKenzie的答案,它不依赖于屏幕投影(即mProjection.toScreenLocation()),我的猜测是当地图缩放级别低时投影分辨率会变差,这让我有时候不能获得准确的位置。因此,基于谷歌地图规范的计算肯定会解决问题。
以下是将标记从底部移动到屏幕尺寸的30%的示例代码。
zoom_lvl = mMap.getCameraPosition().zoom;
double dpPerdegree = 256.0*Math.pow(2, zoom_lvl)/170.0;
double screen_height = (double) mapContainer.getHeight();
double screen_height_30p = 30.0*screen_height/100.0;
double degree_30p = screen_height_30p/dpPerdegree;
LatLng centerlatlng = new LatLng( latlng.latitude + degree_30p, latlng.longitude );
mMap.animateCamera( CameraUpdateFactory.newLatLngZoom( centerlatlng, 15 ), 1000, null);
答案 3 :(得分:3)
我有同样的问题,我尝试了以下完美的解决方案
mMap.setOnMarkerClickListener(new OnMarkerClickListener()
{
@Override
public boolean onMarkerClick(Marker marker)
{
int yMatrix = 200, xMatrix =40;
DisplayMetrics metrics1 = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics1);
switch(metrics1.densityDpi)
{
case DisplayMetrics.DENSITY_LOW:
yMatrix = 80;
xMatrix = 20;
break;
case DisplayMetrics.DENSITY_MEDIUM:
yMatrix = 100;
xMatrix = 25;
break;
case DisplayMetrics.DENSITY_HIGH:
yMatrix = 150;
xMatrix = 30;
break;
case DisplayMetrics.DENSITY_XHIGH:
yMatrix = 200;
xMatrix = 40;
break;
case DisplayMetrics.DENSITY_XXHIGH:
yMatrix = 200;
xMatrix = 50;
break;
}
Projection projection = mMap.getProjection();
LatLng latLng = marker.getPosition();
Point point = projection.toScreenLocation(latLng);
Point point2 = new Point(point.x+xMatrix,point.y-yMatrix);
LatLng point3 = projection.fromScreenLocation(point2);
CameraUpdate zoom1 = CameraUpdateFactory.newLatLng(point3);
mMap.animateCamera(zoom1);
marker.showInfoWindow();
return true;
}
});
答案 4 :(得分:3)
如果您不关心地图放大并且只想将标记放在底部,请参阅下文,我认为这是一个更简单的解决方案
double center = mMap.getCameraPosition().target.latitude;
double southMap = mMap.getProjection().getVisibleRegion().latLngBounds.southwest.latitude;
double diff = (center - southMap);
double newLat = marker.getPosition().latitude + diff;
CameraUpdate centerCam = CameraUpdateFactory.newLatLng(new LatLng(newLat, marker.getPosition().longitude));
mMap.animateCamera(centerCam);
答案 5 :(得分:1)
我做了一些研究,根据文档,地图是方形的,在零缩放级别,宽度和高度是256dp和+/- 85度N / S.地图宽度随缩放级别增加,因此宽度和高度= 256 * 2N dp。其中N是缩放级别。所以从理论上讲,您可以通过获取地图高度并将其除以170度来确定新位置,以获得每度数dp。然后在dp中将屏幕高度(或mapview高度)除以2并将半视图大小转换为纬度。然后将您的新相机点设置为多个纬度南。如果你需要,我可以添加代码,但我现在正在打电话。
答案 6 :(得分:1)
我也遇到了这个问题,并以骇人的方式解决了它。让我们首先声明一个双字段。您需要根据需要调整其值,但我建议您将其保留在0.001~0.009
之间,否则在缩放动画后可能会错过标记。
double offset = 0.009
/*You can change it based on your requirement.
For left-right alignment please kindly keep it between 0.001~0.005 */
对于居中的人:
LatLng camera = new LatLng(marker.getPosition().latitude+offset , marker.getPosition().longitude);
//Here "marker" is your target market on which you want to focus
对于居中的人:
LatLng camera = new LatLng(marker.getPosition().latitude-offset , marker.getPosition().longitude);
对于左居中的
:LatLng camera = new LatLng(marker.getPosition().latitude, marker.getPosition().longitude+offset);
对于右居:
LatLng camera = new LatLng(marker.getPosition().latitude-offset , marker.getPosition().longitude-offset);
然后最后调用-
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(camera, yourZoom));
答案 7 :(得分:0)
我一直在尝试这里提出的所有解决方案,并附带了它们的组合实现。考虑到,地图投影,倾斜,缩放和信息窗口高度。
它并没有真正将标记放在"摄像机视图的底部,但我认为它在大多数情况下都能很好地适应信息窗口和标记中心。
@Override
public boolean onMarkerClick(Marker marker) {
mIsMarkerClick = true;
mHandler.removeCallbacks(mUpdateTimeTask);
mLoadTask.cancel(true);
getActivity().setProgressBarIndeterminateVisibility(false);
marker.showInfoWindow();
Projection projection = getMap().getProjection();
Point marketCenter = projection.toScreenLocation(marker.getPosition());
float tiltFactor = (90 - getMap().getCameraPosition().tilt) / 90;
marketCenter.y -= mInfoWindowAdapter.getInfoWindowHeight() / 2 * tiltFactor;
LatLng fixLatLng = projection.fromScreenLocation(marketCenter);
mMap.animateCamera(CameraUpdateFactory.newLatLng(fixLatLng), null);
return true;
}
然后,您的自定义适配器必须保留信息窗口膨胀视图的实例,以便能够获取其高度。
public int getInfoWindowHeight(){
if (mLastInfoWindoView != null){
return mLastInfoWindoView.getMeasuredHeight();
}
return 0;
}
答案 8 :(得分:0)
仍然希望根据位置坐标使相机居中的人
CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(Lat, Lon))
.zoom(15)
.bearing(0)
.tilt(45)
.build();
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
答案 9 :(得分:0)
经过一些经验,我已经实施了对我来说很好的解决方案。
DisplayMetrics metrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(metrics);
Point targetPoint = new Point(metrics.widthPixels / 2, metrics.heightPixels - metrics.heightPixels / 9);
LatLng targetLatlng = map.getProjection().fromScreenLocation(targetPoint);
double fromCenterToTarget = SphericalUtil.computeDistanceBetween(map.getCameraPosition().target, targetLatlng);
LatLng center = SphericalUtil.computeOffset(new LatLng(location.latitude, location.longitude), fromCenterToTarget/1.2, location.bearing);
CameraUpdate camera = CameraUpdateFactory.newLatLng(center);
map.animateCamera(camera, 1000, null);
下面。首先,我们选择屏幕上应移动标记的物理点。然后,将其转换为LatLng。下一步 - 计算从当前标记位置(中心)到目标的距离。最后,我们将地图中心从标记直接移动到计算距离。
答案 10 :(得分:0)
我需要类似的东西,但方程式还需要缩放,倾斜和支撑。
我的问题比较复杂,但是解决方案只是一种概括,因此也可以应用于问题中的问题。
就我而言,我以编程方式更新了标记的位置;摄像机可以旋转,缩放和倾斜,但是我希望标记始终在从底部开始的特定视图高度的百分比处可见。 (类似于“地图”导航中的汽车标记位置)
解决方案:
我首先选择屏幕中心的地图位置,以及从底部(以底部视图)的一定百分比可见的点的位置(使用地图投影);我得到了两点之间的距离(以米为单位),然后从标记位置开始计算了一个位置,并朝着轴承方向移动了计算出的距离;这个新职位是我的新Camera目标。
代码(科特琳):
val movePointBearing =
if (PERCENTAGE_FROM_BOTTOM > 50) {
(newBearing + 180) % 360
} else newBearing
val newCameraTarget = movePoint(
markerPosition,
distanceFromMapCenter(PERCENTAGE_FROM_BOTTOM),
markerBearing)
,其中的movePoint
方法是从此处复制的:
https://stackoverflow.com/a/43225262/2478422
和distanceFromMapCenter
方法定义为:
fun distanceFromMapCenter(screenPercentage: Int): Float {
val screenHeight = mapFragment.requireView().height
val screenWith = mapFragment.requireView().width
val projection = mMap.projection
val center = mMap.cameraPosition.target
val offsetPointY = screenHeight - (screenHeight * screenPercentage / 100)
val offsetPointLocation = projection.fromScreenLocation(Point(screenWith / 2, offsetPointY))
return distanceInMeters(center, offsetPointLocation)
}
然后只需定义一个distanceInMeters
方法(例如使用android Location类)
我希望这个主意很明确,无需进一步解释。
一个明显的局限性:它使用当前的缩放和倾斜来应用逻辑,因此如果新的摄像头位置也需要不同的zoom_level和倾斜,则该逻辑将不起作用。