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();
}
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é!
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;
}
}
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);
}
}
}
});
}
Enfin écrit le code qui fonctionne exactement de la même manière que OLA CABS fait ...
C'est ici -
Placez votre fragment de google maps dans une mise en page relative et placez le marqueur (en tant que vue d'image) au centre -
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);
}
});
}
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 .