I would like to translate a view from pointA to pointB. imagine a line is drawn from pointA to pointB. the view should be translated to pointB along that invisible line. how a can i acheieve this. here is what i have tried so far:
getView().animate().translationX(deltaX)
getView().animate().translationY(deltaY)
but im not getting the results i want. to be specific i am using a google map and i want to move one marker to another location using translation.
I believe this repo will help you achieve your desired goal.
i am using a google map and i want to move one marker to another
location
I think the animateMarker() method in the MapUtils.java will help you achieve this,
public static void animateMarker(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 LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(1000); // duration 1 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(computeRotation(v, startRotation, destination.getBearing()));
} catch (Exception ex) {
// I don't care atm..
}
}
});
valueAnimator.start();
}
}
I think your way must be more complex to achieve this goal.
Need to draw a transparent cover that must be clickable and focusable to receive touch events and prevent map changes from user input (for example, FrameLayout or custom View) above MapView. And then draw a "fake marker" on this Surface, animate, and finally destroy them.
The trick is next:
You have a marker at point A
Show Surface above all map to prevent touch
Draw new view "fake marker" on this Surface (above original marker)
Remove the original marker from the map
Animate/Translate your new marker to point B
Draw a new marker on the map at point B
Hide Surface with "fake marker"
Related
The google map marker can be dragged around the screen so I want to know if there's a way to trigger an event when the marker is dropped at a certain location on the screen, say, bottom left.
After layout created and map initialized add the following code in onCreate();
View mapView = getSupportFragmentManager().findFragmentById(R.id.map).getView();
if (mapView.getViewTreeObserver().isAlive()) {
mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(CENTER, 15));
Point markerScreenPosition = map.getProjection().toScreenLocation(marker.getPosition());
int x = markerScreenPosition.getX();
int y = markerScreenPosition.getY();
if(x == yourValue && y == yourValue){
//your trigger code goes here
}
}
});
}
I think markers are not automatically dropped. they are handled by your code. for example you can add a marker on map click or on map long click. get that event and try fixing
I am creating markers based on my location and I would like to make the markers draggable within 1km of that location.
So, basically I want to know how to make a marker draggable within a certain area/region only and not the entire map.
Thank you
You have to define bounds and check if the new position is outside the bounds in the onDragListener of the marker: if the new position is outside the bounds you can reset the marker to the last valid position or do whatever you want.
To match if the marker is-or-not inside the bounds you must use the method contains of the LatLngBounds object.
Something like this:
LatLngBounds bounds;
LatLngBounds.Builder builder = new LatLngBounds.Builder();
// You construct your bounds in a way like this
builder.include(new LatLng(latitude1, longitude1));
builder.include(new LatLng(latitude2, longitude2));
builder.include(new LatLng(latitude3, longitude3));
// etc
bounds = builder.build();
googleMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
#Override
public void onMarkerDragStart(Marker marker) {
}
#Override
public void onMarkerDrag(Marker marker) {
}
#Override
public void onMarkerDragEnd(Marker marker) {
if (bounds.contains(marker.getPosition())) {
// cast your spell
} else {
// you can't drag here
}
}
});
I have more then 300 markers on top of Google Map in my Android project. They are vehicles in San Francisco as you can see from the screenshot.
I have direction and speed of the vehicles and I want to animate them for 10 seconds before the next call to the API.
To animate one marker I use this code:
static void animateMarkerToICS(Marker marker, LatLng finalPosition, final LatLngInterpolator latLngInterpolator) {
TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() {
#Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
return latLngInterpolator.interpolate(fraction, startValue, endValue);
}
};
Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position");
ObjectAnimator animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(ANIMATION_MILLIS);
animator.start();
}
When I call this for all 300 marker the map is, as expected, slow and not very responsive.
The question is, what is the best way to animate 300 markers at the same time?
Is there an efficient way to achieve good performance for this task?
(I'm using Google Maps v2 on Android > 4.0)
p.s. I'm not planning to run the animation when the map if fully zoomed out so probably I will never have all 300 markers moving at the same time but still I would like to have feedback about the best way to work on this problem. Thanks!
Have you considered using a asynchronous task?
This will take the emphasis off your main UI thread and throw the "computation" to the background. Thus making your map more responsive and not lag.
This is something I would possibly consider....
Create a Asynch Class.
In the Do background method put your marker calculation method etc.
protected String doInBackground(Location... params) {
// Show user a Progress bar/Dialog
// your markers plotting function here...
}
In the post post execute function revert back to the map
protected void onPostExecute(String result) {
// Revert back to map
}
Note I am assuming you already have the Lat/Lng coordinates for the 300 markers and only plotting them takes forever. If however you don't have the coordinates you can create a Asych task for that aswell and free up your main thread.
In our application, a lot of markers are drawn in different locations and in certain cases at a certain zoom level, markers overlap each other. So when I click on the marker, I expect the top marker's onMarkerClick to be fired but instead it is fired for the last hidden marker i-e the last marker, with no markers behind it.
What do you suggest I do? Also, I have no info windows, therefore I return true from onMarkerClick method.
I found the solution here: https://github.com/googlemaps/android-maps-utils/issues/26
mGoogleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter()
{
#Override
public View getInfoWindow(Marker marker)
{
// Empty info window.
return new View(getApplicationContext());
}
#Override
public View getInfoContents(Marker marker)
{
return null;
}
});
Identify the size of your maker relative to the overall screen (e.g. 10%). Define this as a float called IMAGE_SIZE_RATIO
Maintain List markers as you add markers to your map. In your OnMarkerClickListener onMarkerClick method iterate through your other markers and compare distance between the markers relative to the current visible map dimensions and the marker size. As in the following example code:
static final float IMAGE_SIZE_RATIO = .15f; //define how big your marker is relative to the total screen
private void setupListeners() {
getMap().setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
LatLngBounds b = getMap().getProjection().getVisibleRegion().latLngBounds;
Float distance = distanceBetweenPoints(b.northeast, b.southwest) * IMAGE_SIZE_RATIO;
for (Marker m : makers ) {
if (marker.equals(m) ) { continue; } //don't compare the same one
if (distanceBetweenPoint(m.getPosition(), marker.getPosition()) {
/*Note do onMarkerClick this as an Aynch task and continue along
if also want to fire off against the main object.
*/
return onMarkerClick(m);
}
}
// do the operation you want on the actual marker.
}
....(remainder of listener)...
}
}
protected Float getDistanceInMeters(LatLng a, LatLng b) {
Location l1 = new Location("");
Location l2 = new Location("");
l1.setLatitude(a.latitude);
l1.setLongitude(a.longitude);
l2.setLatitude(b.latitude);
l2.setLongitude(b.longitude);
return l1.distanceTo(l2)
}
I am using this to get the bounds of markers on my map:
markerList.add(m);
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker marker : markerList) {
builder.include(marker.getPosition());
}
LatLngBounds bounds = builder.build();
CameraUpdate updatecamera = CameraUpdateFactory.newLatLngBounds(bounds, 50);
map.animateCamera(updatecamera);
After getting update, I would like to tilt the map to 30 degrees.
I have used this to tilt the camera in the past, but it is not working with the bounds feature:
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(meLoc).zoom(6).bearing(0).tilt(30).build();
map.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
How do I add this tilt after getting the bounds?
Thanks
As you say, the Android Maps API v2 doesn't currently directly support animating the camera with both bounds and tilt info.
One workaround is to use the following steps:
Do the camera animation you want to perform with the bounds, but leave out the tilt
Listen for the end of the above camera animation, get the current camera position, and then perform the tilt
This has the effect of moving the camera to the bounds while looking straight down (i.e., tilt = 0), and then tilting the camera in place. I've found that this works well in some use cases, and actually looks nice, but in others its kind of awkward. It may or may not work for your particular use case.
To implement this, let's assume you have a main class MapScreen.java where your map is implemented. You'll need change it to include the camera listener interface, a reference to the camera position, a reference to your activity, an initial tilt value you want to use (you can alternately set this at runtime), and a default camera padding:
public class MapScreen extends FragmentActivity implements GoogleMap.OnCameraChangeListener {
...
private GoogleMap map;
public static CameraPosition lastCameraPosition;
public static MapScreen mapScreen;
public static float CAMERA_INITIAL_TILT = 30.0f;
public static int CAMERA_PADDING = 100;
...
public void onCreate(Bundle savedInstanceState) {
...
mapScreen = this;
...
//Set up map object here like normal
map = ((SupportMapFragment)(getSupportFragmentManager().findFragmentById(R.id.map))).getMap();
...
//Set camera change listener
map.setOnCameraChangeListener(this);
}
...
}
In this class, you'll also need to add a method to listen and save the location of the camera when the first animation stops:
#Override
public void onCameraChange(CameraPosition position) {
//Save the last camera position so we can reference it when tilting the camera following animations
lastCameraPosition = position;
}
Also, add an inner class you can reference that performs the tilt after the first animation finishes (with a slight delay to get the correct CameraPosition):
public class tiltOnFinishAnimation implements CancelableCallback {
#Override
public void onCancel() {
//Do nothing
}
#Override
public void onFinish() {
//We want to run the tilt animation, but the CameraPosition needed to center the camera in the right place
//is only available after the onFinish() method completes. So, we delay this by 10 ms to let the CameraPosition update
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
mapScreen.runOnUiThread(new Runnable() {
public void run() {
if(lastCameraPosition != null){
//Finish with a tilt
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(lastCameraPosition.target)
.zoom(lastCameraPosition.zoom)
.bearing(lastCameraPosition.bearing)
.tilt(CAMERA_INITIAL_TILT)
.build();
//Perform the tilt!
mapScreen.map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
});
}
}, 10);
}
}
Finally, when you want to move the camera, execute your normal code, but first identify some of the map view attributes needed for animating the camera correctly based on orientation, and include a reference to the callback to execute when the first part of the animation without the tilt stops:
//Get the View height and width, so we don't exceed the screen size after padding for the camera updates
int width;
int height;
if(mapFragment != null){
width = mapFragment.getView().getWidth();
height = mapFragment.getView().getHeight();
}else{
//If the map fragment hasn't been instantiated yet, use the entire display
if (android.os.Build.VERSION.SDK_INT >= 13){
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
}else{
Display display = getWindowManager().getDefaultDisplay();
width = display.getWidth();
height = display.getHeight();
}
}
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
//Use verticle size for padding
CAMERA_PADDING = (int) (height * 0.2f);
}else{
//Use horizontal size for padding
CAMERA_PADDING = (int) (width * 0.2f);
}
//Your code
markerList.add(m);
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker marker : markerList) {
builder.include(marker.getPosition());
}
LatLngBounds bounds = builder.build();
//Here's the new code below that triggers first the movement to the bounds, then the tilt (as a callback)
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, width, height, CAMERA_PADDING), new tiltOnFinishAnimation());
In order to set GoogleMap Tilt and Bound all marker you need to use following code.
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 75));
CameraPosition camPos = new CameraPosition.Builder(googleMap.getCameraPosition())
.target(bounds.getCenter())
.bearing(bearing).tilt(45).build();
googleMap.animateCamera(CameraUpdateFactory
.newCameraPosition(camPos));
The key point is not having an animateCamera(..) followed by another animateCamera(..) without enough delay, as they overlap. So you should better use moveCamera(..) first and then animateCamera(..), or use some delay technique for the second animateCamera(..) such as new Handler().postDelayed(..).