24

Voglio implementare una transizione graduale per emulare il marcatore auto che si sposta sulla mappa.Come animare il marker in Android map api V2?

È possibile animare il marker in Android map api v2?

+0

quanto ho capito è necessario un comportamento nativo mappe API V2 per spostare indicatore da una posizione all'altra senza intoppi? –

+0

si può guardare in questo post http://stackoverflow.com/questions/13728041/move-markers-in-google-map-v2-android –

+0

possibile duplicato di [Come animare marcatore quando viene aggiunto alla mappa su Android? ] (http://stackoverflow.com/questions/8191582/how-to-animate-marker-when-it-is-added-to-map-on-android) – bummi

risposta

24

Prova il codice seguente per animare l'indicatore su Google Map V2. È necessario utilizzare la classe Interpolator per applicare l'animazione sul Marker e gestirlo nel gestore per l'animazione come di seguito:

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

Grazie mille. E 'stato estremamente utile. – Anil

+0

Come implementa esattamente questo codice? @Anil? puoi ottenere l'indicatore spostandosi lungo le coordinate GPS? Si prega di inviare la risposta. – momokjaaaaa

+2

Ehi, grazie mille. Funziona. Ma il segnalino si muove avanti e indietro prima di avviare l'animazione del marker. Puoi per favore dirmi come aggiustarlo. – Sadia

4

appena implementato una versione, provate questo

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(); 
    } 

La classe LatLngInterpolator è pre-scritta da Google guys che è possibile utilizzare come segue:

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))); 
    } 
} 
} 

Poi un'istanza di un oggetto della classe MarkerAnimation e chiamare il metodo come questo:

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

Nessuna delle versioni fornite lavorato per me, così ho implementato la mia soluzione personalizzata. Fornisce sia l'animazione di posizione che quella di rotazione.

/** 
* 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(); 
    } 
} 

Calcolo della rotazione per la frazione di animazione specificata. Marker viene ruotato in senso che è più vicino dall'inizio alla rotazione finale:

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; 
} 

E infine di 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

Sto cercando di implementarlo come aggiungo il rilevamento alla destinazione ?, hai qualche fonte su github del progetto finale? –

+0

@FrankOdoom È necessario impostare correttamente il rilevamento tramite il metodo 'setBearing (float)' o 'bearingTo (Location)' sul parametro 'Destinazione destinazione' passato. – skywall

+0

Questa è la migliore risposta che ho trovato. Non c'è affatto sfarfallio. –

Problemi correlati