从点和填充创建 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 以很好地显示标记的主要内容,如果未能解决你的问题,请参考以下文章

json 使用动态填充检查复选框时,重力形式不能很好地发挥作用

从 groovy 模板“很好地”访问 Json

mysql 查询 - 不能很好地扩展,15k 记录很慢

很好地获取Android用户的电子邮件地址

POJ2777解题报告

创建组件后很好地显示 Qml-Window