Adjust the map view
The Maps SDK for Android provides multiple ways to modify the map view, center on coordinates or areas, including MapView functionality for exploring different perspectives.
The SDK enables a range of features, including zooming in and out, tilting the camera, centering on specific locations, and more, all through the MapView and MapViewPreferences classes provided by the SDK.
- Use
viewportproperty to return the current viewport of the map view. - Center on specific coordinates with
centerOnCoordinateswhich takes extra parameters for centering preferences such as zoom level, screen position, map angle, animation and more. - Center on a specific geographic area represented by a rectangle with coordinates as corners with
centerOnAreaandcenterOnRectArea. - Align map according to the north direction by using
alignNorthUp. - Adjust the current zoom level using
setZoomLevel, where lower values result in a more zoomed-out view. - Perform a scrolling behavior based on horizontal and vertical scroll offsets with
scrollmethod. MapCameraclass provides further functionality such as manipulating orientation, position, and state.
Map viewport
The map viewport refers to the area displayed by the MapView. Getting the current viewport provides a Rect object which consists of x, y (left and top) screen coordinates and width and height.
The top left coordinate of the screen is represented by [0, 0] and bottom right [viewport.width, viewport.height].
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val currentViewport = mapView?.viewport
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
Rect currentViewport = mapView != null ? mapView.getViewport() : null;
This viewport can be useful when you need to use methods such as centerOnRectArea.
The width and height of the map view is measured in physical pixels. To transform them into logical pixels you may need to consider the device's pixel density.
Map centering
Map centering can be achieved using the centerOnCoordinates, centerOnArea, centerOnRectArea, centerOnRoute, centerOnDistRoute, centerOnRouteInstruction, centerOnRouteTrafficEvent methods.
Map centering on coordinates
In order to center the WGS coordinates on the viewport coordinates you can use the centerOnCoordinates method like so:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
mapView?.centerOnCoordinates(Coordinates(45.0, 25.0))
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
if (mapView != null) {
mapView.centerOnCoordinates(new Coordinates(45.0, 25.0));
}
A linear animation can be incorporated while centering, as demonstrated below:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
mapView?.centerOnCoordinates(
Coordinates(52.14569, 1.0615),
animation = Animation(EAnimation.Linear, 2000)
)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
if (mapView != null) {
mapView.centerOnCoordinates(
new Coordinates(52.14569, 1.0615),
new Animation(EAnimation.Linear, 2000)
);
}
You can call the skipAnimation() method of MapView to bypass the animation. To check if an animation is in progress the isAnimationInProgress() method can be used. To check if the camera is moving (as a consequence of an animation or not), the isCameraMoving() method can be used.
Do not confuse the zoomLevel with the slippyZoomLevel. The slippyZoomLevel is a value linked with the tile system.
Converting between screen and WGS coordinates
In order to convert a screen position to WGS coordinates, the MapView.transformScreenToWgs() method is used:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val coordsToCenter = mapView?.transformScreenToWgs(Xy(pos.x, pos.y))
coordsToCenter?.let {
mapView?.centerOnCoordinates(it, zoomLevel = 70)
}
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
Coordinates coordsToCenter = mapView != null ? mapView.transformScreenToWgs(new Xy(pos.x, pos.y)) : null;
if (coordsToCenter != null && mapView != null) {
mapView.centerOnCoordinates(coordsToCenter, 70);
}
If the applied style includes elevation and terrain data is loaded, the transformScreenToWgs method returns Coordinates objects that include altitude.
To convert WGS coordinates to screen coordinates, the MapView.transformWgsToScreen() method is used:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val wgsCoordinates = Coordinates(8.0, 25.0)
val screenPosition = mapView?.transformWgsToScreen(wgsCoordinates)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
Coordinates wgsCoordinates = new Coordinates(8.0, 25.0);
Xy screenPosition = mapView != null ? mapView.transformWgsToScreen(wgsCoordinates) : null;
In order to convert a screen rectangle to a list of WGS geographic areas, use MapView.transformScreenToWgsListArea method.
This centers the view precisely on the specified coordinates, positioning them at the cursor position (which by default is in the center of the screen).
Map centering on coordinates at given screen position
To center on a different area of the viewport (not the cursor position), provide an xy parameter, represented as an Xy. Note that x coordinate should be in [0, viewport.width] and y coordinate between [0, viewport.height].
The xy parameter is defined in physical pixels.
The following example demonstrates how to center the map at one-third of its height:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val physicalHeightPixels = mapView?.viewport?.height ?: 0
val physicalWidthPixels = mapView?.viewport?.width ?: 0
mapView?.centerOnCoordinates(
Coordinates(52.48209, -2.48888),
zoomLevel = 40,
xy = Xy(physicalWidthPixels / 2, physicalHeightPixels / 3)
)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
int physicalHeightPixels = mapView != null && mapView.getViewport() != null ? mapView.getViewport().getHeight() : 0;
int physicalWidthPixels = mapView != null && mapView.getViewport() != null ? mapView.getViewport().getWidth() : 0;
if (mapView != null) {
mapView.centerOnCoordinates(
new Coordinates(52.48209, -2.48888),
40, // zoomLevel
new Xy(physicalWidthPixels / 2, physicalHeightPixels / 3)
);
}
More parameters such as animation, mapAngle, viewAngle and zoomLevel can be passed to the method in order to achieve a higher level of control.
Map centering on area
Centering can be done on a specific RectangleGeographicArea which consists of top left and bottom right coordinates.
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val topLeftCoords = Coordinates(44.93343, 25.09946)
val bottomRightCoords = Coordinates(44.93324, 25.09987)
val area = RectangleGeographicArea(topLeftCoords, bottomRightCoords)
mapView?.centerOnArea(area)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
Coordinates topLeftCoords = new Coordinates(44.93343, 25.09946);
Coordinates bottomRightCoords = new Coordinates(44.93324, 25.09987);
RectangleGeographicArea area = new RectangleGeographicArea(topLeftCoords, bottomRightCoords);
if (mapView != null) {
mapView.centerOnArea(area);
}
This will center the view on the geographic area ensuring the RectangleGeographicArea covers most of the viewport. For centering the geographic area on a particular coordinate of the viewport, the xy parameter, represented as an Xy should be provided.
Alternatively, to center the RectangleGeographicArea on a specific region of the viewport, you can use the centerOnRectArea method. This requires passing the viewRc parameter, represented as a Rect, which defines the targeted region of the screen. The Rect passed to the viewRc parameter determines the positioning of the centered area relative to the top-left coordinates. Consequently, the bottom-right corner will be at left + Rect's width and top + Rect's height.
As the width and height of Rect decrease, the centering will result in a more zoomed-out view. For a more zoomed-in perspective, use larger values within the range [1, viewport.width - x] and [1, viewport.height - y].
Use the getOptimalRoutesCenterViewport and getOptimalHighlightCenterViewport methods to compute the viewport region that best fits given routes and highlights.
Map centering on area with padding
Centering on an area using padding can be done by altering the screen coordinates (in physical pixels) by adding/subtracting the padding value. Then a new RectangleGeographicArea object needs to be instantiated with the padded screen coordinates transformed into WGS coordinates using MapView.transformScreenToWgs(xy).
The following code exemplifies the process:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
// Getting the RectangleGeographicArea in which the route belongs
val routeArea = route.geographicArea
val paddingPixels = 200
// Getting the top left point screen coordinates in physical pixels
val routeAreaTopLeftPoint = mapView?.transformWgsToScreen(routeArea.topLeft)
// Adding padding by shifting point in the top left
val topLeftPadded = routeAreaTopLeftPoint?.let { point ->
Xy(
point.x - paddingPixels,
point.y - paddingPixels
)
}
val routeAreaBottomRightPoint = mapView?.transformWgsToScreen(routeArea.bottomRight)
// Adding padding by shifting point downwards three times the padding
val bottomRightPadded = routeAreaBottomRightPoint?.let { point ->
Xy(
point.x + paddingPixels,
point.y + 3 * paddingPixels
)
}
// Converting points with padding to WGS coordinates
val paddedTopLeftCoordinate = topLeftPadded?.let { mapView?.transformScreenToWgs(it) }
val paddedBottomRightCoordinate = bottomRightPadded?.let { mapView?.transformScreenToWgs(it) }
if (paddedTopLeftCoordinate != null && paddedBottomRightCoordinate != null) {
mapView?.centerOnArea(
RectangleGeographicArea(
paddedTopLeftCoordinate,
paddedBottomRightCoordinate
)
)
}
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
// Getting the RectangleGeographicArea in which the route belongs
RectangleGeographicArea routeArea = route.getGeographicArea();
int paddingPixels = 200;
// Getting the top left point screen coordinates in physical pixels
Xy routeAreaTopLeftPoint = mapView != null ? mapView.transformWgsToScreen(routeArea.getTopLeft()) : null;
// Adding padding by shifting point in the top left
Xy topLeftPadded = null;
if (routeAreaTopLeftPoint != null) {
topLeftPadded = new Xy(
routeAreaTopLeftPoint.x - paddingPixels,
routeAreaTopLeftPoint.y - paddingPixels
);
}
Xy routeAreaBottomRightPoint = mapView != null ? mapView.transformWgsToScreen(routeArea.getBottomRight()) : null;
// Adding padding by shifting point downwards three times the padding
Xy bottomRightPadded = null;
if (routeAreaBottomRightPoint != null) {
bottomRightPadded = new Xy(
routeAreaBottomRightPoint.x + paddingPixels,
routeAreaBottomRightPoint.y + 3 * paddingPixels
);
}
// Converting points with padding to WGS coordinates
Coordinates paddedTopLeftCoordinate = topLeftPadded != null && mapView != null ? mapView.transformScreenToWgs(topLeftPadded) : null;
Coordinates paddedBottomRightCoordinate = bottomRightPadded != null && mapView != null ? mapView.transformScreenToWgs(bottomRightPadded) : null;
if (paddedTopLeftCoordinate != null && paddedBottomRightCoordinate != null && mapView != null) {
mapView.centerOnArea(
new RectangleGeographicArea(
paddedTopLeftCoordinate,
paddedBottomRightCoordinate
)
);
}
When applying padding, note that the height is measured in physical pixels. A conversion may be required depending on your use case.
Map zoom
To get the current zoom level use the zoomLevel property. A bigger value means the camera is closer to the terrain.
Changing the zoom level is done through the setZoomLevel method of the MapView class in the following way:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val zoomLevel = mapView?.zoomLevel
mapView?.setZoomLevel(50)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
Integer zoomLevel = mapView != null ? mapView.getZoomLevel() : null;
if (mapView != null) {
mapView.setZoomLevel(50);
}
The maximum allowed zoom level can be accessed via the maxZoomLevel property from the MapView class.
In order to check if a particular zoom level can be applied, check if it's within the valid range.
Map rotation angle
To get the current rotation angle of the map, use the rotationAngle property from the MapViewPreferences class.
Changing the rotation angle is done through the rotationAngle setter of MapViewPreferences like so:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val rotationAngle = mapView?.preferences?.rotationAngle ?: 0.0
mapView?.preferences?.rotationAngle = 45.0
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
double rotationAngle = mapView != null && mapView.getPreferences() != null ? mapView.getPreferences().getRotationAngle() : 0.0;
if (mapView != null && mapView.getPreferences() != null) {
mapView.getPreferences().setRotationAngle(45.0);
}
The provided value needs to be between 0 and 360. By default, the camera has a rotation angle value of 0 degrees corresponding to the north-up alignment. Note that the rotation axis is always perpendicular to the ground and passes through the camera, regardless of the current camera orientation.
Map view angle
The camera can transform the flat 2D map into a 3D perspective, allowing you to view features like distant roads appearing on the horizon. By default, the camera has a top-down perspective (viewAngle = 90°).
In addition to adjusting the camera's view angle, you can modify its tilt angle. The tiltAngle is defined as the complement of the viewAngle, calculated as tiltAngle = 90-viewAngle
In order to change the view angle of camera you need to access the preferences field of MapView like so:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val viewAngle = mapView?.preferences?.viewAngle ?: 30
mapView?.preferences?.setViewAngle(45)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
int viewAngle = mapView != null && mapView.getPreferences() != null ? mapView.getPreferences().getViewAngle() : 30;
if (mapView != null && mapView.getPreferences() != null) {
mapView.getPreferences().setViewAngle(45);
}
To adjust the camera's perspective dynamically, you can utilize both the tiltAngle and viewAngle properties.
The difference between the different types of angles is shown below:
Keep in mind that adjusting the rotation value produces different outcomes depending on the camera's tilt. When the camera is tilted, changing the rotation will shift the target location, whereas with no tilt, the target location remains fixed.
Map perspective
Map perspective can be either two dimensional or three dimensional and can also be set by using MapViewPreferences method setMapViewPerspective:
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val perspective = mapView?.preferences?.mapViewPerspective ?: EMapViewPerspective.ThreeDimensional
mapView?.preferences?.setMapViewPerspective(EMapViewPerspective.ThreeDimensional)
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
EMapViewPerspective perspective = mapView != null && mapView.getPreferences() != null ? mapView.getPreferences().getMapViewPerspective() : EMapViewPerspective.ThreeDimensional;
if (mapView != null && mapView.getPreferences() != null) {
mapView.getPreferences().setMapViewPerspective(EMapViewPerspective.ThreeDimensional);
}
By default, the map perspective is three-dimensional.
A three-dimensional perspective gives buildings a realistic, 3D appearance, while a two-dimensional perspective makes them appear as flat shapes.
To ensure three-dimensional buildings are visible, the camera angle should not be perpendicular to the map. Instead, the view angle must be less than 90 degrees.
The same effect can be implemented more precisely using the tiltAngle/viewAngle fields.
Building visibility
Building visibility can be controlled using the buildingsVisibility property from the MapViewPreferences class:
EBuildingsVisibility.Default: Uses the default visibility defined in the map style.EBuildingsVisibility.Hide: Hides all buildings.EBuildingsVisibility.TwoDimensional: Displays buildings as flat 2D polygons without height.EBuildingsVisibility.ThreeDimensional: Displays buildings as 3D polygons with height.
- Kotlin
- Java
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView
val visibility = mapView?.preferences?.buildingsVisibility ?: EBuildingsVisibility.Default
mapView?.preferences?.buildingsVisibility = EBuildingsVisibility.TwoDimensional
// Get MapView from GemSurfaceView
GemSurfaceView gemSurfaceView = findViewById(R.id.gem_surface);
MapView mapView = gemSurfaceView.getMapView();
EBuildingsVisibility visibility = mapView != null && mapView.getPreferences() != null ? mapView.getPreferences().getBuildingsVisibility() : EBuildingsVisibility.Default;
if (mapView != null && mapView.getPreferences() != null) {
mapView.getPreferences().setBuildingsVisibility(EBuildingsVisibility.TwoDimensional);
}
Buildings become visible when the camera is zoomed in close to the ground. The 3D effect is most noticeable when viewed from a tilted angle. Note that the 3D buildings do not reflect realistic or accurate heights.
Store and restore a view
The map camera object has properties and methods for position and orientation ensuring a high level of control over the map view.
For storing a particular view the saveCameraState method can be used. This method returns a DataBuffer object and depending on the use case this can be stored inside a variable or serialized to a file.
- Kotlin
- Java
val state = mapView.camera?.saveCameraState()
DataBuffer state = mapView.getCamera() != null ? mapView.getCamera().saveCameraState() : null;
Restoring a saved view can be done easily using the restoreCameraState method:
- Kotlin
- Java
state?.let {
mapView.camera?.restoreCameraState(it)
}
if (state != null && mapView.getCamera() != null) {
mapView.getCamera().restoreCameraState(state);
}
Alternatively the position and orientation can be stored and restored separately using the provided properties.
Please note that saveCameraState does not contain information about the current style.
Download individual map tiles
A map tile is a small, rectangular image or data chunk that represents a specific geographic area at a particular zoom level on a MapView. Tiles are usually downloaded when panning or zooming in on a map, and they are used to render the map's visual content. However, you can also download tiles that are not currently visible on the screen, using the MapDownloaderService class.
Configuring the MapDownloaderService
The service can be configured by setting specific maximum area size in square kilometers to download by using the maxSquareKm property:
- Kotlin
- Java
val service = MapDownloaderService()
// Set a new value
service.maxSquareKm = 100
// Verify the new value
val updatedMaxSquareKm = service.maxSquareKm
MapDownloaderService service = new MapDownloaderService();
// Set a new value
service.setMaxSquareKm(100);
// Verify the new value
int updatedMaxSquareKm = service.getMaxSquareKm();
The larger the area, the more tiles can be downloaded, which can lead to increased memory usage. The default value is 1000 square kilometers.
If the RectangleGeographicArea surface exceeds the maxSquareKm, the MapDownloaderService will return GemError.OutOfRange.
Downloading tiles is done by calling the startDownload method of MapDownloaderService like so:
- Kotlin
- Java
val service = MapDownloaderService()
service.maxSquareKm = 300
val areas = arrayListOf(
// Area in which the tiles will be downloaded that is under 300 square kilometers
RectangleGeographicArea(
Coordinates(67.69866, 24.81115),
Coordinates(67.58326, 25.36093)
)
)
service.startDownload(areas, object : ProgressListener() {
override fun notifyComplete(errorCode: ErrorCode, hint: String) {
// Handle completion
}
})
MapDownloaderService service = new MapDownloaderService();
service.setMaxSquareKm(300);
ArrayList<RectangleGeographicArea> areas = new ArrayList<>();
// Area in which the tiles will be downloaded that is under 300 square kilometers
areas.add(new RectangleGeographicArea(
new Coordinates(67.69866, 24.81115),
new Coordinates(67.58326, 25.36093)
));
service.startDownload(areas, new ProgressListener() {
@Override
public void notifyComplete(ErrorCode errorCode, String hint) {
// Handle completion
}
});
When tiles are downloaded, the notifyComplete callback is invoked with an ErrorCode parameter indicating the success or failure of the operation. If the download is successful, the error will be ErrorCode.Success. Downloaded tiles are stored in the cache and can be used later for features such as viewing map content without requiring an internet connection.
SearchService.search method will return an error when trying to search in a downloaded tiles area as it requires indexing, which is not available for downloaded tiles.
Download can be canceled by calling the cancelDownload method of MapDownloaderService and the notifyComplete callback will be invoked with ErrorCode.Cancelled.
Trying to download previously downloaded tiles will not result in an error, as downloaded tiles are present inside the application's cache folder as data files.
You can access detailed download statistics for map tiles using the transferStatistics property.
Downloaded map tiles via MapDownloaderService do not support operations such as free-text search, routing, or turn-by-turn navigation while offline. They are primarily intended for caching map data for visual display purposes only.
For full offline functionality, including search and navigation, refer to the Manage Offline Content Guide to learn how to download roadmap data designed for full offline use.
Change map settings while following the current position
The FollowPositionPreferences class provides more customization while the camera is in the follow position mode. To retrieve an instance, use the snippet below:
- Kotlin
- Java
val preferences = mapView.preferences?.followPositionPreferences
FollowPositionPreferences preferences = mapView.getPreferences() != null ? mapView.getPreferences().getFollowPositionPreferences() : null;
See the customize follow position settings guide for more details.







