24

Chcę zaimplementować płynne przejście do emulacji znacznika samochodowego poruszającego się po mapie.Jak animować znacznik w api V2 mapy Androida?

Czy można animować znacznik w api v2 na mapie Androida?

+0

Jak rozumiem trzeba natywną zachowanie Maps API V2 aby przesunąć znacznik z jednego miejsca do drugiego płynnie? –

+0

możesz zajrzeć do tego posta http://stackoverflow.com/questions/13728041/move-markers-in-google-map-v2-android –

+0

możliwy duplikat [Jak animować znacznik, kiedy zostanie dodany do mapy na Androida? ] (http://stackoverflow.com/questions/8191582/how-to-animate-marker-when-it-is-added-to-map-on-android) – bummi

Odpowiedz

24

Wypróbuj poniższy kod, aby animować znacznik na mapie Google Map V2. trzeba użyć klasy Interpolator zastosować animację na znacznik i obsługiwać go w Handler dla animacji, jak poniżej:

public void animateMarker(final Marker marker, final LatLng toPosition, 
     final boolean hideMarker) { 
    final Handler handler = new Handler(); 
    final long start = SystemClock.uptimeMillis(); 
    Projection proj = mGoogleMapObject.getProjection(); 
    Point startPoint = proj.toScreenLocation(marker.getPosition()); 
    final LatLng startLatLng = proj.fromScreenLocation(startPoint); 
    final long duration = 500; 
    final Interpolator interpolator = new LinearInterpolator(); 
    handler.post(new Runnable() { 
     @Override 
     public void run() { 
      long elapsed = SystemClock.uptimeMillis() - start; 
      float t = interpolator.getInterpolation((float) elapsed 
        /duration); 
      double lng = t * toPosition.longitude + (1 - t) 
        * startLatLng.longitude; 
      double lat = t * toPosition.latitude + (1 - t) 
        * startLatLng.latitude; 
      marker.setPosition(new LatLng(lat, lng)); 
      if (t < 1.0) { 
       // Post again 16ms later. 
       handler.postDelayed(this, 16); 
      } else { 
       if (hideMarker) { 
        marker.setVisible(false); 
       } else { 
        marker.setVisible(true); 
       } 
      } 
     } 
    }); 
} 
+0

Wielkie dzięki. To było bardzo pomocne. – Anil

+0

Jak dokładnie wdrażasz ten kod? @Anil? czy możesz przesunąć znacznik wzdłuż współrzędnych GPS? Proszę zamieścić odpowiedź. – momokjaaaaa

+2

Hej, wielkie dzięki. To działa. Ale znacznik przesuwa się do przodu i do tyłu przed rozpoczęciem animacji znacznika. Czy możesz mi powiedzieć, jak to naprawić? – Sadia

4

Właśnie wdrożyliśmy wersję, spróbuj tego

public class MarkerAnimation { 
static GoogleMap map; 
ArrayList<LatLng> _trips = new ArrayList<>() ; 
Marker _marker; 
LatLngInterpolator _latLngInterpolator = new LatLngInterpolator.Spherical(); 

public void animateLine(ArrayList<LatLng> Trips,GoogleMap map,Marker marker,Context current){ 
    _trips.addAll(Trips); 
    _marker = marker; 

animateMarker(); 
} 

    public void animateMarker() { 
     TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() { 
      @Override 
      public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { 
       return _latLngInterpolator.interpolate(fraction, startValue, endValue); 
      } 
     }; 
     Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position"); 

     ObjectAnimator animator = ObjectAnimator.ofObject(_marker, property, typeEvaluator, _trips.get(0)); 

     //ObjectAnimator animator = ObjectAnimator.o(view, "alpha", 0.0f); 
     animator.addListener(new Animator.AnimatorListener() { 
      @Override 
      public void onAnimationCancel(Animator animation) { 
       // animDrawable.stop(); 
      } 

      @Override 
      public void onAnimationRepeat(Animator animation) { 
       // animDrawable.stop(); 
      } 

      @Override 
      public void onAnimationStart(Animator animation) { 
       // animDrawable.stop(); 
      } 

      @Override 
      public void onAnimationEnd(Animator animation) { 
       // animDrawable.stop(); 
       if (_trips.size() > 1) { 
        _trips.remove(0); 
        animateMarker(); 
       } 
      } 
     }); 

     animator.setDuration(300); 
     animator.start(); 
    } 

Klasa LatLngInterpolator została wcześniej napisana przez Google facetów, z których można korzystać w następujący sposób:

public interface LatLngInterpolator { 

public LatLng interpolate(float fraction, LatLng a, LatLng b); 

public class Spherical implements LatLngInterpolator { 
    @Override 
    public LatLng interpolate(float fraction, LatLng from, LatLng to) { 
     // http://en.wikipedia.org/wiki/Slerp 
     double fromLat = toRadians(from.latitude); 
     double fromLng = toRadians(from.longitude); 
     double toLat = toRadians(to.latitude); 
     double toLng = toRadians(to.longitude); 
     double cosFromLat = cos(fromLat); 
     double cosToLat = cos(toLat); 

     // Computes Spherical interpolation coefficients. 
     double angle = computeAngleBetween(fromLat, fromLng, toLat, toLng); 
     double sinAngle = sin(angle); 
     if (sinAngle < 1E-6) { 
      return from; 
     } 
     double a = sin((1 - fraction) * angle)/sinAngle; 
     double b = sin(fraction * angle)/sinAngle; 

     // Converts from polar to vector and interpolate. 
     double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng); 
     double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng); 
     double z = a * sin(fromLat) + b * sin(toLat); 

     // Converts interpolated vector back to polar. 
     double lat = atan2(z, sqrt(x * x + y * y)); 
     double lng = atan2(y, x); 
     return new LatLng(toDegrees(lat), toDegrees(lng)); 
    } 

    private double computeAngleBetween(double fromLat, double fromLng, double toLat, double toLng) { 
     // Haversine's formula 
     double dLat = fromLat - toLat; 
     double dLng = fromLng - toLng; 
     return 2 * asin(sqrt(pow(sin(dLat/2), 2) + 
       cos(fromLat) * cos(toLat) * pow(sin(dLng/2), 2))); 
    } 
} 
} 

Następnie instancję obiektu klasy MarkerAnimation i wywołać metodę tak:

MarkerAnimation.animateLine(TripPoints,map,MovingMarker,context); 
17

Żadna z wersji dostarczonych pracował dla mnie, więc ja już wdrożone Moje niestandardowe rozwiązania. Zapewnia on zarówno animację lokalizacji, jak i rotacji.

/** 
* Method to animate marker to destination location 
* @param destination destination location (must contain bearing attribute, to ensure 
*     marker rotation will work correctly) 
* @param marker marker to be animated 
*/ 
public static void animateMarker(Location destination, Marker marker) { 
    if (marker != null) { 
     LatLng startPosition = marker.getPosition(); 
     LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude()); 

     float startRotation = marker.getRotation(); 

     LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed(); 
     ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); 
     valueAnimator.setDuration(1000); // duration 1 second 
     valueAnimator.setInterpolator(new LinearInterpolator()); 
     valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
      @Override public void onAnimationUpdate(ValueAnimator animation) { 
       try { 
        float v = animation.getAnimatedFraction(); 
        LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition); 
        marker.setPosition(newPosition); 
        marker.setRotation(computeRotation(v, startRotation, destination.getBearing())); 
       } catch (Exception ex) { 
        // I don't care atm.. 
       } 
      } 
     }); 

     valueAnimator.start(); 
    } 
} 

Obliczenia rotacji dla określonej części animacji. Marker obraca się w kierunku, który jest bliżej od początku do obrotu końcowego:

private static float computeRotation(float fraction, float start, float end) { 
    float normalizeEnd = end - start; // rotate start to 0 
    float normalizedEndAbs = (normalizeEnd + 360) % 360; 

    float direction = (normalizedEndAbs > 180) ? -1 : 1; // -1 = anticlockwise, 1 = clockwise 
    float rotation; 
    if (direction > 0) { 
     rotation = normalizedEndAbs; 
    } else { 
     rotation = normalizedEndAbs - 360; 
    } 

    float result = fraction * rotation + start; 
    return (result + 360) % 360; 
} 

i wreszcie Google LatLngInterpolator:

private interface LatLngInterpolator { 
    LatLng interpolate(float fraction, LatLng a, LatLng b); 

    class LinearFixed implements LatLngInterpolator { 
     @Override 
     public LatLng interpolate(float fraction, LatLng a, LatLng b) { 
      double lat = (b.latitude - a.latitude) * fraction + a.latitude; 
      double lngDelta = b.longitude - a.longitude; 
      // Take the shortest path across the 180th meridian. 
      if (Math.abs(lngDelta) > 180) { 
       lngDelta -= Math.signum(lngDelta) * 360; 
      } 
      double lng = lngDelta * fraction + a.longitude; 
      return new LatLng(lat, lng); 
     } 
    } 
} 
+0

Próbuję zaimplementować to w jaki sposób dodać namiar do miejsca docelowego ?, czy masz jakieś źródło na github końcowego projektu? –

+0

@FrankOdoom Powinieneś poprawnie ustawić łożysko za pomocą metody 'setBearing (float)' lub 'bearingTo (Location)' w podanym parametrze 'Location destination'. – skywall

+0

To jest najlepsza odpowiedź, którą znalazłem. W ogóle nie ma migotania. –

Powiązane problemy