Skip to content

Making Custom Overlays

spyhunter99 edited this page Jan 27, 2018 · 4 revisions

** Notice: This article is still being written and targets osmdroid v6.0.0 and higher**

Making Custom Overlays

Introduction

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.

Hello World of Overlays

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
}

Understanding the Draw cycle

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.

Drawing Static UI elements

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.

Drawing geospatially referenced elements

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).

Handling Android Lifecycle Events

onDetach

This is required for releasing resources. This happens when

  • Your overlay is removed from the map view
  • When the map view is destroyed

onPause and onResume

This happens when

  • MapView#onPause() is called
  • MapView#onResumse() is called

Handing user input

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.