Is it possible to set a visibile region to a MapView in osmdroid?

928 views Asked by At

I have translucent fragments overlaying a MapView on the top and bottom. Therefore the map should be visible below the fragment, but for centering an item it should ignore the parts where the fragments are overlaying it.

In the GoogleMaps SDK it is done via the setPadding method and is described as follows:

Sets padding on the map.

This method allows you to define a visible region on the map, to signal to the map that portions of the map around the edges may be obscured, by setting padding on each of the four edges of the map. Map functions will be adapted to the padding. For example, the zoom controls, compass, copyright notices and Google logo will be moved to fit inside the defined region, camera movements will be relative to the center of the visible region, etc.

How can something like this be done with osmdroid?

Does a similar method exist? or do I need to implement it by myself? if so, can anybody point me to existing examples?

3

There are 3 answers

0
avlacatus On

Since version 6.1.1 there is a method called setMapCenterOffset(int, int). I used this to set map bottom padding.

0
BrantApps On

Ok, so I have an implementation working @Sven.

I have a pin sitting in the centre of a map which (as your question describes) has an offset owing to an overlapping fragment - see Figure 1;

enter image description here

The pin 'drops' when the map comes to rest (using a org.osmdroid.events.DelayedMapListener if you are interested) but to line up the map 'centre' (as the user sees it) with the top portion of the exposed map I have overridden the MapView#getCenter() call and used an old Google Maps V1 trick as described here which get's the "top-left and bottom-right corners [which you] divide by the screen size, to get the value per pixel."

Not as sexy an API setPadding(...) but works just as well.

0
Roland Mostoha On

I've created a Kotlin extension function which adjusts a BoundingBox based on the defined paddings.

The function creates a projection with the initial bounding box and adjusts the edges by the pixel-per-latitude/longitude values.

You can use it with the combination of zoomToBoundingBox

mapView.zoomToBoundingBox(boundingBox.withOffset(mapView, top, bottom, left, right), false)

The function:

fun BoundingBox.withOffset(
    mapView: MapView,
    @DimenRes top: Int,
    @DimenRes bottom: Int,
    @DimenRes left: Int,
    @DimenRes right: Int
): BoundingBox {
    val topPx = mapView.context.resources.getDimensionPixelSize(top)
    val bottomPx = mapView.context.resources.getDimensionPixelSize(bottom)
    val leftPx = mapView.context.resources.getDimensionPixelSize(left)
    val rightPx = mapView.context.resources.getDimensionPixelSize(right)

    val width = mapView.width
    val height = mapView.height

    val nextZoom = MapView.getTileSystem().getBoundingBoxZoom(
        this,
        width - (leftPx + rightPx),
        height - (topPx + bottomPx)
    )
    val projection = Projection(
        nextZoom, width, height,
        centerWithDateLine,
        mapView.mapOrientation,
        mapView.isHorizontalMapRepetitionEnabled, mapView.isVerticalMapRepetitionEnabled,
        mapView.mapCenterOffsetX, mapView.mapCenterOffsetY
    )

    val northWest = projection.fromPixels(0, 0)
    val southEast = projection.fromPixels(width, height)

    val lonPerPx = (southEast.longitude - northWest.longitude) / width
    val latPerPx = (southEast.latitude - northWest.latitude) / height

    return BoundingBox(
        latNorth - topPx * latPerPx,
        lonEast + rightPx * lonPerPx,
        latSouth + bottomPx * latPerPx,
        lonWest - leftPx * lonPerPx
    )
}