Overlays
An overlay is an element visually representing geographical information, which you can freely place on your map. The NAVER Maps SDK provides various types of overlays, such as markers, info windows and shapes. For more information, refer to the documentation of each overlay.
Add and remove overlays
Create objects
All overlays except location overlays can be created just like a general Java object.
The following code example creates a marker object.
Marker marker = new Marker();
Java
Marker marker = new Marker();
Kotlin
val marker = Marker()
You can get a location overlay object, with the locationOverlay
property of NaverMap
.
The following code example gets a location overlay object.
LocationOverlay locationOverlay = naverMap.getLocationOverlay();
Java
LocationOverlay locationOverlay = naverMap.getLocationOverlay();
Kotlin
val locationOverlay = naverMap.locationOverlay
Add overlays
All overlays except location overlays can be added to the map by specifying the map
property. For information on how to add location overlays to the map, refer to Location Overlays.
The following code example adds a marker to the map.
Besides the map
property, you can also use the open()
method, to open an info window for your map or markers.
The following code example adds an info window to a marker.
As the map
is the property of an overlay, one overlay cannot be displayed on two or more maps at the same time. If you newly set the map
property to an overlay that is already on the map, the overlay disappears from the previous map and appears on the new map.
Remove overlays
All overlays except location overlays can be removed from the map by setting the map
property to null
. For information on how to remove location overlays from the map, refer to Location Overlays.
The following code example removes a marker from the map.
Besides the map
property, you can also use the close()
method to close an info window.
The following code example closes an info window.
Multithreading
An overlay object can be created by any thread. However, since an overlay’s properties are not thread-safe, it cannot be accessed simultaneously by multiple threads. Especially the properties of an overlay added to a map should be accessed by the main thread; otherwise, CalledFromWrongThreadException
occurs. Note that the exception does not occur even if other threads access the properties of the overlay that is not added to a map.
Therefore, when handling a large number of overlays, you can use a background thread to create an object and set initial options while using the main thread only to add an overlay to the map for efficiency. The following code example creates 1,000 markers and set their properties in a background thread and adds them to the map.
Executor executor = ...
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
// Background thread
List<Marker> markers = new ArrayList<>();
for (int i = 0; i < 1000; ++i) {
Marker marker = new Marker();
marker.setPosition(...);
marker.setIcon(...);
marker.setCaptionText(...);
markers.add(marker);
}
handler.post(() -> {
// Main thread
for (Marker marker : markers) {
marker.setMap(naverMap);
}
});
});
Java
Executor executor = ...
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
// Background thread
List<Marker> markers = new ArrayList<>();
for (int i = 0; i < 1000; ++i) {
Marker marker = new Marker();
marker.setPosition(...);
marker.setIcon(...);
marker.setCaptionText(...);
markers.add(marker);
}
handler.post(() -> {
// Main thread
for (Marker marker : markers) {
marker.setMap(naverMap);
}
});
});
Kotlin
val executor: Executors = ...
val handler = Handler(Looper.getMainLooper())
executor.execute {
// Background thread
val markers = mutableListOf<Marker>()
repeat(1000) {
markers += Marker().apply {
position = ...
icon = ...
captionText = ...
}
}
handler.post {
// Main thread
markers.forEach { marker ->
marker.map = naverMap
}
}
}
Bitmap
Most overlays including markers, info windows, location overlays, ground overlays and path overlays use bitmap images. To use bitmap images for your overlays, you should create an OverlayImage
object.
Create OverlayImage objects
OverlayImage
is an immutable class representing a bitmap image that can be used as an icon. Using the factory methods defined in the OverlayImage
class, you can create an instance from Drawable resources, assets and bitmaps. The list below describes some factory methods.
fromResource()
: Creates an object from drawable resources.fromAsset()
: Creates an object from assets.fromBitmap()
: Creates an object fromBitmap
.fromView()
: Creates an object fromView
. The view is rendered as soon as the method is called, and the rendered result is saved as a bitmap.
The following code example creates an OverlayImage
object from drawable resources.
OverlayImage image = OverlayImage.fromResource(R.drawable.marker_icon);
Java
OverlayImage image = OverlayImage.fromResource(R.drawable.marker_icon);
Kotlin
val image = OverlayImage.fromResource(R.drawable.marker_icon)
Set the OverlayImage
object to the property of the overlay that needs a bitmap, and the image is reflected. For more information, refer to the documentation of each overlay.
The following code example sets a marker icon.
OverlayImage image = OverlayImage.fromResource(R.drawable.marker_icon);
marker.setIcon(image);
Java
OverlayImage image = OverlayImage.fromResource(R.drawable.marker_icon);
marker.setIcon(image);
Kotlin
val image = OverlayImage.fromResource(R.drawable.marker_icon)
marker.icon = image
Memory management
Since the OverlayImage
object handles bitmap images, you should carefully manage memory. If multiple overlays use the same image, only one OverlayImage
instance is needed.
The following code example shows a bad case where marker1
and marker2
share one bitmap image but marker3
and marker4
each have the same bitmap image.
// Good: marker1 and 2 share the same bitmap.
OverlayImage image = OverlayImage.fromBitmap(bitmap)
marker1.setIcon(image);
marker2.setIcon(image);
// Bad: marker3 and 4 each have the same bitmap.
marker3.setIcon(OverlayImage.fromBitmap(bitmap));
marker4.setIcon(OverlayImage.fromBitmap(bitmap));
Java
// Good: marker1 and 2 share the same bitmap.
OverlayImage image = OverlayImage.fromBitmap(bitmap)
marker1.setIcon(image);
marker2.setIcon(image);
// Bad: marker3 and 4 each have the same bitmap.
marker3.setIcon(OverlayImage.fromBitmap(bitmap));
marker4.setIcon(OverlayImage.fromBitmap(bitmap));
Kotlin
// Good: marker1 and 2 share the same bitmap.
OverlayImage image = OverlayImage.fromBitmap(bitmap)
marker1.icon = image
marker2.icon = image
// Bad: marker3 and 4 each have the same bitmap.
marker3.icon = OverlayImage.fromBitmap(bitmap)
marker4.icon = OverlayImage.fromBitmap(bitmap)
Note that if OverlayImage
objects are created from resources and assets, and the resource and asset represented by OverlayImage
are the same, the instances share the same bitmap even if they are different.
The following code example shows a case where marker1
, marker2
, marker3
, and marker4
share the same bitmap.
// Good: marker1 and 2 share the same bitmap.
OverlayImage image = OverlayImage.fromResource(R.drawable.marker_icon);
marker1.setIcon(image);
marker2.setIcon(image);
// OK: marker3 and 4 each use different OverlayImage objects but refer to the same resource, so they share the same bitmap.
marker3.setIcon(OverlayImage.fromResource(R.drawable.marker_icon));
marker4.setIcon(OverlayImage.fromResource(R.drawable.marker_icon));
Java
// Good: marker1 and 2 share the same bitmap.
OverlayImage image = OverlayImage.fromResource(R.drawable.marker_icon);
marker1.setIcon(image);
marker2.setIcon(image);
// OK: marker3 and 4 each use different OverlayImage objects but refer to the same resource, so they share the same bitmap.
marker3.setIcon(OverlayImage.fromResource(R.drawable.marker_icon));
marker4.setIcon(OverlayImage.fromResource(R.drawable.marker_icon));
Kotlin
// Good: marker1 and 2 share the same bitmap.
val image = OverlayImage.fromResource(R.drawable.marker_icon)
marker1.icon = image
marker2.icon = image
// OK: marker3 and 4 each use different OverlayImage objects but refer to the same resource, so they share the same bitmap.
marker3.icon = OverlayImage.fromResource(R.drawable.marker_icon)
marker4.icon = OverlayImage.fromResource(R.drawable.marker_icon)
If too many bitmap images are used for the map to handle, the map rendering becomes very slow with a log message saying "Overlay image atlas overflow" in Logcat. And if the memory usage is too high, the process will be terminated because of out of memory (OOM).
Stacking order of overlays
When multiple overlays are overlapped on the screen, an overlay with a higher stack order is displayed on top of those with lower stack orders. The stack order is specified depending on the type of an overlay by default, but can be changed.
Global z-index
The globalZIndex
property specifies the stack order of an overlay. If globalZIndex
is 0
or bigger, the overlay is drawn on top of symbols; if the property is smaller than 0
, it is drawn beneath symbols. Note that an overlay is always drawn on top of the map background no matter how small globalZIndex
is. The default globalZIndex
values for each overlay type are as follows.
- Info window:
400000
- Location overlay:
300000
- Marker:
200000
- Arrowhead path overlay:
100000
- (Map symbols)
- Path overlay:
-100000
- Shape (polygon, polyline, circle):
-200000
- Ground overlay:
-300000
- (Map background)
For example, a path is drawn on top of a shape, and beneath a symbol on the map by default. However, if the globalZIndex
property of a path is set to 250000
, it is drawn on top of markers and beneath a location overlay.
The following code example specifies the stacking order of three overlays, as polygon -> path -> marker.
polygon.setGlobalZIndex(150000);
path.setGlobalZIndex(50000);
marker.setGlobalZIndex(-50000);
Java
polygon.setGlobalZIndex(150000);
path.setGlobalZIndex(50000);
marker.setGlobalZIndex(-50000);
Kotlin
polygon.globalZIndex = 150000
path.globalZIndex = 50000
marker.globalZIndex = -50000
Local z-index
The zIndex
property specifies the stack order of overlays with the same globalZIndex
. If two overlays have the same globalZIndex
value, an overlay with the higher zIndex
is displayed on top of the other. For example, even if the zIndex
of a marker is set to 1
, and the zIndex
of a ground overlay is set to 2
, the marker is drawn on top of the ground overlay because the marker’s default globalZIndex
is 200000
, and that of the ground overlay is -300000
. Since the default value of the zIndex
property is 0
regardless of the type of an overlay, zIndex
can be used more intuitively than globalZIndex
to specify the stack order of overlays with the same type.
The following code example specifies the stacking order of three markers as yellow -> green -> blue.
yellowMarker.setZIndex(100);
greenMarker.setZIndex(0);
blueMarker.setZIndex(-10);
Java
yellowMarker.setZIndex(100);
greenMarker.setZIndex(0);
blueMarker.setZIndex(-10);
Kotlin
yellowMarker.zIndex = 100
greenMarker.zIndex = 0
blueMarker.zIndex = -10
Show and hide overlays
All overlays have the visibility and maximum/minimum zoom level properties. To hide an overlay temporarily or in a certain situation, use these properties, rather than the map
property.
Visibility
Set isVisible
to false
to hide an overlay. The relation between the overlay and the map still remains the same.
The following code example hides an overlay.
overlay.setVisible(false);
Java
overlay.setVisible(false);
Kotlin
overlay.isVisible = false
Minimum and maximum zoom levels
Use minZoom
and maxZoom
to show an overlay at a specified zoom level. If the camera’s zoom level is out of the range between the minZoom
and the maxZoom
, the overlay is hidden.
The following code example sets an overlay to be shown only at the levels, between 12 and 16.
overlay.setMinZoom(12);
overlay.setMaxZoom(16);
Java
overlay.setMinZoom(12);
overlay.setMaxZoom(16);
Kotlin
overlay.minZoom = 12.0
overlay.maxZoom = 16.0
Event
All overlays can receive and consume click events. A click event listener for overlays should be added to each overlay, not the map.
Click event
Add Overlay.OnClickListener
with the setOnClickListener()
method to receive a click event for the overlay. When the overlay is clicked, the onClick()
callback method is called with the clicked overlay object passed as a parameter.
The following code example adds a click event listener to display a toast message saying “Overlay is clicked” whenever an overlay is clicked.
overlay.setOnClickListener(o -> {
Toast.makeText(context, "Overlay is clicked", Toast.LENGTH_SHORT).show();
return true;
});
Java
overlay.setOnClickListener(o -> {
Toast.makeText(context, "Overlay is clicked", Toast.LENGTH_SHORT).show();
return true;
});
Kotlin
overlay.setOnClickListener { o ->
Toast.makeText(context, "Overlay is clicked", Toast.LENGTH_SHORT).show()
true
}
Only one click event listener can be added to an overlay. To remove the click event listener, set the onClickListener
property to null
.
The following code example removes the click event listener of an overlay.
overlay.setOnClickListener(null);
Java
overlay.setOnClickListener(null);
Kotlin
overlay.onClickListener = null
An event listener should be added to every overlay which needs to receive events. If an overlay has no event listener added, a click on the overlay is ignored. For example, if there are two overlays overlapped with each other and the one on top of the other does not have an event listener added, the other one receives a click event. If there is no overlapped overlay or an event listener is not added, it is considered that the map is clicked.
Propagate and consume events
An overlay click event can be propagated to the map. To propagate the event to the map, you should make Overlay.OnClickListener
’s onClick()
return false
. After the onClick()
returns false
, the OnClickListener.onClick()
of the map is called. On the contrary, if the onClick()
returns true
, it is considered that the symbol consumes the event and thus the map’s OnClickListener.onClick()
is not called.
In the following code example, marker1
propagates click events and marker2
consumes them. Whereas both toast messages, “Marker is clicked” and “Map is clicked” are displayed when the marker1
is clicked, only the toast message, “Marker 2 is clicked” is displayed when the marker2
is clicked.
marker1.setOnClickListener(overlay -> {
Toast.makeText(context, "Marker 1 is clicked", Toast.LENGTH_SHORT).show();
// Propagates the event.
return false;
});
marker2.setOnClickListener(overlay -> {
Toast.makeText(context, "Marker 2 is clicked", Toast.LENGTH_SHORT).show();
// Consumes the event.
return true;
});
naverMap.setOnMapClickListener((point, coord) -> {
Toast.makeText(context, "Map is clicked", Toast.LENGTH_SHORT).show();
});
Java
marker1.setOnClickListener(overlay -> {
Toast.makeText(context, "Marker 1 is clicked", Toast.LENGTH_SHORT).show();
// Propagates the event.
return false;
});
marker2.setOnClickListener(overlay -> {
Toast.makeText(context, "Marker 2 is clicked", Toast.LENGTH_SHORT).show();
// Consumes the event.
return true;
});
naverMap.setOnMapClickListener((point, coord) -> {
Toast.makeText(context, "Map is clicked", Toast.LENGTH_SHORT).show();
});
Kotlin
marker1.setOnClickListener {
Toast.makeText(context, "Marker 1 is clicked", Toast.LENGTH_SHORT).show()
// Propagates the event.
false
}
marker2.setOnClickListener {
Toast.makeText(context, "Marker 2 is clicked", Toast.LENGTH_SHORT).show()
// Consumes the event.
true
}
naverMap.setOnMapClickListener {
Toast.makeText(context, "Map is clicked", Toast.LENGTH_SHORT).show()
}
Overlays can propagate an event only to the map. That is, even if there are multiple overlays or symbols overlapped under the overlay that triggers an event, it is not propagated to those overlays or symbols.
Tag
The tag
property specifies additional information for an overlay. This property is useful especially when combined with a click event listener. Since you can use the tag to check which overlay is clicked in the onClick()
method, you can let multiple overlays share an event listener.
The following code example adds the tag property to marker1
and marker2
to share a click event listener.
Overlay.OnClickListener listener = overlay -> {
Toast.makeText(context, "Marker " + overlay.getTag() + " is clicked",
Toast.LENGTH_SHORT).show();
return false;
};
marker1.setTag(1);
marker2.setTag(2);
marker1.setOnClickListener(listener);
marker2.setOnClickListener(listener);
Java
Overlay.OnClickListener listener = overlay -> {
Toast.makeText(context, "Marker " + overlay.getTag() + " is clicked",
Toast.LENGTH_SHORT).show();
return false;
};
marker1.setTag(1);
marker2.setTag(2);
marker1.setOnClickListener(listener);
marker2.setOnClickListener(listener);
Kotlin
val listener = Overlay.OnClickListener { overlay ->
Toast.makeText(context, "Marker ${overlay.tag} is clicked",
Toast.LENGTH_SHORT).show()
false
}
marker1.tag = 1
marker2.tag = 2
marker1.onClickListener = listener
marker2.onClickListener = listener