2015-11-02 49 views
11

我尝试在地图和我的标记之间放置背景;此图像应始终(!)留在所有标记之后。Android Google Maps - 所有标记背后的自定义背景

我尝试了几种方法,例如, showInfoWindow()除了背景图像之外的所有标记,但它似乎只会对最后一个有帮助。

然后我尝试了使用GroundOverlay的解决方案,但我需要我的图像始终保持相同的大小(例如设备大小的一半),而与缩放因子无关。

Android上有这个解决方案吗?

+0

为什么不简单地为您的标记设置自定义图标?在地图中有大量的标记和GroundOverlays会影响性能,所以我会尽量不设置一个标记和一个GroundOverlay,而应该只有一个标记 – antonio

+0

我的标记有自定义图标,但应该有一个作为背景使用;这是不可能的,因为我不能配置z-index – swalkner

+0

好吧,对不起,我还没有理解你的问题 – antonio

回答

-1

您最好的选择是使用GroundOverlay来显示背景,在视图更改时添加和删除它,并根据地图的VisibleRegion计算尺寸,以便它在缩放之间保持正确的大小。

the documentation

位置

有指定地面叠加层的位置有两种方式:

  • 使用位置:您必须提供的图像地面覆盖层,锚将固定到的LatLng以及覆盖层的宽度(以米为单位)。默认情况下,锚点距图像顶部50%,图像左侧50%。这可以改变。您可以选择提供覆盖层的高度(以米为单位)。如果您未提供叠加层的高度,则会自动计算以保留图像的比例。

  • 使用界限:您必须提供一个包含图像的LatLngBounds。

以下示例使用一OnCameraChangeListener移除并添加GroundOverlay,显示在地图上的中心的ic_launcher绘制,地图的宽度的75%(卸下和在onCameraChange添加GroundOverlay事件可确保图像的大小始终与缩放级别无关)。

public class MyMapActivity extends Activity implements OnCameraChangeListener { 
    GroundOverlay backgroundOverlay = null; 
    GoogleMap map; 

    // ... 

    @Override 
    public void onCameraChange(final CameraPosition cameraPosition) { 
     if (backgroundOverlay != null) { 
      backgroundOverlay.remove(); 
     } 

     VisibleRegion visibleRegion = map.getProjection() 
       .getVisibleRegion(); 

     Location nearLeftLocation = new Location("nearLeftLocation"); 
     nearLeftLocation.setLatitude(visibleRegion.nearLeft.latitude); 
     nearLeftLocation.setLongitude(visibleRegion.nearLeft.longitude); 

     Location nearRightLocation = new Location("nearRightLocation"); 
     nearRightLocation.setLatitude(visibleRegion.nearRight.latitude); 
     nearRightLocation.setLongitude(visibleRegion.nearRight.longitude); 

     float width = nearLeftLocation.distanceTo(nearRightLocation); 

     GroundOverlayOptions background = new GroundOverlayOptions() 
       .image(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)) 
       .position(cameraPosition.target, width * 0.75f); 

     backgroundOverlay = map.addGroundOverlay(background); 
    } 
} 

UPDATE:

正如我在对现有GroundOverlay,而不是添加/在每个摄像头的变化中取出的评论,我们可以和setDimensions说。

我已经在几个设备上测试过它,它似乎减少了低端设备上的闪烁,但仍然不是完美的解决方案(图像在缩放之间调整大小)。我非常肯定,这是我们可以使用GroundOverlay的最佳选择。

public class MyMapActivity extends Activity implements OnCameraChangeListener { 
    GroundOverlay backgroundOverlay = null; 
    GoogleMap map; 

    // ... 

    @Override 
    public void onCameraChange(final CameraPosition cameraPosition) { 
     VisibleRegion visibleRegion = map.getProjection().getVisibleRegion(); 

     Location nearLeftLocation = new Location("nearLeftLocation"); 
     nearLeftLocation.setLatitude(visibleRegion.nearLeft.latitude); 
     nearLeftLocation.setLongitude(visibleRegion.nearLeft.longitude); 

     Location nearRightLocation = new Location("nearRightLocation"); 
     nearRightLocation.setLatitude(visibleRegion.nearRight.latitude); 
     nearRightLocation.setLongitude(visibleRegion.nearRight.longitude); 

     float width = nearLeftLocation.distanceTo(nearRightLocation); 

     if (backgroundOverlay == null) { 
      GroundOverlayOptions background = new GroundOverlayOptions() 
        .image(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)) 
        .position(cameraPosition.target, width * 0.75f); 

      backgroundOverlay = map.addGroundOverlay(background); 
     } else { 
      backgroundOverlay.setPosition(cameraPosition.target); 
      backgroundOverlay.setDimensions(width * 0.75f); 
     } 
    } 
} 

UPDATE

我已经找到另一种解决方案。如果您的背景是简单的半透明颜色,则可以使用TileOverlay将其设置为低于所有标记。

这个想法是创建一个TileProvider,它总是返回一个非常小(在我的例子中是2×2像素)的图像,将在所有标记下绘制。为确保性能,由TileProvider返回的Tile将始终相同。

下面是代码:

public class BackgroundTileProvider implements TileProvider { 
    private Tile tile; 

    @Override 
    public Tile getTile(int x, int y, int zoom) { 
     if (tile == null) { 
      // Create a very small (for performance) bitmap with alpha 
      Bitmap bmp = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); 

      // Draw the desired color to use as background 
      Canvas canvas = new Canvas(bmp); 
      canvas.drawColor(Color.argb(150, 255, 0, 0)); 

      // Get the bytes and create the Tile 
      ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
      bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); 

      tile = new Tile(2, 2, stream.toByteArray()); 
     } 

     return tile; 
    } 
} 

您需要将TileOverlay添加到您的地图如下:

TileProvider tileProvider = new BackgroundTileProvider(); 
TileOverlay tileOverlay = map.addTileOverlay(
    new TileOverlayOptions().tileProvider(tileProvider)); 

结果将是这样的:

enter image description here

+1

非常感谢,目前它是最有前途的解决方案,不幸的是图像在缩放变化期间被隐藏;它由于删除/添加而闪烁很多,你能想出一个解决方案如何使这更加顺利吗? – swalkner

+1

您可以尝试在现有的'GroundOverlay'上设置'setPosition'和'setDimensions',而不是在每次更改摄像机时添加/删除它,但是您不会摆脱您陈述的问题。我知道您希望背景能够“跟随”您的相机动作,但考虑到GoogleMaps API(https://developers.google.com/maps/documentation/android-api/events)以及您的要求(你需要把背景放在你的标记下面)这是我能想到的最好的解决方案。也许另一位开发人员可以给出更好的答案... – antonio

+0

可以@downvoter请解释一下吗? – antonio

0

你可以试试这个,计算dimensi ons根据变焦因子并将这些尺寸应用于GroundOverlay

float zoomLevel=mMap.getCameraPosition().zoom; 
    //calculate meters*********************   
    myBounds = mMap.getProjection().getVisibleRegion().latLngBounds; 
    myCenter= mMap.getCameraPosition().target; 
    if (myCenter.latitude==0 || myCenter.longitude==0) { 
     myCenter=new LatLng(myLocation.getLatitude(),myLocation.getLongitude()); 
    } 

    LatLng ne = myBounds.northeast; 

    // r = radius of the earth in statute miles 
    double r = 3963.0; 

    // Convert lat or lng from decimal degrees into radians (divide by 57.2958) 
    double lat1 = myCenter.latitude/57.2958; 
    double lon1 = myCenter.longitude/57.2958; 
    final double lat2 = ne.latitude/57.2958; 
    final double lon2 = ne.longitude/57.2958; 

    // distance = circle radius from center to Northeast corner of bounds 
    double dis = r * Math.acos(Math.sin(lat1) * Math.sin(lat2) + 
     Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)); 

    //1 Meter = 0.000621371192237334 Miles 
    double meters_calc=dis/0.000621371192237334; 

    float factor=1; 
    if (zoomLevel==15) { // my default zoom level yours can be different 
     metersoverlay=meters_calc; // global variable metersoverlay set 
    } 
    else { // if my zoom level change then I have to calculate dimension scale factor 
     factor=(float) (meters_calc/metersoverlay); 
    } 

    //******************************* now we are ready to set dimension of background overlay 
    float dimensions=1000*factor; 
    loadingGroundOverlayBg.setDimensions(dimensions); 
+0

哪里你会把这个?在'''onCameraChange-Listener'''?以及如何创建loadingGroundOverlay - 正如@antonio所描述的那样? – swalkner

+0

是的,你可以把它放在'onCameraChanged'上,看看它是否可以工作 和'loadingGroundOverlayBg'是'GroundOverlay'的对象名称。 –

+0

没有必要每次在摄像机上添加/删除覆盖像@antonio所说的那样改变,只需setDimensions即可。 –

5

这很容易做到。

添加两个标记而不是一个。首先在lat_lng处添加背景作为位图。

事情是这样的:

map.addMarker(new MarkerOptions() 
     .position(lat_lng) 
     .anchor(0.5f, 0.5f) 
     .icon(BitmapDescriptorFactory.fromBitmap(bitmap))); 

添加您的标记像平时一样在同一lat_lng。

为每个标记执行上述操作。

+1

我想我不明白它的意思;背景应该总是覆盖整个地图,它不是一个固体图像,但看起来像一个雷达,所以我不能将它添加多次和不同的位置 – swalkner