Example to implement a bouncing marker:
//Make the marker bounce
final Handler handler = new Handler();
final long startTime = SystemClock.uptimeMillis();
final long duration = 2000;
Projection proj = myMap.getProjection();
final LatLng markerLatLng = marker.getPosition();
Point startPoint = proj.toScreenLocation(markerLatLng);
startPoint.offset(0, -100);
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final Interpolator interpolator = new BounceInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - startTime;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * markerLatLng.longitude + (1 - t) * startLatLng.longitude;
double lat = t * markerLatLng.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}
}
});
The code in main activity:
package com.example.androidmapsv2;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
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 android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.graphics.Point;
import android.view.Menu;
import android.view.MenuItem;
import android.view.animation.BounceInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity
implements OnMapLongClickListener, OnMarkerClickListener{
final int RQS_GooglePlayServices = 1;
GoogleMap myMap;
TextView tvLocInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvLocInfo = (TextView)findViewById(R.id.locinfo);
FragmentManager myFragmentManager = getFragmentManager();
MapFragment myMapFragment
= (MapFragment)myFragmentManager.findFragmentById(R.id.map);
myMap = myMapFragment.getMap();
myMap.setMyLocationEnabled(true);
//myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//myMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//myMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
myMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
myMap.getUiSettings().setZoomControlsEnabled(true);
myMap.getUiSettings().setCompassEnabled(true);
myMap.getUiSettings().setMyLocationButtonEnabled(true);
myMap.getUiSettings().setRotateGesturesEnabled(true);
myMap.getUiSettings().setScrollGesturesEnabled(true);
myMap.getUiSettings().setTiltGesturesEnabled(true);
myMap.getUiSettings().setZoomGesturesEnabled(true);
//or myMap.getUiSettings().setAllGesturesEnabled(true);
myMap.setTrafficEnabled(true);
myMap.setOnMapLongClickListener(this);
myMap.setOnMarkerClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_legalnotices:
String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
getApplicationContext());
AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
LicenseDialog.setTitle("Legal Notices");
LicenseDialog.setMessage(LicenseInfo);
LicenseDialog.show();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
if (resultCode == ConnectionResult.SUCCESS){
Toast.makeText(getApplicationContext(),
"isGooglePlayServicesAvailable SUCCESS",
Toast.LENGTH_LONG).show();
}else{
GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices);
}
}
@Override
public void onMapLongClick(LatLng point) {
tvLocInfo.setText("New marker added@" + point.toString());
BitmapDescriptor bitmapDescriptor
= BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher);
myMap.addMarker(new MarkerOptions()
.position(point)
.icon(bitmapDescriptor)
.title(point.toString()));
}
@Override
public boolean onMarkerClick(final Marker marker) {
//Make the marker bounce
final Handler handler = new Handler();
final long startTime = SystemClock.uptimeMillis();
final long duration = 2000;
Projection proj = myMap.getProjection();
final LatLng markerLatLng = marker.getPosition();
Point startPoint = proj.toScreenLocation(markerLatLng);
startPoint.offset(0, -100);
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final Interpolator interpolator = new BounceInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - startTime;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * markerLatLng.longitude + (1 - t) * startLatLng.longitude;
double lat = t * markerLatLng.latitude + (1 - t) * startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}
}
});
//return false; //have not consumed the event
return true; //have consumed the event
}
}
Download the files.
The series:
A simple example using Google Maps Android API v2, step by step.
Hi,
ReplyDeleteI think it could be better using the anchor attribute of the marker instead of the position, because the position is the thing that the marker represents.
I've done it based on your code and it works very well.
Some improvements could be that the makrer position doesn't change, and if you use the map rotation or the map zoom the bouncing effect won't be affected.
A negative thing could be if you don't know the default marker anchor, because you only can set the anchor value but reading it is not possible
Best wishes,
Damián.
ReplyDeleteThe marker change his original position when I use the bouncing effect. The change depends of the zoom.
Someone knows how can I solve it.
Thank you.
Store marker's properties somewhere and restore back after finishing animation :)
ReplyDeleteAwesome. Thanks :)
ReplyDelete