Android Google Maps - пользовательский фон за всеми маркерами
Я пытаюсь установить фон между картой и моим маркером; это изображение должно всегда (!) оставаться за всеми маркерами.
Я попробовал несколько способов, например. showInfoWindow()
на всех моих маркерах, кроме фонового изображения, но похоже, что это поможет только для последнего.
Затем я попробовал решение с помощью GroundOverlay
, но мне нужно, чтобы мое изображение всегда оставалось того же размера (например, половину размера устройства), независимо от коэффициента масштабирования.
Есть ли решение для Android?
Ответы
Ответ 1
Это легко сделать.
Добавьте два маркера вместо одного. Сначала добавьте фон как растровое изображение в lat_lng.
Что-то вроде этого:
map.addMarker(new MarkerOptions()
.position(lat_lng)
.anchor(0.5f, 0.5f)
.icon(BitmapDescriptorFactory.fromBitmap(bitmap)));
Затем добавьте маркер, как обычно, с тем же lat_lng.
Сделайте выше для каждого из ваших маркеров.
Ответ 2
Вы можете попробовать это, рассчитать размеры в соответствии с коэффициентом масштабирования и применить эти измерения к 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);
Ответ 3
Ваш лучший вариант - использовать GroundOverlay
для отображения фона, добавления и удаления его при изменении вида и вычисления его размеров на основе VisibleRegion
карты, чтобы он поддерживал правильный размер между масштабированиями.
Из документация:
Позиция
Существует два способа задания положения наложения на землю:
-
Использование местоположения: вы должны предоставить изображение наземного наложения, LatLng, на который будет закреплен якорь, и ширину наложения (в метрах). Якорь по умолчанию составляет 50% от верхней части изображения и 50% слева от изображения. Это можно изменить. Вы можете дополнительно указать высоту наложения (в метрах). Если вы не обеспечиваете высоту наложения, он будет автоматически рассчитан для сохранения пропорций изображения.
-
Использование границ: вы должны предоставить LatLngBounds, который будет содержать изображение.
В следующем примере используется OnCameraChangeListener
для удаления и добавления GroundOverlay
, который отображает ic_launcher
, который можно извлечь в центре карты, 75% от ширины карты (удаление и добавление GroundOverlay
на событие onCameraChange
гарантирует, что размер вашего изображения всегда один и тот же независимо от уровня масштабирования).
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:
Как я уже сказал в комментариях, мы можем setPosition
и setDimensions
в существующем GroundOverlay
вместо добавления/удаления его при каждом изменении камеры.
Я тестировал его на нескольких устройствах и, похоже, уменьшал мерцание на низкоуровневых устройствах, но все же не идеальное решение (изменение изображения между масштабированием). Я уверен, что это лучшее, что мы можем использовать GroundOverlay
s.
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, который возвращает всегда очень маленькое (2x2 пикселя в моем примере) изображение, которое будет рисоваться ниже всех ваших маркеров. Чтобы обеспечить производительность, Tile
, возвращаемый TileProvider
, всегда будет одним и тем же.
Вот код:
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));
Результат будет выглядеть следующим образом:
![введите описание изображения здесь]()