I have an activity that extends MapActivity, and inside onCreate() I have this code
GeoPoint point = new GeoPoint((int)(1.3*1E6),(int)(34.45*1E6));
final MapController mc;
mc.animateTo(point);
that animates, to that point, however, when it animates, the point is in the center of the screen, and I want it to be in a fixed (X,Y) position on the screen. Is there an mc.animatetoLeftBottom(point) function?
Edit :
I used the
Projection p = mapView.getProjection();
point = p.fromPixels(50, 60);
mc.animateTo(point);
pictures:
When I start the app, it looks like this :
After I tap once on the pin, it looks like this
And, if I tap again on the pin, it will look like this:
This is how it should look like, no matter where I tap it from, or if I scroll, zoom and then tap again:
What I want is for it to automatically move to that position(see last picture) when I tap the pin
Can't you just change the GeoPoint to account for the fact, and animate to a different point?
Try this:
MapView mv = getMapView(); // fetch your map view
Projection p = mv.getProjection();
GeoPoint point = p.fromPixels(X, Y);
mc.animateTo(point);
Related
I'm writing an application on android that will show a map from google maps. When I start the app, the map is centered on the current location. When I use animateCamera, I can see the zoom-in animation from the whole world until it focuses on current location.
The problem is that I need to touch the map to get the map to display at the zoom level I expected.
Here is what I get before I touch the screen :
Before touch
Here is what I get after having touch the screen :
After touch
If I touch the screen, the image will remain fine, until I drive a few hundred meters and then it's again unuseable. Sometimes the image appears, but it's only 1 or 2 times per 10km.
Here is how I move the camera inside LocationListener::onLocationChanged :
float zoom = 19.0f;
LatLng target = new LatLng(location.getLatitude(), location.getLongitude());
// moving car marker
m_locationMarkerG.setPosition(target);
m_locationMarkerG.setRotation(location.getBearing());
// tilting camera depending on speed
float tilt = Math.min(90, location.getSpeed()*10);
m_mapViewG.animateCamera(CameraUpdateFactory.newCameraPosition(CameraPosition.builder().zoom(zoom).bearing(location.getBearing()).
target(target).tilt(tilt).build()));
What could I try to solve this ?
Thanks
Found solution :
animateCamera MUST be called from the main looper. The LocationListener is called from another thread (sensor's thread).
So the code become :
final float zoom = 19.0f;
final LatLng target = new LatLng(location.getLatitude(), location.getLongitude());
// tilting camera depending on speed
final float tilt = Math.min(90, location.getSpeed()*10);
m_handler.post(new Runnable() {
public void run() {
// moving car marker
m_locationMarkerG.setPosition(target);
m_locationMarkerG.setRotation(location.getBearing());
// moving camera
m_mapViewG.animateCamera(CameraUpdateFactory.newCameraPosition(CameraPosition.builder().zoom(zoom).bearing(location.getBearing()).target(target).tilt(tilt).build()));
}
});
I have the following functionality working in my app.
I Use MyLocationOverlay to get my current location.
I extended MyLocationOverlay in order to be able to drop a custom marker instead of the blinking blue marker.
I need help on the last requirement. I simply want a marker to stay fixed on the location that MyLocationOverlay says it found originally and not move around as it jumps from satellite to satellite.
What are my options for creating this type of user experience?
I would recommend saving off the first geopoint that gets fed into the drawMyLocation function inside the CustomLocationOverlay and using that instead of the myLocation fed to the function.
int intFirstGeoPoint = 0;
GeoPoint FirstGeoPoint;
protected void drawMyLocation(Canvas canvas, MapView mapView, Location lastFix, GeoPoint myLocation, long when) {
if(intFirstGeoPoint == 0){
FirstGeoPoint=myLocation;
intFirstGeoPoint=1;
}else{
myLocation=FirstGeoPoint;
}
// translate the GeoPoint to screen pixels
Point screenPts = mapView.getProjection().toPixels(myLocation, null);
...
...
You could also capture this location and create a new DrawableMapOverlay that only draws this point instead of hijacking the LocationOverlay
when i added x and y coordinates to MapView.LayoutParams constructor. its MODE_VIEW behaviour disappears. I want this behaviour along with x and y coordinates. I am not getting the problem why this is happening.
public void addMarkerToMAp(GeoPoint geoPoint) {
mapView.removeAllViews();
final ImageView view = new ImageView(mapView.getContext());
view.setImageResource(R.drawable.map_marker_anim);
view.post(new Runnable() {
#Override
public void run() {
AnimationDrawable animationDrawable = (AnimationDrawable) view.getDrawable();
animationDrawable.start();
}
});
mapView.addView(view);
MapView.LayoutParams layoutParams = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT,
MapView.LayoutParams.WRAP_CONTENT,
geoPoint,
MapView.LayoutParams.MODE_VIEW);
view.setLayoutParams(layoutParams);
}
So, I got the geoPoint as
geoPoint = mapView.getProjection().fromPixels((int)event.getX(), (int)event.getY());
where event is click event.
Also I want to show marker pin at (event.getX(), event.getY()), but it shows below the click.
If you code in eclipse, press ctrl+shift+f. That will make your code more readable.
That being said, When you show a marker, which points do you use?
If im not wrong then the point you will insert, will be the bottom left if its an overlay drawable.
topleft if its a view(i think thats what you are doing) and therefor it will appear under your click.
You can add an offsetx and offsety to it being -view.getWidth()/2 and -view.getHeight/2. which should then make your view directly centered under your pressed point.
You might have trouble getting view.getWidth/Height though, so make sure it doesnt return 0.
I am working on an Android app that displays multiple markers on a Google MapView. Everything works perfectly but I would like the markers to have an animation when they appear on the map.
Here's an example of something similar on iPhone. See 1'20".
Here is how I add them to my MapView.
for(int i=0; i<myMarkerList.length(); i++){
GeoPoint x = new GeoPoint(
(int)(lat*1E6),
(int)(lng*1E6));
oItem = new OverlayItem(x, title, String.valueOf(nb_marker));
pin.setAlpha(255);
oItem.setMarker(pin);
if (oItem != null)
mapOverlay.addOverlay(oItem); // add the overlay item to the overlay
}
mapOverlays.add(mapOverlay); // add the overlay to the list of overlays
mapView.invalidate(); // update the map shown
It is so pretty on iPhone, and someone must have already done something similar on Android but I can't seem to find any useful info.
EDIT: Okay so I recon I either have to override the draw method which will be long and not that pretty, or just give up with OverlayItems.
Thank you for your time.
Best regards,
Tom
You can use this tutorial for a reference, it uses animations, so I think that suits your solution.
Code from the tutorial :
//Reference to our MapView
MapView mapView = (MapView) activity.findViewById(R.id.mapview);
//Get a LayoutInflater and load up the view we want to display.
//The false in inflater.inflate prevents the bubble View being added to the MapView straight away
LayoutInflater inflater = activity.getLayoutInflater();
LinearLayout bubble = (LinearLayout) inflater.inflate(R.layout.bubble, mapView, false);
//Set up the bubble's close button
ImageButton bubbleClose = (ImageButton) bubble.findViewById(R.id.bubbleclose);
bubbleClose.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Animation fadeOut = AnimationUtils.loadAnimation(ResultsMapResultsDisplayer.this.activity, R.anim.fadeout);
bubble.startAnimation(fadeOut);
bubble.setVisibility(View.GONE);
}
});
private void displaySearchResultBubble(final SearchResult result) {
//Hide the bubble if it's already showing for another result
map.removeView(bubble);
bubble.setVisibility(View.GONE);
//Set some view content
TextView venueName = (TextView) bubble.findViewById(R.id.venuename);
venueName.setText(result.getName());
//This is the important bit - set up a LayoutParams object for positioning of the bubble.
//This will keep the bubble floating over the GeoPoint result.getPoint() as you move the MapView around,
//but you can also keep the view in the same place on the map using a different LayoutParams constructor
MapView.LayoutParams params = new MapView.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
result.getPoint(), MapView.LayoutParams.BOTTOM_CENTER);
bubble.setLayoutParams(params);
map.addView(bubble);
//Measure the bubble so it can be placed on the map
map.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
//Runnable to fade the bubble in when we've finished animatingTo our OverlayItem (below)
Runnable r = new Runnable() {
public void run() {
Animation fadeIn = AnimationUtils.loadAnimation(activity, R.anim.fadein);
bubble.setVisibility(View.VISIBLE);
bubble.startAnimation(fadeIn);
}
};
//This projection and offset finds us a new GeoPoint slightly below the actual OverlayItem,
//which means the bubble will end up being centered nicely when we tap on an Item.
Projection projection = map.getProjection();
Point p = new Point();
projection.toPixels(result.getPoint(), p);
p.offset(0, -(bubble.getMeasuredHeight() / 2));
GeoPoint target = projection.fromPixels(p.x, p.y);
//Move the MapView to our point, and then call the Runnable that fades in the bubble.
mapController.animateTo(target, r);
}
I seen your example app. From that i think you need only Glow in your markers, right? If yes then its possible through the styles and its having glow property also.
So I got it to work using a simple ArrayList of ImageViews and animation on them, no MapOverlay.
I'm porting a Google Maps based project to Osmdroid in order to use OpenStreetMaps. The port is working OK apart from adding my overlay which consists of a number of straight lines and some text. In both projects I add the Overlay by means of a timer thread and handler calling redrawOverlay.
In the OSM project my overlay is just a grey square completely hiding the map. If I remove the call to redrawOveraly, the OSM tiles are shown OK. I've reduced the overlay code to the bare minimum of a single diagonal line in the code samples below. It works fine in the Google app, overlaying the map tile. The com.google.android.maps.Overlay has a draw method, the OSM has an onDraw, so I have in the OSM version:
private MapView mv;
private MapOverlay mmapOverlay = null;
private void redrawOverlay() {
gPt = mv.getMapCenter();
if (mmapOverlay == null)
mmapOverlay = new MapOverlay(getApplicationContext());
List<Overlay> listOfOverlays = mv.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mmapOverlay);
mv.invalidate();
}
public class MapOverlay extends org.osmdroid.views.overlay.Overlay {
public MapOverlay(Context ctx) {
super(ctx);
// TODO Auto-generated constructor stub
}
#Override
public void onDraw(Canvas canvas, MapView mapView) {
Paint lp3;
lp3 = new Paint();
lp3.setColor(Color.RED);
lp3.setAntiAlias(true);
lp3.setStyle(Style.STROKE);
lp3.setStrokeWidth(1);
lp3.setTextAlign(Paint.Align.LEFT);
lp3.setTextSize(12);
canvas.drawLine(10, 10, 150, 150, lp3);
}
Whilst in the Google maps original I have the equivalent :
public class MapOverlay extends com.google.android.maps.Overlay {
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when) {
super.draw(canvas, mapView, shadow);
Paint lp3;
lp3 = new Paint();
.....etc.
redrawOverlay is the same except the instantiation of the overlay is just:
mmapOverlay = new MapOverlay();
All suggestions will be gratefully received
UPDATE Question for kurtzmarc:
Thanks for you help so far, I see that you are one of the authors of Osmdroid. I like what it's doing so far. I would like to suppress the 'jump to and zoom in' that you get on double tap. I'd like it to do nothing at all. I think it's probably hitting this bit in your source and doing the zoomInFixing:
private class MapViewDoubleClickListener implements GestureDetector.OnDoubleTapListener {
#Override
public boolean onDoubleTap(final MotionEvent e) {
for (int i = mOverlays.size() - 1; i >= 0; i--)
if (mOverlays.get(i).onDoubleTapUp(e, MapView.this))
return true;
final GeoPoint center = getProjection().fromPixels(e.getX(), e.getY());
return zoomInFixing(center);
}
It doesn't seem that I can override it. I'm using the 3.0.1 jar and the associated javadocs. I'm wondering if the Mapview's setTouchDelegate method would help, but there is no reference to it in the javadocs. Have you any suggestions please?
I'm not sure where you are calling redrawOverlay() from, but if you look at the MinimapOverlay you will see an example where something is drawn at a fixed location on the screen. In other words, you are drawing in screen coordinates not in map coordinates.
Example:
#Override
protected void onDraw(final Canvas pC, final MapView pOsmv) {
// Calculate the half-world size
final Rect viewportRect = new Rect();
final Projection projection = pOsmv.getProjection();
final int zoomLevel = projection.getZoomLevel();
final int tileZoom = projection.getTileMapZoom();
mWorldSize_2 = 1 << (zoomLevel + tileZoom - 1);
// Find what's on the screen
final BoundingBoxE6 boundingBox = projection.getBoundingBox();
final Point upperLeft = org.osmdroid.views.util.Mercator
.projectGeoPoint(boundingBox.getLatNorthE6(), boundingBox.getLonWestE6(),
zoomLevel + tileZoom, null);
final Point lowerRight = org.osmdroid.views.util.Mercator
.projectGeoPoint(boundingBox.getLatSouthE6(), boundingBox.getLonEastE6(), zoomLevel
+ tileZoom, null);
// Save the Mercator coordinates of what is on the screen
viewportRect.set(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y);
// Offset into OSM coordinates
viewportRect.offset(-mWorldSize_2, -mWorldSize_2);
// Draw a line from one corner to the other
canvas.drawLine(viewportRect.left, viewportRect.top, viewportRect.right, viewportRect.bottom);
From here viewportRect represents the upper left to the lower right of the screen. You can use this to draw at any fixed points on the screen.
UPDATE:
To answer your second question - what you need to do is override onDoubleTap in your Overlay and return "true". Returning "true" indicates to the base class that you "consumed" the event and no further processing should take place. Take a look at the minimap overlay code for a good example:
http://code.google.com/p/osmdroid/source/browse/trunk/osmdroid-android/src/org/osmdroid/views/overlay/MinimapOverlay.java
We are right in the middle of overhauling the Overlays, so some of this will be handled a little better in the near future. For example, the getOverlays().clear() bug you ran into has also been reported elsewhere and we've since fixed it.