Making Custom Overlays
** Notice: This article is still being written and targets osmdroid v6.0.0 and higher**
An overlay is similar to a paper map with acetate overlay on top of it. Overlays are responsible for drawing/rendering content on the screen (what you see on an Android device). This article describes some common pitfalls, coordinate systems, and common procedures that you will need for creating a custom overlay. This is an advanced topic and care must be taken to optimize performance.
In your favorite IDE or text editor, make a new class that extend the class org.osmdroid.views.overlay.Overlay
. It will make you implement the following method:
@Override
public void draw(Canvas canvas, MapView map, boolean shadow) {
if (!isEnabled()) return;
if (shadow) {
//draw a shadow if needed, otherwise return
return;
}
//draw your stuff here
}
First of all, the draw cycle happens on the UI thread. It's the only thread that's allowed to manipulate the user interface in an android application. Optimization is import for rendering speeds.
The Draw Cycle is what we (osmdroid) refer to as the process of rendering the map on screen. When one of the following conditions occurs, the draw cycle will start.
-
MapView#invalidate
is called - The zoom level changes
- The map's view port changes (panning, rotation)
- Android life cycle events that cause invalidate to occur
The Overlay#draw
method is called twice on every draw cycle. Once for the shadow
and once for the overlay
itself.
As you can image, this happens frequently.
Static elements UI do not move with the map panning, zooming or rotation. This can be used for maps controls, minimaps, etc, however custom UI elements are often best implemented using android layouts, buttons, widgets, etc. But if you need them map integrated, it's completely feasible.
Here's an example taken from CopyrightOverlay
.
Paint paint = new Paint();
....
map.getProjection().save(canvas, false, false);
//draw here
canvas.drawText(map.getTileProvider().getTileSource().getCopyrightNotice(), x, y, paint);
map.getProjection().restore(canvas, false);
This draws at the on screen pixel coordinate point of x,y using the paint
object's styling.
These elements scale on zoom, rotate with rotation, and pan with the map as if they are anchored to it.
Assuming your "stuff to draw on screen" has some kind of geo point associated with it, the first thing you'll probably need to do is to figure out if your stuff needs to be drawn on screen.
final Projection pj = mapView.getProjection();
The Projection
class is super important and provides the ability to convert to/from
- Integer Screen pixel coordinates
- Long Canvas coordinates
- Double Latitude/Longitude coordinates
Most if the time, you'll need some code that looks like this:
canvas.save();
//draw here
canvas.restore();
This will draw your stuff oriented in the same direction as the map (osmdroid can rotate the map so that north is in any direction needed).
This is required for releasing resources. This happens when
- Your overlay is removed from the map view
- When the map view is destroyed
This happens when
- MapView#onPause() is called
- MapView#onResumse() is called
The Overlay
class has a whole bunch of methods you can override in order to support different types of user input, such as touch, long press, short press, mouse actions, scrolling, etc.
It is often that you may want to perform some kind of "hit test" in your code, specifically on press/tap events. This is useful for when a user clicks on your map "thing". For non-static elements, you'll want to take the user point Point
, which is on screen pixel coordinates, then use the Projection
class's methods to convert the Point
to a GeoPoint
then make your own comparisons in order to determine if your overlay should handle the event.