Довольно часто перед разработчиком мобильного приложения возникает необходимость отобразить что либо на карте. Какие же варианты есть у разработчика?
Я рассматривал два варианта.
Вариант 1. Внешнее приложение с картой
Пожалуй, самый простой в реализации вариант. Когда нужно, вы просто открываете сторонее приложение с картой — создаете uri вида geo: широта, долгота, в параметре z можно указать масштаб (от 1 до 23):
String uri = String.format("geo:%s,%s?z=16", Double.toString(lat), Double.toString(lng));
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
При этом, если на аппарате пользователя установлено несколько приложений с картами, то пользователю будет предложено выбрать в каком приложении должна быть показана заданная точка:
Да-да. Таким способ показывается именно заданная точка, а не просто карта (хотя, Яндекс.Карты показывают просто карту и, судя по моей переписке с ними, считают, что так и надо).
Преимущества данного варианта:
- простота реализации;
- все возможности внешнего приложения (например, в iGo можно сразу проложить маршрут к показанной точке; карты в некоторых приложениях будут доступны офлайн).
- нет возможности вывести дополнительную информацию (как, например, на первом в этой статье скриншоте — метки, всплывающие подсказки и т.п.).
Вариант 2. Встроенная карта
Встроенная карта более сложна в реализации. Не буду останавливаться на всех деталях, основное хорошо описано в документации.
Остановлюсь лишь на некоторых тонкостях.
Maps API Key
Для работы встроенной карты необходимо получить ключи. Ключи, а не ключ, потому что для debug-версии и для release-версии вашего приложения ключи будут разными.
Чтоб не менять ключи вручную каждый раз, можно создать два layout'a с картой и написать в коде что-то типа:
// choose layout with correct API key
if (debug) {
setContentView(R.layout.map_debug);
} else {
setContentView(R.layout.map_release);
}
Другие варианты (в т.ч. для определения debug/release-версии сборки) можно найти тут.
Текущее положение
Для отображения текущего положения на карте необходимо написать следующее:
private MyLocationOverlay myLocationOverlay;
MapView mapView = (MapView) findViewById(R.id.mapview);
myLocationOverlay = new MyLocationOverlay(this, mapView);
myLocationOverlay.enableMyLocation();
mapView.getOverlays().add(myLocationOverlay);
Не забудьте отключить определение местоположения при остановке/закрытии activity:
myLocationOverlay.disableMyLocation();
Маркеры
На карту маркеры добавляются просто:
List<Overlay> mapOverlays;
Drawable drawable;
MapOverlay itemizedOverlay;
mapOverlays = mapView.getOverlays();
drawable = this.getResources().getDrawable(R.drawable.map_dot_green);
itemizedOverlay = new MapOverlay(drawable, mapView);
GeoPoint markerPoint = new GeoPoint(lat, lng);
OverlayItem overlayItem = new OverlayItem(markerPoint, "name", "description");
itemizedOverlay.addOverlay(overlayItem);
mapOverlays.add(itemizedOverlay);
При этом если добавить несколько маркеров, то все маркеры на одном слое будут одинаковыми. Как сделать маркеры разными (как на скриншоте выше — желтыми, красными, зелеными)? Либо создать несколько слоев, либо воспользоваться методом SetMarker:
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
drawable.setBounds(-w / 2, -h, w / 2, 0);
overlayItem.setMarker(drawable);
Без первых трех строк вместо маркера будет показана пустота.
Если не использовать отрицательные значения w и h и не делить их пополам, то у маркеров будет неправильная тень.
Преимущества и недостатки данного варианта
Преимущества:
- возможность создавать свои слои и свои метки;
- возможность оставить пользователя в своем приложении (добавив, например, заголовок окна).
- относительная сложность реализации;
- нет всех возможностей сторонних приложений;
- activity с картой запускается достаточно долго.
Заключение
В итоге, я так и не смог сделать выбор за пользователя. Потому в моем приложении поддерживаются оба варианта — в настройках пользователь может указать хочет ли он использовать внешние приложения (по умолчанию, используется встроенная карта).