Animate marker movements along prepared coordinates. - android

I need to make animated movement if the airplane marker along stored coordinates in ArrayList collection. I've found the solution, how to do move marker from one coordinate to another. Here is the code of the method, which moves it:
private void animateMarker(final Marker plane,
final LatLng toPosition,
final boolean hideMarker,
int currentIndex) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = gMap.getProjection();
Point startPoint = proj.toScreenLocation(plane.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final long duration = 2500;
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 lat = t * toPosition.latitude + (1 - t) * startLatLng.latitude;
double lng = t * toPosition.longitude + (1 - t) * startLatLng.longitude;
plane.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
plane.setVisible(false);
} else {
plane.setVisible(true);
}
}
}
});
//Call the method which will start another animateMarker()
// after this thread is finished
currentIndex++;
if(currentIndex < theRoute.size()-1){
movePlane(plane, currentIndex);
}
}
This method works perfectly, when I'm trying to move the object from one coordinate to another, but I need to move it along the collection of coordinates. As you recognized, in the end of the code I increment the "currentIndex" value, and call movePlane method, which accepts the instance of the marker and new index value. Here the chaos starts, but let me show you the code:
private void movePlane(Marker plane, int index){
if(currentCoordIndex < theRoute.size()){
animateMarker(plane, theRoute.get(index), false, index);
}
}
So, the plane marker is moving chaotically back and forth from coordinate to another and it is not acceptable. I suppose, that new thread is called, when the other is not finished. Maybe, solution is quite simple, but I really don't know how to do, what I expect.
Also i need to rotate the marker towards the next point, could you help me with that?

Related

Animations for the group of markers to rotate at the same time in google maps v2 android

I'm implementing the animations for the group of cars(Markers) to rotate at the same time in google map v2.
so that i need to code my animation part inside handler.post() method.
By doing this the animation part(handler.post() method) is running for only one marker.
i have coded handler.post() method inside the for loop. It runs only for the first time which means only one marker is rotating. after that it is not working. My code is as follows.
private void animateCarsInMarkers(final MarkerOptions mark, final long bearing, final LatLng startPosition, final int position){
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final long duration = 3000;
final Interpolator interpolator = new LinearInterpolator();
final Marker marker = mGoogleMap.addMarker(mark);
final float rotationValue = Float.parseFloat(String.valueOf(bearing));
try {
if(tempCarsArray != null && !tempCarsArray.isEmpty()){
sLongitude = tempCarsArray.get(position).getDouble(LONGITUDE);
sLatitude = tempCarsArray.get(position).getDouble(LATITUDE);
sBearing = tempCarsArray.get(position).getLong("Bearing");
final double dLongitude = startPosition.longitude;
final double dLatitude = startPosition.latitude;
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float time = interpolator.getInterpolation((float) elapsed / duration);
double lng = time * dLongitude + (1 - time) * sLongitude;
double lat = time * dLatitude + (1 - time) * sLatitude;
float rotationValue = time * dbearing + (1-time) * sBearing;
marker.setRotation((-rotationValue > 180) ? (rotationValue / 2) : rotationValue);
marker.setPosition(new LatLng(lat, lng));
if (time < 1.0) {
handler.postDelayed(this, 16);
}
}
});
tempCarsArray.clear();
} else {
marker.setPosition(startPosition);
marker.setRotation(-rotationValue > 180 ? rotationValue / 2 : rotationValue);
}
}catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
This is the method which i called inside for loop. But it runs only for the first time in loop. Later it is not working. So only one marker is animated among the group of markers. My for loop is as follows :
for(int i=0; i<size; i++){
animateCarsInMarkers(mark, bearing, latLng, i);
}
This loop runs only when the value of i=0 and it wont runs again.
Thanks in advance.
If your 'for loop' ran only once, it means that your "for loop condition part", i<size for this instance, has already satisfied the condition. What I would suggest is for you to actually log "size" and check its value.
If you're looking for the size of an array, use tempCarsArray.length like:
for(int i=0; i < tempCarsArray.length; i++){
animateCarsInMarkers(mark, bearing, latLng, i);
}
To check if size is causing the problem, try this.
If you know the actual number of markers you're expecting to rotate, try to substitute with an integer for now, like:
//if you're expecting 5 markers
for(int i=0; i < 5 ; i++){
animateCarsInMarkers(mark, bearing, latLng, i);
}
If all markers did rotate, it means your size variable has only a value of 1.

Google map: moving marker and map together smoothly along with the user?

I have to show real time/live user moving location in google map once user turn on the feature and up-to terminating it.
I have had used the method below to animate the marker.
private void animateMarker(final Marker marker, final LatLng toPosition,
final boolean hideMarker) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = mMap.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
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);
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);
}
}
}
});
}
And using the following code am moving the map too.
// Showing the current location in Google Map
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// Zoom in the Google Map
mMap.animateCamera(CameraUpdateFactory.zoomTo(15));
What I had done so far isn't good enough to move the marker and map together. it's not looking that perfect. I have to move the map along with marker together.
Source Code
Thank you.
What I done in my similar project is like: Assume I have a list of point where user navigated one by one so, I want to display that trip in map with animation. Instead of moving both marker and camera same time you can move marker between two points and then animate camera to that second point, now again move marker to next point and then when marker reach out next point animate your camera.
To get this working you have to modify your code little bit.
Add this code:
private static final int ANIMATE_SPEEED_TURN = 1000;
private static final int BEARING_OFFSET = 20;
if (t < 1) {
mHandler.postDelayed(this, 16);
} else {
// your code
if (hideMarker) {
marker.setVisible(false);
} else {
marker.setVisible(true);
}
//my added code
LatLng begin = getBeginLatLng();// current point
LatLng end = getEndLatLng();// next point
float bearingL = bearingBetweenLatLngs(begin, end);
CameraPosition cameraPosition =
new CameraPosition.Builder()
.target(end)
.bearing(bearingL + BEARING_OFFSET)
.tilt(tilt)
.zoom(googleMap.getCameraPosition().zoom)
.build();
googleMap.animateCamera(
CameraUpdateFactory.newCameraPosition(cameraPosition),
ANIMATE_SPEEED_TURN,
null
);
mHandler.postDelayed(animator, 16);
}
Let me know If anything goes wrong!!!
For detailed step visit Animating the map

Unable to implement dropping pin animation on map markers in android

I am trying to implement dropping pin effect on the map markers. I have implemented the code as below but I can't find the animation occurring on the marker. Can anyone guide me step by step how to do it.
final LatLng latlang = new LatLng(15.4989, 73.8278);
final MarkerOptions marker = new MarkerOptions().position(latlang).title("Hello Maps ");
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlang, 17));
mGoogleMap.addMarker(marker);
final long start = SystemClock.uptimeMillis();
Projection proj = mGoogleMap.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final Interpolator interpolator = new LinearInterpolator();
handler.postDelayed(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / 1000);
double lng = t * latlang.longitude + (1 - t) * startLatLng.longitude;
double lat = t * latlang.latitude + (1 - t) * startLatLng.latitude;
Log.i("marker thread","elapsed"+elapsed+",t"+t+"lng,"+lng+",lat"+lat);
marker.position(new LatLng(lat, lng));
}
}, 1000);
There are 3 problems in your code,
firstly, your handler never reply itself, it is just waiting for one second. To fix it, you have to call your handler within your handler like handler.postDelayed(this, 16); until your t >= 1 (One second)
secondly, you should have wait 0.016 seconds, rather than 1 whole seconds for your outer handler call.
lastly, your "marker", is actually the markerOption, so your code should looked like this instead:
final MarkerOptions markerOptions = new MarkerOptions().position(latlang).title("Hello Maps ");
final Marker marker = googleMap.addMarker(markerOptions);
and do rather than using marker.position, you do marker.setPosition(new LatLng(lat, lng));

Android Maps v2 - animate markers

I'm creating a cluster feature for maps (v2). I group location into clusters and then display the clusters as custom markers:
This works great, but I would like to create an animation when clusters get created and split up. I successfully did this with iOS by creating a UIView Animation on the markers (annotations). I couldn't find any code / hints online for android.
I managed to get a simple ImageView as overlay to resemble a cluster and then use a TranslateAnimation to get the desired animation. At the end I removed this view and added the marker.
Is there a better way to animate a marker?
You're on the right track by animating the Marker object rather than adding and removing Views in front of the GoogleMap, but you can get better performance if you use an Animator object to animate the Marker.
With the Handler and delayed Runnable approach, you're effectively hard coding a target frame rate. If you post the Runnable with too low of a delay, your animation will take longer to execute. If too high, the frame rate will be too slow, and it'll look choppy even on powerful devices. The advantage to using an Animator over a Handler and delayed Runnable is that it will only call onAnimationUpdate() to draw the next frame as often as the system can handle.
In my clustering library, Clusterkraf, I used an ObjectAnimator (from NineOldAndroids for backwards compatibility) to animate cluster transitions when changing zoom level. It can smoothly animate around 100 markers on my Galaxy Nexus.
Below is a snippet with an overview of how to make that work.
class ClusterTransitionsAnimation implements AnimatorListener, AnimatorUpdateListener {
private ObjectAnimator animator;
private AnimatedTransitionState state;
private ClusterTransitions transitions;
private Marker[] animatedMarkers;
void animate(ClusterTransitions transitions) {
if (this.state == null) {
Options options = optionsRef.get();
Host host = hostRef.get();
if (options != null && host != null) {
this.state = new AnimatedTransitionState(transitions.animated);
this.transitions = transitions;
animator = ObjectAnimator.ofFloat(this.state, "value", 0f, 1f);
animator.addListener(this);
animator.addUpdateListener(this);
animator.setDuration(options.getTransitionDuration());
animator.setInterpolator(options.getTransitionInterpolator());
host.onClusterTransitionStarting();
animator.start();
}
}
}
#Override
public void onAnimationStart(Animator animator) {
// Add animatedMarkers to map, omitted for brevity
}
#Override
public void onAnimationUpdate(ValueAnimator animator) {
if (state != null && animatedMarkers != null) {
LatLng[] positions = state.getPositions();
for (int i = 0; i < animatedMarkers.length; i++) {
animatedMarkers[i].setPosition(positions[i]);
}
}
}
}
The code below is correct, but I would puntualize something. I would use 16 ms == 60fps. The human eye can't distinguis less than 16 ms, so:
final LatLng target = NEW_LOCATION;
final long duration = 400;
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = map.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
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 * target.longitude + (1 - t) * startLatLng.longitude;
double lat = t * target.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later == 60 frames per second
handler.postDelayed(this, 16);
} else {
// animation ended
}
}
});
I found a solution that works:
final LatLng target = NEW_LOCATION;
final long duration = 400;
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = map.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
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 * target.longitude + (1 - t) * startLatLng.longitude;
double lat = t * target.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 10ms later.
handler.postDelayed(this, 10);
} else {
// animation ended
}
}
});
It's a bit slow with about 20 simultaneously, maybe there is a better way?

How to animate marker when it is added to map on Android?

I want to animate map markers when they are added to map.
User should see the map with markers around him. Each new marker should bounce.
You can implement the onMarkerClick() and make the marker bounce whenever user clicks on it.
Just try out below code implementation. I have tried it and it works totally fine.
private Marker mPerth;
private Marker mPerth = mMap.addMarker(new MarkerOptions()
.position(PERTH)
.title("Perth")
.snippet("Population: 1,738,800"));
#Override
public boolean onMarkerClick(final Marker marker)
{
// This causes the marker at Perth to bounce into position when it is clicked.
if (marker.equals(mPerth)) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = mMap.getProjection();
Point startPoint = proj.toScreenLocation(PERTH);
startPoint.offset(0, -100);
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final long duration = 1500;
final Interpolator interpolator = new BounceInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * PERTH.longitude + (1 - t) * startLatLng.longitude;
double lat = t * PERTH.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}
}
});
}
// We return false to indicate that we have not consumed the event and that we wish
// for the default behavior to occur (which is for the camera to move such that the
// marker is centered and for the marker's info window to open, if it has one).
return false;
}
You can also use this at the time of adding the marker in your application besides onClick event.
I hope this what you want only.
Anchor the marker off screen or at your start position then start the animation.
Note the .setAnchor used in this method was added to the google map api v2 in May 2013
I've just now got this working for one marker by tweaking the extras samples maps demo and I don't like the performance of this implementation. The most important piece is to anchor the marker off screen or off at your start position. I'm using off screen above.
Anchor the marker off screen .setAnchor(.5f,(size of screen above marker / size of marker )) //for the map demo perth is about 6f for my test phone. Change the animation to bounce to the same value it was 6f for my test phone.
private void addMarkersToMap() {
// A few more markers for good measure.
mPerth = mMap.addMarker(new MarkerOptions().position(PERTH)
.title("Perth").snippet("Population: 1,738,800")
.anchor(.5f, 6f)
);
Change the animation so it bounces to (size of screen above marker/size of marker) (6f on my test phone). I'm just using the onclick handler because it's already setup to bounce with tweaks bounce to 6f and a longer duration. So after all the markers have been added to the map I fire off the click handler.
this.onMarkerClick(mPerth);
The changed onMarkerClick handler with the 6f and longer duration.
#Override
public boolean onMarkerClick(final Marker marker) {
if (marker.equals(mPerth)) {
// This causes the marker at Perth to bounce into position when it
// is clicked.
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final long duration = 2500;
final Interpolator interpolator = new BounceInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = Math.max(
1 - interpolator.getInterpolation((float) elapsed
/ duration), 0);
marker.setAnchor(0.5f, 1.0f + 6 * t);
if (t > 0.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}
}
});
} else if (marker.equals(mAdelaide)) {
// This causes the marker at Adelaide to change color.
marker.setIcon(BitmapDescriptorFactory.defaultMarker(new Random()
.nextFloat() * 360));
}
// We return false to indicate that we have not consumed the event and
// that we wish
// for the default behavior to occur (which is for the camera to move
// such that the
// marker is centered and for the marker's info window to open, if it
// has one).
return false;
}
Good Luck
You can add any new layout to MapView as map marker:
public void AddAnimMarkerToMap(MapView map, GeoPoint geoPoint, int id, int animResId)
{
var layoutParams = new MapView.LayoutParams(ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent,
geoPoint,
MapView.LayoutParams.Center);
var ll = new LinearLayout(map.Context) { Id = id, Orientation = Orientation.Vertical };
ll.SetGravity(GravityFlags.Center);
var iv = new ImageView(map.Context);
iv.SetImageResource(animResId);
ll.AddView(iv);
map.AddView(ll, layoutParams);
var markerAnimation = (AnimationDrawable)iv.Drawable;
markerAnimation.Start();
ll.LayoutParameters = layoutParams;
}
probably you can add ImageView directly without wraping layout.
animResId is the Frame animation drawable resource (similar as Android Mylocation marker).
http://developer.android.com/guide/topics/resources/animation-resource.html#Frame

Categories

Resources