web-dev-qa-db-fra.com

Faire pivoter le marqueur et déplacer l’animation sur la carte, comme Uber Android

Je travaille sur un projet similaire à UBER, Lyft ou OLA. Carte sur la maison avec les voitures en mouvement disponibles. Je cherche une sorte de bibliothèque qui puisse faire bouger les voitures et les faire tourner comme UBER. Pour l’instant, j’étais capable de passer d’une voiture à l’autre avec le code ci-dessous. Mais la partie la plus délicate est de prendre son tour et assurez-vous que la voiture soit face à l’avant lorsqu’elle se déplace en direction.

Code voiture en mouvement lisse:

    final LatLng SomePos = new LatLng(12.7796354, 77.4159606);

    try {
        if (googleMap == null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
            }
        }
        googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        googleMap.setMyLocationEnabled(true);
        googleMap.setTrafficEnabled(false);
        googleMap.setIndoorEnabled(false);
        googleMap.setBuildingsEnabled(true);
        googleMap.getUiSettings().setZoomControlsEnabled(true);
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(SomePos));
        googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                .target(googleMap.getCameraPosition().target)
                .zoom(17)
                .bearing(30)
                .tilt(45)
                .build()));

        myMarker = googleMap.addMarker(new MarkerOptions()
                .position(SomePos)
                .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_launcher))
                .title("Hello world"));


        googleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker arg0) {

                final LatLng startPosition = myMarker.getPosition();
                final LatLng finalPosition = new LatLng(12.7801569, 77.4148528);
                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;

                        LatLng currentPosition = new LatLng(
                                startPosition.latitude * (1 - t) + finalPosition.latitude * t,
                                startPosition.longitude * (1 - t) + finalPosition.longitude * t);

                        myMarker.setPosition(currentPosition);

                        // Repeat till progress is complete.
                        if (t < 1) {
                            // Post again 16ms later.
                            handler.postDelayed(this, 16);
                        } else {
                            if (hideMarker) {
                                myMarker.setVisible(false);
                            } else {
                                myMarker.setVisible(true);
                            }
                        }
                    }
                });

                return true;

            }

        });

    } catch (Exception e) {
        e.printStackTrace();
    }
54
VipiN Negi

Je suis récemment tombé sur le même cas d'utilisation. Voici ma solution à ce sujet.

Tout d’abord, je voudrais remercier @VipiN d’avoir partagé "Le code de la voiture qui bouge doucement". Cela fonctionne bien.

La deuxième partie consiste à placer le marqueur dans la bonne direction et à le faire pivoter en fonction des virages. Pour ce faire, j’ai calculé le relèvement ou l’angle de cap entre deux points successifs (c’est-à-dire les mises à jour d’emplacement que vous recevez de l’appareil/serveur). Ce lien vous aidera à comprendre le calcul qui en découle.

Le code suivant vous donnera reliant entre deux endroits:

private double bearingBetweenLocations(LatLng latLng1,LatLng latLng2) {

    double PI = 3.14159;
    double lat1 = latLng1.latitude * PI / 180;
    double long1 = latLng1.longitude * PI / 180;
    double lat2 = latLng2.latitude * PI / 180;
    double long2 = latLng2.longitude * PI / 180;

    double dLon = (long2 - long1);

    double y = Math.sin(dLon) * Math.cos(lat2);
    double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
            * Math.cos(lat2) * Math.cos(dLon);

    double brng = Math.atan2(y, x);

    brng = Math.toDegrees(brng);
    brng = (brng + 360) % 360;

    return brng;
}

Enfin, nous devons faire pivoter le marqueur de voiture selon l’angle que nous obtenons de la méthode ci-dessus.

private void rotateMarker(final Marker marker, final float toRotation) {
    if(!isMarkerRotating) {
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        final float startRotation = marker.getRotation();
        final long duration = 1000;

        final Interpolator interpolator = new LinearInterpolator();

        handler.post(new Runnable() {
            @Override
            public void run() {
                isMarkerRotating = true;

                long elapsed = SystemClock.uptimeMillis() - start;
                float t = interpolator.getInterpolation((float) elapsed / duration);

                float rot = t * toRotation + (1 - t) * startRotation;

                marker.setRotation(-rot > 180 ? rot / 2 : rot);
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                } else {
                    isMarkerRotating = false;
                }
            }
        });
    }
}

À votre santé!

46
Prasad

Voici mon code pour déplacer le marqueur comme uber. J'ai montré deux façons de déplacer le marqueur.

Remarque importante: pour déplacer une voiture sur une route appropriée [comme ola, uber], vous devez utiliser un api routier fourni par Google

1.Par la latitude et la longitude statiques

2.Par la latitude et la longitude en temps réel

package com.gangsofcoder.googlemapdemo;

import Android.animation.Animator;
import Android.animation.AnimatorListenerAdapter;
import Android.animation.ValueAnimator;
import Android.location.Location;
import Android.location.LocationManager;
import Android.os.Bundle;
import Android.os.Handler;
import Android.os.PersistableBundle;
import Android.support.annotation.Nullable;
import Android.support.v7.app.AppCompatActivity;
import Android.util.Log;
import Android.view.animation.LinearInterpolator;
import Android.widget.Button;
import Android.widget.Toast;

import com.google.Android.gms.maps.CameraUpdateFactory;
import com.google.Android.gms.maps.GoogleMap;
import com.google.Android.gms.maps.OnMapReadyCallback;
import com.google.Android.gms.maps.SupportMapFragment;
import com.google.Android.gms.maps.model.BitmapDescriptorFactory;
import com.google.Android.gms.maps.model.CameraPosition;
import com.google.Android.gms.maps.model.LatLng;
import com.google.Android.gms.maps.model.Marker;
import com.google.Android.gms.maps.model.MarkerOptions;
import com.loopj.Android.http.AsyncHttpResponseHandler;
import com.loopj.Android.http.RequestParams;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import Java.util.ArrayList;

import cz.msebera.Android.httpclient.Header;

public class MoveCar extends AppCompatActivity {
    private GoogleMap googleMap;
    SupportMapFragment mapFragment;
    Marker marker;
    private boolean isMarkerRotating = false;
    ArrayList<LatLng> listOfPoints = new ArrayList<>();
    int currentPt = 0;
    LatLng finalPosition;
    Marker mMarker;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setUpMapIfNeeded();
    //new location details
    listOfPoints.add(new LatLng(30.701623, 76.684220));
    listOfPoints.add(new LatLng(30.702486, 76.685487));
    listOfPoints.add(new LatLng(30.703135, 76.684891));
    listOfPoints.add(new LatLng(30.703256, 76.685000));
    listOfPoints.add(new LatLng(30.703883, 76.685941));
    listOfPoints.add(new LatLng(30.703413, 76.685190));
}

private void setUpMapIfNeeded() {
    if (mapFragment == null) {
        mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

        if (mapFragment != null) {
            mapFragment.getMapAsync(new OnMapReadyCallback() {
                @Override
                public void onMapReady(GoogleMap googleMap) {
                    loadMap(googleMap);
                }
            });
        }
    }
}

private void loadMap(GoogleMap map) {
    googleMap = map;

    mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(30.701623, 76.684220)).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));      


    final Handler handler = new Handler();
    //Code to move car along static latitude and longitude

  /*  handler.postDelayed(new Runnable() {
        @Override
        public void run() {

            if (currentPt < listOfPoints.size()) {
                //post again
                Log.d("tess", "inside run ");
                Location targetLocation = new Location(LocationManager.GPS_PROVIDER);
                targetLocation.setLatitude(listOfPoints.get(currentPt).latitude);
                targetLocation.setLongitude(listOfPoints.get(currentPt).longitude);
                animateMarkerNew(targetLocation, mMarker);
                handler.postDelayed(this, 3000);
                currentPt++;
            } else {
                Log.d("tess", "call back removed");
                //removed callbacks
                handler.removeCallbacks(this);
            }
        }
    }, 3000);*/

    //Here move marker along real time updates
    final RequestParams params = new RequestParams();
    params.put("source_lattitude", "lat");
    params.put("source_longitude", "long");
    params.put("date", "date");

    //new handler
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {

            LoopjHttpClient.post(getString(R.string.default_upload_website), params, new AsyncHttpResponseHandler() {
                @Override
                public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {

                    try {
                        JSONObject jsonObject = new JSONObject(new String(responseBody));
                        String status = jsonObject.getString("status");
                        String text = jsonObject.getString("text");
                        //reading json array
                        JSONArray jsonArray = jsonObject.getJSONArray("result");
                        String source = jsonArray.getJSONObject(0).getString("source");

                        String[] latLong = source.split(",");
                        Location location = new Location(LocationManager.GPS_PROVIDER);
                        location.setLatitude(Double.parseDouble(latLong[0]));
                        location.setLongitude(Double.parseDouble(latLong[1]));
                        //calling method to animate marker  
                        animateMarkerNew(location, mMarker);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                    Log.d("onFailure", "onFailure");
                }
            });

            handler.postDelayed(this, 3000);
        }
    }, 3000);

}

private void animateMarkerNew(final Location destination, final Marker marker) {

    if (marker != null) {

                final LatLng startPosition = marker.getPosition();
                final LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());

                final float startRotation = marker.getRotation();
                final LatLngInterpolatorNew latLngInterpolator = new LatLngInterpolatorNew.LinearFixed();

                ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
                valueAnimator.setDuration(3000); // duration 3 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);
                            googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                                    .target(newPosition)
                                    .zoom(15.5f)
                                    .build()));

                            marker.setRotation(getBearing(startPosition, new LatLng(destination.getLatitude(), destination.getLongitude())));
                        } catch (Exception ex) {
                            //I don't care atm..
                        }
                    }
                });
                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);

                        // if (mMarker != null) {
                            // mMarker.remove();
                        // }
                        // mMarker = googleMap.addMarker(new MarkerOptions().position(endPosition).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));

                    }
                });
                valueAnimator.start();
    }
}

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

    class LinearFixed implements LatLngInterpolatorNew {
        @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);
        }
    }
}


//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;
}
}
15
Suraj Bahadur

Depuis, il est un peu déroutant pour SO les utilisateurs de rechercher du code de travail dans deux messages différents. Voici le code de travail de Rotate and Move Marker qui a fonctionné de manière transparente pour moi.

dans MainActivity.Java

public void rotateMarker(final Marker marker, final float toRotation, final float st) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    final float startRotation = st;
    final long duration = 1555;

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

            float rot = t * toRotation + (1 - t) * startRotation;

            marker.setRotation(-rot > 180 ? rot / 2 : rot);
            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            }
        }
    });
}


public void animateMarker(final LatLng toPosition,final boolean hideMarke) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    Projection proj = googleMap.getProjection();
    Point startPoint = proj.toScreenLocation(m.getPosition());
    final LatLng startLatLng = proj.fromScreenLocation(startPoint);
    final long duration = 5000;

    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;
            m.setPosition(new LatLng(lat, lng));

            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            } else {
                if (hideMarke) {
                    m.setVisible(false);
                } else {
                    m.setVisible(true);
                }
            }
        }
    });
}
11
VipiN Negi

Enfin écrit le code qui fonctionne exactement de la même manière que OLA CABS fait ...

C'est ici -

  1. Placez votre fragment de google maps dans une mise en page relative et placez le marqueur (en tant que vue d'image) au centre -

  2. Dans le code de votre fragment, une fois que vous avez configuré toutes les bases de Google Maps, écrivez le code suivant pour la fonction onMapReady (GoogleMap googleMap) -

Mon code est comme suit -

//Étape 1 -

 <RelativeLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">



<fragment
    Android:id="@+id/map"
    Android:name="com.google.Android.gms.maps.SupportMapFragment"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    tools:context=".MapsActivity_for_request_pages" />

    <ImageView
        Android:layout_width="30sp"
        Android:layout_height="30sp"
        Android:layout_centerInParent="true"
        Android:id="@+id/central_marker"
        Android:src="@drawable/marker_pic"/>

</RelativeLayout>

//Étape 2 -

@Override
public void onMapReady(GoogleMap googleMap) {


     central_marker = (ImageView)v.findViewById(R.id.central_marker);
     int init_loc = 0,final_loc = -300;
     mMap = googleMap;

 final  CountDownTimer timer = new CountDownTimer(300,300) {
       @Override
       public void onTick(long millisUntilFinished) {

       }

       @Override
       public void onFinish() {
           init_loc = 0;
           ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(central_marker, "translationY", final_loc, init_loc);
           objectAnimatorY.setDuration(200);
           objectAnimatorY.start();
       }
   };


    mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
        @Override
        public void onCameraMoveStarted(int i) {

            System.out.println("Camera started moving worked");
            timer.cancel();
            ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(central_marker, "translationY", init_loc, final_loc);
            objectAnimatorY.setDuration(200);
            objectAnimatorY.start();
            init_loc = -300;

        }
    });



    mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
            System.out.println("Camera idle worked");
            if(initial_flag!=0)
            {
                System.out.println("Camera Setting timer now");
                timer.cancel();
                timer.start();
            }
            initial_flag++;
            System.out.println("Camera Value of initial_flag ="+initial_flag);
        }
    });

}
5
Shubham Arora

Tout d’abord, je tiens à vous remercier tous deux @Vipin Negi & @Prasad pour un code aussi efficace et astucieux. Puisqu'il y a beaucoup de requêtes en suspens ci-dessus, je souhaite simplifier un peu plus tout ce qui précède. Les gars, il suffit de suivre les étapes suivantes pour réaliser la rotation du marqueur.

1. Définissez ci-dessous deux méthodes dans votre fichier MainActivity.Java

private double bearingBetweenLocations(LatLng latLng1, LatLng latLng2) {

    double PI = 3.14159;
    double lat1 = latLng1.latitude * PI / 180;
    double long1 = latLng1.longitude * PI / 180;
    double lat2 = latLng2.latitude * PI / 180;
    double long2 = latLng2.longitude * PI / 180;

    double dLon = (long2 - long1);

    double y = Math.sin(dLon) * Math.cos(lat2);
    double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
            * Math.cos(lat2) * Math.cos(dLon);

    double brng = Math.atan2(y, x);

    brng = Math.toDegrees(brng);
    brng = (brng + 360) % 360;

    return brng;
}

Et

private void rotateMarker(final Marker marker, final float toRotation) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    final float startRotation = marker.getRotation();
    final long duration = 1000;

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

            float rot = t * toRotation + (1 - t) * startRotation;

            marker.setRotation(-rot > 180 ? rot / 2 : rot);
            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            }
        }
    });

}

2. Après cela, ajoutez les lignes suivantes au code dans lequel vous souhaitez que votre marqueur fasse pivoter.

double bearing = bearingBetweenLocations(m.getPosition(), updatedLatLng);
rotateMarker(m, (float) bearing);

Notez que "m" est l’objet marqueur que vous souhaitez faire pivoter. Et tu as fini!!!

Si vous souhaitez une aide relative à l’animation de marqueurs, vous pouvez utiliser le code this .

0