I have a MapView (provided by Google Maps Android API v2) and what I'm trying to achieve should be simple enough, which is simply to draw a curved Polyline.
To be specific, I have an array of LatLngs and rather than having them joined at sharp angles, I want to have the route rounded off nicely, so that the line through the points follows a curve rather than straight lines and sharp angles.
Now, this used to be possible in the old Google Maps API by creating a custom Overlay, overriding draw(), and then manually drawing onto the map (e.g. with a custom Paint and Path with the desired settings).
Unfortunately it seems that in v2, Google have removed the Overlay class and moved to higher-level abstractions which no longer provide access to the draw() method. PolylineOptions is fairly basic and doesn't provide any option to draw a curved line.
Is there any way to override draw() or use other features of Google Maps API v2 in order to draw a curved Polyline?
There are a few questions already on SO which cover this issue, however there isn't really a satisfactory answer as yet:
Custom Overlays in Google Maps API v2
Overrinding draw() in customized MapView in Google Maps Android API v2
I'm sure there must be a way to do custom drawing on Google Maps v2, and whilst creating a custom overlay View and drawing onto that once the coordinates are synced up with the map is an option, it will quickly get extremely complicated when dealing with scaling and panning the map, so it's something I want to avoid if at all possible.
I have developed an abstract class CanvasTileProvider() where you just have to override the onDraw method, in order to perform your drawing as usual into a Canvas. A TileProjection object, which is passed into the onDraw method in addition, helps you to do the back and forth calculation between LatLng and points on the Canvas.
The only limitation is, that tiles are usually loaded only once. So this way of drawing into the map is suitable for shapes which do not frequently change. Thus it may not be suitable if your array of LatLng objects is continuously changing (e.g. because it shows the current movement of the device).
You can find the CanvasTileProvider class in the answer to this SO question
Related
Background: I want to draw several Polygons on a map (few thousand coordinates in all). This worked pretty fast on Google Maps V1 by Overlays. But Google Maps V2 seems to be ineligible for that.
First of all I tried to add polygons directly to the map by
googleMap.addPolygon(myPolygonOptions);
but this is not just unusable slow, it seems to be buggy too, because it always forgets some polygons.
Then I tried to draw the polygon on an invisible view placed above the map, by drawing paths. But the method
projection.toScreenLocation(geoCoordinate);
is a joke to its "toPixels" Google Maps V1 counterpart. Where Google Maps V1 takes 1 second, Google Maps V2 takes 21(!) seconds, so this is unusable too.
Then I thought about giving Overlays a try. Ground overlays seems to be what I'm looking for:
A ground overlay is an image that is fixed to a map. Unlike markers,
ground overlays are oriented against the Earth's surface rather than
the screen, so rotating, tilting or zooming the map will change the
orientation of the image. Ground overlays are useful when you wish to
fix a single image at one area on the map.
But then I read a comment in this posting that it is not performant too and doesn't even work well.
So the last hope are Tile Overlays. The question is: What happens with tile overlays when I rotate the map. Do they change their orientation too or will they stay oriented as loaded?
[UPDATE]
I tried GroundOverlays and they are pretty fast, even on old Smartphones, so I will choose this approach.
The tile will be rotated together with the map. The TileProvider will not get aware of the rotation at all. While drawing the tile is always oriented north up. You may have a look at the answer to this SO question for a very handy tile provider: Google Maps API v2 draw part of circle on MapFragment
Very simple question : since MapView inherits from View, is it possible to override draw() to draw whatever you want on the map ?
No, but you can use polylines, polygons, circles. If that's not enough you can put any bitmap (even one you draw to using Canvas) combined with ground overlay. If that's not enough, you can also use tile overlay to draw on entire map efficiently.
It's all there in the documentation, I encourage you to study.
Drawing directly can be always done on a view that overlaps with map, but it won't scroll with map nicely, so better to use technics above.
Drawing directly on the map is impossible, because it doesn't happen in your process afaik.
In the original version of the Android Google Maps API it was very easy to implement an overlay with the following code:
List<Overlay> mapOverlays = mapView.getOverlays();
AlarmOverlay alarmOverlay = new AlarmOverlay();
mapOverlays.add(alarmOverlay);
...it was then possible to override the overlays draw() method and paint vector graphics, override the overlays onTouchEvent() method and give custom controls, etc.
I am at a loss as to how to architect similar custom controls in v2, as the use-case for overlays is not mentioned in the API reference (and markers and polygons are not enough). Does anyone have a suggested way of implementing in v2?
If you need to place your own image on the surface of the earth, use GroundOverlay. The method addGroundOverlay adds such image. It takes GroundOverlayOptions that allow to specify the image size and location (in lat long terms) and also BitmapDescriptor that, among other options, can use the ordinary Bitmap as the image source. So you can create a new Bitmap, create Canvas around this bitmap and paint there.
Seems a good approach if you need to draw something really complex, something for that polygons and markers are not sufficient. Also, the old code that draws on Canvas probably can be reused.
I have not done enough testing how soon the map will be updated after we update the bitmap. In the worst case, maybe the ground overlay needs to be removed and the new ground overlay added. The bitmap itself probably still can be reused.
Putting additional component on the top may be problematic as it must support zooming, moving around and the map is now even 3D.
I have an app that use the old google map API and add a layer over the map to display a more precise map of my own over the map.
I'm trying to do this in the API v2 using the TileOverlay but the text of the google map are displayed over my tiles.
Here are 2 screenshots, one with the map, and one with the map with an overlay (just based on the API demo)
I tried to add a big Z-Index to the tiles without any results.
Is there any way to really cover the map with custom tiles ?
The reason why you keep seeing the labels, is that in google maps v2 the labels are rendered locally instead of being part of tile bitmaps. The benefit of this, is that you can rotate the map and still have the labels without rotation for easy reading.
Solution
The only solution I know so far is to disable the map base layer using setMapType(MAP_TYPE_NONE). However, this may have the undesireble effect of also disabling parts of the map that are not being covered by your overlay.
Regards.
In android, is it possible that I would create my own Map figure, and then use this Map with the gps location from Google Map API
Example, I draw a map for my own house, then apply Google Map API to be able to make the location of each point in the map
Yes, I believe you can. A couple of options are as follows:
Draw your 'map figure' in an overlay - if the background is translucent, then you'll be able to see the Google map underneath.
Alternatively, use a dummy Google maps API key - in this case the MapView layer is rendered as a grey background but all the API calls appear to work. Again render your 'map figure' in the Overlay draw method.
In both cases, you'll have to ensure the map projection (scale, position, etc) match up with the coordinates of your 'map figure', especially if you scroll or zoom the map view.
It might be best going with the first option, initially, then you'll have a visual confirmation if you're code is correct.