Rotate Marker And Move Animation On Google Map
I spent days figuring this all out the first time. It’s actually really easy once you know how, but the information was so fragmented it took forever to put the pieces together.
Then I forgot to write it down. Then I went out and drank a bunch of beer to celebrate putting it together, and probably screwed up my memory of the process. A month later, I went to do it again and um… uh… hmmm… SHOOT!
So here it all is in writing for the benefit of you and my future self. Past Self: “Sorry current self.” ðŸ˜
Here is my code to move a car like ola uber
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;
}
}
*********************************************************************************
****************************SECOND MODULE***********************************
*********************************************************************************
package com.example.gangsofcoder.carmoving; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.location.Location; import android.location.LocationManager; import android.nfc.Tag; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.animation.LinearInterpolator; 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.AsyncHttpClient; 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 java.util.LinkedHashSet; import cz.msebera.android.httpclient.Header; public class MainActivity extends AppCompatActivity { private GoogleMap googleMap; SupportMapFragment mapFragment; ArrayList<String> listOfPointsFromServer = new ArrayList<>(); ArrayList<LatLng> listOfPointsFromRoadApi = new ArrayList<>(); int currentPt = 0; LatLng finalPosition; Marker mMarker; private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setUpMapIfNeeded(); } 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; Log.d(TAG, "loadMap"); //mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(30.701623, 76.684220)).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car))); final Handler handler = new Handler(); //Here move marker along real time updates handler.postDelayed(new Runnable() { @Override public void run() { AsyncHttpClient client = new AsyncHttpClient(); client.get(getString(R.string.default_upload_website), 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"); if (jsonObject.getString("code").equals("201")) { //reading json array JSONArray jsonArray = jsonObject.getJSONArray("result"); for (int i = 0; i < jsonArray.length(); i++) { if (jsonArray.length() == 1) { listOfPointsFromServer.add(String.valueOf(jsonArray.get(i))); // } else { listOfPointsFromServer.add(String.valueOf(jsonArray.get(i))); } } pointsFromServer(listOfPointsFromServer); } //End of 201 /*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]));*/ //animateMarker(location, mMarker); } catch (JSONException e) { e.printStackTrace(); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { } }); } }, 1000); } private void pointsFromServer(ArrayList<String> listOfPointsFromServer) { Log.d(TAG, "pointsFromServer"); this.listOfPointsFromServer = listOfPointsFromServer; LinkedHashSet<String> set = new LinkedHashSet<>(listOfPointsFromServer); final ArrayList<String> pointsWithoutDuplicates = new ArrayList<>(set); /*Below code for google map road api *We can hit the road api with maximum 100 points */ String startUrl = "https://roads.googleapis.com/v1/snapToRoads?path="; String endUrl = "&interpolate=true&key=YOUR_API_KEY_HERE"; StringBuilder middleUrl = new StringBuilder(); //Code to create middle url for (int i = 0; i < pointsWithoutDuplicates.size(); i++) { if (pointsWithoutDuplicates.size() == 1) { //Do your work here if we get single location } else { if (i < pointsWithoutDuplicates.size() - 1) { middleUrl.append(pointsWithoutDuplicates.get(i)); middleUrl.append("|"); } else { middleUrl.append(pointsWithoutDuplicates.get(i)); } } }//End of for loop //Url to hit the road api String roadApiUrl = startUrl + middleUrl + endUrl; Log.d(TAG, roadApiUrl); //Code to hit road api url AsyncHttpClient client = new AsyncHttpClient(); client.get(roadApiUrl, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { try { JSONObject locationDataToParse = new JSONObject(new String(responseBody)); JSONArray snappedPoints = locationDataToParse.getJSONArray("snappedPoints"); //Looping through all location points Log.d(TAG, String.valueOf(snappedPoints.length())); for (int i = 0; i < snappedPoints.length(); i++) { JSONObject c = snappedPoints.getJSONObject(i); //Parse latitude and longitude inside location object JSONObject location = c.getJSONObject("location"); String latitude = location.getString("latitude"); String longitude = location.getString("longitude"); LatLng latLng = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude)); listOfPointsFromRoadApi.add(latLng); } if (listOfPointsFromRoadApi != null) { pointsFromRoadApi(listOfPointsFromRoadApi); } } catch (JSONException e) { e.printStackTrace(); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { } }); } private void pointsFromRoadApi(final ArrayList<LatLng> listOfPointsFromRoadApi) { /* this.listOfPointsFromRoadApi = listOfPointsFromRoadApi; //LinkedHashSet preserved the insertion order and automatically remove the duplicates values LinkedHashSet<String> set = new LinkedHashSet<>(listOfPointsFromServer); final ArrayList<String> pointsWithoutDuplicates = new ArrayList<>(set);*/ final Handler handler = new Handler(); //Code to move car along static latitude and longitude handler.postDelayed(new Runnable() { @Override public void run() { if (currentPt < listOfPointsFromRoadApi.size()) { //post again Log.d("tess", "Inside Run"); Location targetLocation = new Location(LocationManager.GPS_PROVIDER); targetLocation.setLatitude(listOfPointsFromRoadApi.get(currentPt).latitude); targetLocation.setLongitude(listOfPointsFromRoadApi.get(currentPt).longitude); animateCar(targetLocation, mMarker); handler.postDelayed(this, 3000); currentPt++; } else { Log.d("tess", "call back removed"); //removed callbacks handler.removeCallbacks(this); } } }, 1000); } private void animateCar(final Location destination, final Marker marker) { if (marker != null) { Log.d(TAG, "marker not null"); final LatLng startPosition = marker.getPosition(); final LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude()); // final float startRotation = marker.getRotation(); final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.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); 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); } }); valueAnimator.start(); } else { //set marker here Log.d(TAG, "Marker is null"); mMarker = googleMap.addMarker(new MarkerOptions().position(new LatLng(destination.getLatitude(), destination.getLongitude())).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car))); googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder() .target(new LatLng(destination.getLatitude(), destination.getLongitude())) .zoom(15.5f) .build())); } } 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); } } } //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; } }
No comments :
Post a Comment