从点和填充创建 CameraUpdate 以很好地显示标记
Posted
技术标签:
【中文标题】从点和填充创建 CameraUpdate 以很好地显示标记【英文标题】:Create CameraUpdate from points and padding to show markers nicely 【发布时间】:2016-11-04 19:59:02 【问题描述】:我有一个 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 为单位获取地图宽度(未明确定义),找到像素/lng 比率,将所需的填充从像素转换为 lng,然后重新计算 LatLngBounds 添加一个假离我原来的边界那么远的点(每边一个)。
【问题讨论】:
【参考方案1】:实际上有一个更简单、更短的解决方案,只需要三行代码。 感谢https://***.com/a/27937256/10035225 的解决方案。
首先,将工具栏和底部卡片大小转换为像素。
然后,添加这三行代码:
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
,左右可以是任何填充,只要看起来不错。
第二行:将您的相机移动/动画到边界和remember to set the padding to 0
,因为您不需要任何额外的填充,因为您已经在第一行设置了它。
第三行:设置地图填充 back to original padding
(我的情况为 0),因为第一行中设置的地图填充是永久的。
就是这样,你去吧!希望对您有所帮助!
【讨论】:
【参考方案2】:这似乎可行,但如果有更好的解决方案,我会等待。
您需要传递持有地图的视图的宽度和高度(以像素为单位),以便我们可以计算一个像素到投影坐标的系数。
然后在 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;
【讨论】:
【参考方案3】:您可以使用public static CameraUpdate newLatLngBounds (LatLngBounds bounds, int width, int height, int padding)
返回一个 CameraUpdate 来转换相机,使得 指定的纬度/经度边界在屏幕上居中 以最大可能缩放指定尺寸的边界框 等级。您可以指定额外的填充,以进一步限制 边界框的大小。
see ref
您将定义一个具有宽度和高度的框,该框将在地图的可用区域内居中。然后边界将在该框内尽可能集中和缩放。
您可以通过该框“模拟”填充,而无需对地图应用填充(然后无需移动地图叠加层,例如水印等)。
如果您想要 16dp 的水平内边距,请将框的宽度设置为:mapWidth - dpToPx(2 * 16)
-
2 * 是必需的,因为同样,您的框将在地图内居中。因此,如果您只删除 16dp,那么每边都会有 8dp。
我跳过了转换 dpToPx 的方法,但您可以在 SO 上轻松找到它。
该方法的局限性在于,由于框居中,左右填充必须相同。 (顶部和底部相同)。
最后的想法:
当地图有填充时,会发生一些奇怪的事情。地图的填充应用到您正在定义的框,或者发生其他事情。
当我将框的高度定义为mapHeight - verticalPaddingOfTheMap
时,结果并不如预期。我终于输入了mapHeight
,一切都很好。 如果您操作有填充的地图,请记住这一点
【讨论】:
以上是关于从点和填充创建 CameraUpdate 以很好地显示标记的主要内容,如果未能解决你的问题,请参考以下文章