Android 从点和填充创建CameraUpdate,以很好地显示标记
我有一个Latling点的列表,我想在谷歌地图上显示为标记。 我目前正在通过以下方式计算适合我所有点的摄影机视图:Android 从点和填充创建CameraUpdate,以很好地显示标记,android,google-maps,google-maps-markers,google-maps-android-api-2,android-maps-utils,Android,Google Maps,Google Maps Markers,Google Maps Android Api 2,Android Maps Utils,我有一个Latling点的列表,我想在谷歌地图上显示为标记。 我目前正在通过以下方式计算适合我所有点的摄影机视图: 首先,我用我所有的点计算一个LatLngBounds Iterator<LatLng> i = items.iterator(); LatLngBounds.Builder builder = LatLngBounds.builder(); while (i.hasNext()) { builder.include(i.next()); } LatLngBoun
Iterator<LatLng> i = items.iterator();
LatLngBounds.Builder builder = LatLngBounds.builder();
while (i.hasNext()) {
builder.include(i.next());
}
LatLngBounds bounds = builder.build();
50dp
),在底部有一个浮动卡(大约200dp
)
如果我不添加填充,一些点将被顶部工具栏或底部卡片覆盖
如果我添加最大填充(200dp
),那么顶部、左侧和右侧都有巨大的间隙。有什么想法吗
__________________________
| ___________o__________ |
| | | |
| |____________________|o|
| o |
| o |
| o |
| MAP |
| o |
| o |
| ______________________ |
| | | |
|o| | |
| | |o|
| |____________________| |
|____________________o___|
我现在唯一的想法是,以像素为单位获取贴图宽度,以Lng为单位获取贴图宽度(没有很好地定义),找到像素/Lng比率,将所需的填充从像素转换为Lng,然后重新计算LatLngBounds,添加一个假点(每边一个),该点与我的原始边界相距太远。这似乎可行,但如果有更好的解决方案,我会等待 您需要传递包含贴图的视图的宽度和高度(以像素为单位),以便我们可以计算像素到投影坐标的系数。 然后在
Rect
对象中传递所需的填充
如果您有很多要点,那么这可能最适合在后台任务中运行
public static CameraUpdate computeCameraView(final List<LatLng> items,
final GoogleMap map, final Rect padding,
final int viewWidth, final int viewHeight) {
// Compute bounds without padding
Iterator<LatLng> i = items.iterator();
LatLngBounds.Builder builder = LatLngBounds.builder();
while (i.hasNext()) {
builder.include(i.next());
}
LatLngBounds bounds = builder.build();
// Create a first CameraUpdate and apply
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 0);
map.moveCamera(cameraUpdate);
// Convert padding to lat/lng based on current projection
bounds = map.getProjection().getVisibleRegion().latLngBounds;
double mapWidth = bounds.northeast.longitude - bounds.southwest.longitude;
double mapHeight = bounds.northeast.latitude - bounds.southwest.latitude;
double pixelToLng = mapWidth / viewWidth;
double pixelToLat = mapHeight / viewHeight;
padding.top = (int) (padding.top * pixelToLat);
padding.bottom = (int) (padding.bottom * pixelToLat);
padding.left = (int) (padding.left * pixelToLng);
padding.right = (int) (padding.right * pixelToLng);
// Now padding holds insets in lat/lng values.
// Let's create two fake points and bound
LatLng northEast = new LatLng(bounds.northeast.latitude + padding.top,
bounds.northeast.longitude + padding.right);
LatLng southWest = new LatLng(bounds.southwest.latitude - padding.bottom,
bounds.southwest.longitude - padding.left);
LatLngBounds newBounds = new LatLngBounds.Builder()
.include(northEast).include(southWest).build();
return CameraUpdateFactory.newLatLngBounds(newBounds, 0);
}
实际上,有一个更简单、更短的解决方案,只需要三行代码。 谢谢你的解决方案 首先,将工具栏和底部卡的大小转换为像素 然后,添加以下三行代码: 第一行:顶部和底部的填充物是你的
工具栏,底部的卡片大小加上一些额外的,左侧和右侧可以是任何填充物,只要看起来不错
第二行:将相机移动/设置动画到边界,并记住将填充设置为0
,因为您不需要任何额外的填充,因为您已经在第一行中设置了它
第三行:将贴图填充设置回原始填充(对于我的情况为0),因为第一行中设置的贴图填充是永久的
就这样,你来了!希望有帮助 您可以使用
public static camera更新新的LatLngBounds(LatLngBounds边界、int-width、int-height、int-padding)
返回一个CameraUpdate,该更新将变换摄影机,使
指定的纬度/经度边界在屏幕上以
以最大可能的缩放比例显示指定尺寸的边界框
水平。您可以指定额外的填充,以进一步限制
边界框的大小
您将定义一个框,其宽度和高度将位于地图可用区域的中心。然后边界将居中,并在该框内尽可能放大
您可以通过该框“模拟”填充,而无需对地图应用填充(然后无需移动地图覆盖,如水印等)。
如果希望水平填充为16dp,则将框的宽度设置为:mapWidth-dpToPx(2*16)
需要2*是因为,同样,您的方框将在地图内居中。因此,如果只移除16 DP,则两侧将有8 DP
我跳过了转换dpToPx的方法,但是你可以很容易地在上面找到它
该方法的局限性在于,由于长方体居中,因此左右填充必须相同。(顶部和底部相同)
最后的想法:
当地图上有填充物时,奇怪的事情就发生了。要么将贴图的填充应用于正在定义的框,要么发生其他情况。
当我将框的高度定义为mapHeight-verticalPaddingOfTheMap
时,结果并不像预期的那样。我终于把mapeheight
放进去了,一切都很好。
如果你操作一个有填充的地图,请记住这一点
public static CameraUpdate computeCameraView(final List<LatLng> items,
final GoogleMap map, final Rect padding,
final int viewWidth, final int viewHeight) {
// Compute bounds without padding
Iterator<LatLng> i = items.iterator();
LatLngBounds.Builder builder = LatLngBounds.builder();
while (i.hasNext()) {
builder.include(i.next());
}
LatLngBounds bounds = builder.build();
// Create a first CameraUpdate and apply
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 0);
map.moveCamera(cameraUpdate);
// Convert padding to lat/lng based on current projection
bounds = map.getProjection().getVisibleRegion().latLngBounds;
double mapWidth = bounds.northeast.longitude - bounds.southwest.longitude;
double mapHeight = bounds.northeast.latitude - bounds.southwest.latitude;
double pixelToLng = mapWidth / viewWidth;
double pixelToLat = mapHeight / viewHeight;
padding.top = (int) (padding.top * pixelToLat);
padding.bottom = (int) (padding.bottom * pixelToLat);
padding.left = (int) (padding.left * pixelToLng);
padding.right = (int) (padding.right * pixelToLng);
// Now padding holds insets in lat/lng values.
// Let's create two fake points and bound
LatLng northEast = new LatLng(bounds.northeast.latitude + padding.top,
bounds.northeast.longitude + padding.right);
LatLng southWest = new LatLng(bounds.southwest.latitude - padding.bottom,
bounds.southwest.longitude - padding.left);
LatLngBounds newBounds = new LatLngBounds.Builder()
.include(northEast).include(southWest).build();
return CameraUpdateFactory.newLatLngBounds(newBounds, 0);
}
public static double computeLngDistance(LatLng east, LatLng west) {
if (east.longitude <= 0 && west.longitude >= 0) {
// We are crossing the 180 line.
return (east.longitude + 180d) + (180d - west.longitude);
} else {
return east.longitude - west.longitude;
}
}
map.setPadding(left, top, right, bottom);
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
map.setPadding(0,0,0,0);