【问题标题】:Create CameraUpdate from points and padding to show markers nicely从点和填充创建 CameraUpdate 以很好地显示标记
【发布时间】:2016-11-04 19:59:02
【问题描述】:

我有一个 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 添加一个假离我原来的边界那么远的点(每边一个)。

【问题讨论】:

    标签: android google-maps google-maps-markers google-maps-android-api-2 android-maps-utils


    【解决方案1】:

    实际上有一个更简单、更短的解决方案,只需要三行代码。 感谢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,左右可以是任何填充,只要看起来不错。

    第二行:将您的相机移动/动画到边界和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)

        1. 2 * 是必需的,因为同样,您的框将在地图内居中。因此,如果您只删除 16dp,那么每边都会有 8dp。
        2. 我跳过了转换 dpToPx 的方法,但您可以在 SO 上轻松找到它。

        该方法的局限性在于,由于框居中,左右填充必须相同。 (顶部和底部相同)。

        最后的想法: 当地图有填充时,会发生一些奇怪的事情。地图的填充应用到您正在定义的框,或者发生其他事情。
        当我将框的高度定义为mapHeight - verticalPaddingOfTheMap 时,结果并不如预期。我终于输入了mapHeight,一切都很好。
        如果您操作有填充的地图,请记住这一点

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-11
          • 1970-01-01
          相关资源
          最近更新 更多