Objects and Interaction
You can select ViewObject
objects by using a single tap gesture. To enable this in your code, create an OnGestureListener
object and pass it to AndroidXMapFragment.getMapGesture().addOnGestureListener(OnGestureListener)
. When a single tap occurs, the listener receives the onTapEvent(PointF)
callback, and if that event is not handled, then the listener receives the onMapObjectsSelected(List<ViewObject>)
callback. The application can then define what to do with the selected ViewObject
.
Types of ViewObject
objects that are selectable are defined within the ViewObject.Type
enumeration includes the following:
-
USER_OBJECT
- an object the application adds to a map with aMapObject
base class (MapPolygon
for example). -
PROXY_OBJECT
- an object that is added automatically to a map with aMapProxyObject
base class. A proxy object may contain special information about the object depending on the type (for example,TransitStopObject
may provide transit stop related information) but it cannot be created or modified. -
UNKNOWN_OBJECT
- a selectable map object that is neitherUSER_OBJECT
norPROXY_OBJECT
.
Map Objects Example on GitHub
You can find an example that demonstrates this feature at https://github.com/heremaps/.
The ViewObject Abstract Class
The ViewObject
abstract class represents the base implementation for all objects selectable on a MapView
or AndroidXMapFragment
. The AndroidXMapFragment
features user-selectable objects.
Sub-classes of the ViewObject
class include MapObject
and MapProxyObject
.
MapObject and Geo Objects
MapObject
represents an abstract class for all map related objects that can be added on a Map
. The subclasses of this abstract class include the following:
-
MapContainer
-
MapCircle
-
MapPolyline
-
MapPolygon
-
MapRoute
-
MapMarker
-
MapLocalModel
-
MapGeoModel
-
MapLabeledMarker
-
MapScreenMarker
These objects can be created by calling the appropriate constructor methods. In some cases a geo object is required in the constructor. Geo objects (for example, GeoPolyline
and GeoPolygon
) are geographical data representations that act as models to MapObjects
, which act as views. Unlike map objects, geo objects cannot be added directly to a Map
. For more information on geo objects and creating map objects see the API Reference.
The following code snippet demonstrates how to create a MapPolyline
and a GeoPolyline
object:
List<GeoCoordinate> testPoints = new ArrayList<GeoCoordinate>();
testPoints.add(new GeoCoordinate(49.163, -123.137766, 10));
testPoints.add(new GeoCoordinate(59.163, -123.137766, 10));
testPoints.add(new GeoCoordinate(60.163, -123.137766, 10));
GeoPolyline polyline = new GeoPolyline(testPoints);
MapPolyline mapPolyline = new MapPolyline(polyline);
To add a MapObject
to the map, use Map.addMapObject(MapObject)
or Map.addMapObjects(List<MapObject>)
. You can use the setOverlayType(MapOverlayType)
method to set the display layer for the map object. By default map objects are assigned to the foreground.
MapLocalModel
or MapGeoModel
. Other map objects are not guaranteed to support 3D. MapContainer
You can use MapContainer
as a container for other MapObject
instances. Map containers determine the stacking order of objects displayed on a map. To add a map object, call the MapContainer.addMapObject(MapObject)
method.
MapRoute
and MapContainer
cannot be added to a MapContainer
. MapContainer
, it has the same MapOverlayType
as the map container. MapCircle
A MapCircle
represents a type of MapObject
in the shape of a circle with an assigned radius distance and a GeoCoordinate
center. It can be created by calling the constructor MapCircle(double radius, GeoCoordinate center)
.

MapPolyline
A MapPolyline
is a MapObject
in the shape of a polyline with anchor points at any number of GeoCoordinate
points. It can be created via a GeoPolyline
object, which can be created by calling the GeoPolyline(List<GeoCoordinate> points)
constructor.
MapPolyline
or MapPolygon
can only contain up to 65536 vertices. 
MapPolygon
A MapPolygon
is a MapObject
in the shape of a polygon. In contrast to a MapPolyline
it is assumed that the last coordinate in the line path is connected to the first coordinate thereby constructing an enclosed geometry. A MapPolygon
may have separate border and fill colors. To create a MapPolygon, use the constructor MapPolygon(GeoPolygon polygon)
. A GeoPolygon
can be created by calling GeoPolygon(List<GeoCoordinate> points)
.

MapRoute
A MapRoute
is a MapObject
that displays a calculated route on a map. For more information on MapRoute
see Routing .
MapMarker
A MapMarker
is a MapObject
that displays an icon at a geographical position on a map. You can create a MapMarker
with your own custom icon by calling MapMarker(GeoCoordinate, Image)
.

MapMarker
instances are always placed on top of other map objects. Refer to the diagram below for more information about z-index ordering for multiple map markers.

You can set MapMarker
to be draggable by using the MapMarker.setDraggable(true)
method. To listen to drag events, such as marker position changes, use MapMarker.OnDragListener
.
MapLabeledMarker
A MapLabeledMarker
is a different type of marker object that avoids overlapping with other icons and text on the map. By default the visual appearance of a MapLabeledMarker
is similar to a point of interest. You can choose a preset category icon (for example, IconCategory.ZOO
) or set your own Image
as the marker icon.

Unlike MapMarker
, setting the label text to a MapLabeledMarker
does not require enabling an info bubble. You can set the marker label text by providing a language and a localized string to the MapLabeledMarker.setLabelText(String, String)
method. The localized text in the language that matches the current Map.getMapDisplayLanguage()
is displayed (if available). Otherwise, the first added localized text is displayed.
MapLabeledMarker
is visually similar to a point of interest, its overlay type is set to FOREGROUND_OVERLAY
by default. MapLocalModel
A MapLocalModel
is an arbitrary 3D map object drawn using a local coordinate (as opposed to a geocoordinate) mesh. You can create a custom MapLocalModel
by calling MapLocalModel()
and setting the model mesh, texture, orientation, and geographical location before adding it to the map. You can set geographical location by providing a geocoordinate to the MapLocalModel.setAnchor(GeoCoordinate)
method. For example:
FloatBuffer buff = FloatBuffer.allocate(12); // Two triangles
buff.put(0- delta);
buff.put(0- delta);
buff.put(1.f);
buff.put(0 + delta);
buff.put(0 - delta);
buff.put(1.f);
buff.put(0 - delta);
buff.put(0 + delta);
buff.put(1.f);
buff.put(0 + delta);
buff.put(0 + delta);
buff.put(1.f);
// Two triangles to generate the rectangle. Both front and back face
IntBuffer vertIndicieBuffer = IntBuffer.allocate(12);
vertIndicieBuffer.put(0);
vertIndicieBuffer.put(2);
vertIndicieBuffer.put(1);
vertIndicieBuffer.put(2);
vertIndicieBuffer.put(3);
vertIndicieBuffer.put(1);
vertIndicieBuffer.put(0);
vertIndicieBuffer.put(1);
vertIndicieBuffer.put(2);
vertIndicieBuffer.put(1);
vertIndicieBuffer.put(3);
vertIndicieBuffer.put(2);
// Texture coordinates
FloatBuffer textCoordBuffer = FloatBuffer.allocate(8);
textCoordBuffer.put(0.f);
textCoordBuffer.put(0.f);
textCoordBuffer.put(1.f);
textCoordBuffer.put(0.f);
textCoordBuffer.put(0.f);
textCoordBuffer.put(1.f);
textCoordBuffer.put(1.f);
textCoordBuffer.put(1.f);
LocalMesh myMesh = new LocalMesh();
myMesh.setVertices(buff);
myMesh.setVertexIndices(vertIndicieBuffer);
myMesh.setTextureCoordinates(textCoordBuffer);
MapLocalModel myObject = new MapLocalModel();
myObject.setMesh(myMesh); //a LocalMesh object
myObject.setTexture(myImage); //an Image object
myObject.setAnchor(myLocation); //a GeoCoordinate object
myObject.setScale(20.0f);
myObject.setDynamicScalingEnabled(true);
myObject.setYaw(45.0f);
map.addMapObject(myObject);
When translating the 3D model mesh to the map a unit of 1.0f
represents 1 meter in the real world. For example, a Vector3f(100,200,300)
represents an offset of +100 meters in the x-axis (East), +200 meters in the y-axis (North), and +300 meters in the z-axis direction (Up). You can further control the size of the 3D model mesh by setting a scaling factor with the setScale()
method.

Aside from setting a texture, a MapLocalModel
can also be customized by setting its material and lighting using the Phong reflection model. For example, the following code sets the ambient color, diffuse color, and light source to the MapLocalModel
.
// This light shines from above in the Z axis
DirectionalLight light = new DirectionalLight(new Vector3f(0, 0.5f, 1));
m_model.addLight(light);
// Give this a default color
PhongMaterial mat = new PhongMaterial();
mat.setAmbientColor(0xffffffff);
mat.setDiffuseColor(0x00000000);
m_model.setMaterial(mat);
- As 3D objects consume large amounts of memory, avoid using
MapLocalModel
andMapGeoModel
to replace 2D map markers. Two examples of recommended uses of these classes are adding a few 3D structures to the map or showing a realistic car model during guidance. - If you use
MapLocalModel
to create a two-dimensional object and an anchor with an undefined or zero altitude value, there is a known rendering issue with OpenGL where parts of the object may conflict with the map layer causing the object to flicker. To get around this issue, use a z-coordinate offset that is greater than 0. For example, you can use a small floating point number such as0.001
so that the user is unable to distinguish between the object altitude and the map.
MapGeoModel
A MapGeoModel
is an arbitrary 3D map object drawn using geocoordinate vertices. You can create a MapGeoModel
by calling its constructor and setting a list of geocoordinates, a list indicating the vertex order, a list of UV coordinates, and a texture Image
. For example:
List<GeoCoordinate> myLocations = Arrays.asList(
new GeoCoordinate(37.783409, -122.439473),
new GeoCoordinate(37.785444, -122.424667),
new GeoCoordinate(37.774149, -122.429345));
// vertices must be specified in a counter-clockwise manner
IntBuffer vertIndicieBuffer = IntBuffer.allocate(3);
vertIndicieBuffer.put(0);
vertIndicieBuffer.put(2);
vertIndicieBuffer.put(1);
FloatBuffer textCoordBuffer = FloatBuffer.allocate(6);
textCoordBuffer.put(0.5f);
textCoordBuffer.put(0.5f);
textCoordBuffer.put(0.5f);
textCoordBuffer.put(0.5f);
textCoordBuffer.put(0.5f);
textCoordBuffer.put(0.5f);
GeoMesh meshy = new GeoMesh();
meshy.setVertices(myLocations);
meshy.setVertexIndices(vertIndicieBuffer);
meshy.setTextureCoordinates(textCoordBuffer);
MapGeoModel myGeoModel = new MapGeoModel();
myGeoModel.setMesh(meshy);
myGeoModel.setTexture(myTexture);
As with MapLocalModel
, you can also set the lighting and color properties for a MapGeoModel
using the addLight(DirectionalLight)
and setMaterial(PhongMaterial)
methods.

MapCartoMarker
Points of interest are represented by instances of the MapCartoMarker
proxy object class.

In the above screenshot there are four points of interests: two shops, one restaurant, and one car dealership. Each of these points of interest may be selected by tapping on the map.
The following is an example of how to retrieve point of interest information from a MapCartoMarker
:
switch (proxyObj.getType()) {
case MAP_CARTO_MARKER:
MapCartoMarker mapCartoMarker =
(MapCartoMarker) proxyObj;
Location location = mapCartoMarker.getLocation();
String placeName =
location.getInfo().getField(Field.PLACE_NAME);
String placeCategory =
location.getInfo().getField(Field.PLACE_CATEGORY);
String placePhone =
location.getInfo().getField(Field.PLACE_PHONE_NUMBER);
//...
break;
//...
default:
Log.d(TAG, "ProxyObject.getType() unknown");
}
You can extract further Point of Interest (POI) information from a cartographic marker by using Places feature in HERE SDK, since cartographic markers contain identification data that can be passed to a Place search request. For example:
if (mapCartoMarker.getLocation() != null &&
mapCartoMarker.getLocation().getInfo() != null)
{
LocationInfo info = mapCartoMarker.getLocation().getInfo();
String foreignSource = info.getField(Field.FOREIGN_ID_SOURCE);
String foreignId = info.getField(Field.FOREIGN_ID);
PlaceRequest request = new PlaceRequest(foreignSource, foreignId);
request.execute(new ResultListener<Place>() {
@Override
public void onCompleted(Place data, ErrorCode error) {
if (error == ErrorCode.NONE) {
// extract Place data
}
}
});
}
For more information about this feature see the External References section.
User Interactions with MapObject
This section provides an example of handling MapObject
tap events. In the following code:
-
addMapObject()
adds the object on the Map. -
List<ViewObject>
holds the objects that have been selected in this tap event. By looping through this list of objects your code can find theMapObject
that should respond to this tap event.
onMapObjectsSelected(List)
callback is triggered after the onTapEvent(PointF)
callback. For more information on this refer to Map Gestures.
// Create a custom marker image
com.here.android.mpa.common.Image myImage =
new com.here.android.mpa.common.Image();
try {
myImage.setImageResource(R.drawable.my_png);
} catch (IOException e) {
finish();
}
// Create the MapMarker
MapMarker myMapMarker =
new MapMarker(new GeoCoordinate(LAT, LNG), myImage);
map.addMapObject(myMapMarker);
...
// Create a gesture listener and add it to the AndroidXMapFragment
MapGesture.OnGestureListener listener =
new MapGesture.OnGestureListener.OnGestureListenerAdapter() {
@Override
public boolean onMapObjectsSelected(List<ViewObject> objects) {
for (ViewObject viewObj : objects) {
if (viewObj.getBaseType() == ViewObject.Type.USER_OBJECT) {
if (((MapObject)viewObj).getType() == MapObject.Type.MARKER) {
// At this point we have the originally added
// map marker, so we can do something with it
// (like change the visibility, or more
// marker-specific actions)
((MapObject)viewObj).setVisible(false);
}
}
}
// return false to allow the map to handle this callback also
return false;
}
...
};
The MapOverlay Class
The MapOverlay
class represents a special type of map object that does not inherit from the MapObject
base class. Instead, it provides a way for any Android View to be displayed at a fixed geographical location on the map.
You can add content to a map overlay by using the MapOverlay(View, GeoCoordinate)
constructor. If complex view contents are required, such as a view with subviews of its own, the content should be fully initialized before adding it to the map overlay.
Due to the extra performance cost of Android views it is recommended that the MapOverlay
only be used in situations where the additional functionality provided by a View
, such as a button, is needed. If the map object only needs to display a static image, use MapMarker
.
MapOverlay
does not inherit from MapObject
but overlays are returned as a MapMarker
from a tap gesture callback by default. To avoid this behavior and these substitute markers, the appropriate gesture handling must be implemented either in a MapOverlay
subclass, or in a custom view added as a subview to a standard MapOverlay
. The following code shows how to use a simple button in a MapOverlay
.
private Button button;
private void onMapFragmentInitializationCompleted() {
// retrieve a reference of the map from the map fragment
map = mapFragment.getMap();
// Set the map center coordinate to the Vancouver region (no animation)
map.setCenter(new GeoCoordinate(49.196261, -123.004773, 0.0),
Map.Animation.NONE);
// Set the map zoom level to the average between min and max (no
// animation)
map.setZoomLevel((map.getMaxZoomLevel() + map.getMinZoomLevel()) / 2);
// create the button
button = new Button(this);
button.setText("TEST");
// create overlay and add it to the map
map.addMapOverlay(
new MapOverlay(button,
new GeoCoordinate(37.77493, -122.419416, 0.0)));
}
Handling MapProxyObject objects
The following code demonstrates how to handle tap events on a MapProxyObject
:
- The
onMapObjectsSelected
event of theOnGestureListener
listens to object selected. For more information onOnGestureListener
refer to Map Gestures. - If the selected object is a
PROXY_OBJECT
, then you can safely cast theViewObject
into aMapProxyObject
. - If the selected object is a
USER_OBJECT
, then you need to find the object using the hash map; refer to the preceding example.
private MapGesture.OnGestureListener listener =
new MapGesture.OnGestureListener.OnGestureListenerAdapter() {
...
@Override
public boolean onMapObjectsSelected(List<ViewObject> objects) {
for (ViewObject obj : objects) {
switch (obj.getBaseType()) {
case PROXY_OBJECT:
MapProxyObject proxyObj = (MapProxyObject) obj;
switch (proxyObj.getType()) {
case TRANSIT_ACCESS:
TransitAccessObject transitAccessObj =
(TransitAccessObject) proxyObj;
Log.d(TAG, "Found a TransitAccessObject");
break;
case TRANSIT_LINE:
TransitLineObject transitLineObj =
(TransitLineObject) proxyObj;
Log.d(TAG, "Found a TransitLineObject");
break;
case TRANSIT_STOP:
TransitStopObject transitStopObj =
(TransitStopObject) proxyObj;
Log.d(TAG, "Found a TransitStopObject");
break;
default:
Log.d(TAG, "ProxyObject.getType() unknown");
}
break;
// User objects are more likely to be handled
// as in the previous example
case USER_OBJECT:
default:
Log.d(TAG,
"ViewObject.getBaseType() is USER_OBJECT or unknown");
break;
}
}
return true;
}
...
};