web-dev-qa-db-ger.com

Animieren von Markern in Google Maps v2

Was ist der beste Weg, um Markierungen in Google Maps mit der v2-API zu animieren?

Ich arbeite an einem Kartenspiel, bei dem ich Orte von Personen nachverfolgen und sie auf der Karte anzeigen kann, damit sie sich gegenseitig sehen können. Wenn sich Menschen bewegen, möchte ich einen Marker von seiner aktuellen Position zu seiner neuesten Position animieren. Jeder Mensch hat eine Richtung, daher muss ich die Markierung entsprechend drehen.

Was ist der beste Weg, um das neue Google Maps-API zu verwenden?

26
Maksim Golivkin

Einige Google-Ingenieure haben ein Nice-Demo-Video mit einem eleganten Beispielcode zur Animation von Markern von einem Ausgangspunkt bis zu einem Endpunkt für alle verschiedenen Android-Versionen zur Verfügung gestellt:

Der entsprechende Code ist hier:

https://Gist.github.com/broady/6314689

Und ein schönes Demo-Video von allem in Aktion.

http://youtu.be/WKfZsCKSXVQ

ALTE ABTEILTE ANTWORT UNTEN

In der Dokumentation wird erwähnt, dass Markierungssymbole nicht geändert werden können:

Symbol

Eine Bitmap, die für die Markierung angezeigt wird. Wenn das Symbol nicht festgelegt ist, wird ein Standardsymbol angezeigt. Sie können mit defaultMarker (float) eine alternative Farbe des Standardsymbols angeben. Sie können das Symbol nicht mehr ändern, wenn Sie die Markierung erstellt haben.

Google Maps API v2-Dokumentation

Sie müssen bestimmte Markierungen verfolgen. Verwenden Sie dazu eine Methode, die der hier beschriebenen ähnelt: Verknüpfen Sie eine Markierung mit einem Objekt , und ermitteln Sie dann, welche Markierung Sie aktualisieren müssen. Rufen Sie .remove() für den Marker auf, erstellen Sie ein gedrehtes Bild in Abhängigkeit von der gewünschten "Richtung", erstellen Sie einen neuen Marker mit diesem Bild und fügen Sie den neuen Marker zur Karte hinzu.

Sie müssen die Karte nicht "löschen". Entfernen Sie einfach die Markierung, die Sie ändern möchten, erstellen Sie eine neue und fügen Sie sie dann wieder der Karte hinzu.

Leider ist die neue Google Maps API noch nicht sehr flexibel. Hoffentlich verbessert Google es weiter.

55
DiscDev

Usage Example für DiscDevs Antwort (oben):

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

Und für diejenigen von Ihnen, die GPS verwenden, oder für jeden Positionsanbieter, der Standortaktualisierungen erhält:

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

WICHTIG:

Innerhalb von 1MarkerAnimation.Java Wenn die Animationsdauer auf X, Eingestellt ist und Sie Standortaktualisierungen mit einer niedrigeren Rate als X empfangen, werden mehrere Animationen ausgelöst, und die Markeranimation kann ein wenig flackern (dies ist kein Nice-Benutzer.) Erfahrung).

Um dies zu vermeiden, sollte die animationMarkerToICS-Methode (ich nahm hier beispielsweise animationMarkerToICS) so aussehen.

vollständige Implementierung der Methode:

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

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

Genießen.

7
Mercury

Marker hat eine neue Funktion hinzugefügt, die ab Version 7 von API v2 hinzugefügt wurde. Marker.setIcon , damit Sie mehrere Richtungen verwenden können, um die Richtung anzuzeigen.

5
MaciejGórski
    //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);
                    }
                }
            }
        });

    }
0