3

我有一个 LatLng 点列表,我想在 GoogleMap 上显示为标记。我目前正在计算一个适合我所有观点的相机视图,方法如下:

  1. 首先,我用我的所有点计算一个 LatLngBounds。

    Iterator<LatLng> i = items.iterator();
    LatLngBounds.Builder builder = LatLngBounds.builder();
    while (i.hasNext()) {
        builder.include(i.next());
    }
    LatLngBounds bounds = builder.build();
    
  2. 然后我使用适当的方法:

    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 添加一个假点(一个对于每一边),这与我原来的界限相距甚远。

4

3 回答 3

6

实际上有一个更简单和更短的解决方案,只需要三行代码。感谢https://stackoverflow.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,left 和 right 可以是任何填充,只要它看起来不错。

第二行:将您的相机移动/动画到边界,remember to set the padding to 0因为您已经在第一行设置了它,因此您不需要任何额外的填充。

第三行:设置地图填充back to original padding(我的情况为 0),因为第一行中设置的地图填充是永久的。

就是这样,你去吧!希望能帮助到你!

于 2018-11-21T10:48:26.500 回答
4

这似乎有效,但如果有更好的解决方案,我会等待。

您需要传递持有地图的视图的宽度和高度(以像素为单位),以便我们可以计算像素到投影坐标的系数。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;
    }
}
于 2016-07-02T22:09:31.323 回答
0

You can use
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.

see ref

You'll define a box with a width and a height that will be centered inside the usable area of your map. Then the bounds will be centered and zoomed as much as possible inside that box.

You can "simulate" padding via that box without applying padding to the map (an then without moving map overlays such as watermark, etc). If you want an horizontal padding of 16dp, you'll set the width of your box to be : mapWidth - dpToPx(2 * 16)

  1. The 2 * is needed because, again, your box will be centered inside the map. so if you remove only 16dp, you'll have 8dp on each sides.
  2. I skipped the method to convert dpToPx but you can easily find it on SO.

The limitation of that method is that, since the box is centered, left and right padding has to be the same. (same for top and bottom).

Final thoughts : When the map has padding something weird occurres. Either the padding of the map is applied to the box you are defining, or something else happens.
When I was defining the height of the box as mapHeight - verticalPaddingOfTheMap the result was not as expected. I finally put mapHeight and it was all good.
Keep that in mind if you manipulate a map that has padding

于 2021-03-30T14:15:49.527 回答