Android 从点和填充创建CameraUpdate,以很好地显示标记

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

我有一个Latling点的列表,我想在谷歌地图上显示为标记。 我目前正在通过以下方式计算适合我所有点的摄影机视图:

  • 首先,我用我所有的点计算一个LatLngBounds

    Iterator<LatLng> i = items.iterator();
    LatLngBounds.Builder builder = LatLngBounds.builder();
    while (i.hasNext()) {
        builder.include(i.next());
    }
    LatLngBounds bounds = builder.build();
    
  • 更新提供了一个很好的观点,我的所有观点,与一些不错的填充

    问题

    我想为paddingTop、paddingBottom、paddingLeft和paddingRight应用不同的值。也就是说,我两边都没有,然后我在顶部有一个浮动工具栏(大约
    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);