Анимация маркеров на Google Maps v2
Каков наилучший способ анимации маркеров на Картах Google с использованием API v2?
Я работаю над картографической игрой, где я отслеживаю местоположения людей и показываю их на карте друг для друга. Когда люди двигаются, я хочу анимировать маркер от его текущего до его последней позиции. У каждого человека есть направление, поэтому мне нужно соответствующим образом повернуть маркер.
Каков наилучший способ сделать это с помощью нового API Карт Google?
- Отсутствие служб Google Play в SDK Manager
- Можно ли написать собственный текст в Google Maps API v3?
- Google Maps, открыть информационное окно после щелчка по ссылке
- Google Map V3 - позволяет одновременно отображать только одну инфобокса
- Как реализовать перетаскиваемую карту, например, uber android, Update with change location
- Найти центр нескольких местоположений на Картах Google
- Google Maps V3 - путевые точки + инфо-окно со случайным текстом
- API Карт Google V3: как получить данные о границе региона (полилиния)?
- Карты Google V3: рисовать германские полигоны?
- Как использовать маркеры SVG в API Карт Google v3
- Android: местоположение Google Maps с низким уровнем использования батареи
- Как установить местоположение по умолчанию и уровень масштабирования для google map api v2?
- Android Google Maps, как заставить каждый маркер InfoWindow открыть другую активность?
Некоторые инженеры Google предоставили приятное демо-видео с некоторым изящным примером кода о том, как оживить маркеры от начальной точки до конечной точки для всех различных версий Android:
Соответствующий код находится здесь:
https://gist.github.com/broady/6314689
И хорошее демо-видео всего этого в действии.
СТАРИННЫЙ ОТПРАВЛЕННЫЙ ОТВЕТ НИЖЕ
В документации упоминается, что значки маркера не могут быть изменены:
Значок
Растровое изображение, отображаемое для маркера. Если значок не отображается, отображается значок по умолчанию. Вы можете указать альтернативную окраску значка по умолчанию, используя defaultMarker (float). Вы не можете изменить значок, как только вы создали маркер.
Документация API Google Maps v2
Вам нужно будет отслеживать определенные маркеры, возможно, используя метод, аналогичный описанному здесь: Связать маркер с объектом , затем выяснить, какой маркер вам нужно обновить. Вызовите .remove()
на маркере, затем создайте повернутое изображение в зависимости от «направления», которое вы хотите, создайте новый маркер с этим изображением и добавьте новый маркер к карте.
Вам не нужно «очищать» карту, просто удалите маркер, который вы хотите изменить, создайте новый, а затем добавьте его обратно на карту.
К сожалению, новый API карт еще не очень гибкий. Надеюсь, Google продолжает улучшать его.
Маркер имеет новую функцию, добавленную с версии 7 API v2. Marker.setIcon , поэтому вы можете использовать несколько значков для отображения направления.
Пример использования ответа DiscDev (выше):
LatLng fromLocation = new LatLng(38.5, -100.4); // Whatever origin coordinates LatLng toLocation = new LatLng(37.7, -107.7); // Whatever destination coordinates Marker marker = mMap.addMarker(new MarkerOptions().position(firstLocation)); MarkerAnimation.animateMarkerToICS(marker, toLocation, new LatLngInterpolator.Spherical());
И для тех из вас, кто использует GPS / или любого поставщика услуг, который получает обновления местоположения:
Marker ourGlobalMarker; // We've got a location from some provider of ours, now we can call: private void updateMarkerPosition(Location newLocation) { LatLng newLatLng = new LatLng(newLocation.getLatitude(), newLocation.getLongitude()); if(ourGlobalMarker == null) { // First time adding marker to map ourGlobalMarker = mMap.addMarker(new MarkerOptions().position(newLatLng)); } else { MarkerAnimation.animateMarkerToICS(ourGlobalMarker, newLatLng, new LatLngInterpolator.Spherical()); } }
ВАЖНЫЙ:
В пределах 1MarkerAnimation.java
Если продолжительность анимации установлена на X, и вы получаете обновления местоположения со скоростью меньше X, будет 1MarkerAnimation.java
несколько анимаций, и вы можете увидеть, что анимация маркера немного мерцает (что не очень приятно для пользователя ).
Чтобы этого избежать, метод animationMarkerToICS
(например, я использовал animationMarkerToICS
) должен выглядеть примерно так:
полная реализация метода:
private static Animator animator; // MAKING ANIMATOR GLOBAL INSTEAD OF LOCAL TO THE STATIC FUNCTION ... // Ice Cream Sandwich compatible @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public static void animateMarkerToICS(Marker marker, LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { TypeEvaluator typeEvaluator = new TypeEvaluator () { @Override public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { return latLngInterpolator.interpolate(fraction, startValue, endValue); } }; Property property = Property.of(Marker.class, LatLng.class, "position"); // ADD THIS TO STOP ANIMATION IF ALREADY ANIMATING TO AN OBSOLETE LOCATION if(animator != null && animator.isRunning()) { animator.cancel(); animator = null; } animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition); animator.setDuration((long) ANIMATION_DURATION); animator.start(); }
Наслаждаться.
//Your code double bearing = 0.0; bearing = getBearing(new LatLng( currentPosition.latitude ,currentPosition.longitude), new LatLng( nextPosition.latitude, nextPosition.longitude)); bearing -= 90; CameraPosition cameraPosition = new CameraPosition .Builder() .target(new LatLng(nextPosition.latitude, nextPosition.longitude)) .bearing((float) bearing) .zoom(ZOOM_LEVEL).build(); mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000, null); animatedMarker(currentPosition,nextPosition,busMarker); //Method for finding bearing between two points private float getBearing(LatLng begin, LatLng end) { double lat = Math.abs(begin.latitude - end.latitude); double lng = Math.abs(begin.longitude - end.longitude); if (begin.latitude < end.latitude && begin.longitude < end.longitude) return (float) (Math.toDegrees(Math.atan(lng / lat))); else if (begin.latitude >= end.latitude && begin.longitude < end.longitude) return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90); else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude) return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180); else if (begin.latitude < end.latitude && begin.longitude >= end.longitude) return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270); return -1; } private void animatedMarker(final LatLng startPosition,final LatLng nextPosition,final Marker mMarker) { final Handler handler = new Handler(); final long start = SystemClock.uptimeMillis(); final Interpolator interpolator = new AccelerateDecelerateInterpolator(); final float durationInMs = 3000; final boolean hideMarker = false; handler.post(new Runnable() { long elapsed; float t; float v; @Override public void run() { // Calculate progress using interpolator elapsed = SystemClock.uptimeMillis() - start; t = elapsed / durationInMs; v = interpolator.getInterpolation(t); LatLng currentPosition = new LatLng( startPosition.latitude * (1 - t) + nextPosition.latitude * t, startPosition.longitude * (1 - t) + nextPosition.longitude * t); mMarker.setPosition(currentPosition); // Repeat till progress is complete. if (t < 1) { // Post again 16ms later. handler.postDelayed(this, 16); } else { if (hideMarker) { mMarker.setVisible(false); } else { mMarker.setVisible(true); } } } }); }