It seems that markers in an ItemizedOverlay are not shown in the map unless you call boundCenter() or boundCenterBottom() on the default marker.
Is this correct, and if so, why? Is it that a (0,0) point is not set at all by default, and thus Android has no idea how to place the markers?
Update:
I see that you also have Drawable.setBounds(), so I assume boundCenter() and boundCenterBottom() is calling this method. How is it decided which part of the Drawable is used as the pin point on the map?
See this example of how to use the boundCenter()
I believe for the boundCenter() call to work, your Drawable should have some intrinsic width and height. I'm guessing it works something like this:
public static Drawable boundCenter(Drawable d)
{
d.setBounds(d.getIntrinsicWidth() /- 2, d.getIntrinsicHeight() / -2,
d.getIntrinsicWidth / 2, d.getIntrinsicHeight() / 2);
return d;
}
This offsets the bounds from Top/Left, to Bottom/Center.
You must set the BOUNDS in some fashion if you wish them to appear. It doesn't matter which method you use, but if there are no bounds on your drawable, its bounds are 0,0,0,0 or something like that, and you will see nothing.
Related
I'm trying to set the user location on the map such that it sits about 1/3 of the way up from the bottom of the screen, and when the map rotates, it will rotate around this point.
The closest I've got to achieving this is by using the setPadding() method, however, this causes the map to sort of shake when rotated, as the center point sort of 'floats' around where it actually should be. It looks quite ugly
int mapHeight = mapView.getHeight();
googleMap.setPadding(0, mapHeight / 5, 0, 0);
Is there a better way to do this?
Edit: Explained in picture below
You don't need paddings
Change mappoint X and Y values as you need you can call this where you want! may be inside your onLocationChanged like changeOffsetCenter(location.getLatitude(),location.getLongitude());
public void changeOffsetCenter(double latitude,double longitude) {
Point mappoint = mGoogleMap.getProjection().toScreenLocation(new LatLng(latitude, longitude));
mappoint.set(mappoint.x, mappoint.y-100); // change these values as you need , just hard coded a value if you want you can give it based on a ratio like using DisplayMetrics as well
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(mGoogleMap.getProjection().fromScreenLocation(mappoint)));
}
output :
Google map v3 beta seems to fix it, using padding now properly move pivotX/pivotY for rotation
https://developers.google.com/maps/documentation/android-sdk/v3-client-migration
Accepted answer might be work of "animateCamera". Its makes "shaking of rotations" almost invisible. So more easy will be using
mMap.setPadding(leftPx, topPx, rightPx, bottomPx)
with mMap.animateCamera
or twice mMap.moveCamera(in case of changing bearing
1nd moveCamera rotate with center of device, 2nd moveCamera make correct center using padding)
Its kind of hack, while google do not fix rotation considering setPadding
Suppose I have six points drawn in a Canvas along the circumference of a circle, in the pattern of a hexagon.
I want to simultaneously move and re-draw each of these six points in a small circular path - for example, each point moves along the circumference of a circle with 1/10th the radius of the larger circle.
I'm a little lost on how to do this with Canvas and onDraw and I don't know if better solutions exist. How would you do this?
Some answers have at least pointed me toward this which shows how a point might move along a circular path, but I don't know how to implement it for this situation:
for (double t = 0; t < 2*Pi; t += 0.01)
{
x = R*cos(t) + x_0;
y = R*sin(t) + y_0;
}
Thank you!
Here's one approach:
Start with a custom view that extends View and overrides onDraw. You are on the right track with using the drawing functions of Canvas.
Give your custom view a field to hold the current angle:
private float mTheta;
Then add a method like:
public void setTheta(float radians) {
mTheta = radians;
invalidate();
}
Then in onDraw, use the current value of mTheta to calculate the position of your points.
Of course, with the custom view you might need to handle sizing with an onMeasure override and possibly some layout with an onLayout override. If you set the dimensions of the view to an absolute dp value, the default behavior should work for you.
Doing it this way will set you up to override onTouch and allow user interaction to move the graphics, or use a ValueAnimator to cycle from 0 to 2π calling setTheta from within your AnimatorUpdateListener.
Put some code together and when you get stuck, post another question. If you add a comment to this answer with a link to the new question, I'll take a look at it.
I have a piece of code where I am displaying some pins (Button with an image) on an image (full screen ImageView). (You can assume that all the pins are created dynamically and have a random position). The requirement is that those pins should not overlap. For each pin created I am checking if it overlaps with any of the other previously created pins.
To do that I am trying to get the Rect of those pins and check if they overlap using Rect.intersects().
The issue is that I cannot use functions like getRight(), getTop(), getWidth(), getHeight() before the view is actually displayed. They all return 0. So I cannot get the correct data for the rectangles.
I tried to put the code in different callbacks like onWindowFocusChanged() or onResume() but I still got the same issue, all dimensions/positions return 0.
I am looking for a solution/advice regarding this problem. How to get the correct positions and dimensions before the pins are displayed ?
I looked at View.measure(), it seems I can get some values using getMeasuredWidth() and getMeasuredHeight() but getRight() and getTop() still return 0.
Add invisible rect first and check the position then move this position as per requirements and the make this visible. This will do the trick.
I have a MapView, with various markers on it. On entering the MapActivity the first time, I set the bounds of drawables set on the markers, and everything appears fine. The markers and shadows all appear correctly. But when I click over to another activity, and return, the shadows, or the markers are no longer bound correctly. Sometimes its only some of the markers that are affected. Can anyone tell me what is going on here? Here is some code. Below is where I set the bounds on the marker drawable:
InputStream is = assetManager.open(imageName);
drawable = Drawable.createFromStream(is, null);
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
drawable.setBounds(-width / 2, -height, width - (width / 2), 0);
And here is how I create/add the overlay item to the map:
GeoPoint point = createGeoPoint(lat, lon);
OverlayItem overlayItem = new OverlayItem(point, character.get_id(), "");
Drawable image = drawable;
overlayItem.setMarker(image);
itemizedOverlay.addOverlay(overlayItem);
From what I can tell, the overlays are not being re-added to the map, this is simply a redraw after an onResume() event. Any ideas?
Update: I've actually figured out, only images of the type tapped move, and its not the shadow, but the image that moves. So, of there are x images of type A, and y images of type B, and I tap on any image of type A, all images of type A are misaligned with their shadows when I return to the MapActivity, while all images of type B are still properly aligned.
Another update: I am outputting the bounds to the log, and see that the bounds are changing after returning to the map screen. When the marker is initially added, its bounds are:
[Rect(-25, -48 - 25, 1)]
But when returning to the map screen, the bounds have changed to:
[Rect(0, 0 - 50, 49)]
...why would this be?
Yet another update: I have a workaround... but I would still like an answer as to why this is happening. The workaround is to override the draw method, and set the bounds (to center bottom) whenever the draw method is called. Here is the code:
#Override
public void draw(Canvas canvas) {
int dWidth = getIntrinsicWidth();
int dHeight = getIntrinsicHeight();
setBounds(-dWidth / 2, -dHeight, dWidth / 2, 0);
super.draw(canvas);
}
I found out what the problem was. You can see from the code in the question, I am reading in BitmapDrawables from an InputStream. To reduce waste, I put all images created in a flyweight and reuse them when I can. That means, when I put 3 'sunshines' on the map, all three are based on the same image. In addition, when I place them on the map via an ItemizedOverlay, I am calling boundCenterBottom() so the shadow will display in the correct place.
When I open a different Activity, that Activity has an ImageView that I was populating with the same image. Turns out, that ImageView must have been resetting the bounds. I know this because, after overriding the draw() method, and setting the bounds on every draw, I was no longer able to see the images in the ImageViews. When I comment out the overridden draw() method, I am able to see the images in the ImageViews, but the images are shifted when I return to the map. This tells me that adding the image to the ImageView must be updating the bounds.
My solution is to create two distinct images for each image type; one for the map, and one for the ImageViews on the other Activities. I can still put them in the flyweight, but they have separate keys so multiple image instances can exist for the same image.
Hope this helps someone. I know there was another question of StackOverflow about this, but I can't find it to link to or to answer.
Hello i am using a resized version of this marker( http://www.clker.com/clipart-orange-pin-4.html ) for showing markers in google maps on android.
The problem is i don't know how to make the marker point match the coordinates.
The arrow point is at about 1/5 of the Width coordinates and MAX of the Height.
here is my class
public class GestionaleItemizedOverlay extends com.google.android.maps.ItemizedOverlay {
public GestionaleItemizedOverlay(Drawable defaultMarker, Context context) {
//super(boundCenterBottom(defaultMarker));
super(boundCenter(defaultMarker));
this.mContext = context;
}
...
And this
this.marker_poi = this.getContext().getResources().getDrawable(R.drawable.marker);
this.marker_poi.setBounds(this.marker_poi.getIntrinsicWidth() / 2, this.marker_poi.getIntrinsicHeight(), this.marker_poi.getIntrinsicWidth() / 2, 0);
new GestionaleItemizedOverlay(this.poi, this.context);
Do i need to setBounds on the marker before passing it to the constructor? and why does super(defaultMarker) makes all the markers not to show ?
The previous answer is right, you need to play with the BOUNDS value of your marker.
As I am sure you know the bounding rectangle determines the size of the object... The marker on your map is going to lay itself out with upper left coordinate of your marker at the GPS coordinate if you just would call a normal setbounds on the size of your image.
What you need to do is modify the bounds on your image so that the part of the image you wnat is over the point on the map you want.
So if your resized image is say 20 x 20, and your actual arrow tip (assuming the image is an arrow, and you want it lined up exactly with the point on the map) is at say X=4 and Y=10, you need to modify the bounds of your image accordingly to "move" the image where you want it.
Since 0,0 would put the image 4 pixels to the right, and 10 pixels below the actual point on the map you associate it with, your bounds should not be 0,0,X,Y but should be -4,-10,X size of image-4,Y size of image-10 (in this exampe case the xsize of image and ysize of image are both 20, but should use the values appropriate for your case.)
Yes you need to setBounds but you can do it in the constructor, this is what I do in the constructor to set it to the left bottom corner:
public class CustomOverlay extends ItemizedOverlay<CustomOverlayItem> {
public CustomOverlay(Drawable defaultMarker, Context context) {
super(defaultMarker);
defaultMarker.setBounds(0, -defaultMarker.getIntrinsicHeight(), defaultMarker.getIntrinsicWidth(), 0);
}
You'll need to add a little extra to the left side of the bounds to make center point at the right position. You should remember this is set in px so make some kind of DP converter so it is set properly for your different images for each screen size.
About the second question, you'll need a context in order to know where to add the overlay. Without the context you just create your overlay without giving it any reference to where it should be used (you could add this later if you wanted to).