从点和填充创建 CameraUpdate 以很好地显示标记
Create CameraUpdate from points and padding to show markers nicely
我有一个 LatLng 点列表,我想在 GoogleMap 上显示为标记。
我目前正在通过以下方式计算适合我所有观点的相机视图:
首先我用我所有的点计算一个 LatLngBounds。
Iterator<LatLng> i = items.iterator();
LatLngBounds.Builder builder = LatLngBounds.builder();
while (i.hasNext()) {
builder.include(i.next());
}
LatLngBounds bounds = builder.build();
那我就用合适的方法:
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, padding);
此更新提供了对我所有观点的良好看法,并有一些漂亮的填充。
问题
我想为 paddingTop、paddingBottom、paddingLeft 和 paddingRight 应用不同的值。即,我两边什么都没有,然后我在顶部有一个浮动工具栏(大约50dp
),在底部有一个浮动卡片(大约200dp
)。
如果我不添加填充,一些点将被顶部工具栏或底部卡片覆盖。
如果我加上最大内边距(200dp
),那么顶部、左侧和右侧就会有巨大的空隙。有什么想法吗?
__________________________
| ___________o__________ |
| | | |
| |____________________|o|
| o |
| o |
| o |
| MAP |
| o |
| o |
| ______________________ |
| | | |
|o| | |
| | |o|
| |____________________| |
|____________________o___|
我现在唯一的想法是,以像素为单位获取地图宽度,以 Lng 为单位获取地图宽度(定义不明确),找到 pixels/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);
}
这里的弱点是double mapWidth = bounds.northeast.longitude - bounds.southwest.longitude
。你不能那样计算经度,因为它是一个循环变量(即,如果可见区域穿过 180 度子午线,就会出现问题)。 我会调查一下。
这应该足够了:
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);
第一行:顶部和底部填充将是您的 toolbar and bottom card size plus some extra
,左侧和右侧可以是任何填充,只要它看起来不错。
第二行:move/animate你的相机到边界并且remember to set the padding to 0
因为你不需要任何额外的填充,因为你已经在第一行中设置了它。
第三行:设置地图填充back to original padding
(我的情况为0)因为第一行中设置的地图填充是永久性的。
到此为止!希望对您有所帮助!
您可以使用
public static CameraUpdate newLatLngBounds (LatLngBounds bounds, int width, int height, int padding)
Returns a CameraUpdate that transforms the camera such that the
specified latitude/longitude bounds are centered on screen within a
bounding box of specified dimensions at the greatest possible zoom
level. You can specify additional padding, to further restrict the
size of the bounding box.
您将定义一个框,其宽度和高度将在地图的可用区域内居中。然后边界将在该框内尽可能居中和缩放。
您可以通过该框“模拟”填充,而无需对地图应用填充(然后无需移动水印等地图覆盖)。
如果你想要 16dp 的水平填充,你将你的框的宽度设置为:mapWidth - dpToPx(2 * 16)
- 2 * 是必需的,因为您的框将在地图内居中。因此,如果您仅删除 16dp,则每边将有 8dp。
- 我跳过了转换 dpToPx 的方法,但您可以在 SO 上轻松找到它。
该方法的局限性在于,由于框居中,因此左右填充必须相同。 (顶部和底部相同)。
最后的想法:
当地图有填充时,会发生一些奇怪的事情。要么将地图的填充应用于您正在定义的框,要么发生其他情况。
当我将框的高度定义为 mapHeight - verticalPaddingOfTheMap
时,结果与预期不符。我终于放了 mapHeight
一切都很好。
如果你操作有填充的地图,请记住这一点
我有一个 LatLng 点列表,我想在 GoogleMap 上显示为标记。 我目前正在通过以下方式计算适合我所有观点的相机视图:
首先我用我所有的点计算一个 LatLngBounds。
Iterator<LatLng> i = items.iterator(); LatLngBounds.Builder builder = LatLngBounds.builder(); while (i.hasNext()) { builder.include(i.next()); } LatLngBounds bounds = builder.build();
那我就用合适的方法:
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, padding);
此更新提供了对我所有观点的良好看法,并有一些漂亮的填充。
问题
我想为 paddingTop、paddingBottom、paddingLeft 和 paddingRight 应用不同的值。即,我两边什么都没有,然后我在顶部有一个浮动工具栏(大约50dp
),在底部有一个浮动卡片(大约200dp
)。
如果我不添加填充,一些点将被顶部工具栏或底部卡片覆盖。
如果我加上最大内边距(200dp
),那么顶部、左侧和右侧就会有巨大的空隙。有什么想法吗?
__________________________
| ___________o__________ |
| | | |
| |____________________|o|
| o |
| o |
| o |
| MAP |
| o |
| o |
| ______________________ |
| | | |
|o| | |
| | |o|
| |____________________| |
|____________________o___|
我现在唯一的想法是,以像素为单位获取地图宽度,以 Lng 为单位获取地图宽度(定义不明确),找到 pixels/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);
}
这里的弱点是double mapWidth = bounds.northeast.longitude - bounds.southwest.longitude
。你不能那样计算经度,因为它是一个循环变量(即,如果可见区域穿过 180 度子午线,就会出现问题)。 我会调查一下。
这应该足够了:
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);
第一行:顶部和底部填充将是您的 toolbar and bottom card size plus some extra
,左侧和右侧可以是任何填充,只要它看起来不错。
第二行:move/animate你的相机到边界并且remember to set the padding to 0
因为你不需要任何额外的填充,因为你已经在第一行中设置了它。
第三行:设置地图填充back to original padding
(我的情况为0)因为第一行中设置的地图填充是永久性的。
到此为止!希望对您有所帮助!
您可以使用
public static CameraUpdate newLatLngBounds (LatLngBounds bounds, int width, int height, int padding)
Returns a CameraUpdate that transforms the camera such that the specified latitude/longitude bounds are centered on screen within a bounding box of specified dimensions at the greatest possible zoom level. You can specify additional padding, to further restrict the size of the bounding box.
您将定义一个框,其宽度和高度将在地图的可用区域内居中。然后边界将在该框内尽可能居中和缩放。
您可以通过该框“模拟”填充,而无需对地图应用填充(然后无需移动水印等地图覆盖)。
如果你想要 16dp 的水平填充,你将你的框的宽度设置为:mapWidth - dpToPx(2 * 16)
- 2 * 是必需的,因为您的框将在地图内居中。因此,如果您仅删除 16dp,则每边将有 8dp。
- 我跳过了转换 dpToPx 的方法,但您可以在 SO 上轻松找到它。
该方法的局限性在于,由于框居中,因此左右填充必须相同。 (顶部和底部相同)。
最后的想法:
当地图有填充时,会发生一些奇怪的事情。要么将地图的填充应用于您正在定义的框,要么发生其他情况。
当我将框的高度定义为 mapHeight - verticalPaddingOfTheMap
时,结果与预期不符。我终于放了 mapHeight
一切都很好。
如果你操作有填充的地图,请记住这一点