Reputation: 116000
Suppose I have a Google maps view, and another view on top of it, that covers a part of it, hiding some content of the map.
I need to make the "camera" of the map, to focus and have a marker on a coordinate , yet let it all be in the middle of the visible part of the map.
Something like this:
The original code was focusing on (about) the center of the entire screen, making the marker almost invisible (as the bottom view covers it).
Thing is, I can't find the proper way to set the correct value to the Y coordinate of the map itself (meaning latitude).
I tried, given the height of the bottom view, and the coordinate that I've put the marker on, to calculate the delta (yet of course not change the marker itself) :
final float neededZoom = 6.5f;
int bottomViewHeight = bottomView.getHeight();
LatLng posToFocusOn = ...;
final Point point = mMap.getProjection().toScreenLocation(posToFocusOn);
final float curZoom = mMap.getCameraPosition().zoom;
point.y += bottomViewHeight * curZoom / neededZoom;
posToFocusOn = mMap.getProjection().fromScreenLocation(point);
final CameraUpdate cameraPosition = CameraUpdateFactory.newCameraPosition(new Builder().target(posToFocusOn).zoom(neededZoom).build());
Sadly, this focuses way above the marker.
What's wrong with what I wrote? What can I do to fix it?
Upvotes: 10
Views: 2035
Reputation: 116000
ok, I've found a workaround, which I think works on all devices (tested on 3, each with a different screen resolution and size) :
I've measured how many pixels (and then converted to DP) a change of one degree has on the marker itself.
From this, I measured the height of each view, and calculated the delta needed to move the camera.
In my case, it's this way (supposing the zoom is 6.5f) :
//measured as 223 pixels on Nexus 5, which has xxhdpi, so divide by 3
final float oneDegreeInPixels = convertDpToPixels( 223.0f / 3.0f);
final float mapViewCenter = mapViewHeight / 2.0f;
final float bottomViewHeight = ...;
final float posToFocusInPixelsFromTop = (mapViewHeight - bottomViewHeight) / 2.0f ;// can optionally add the height of the view on the top area
final float deltaLatDegreesToMove = (mapViewCenter - posToFocusInPixelsFromTop) / oneDegreeInPixels;
LatLng posToFocusOn = new LatLng(latitude - deltaLatDegreesToMove, longitude);
final CameraUpdate cameraPosition = CameraUpdateFactory.newCameraPosition(new Builder().target(posToFocusOn).zoom(neededZoom).build());
And it worked.
I wonder if it can be adjusted to support any value of zoom.
Upvotes: 7
Reputation: 18262
Your code is almost right, but it goes above the marker because you are taking into account bottomViewHeight
when computing point.y
instead of bottomViewHeight/2
(When your view's size is 200px, you only need to displace the map 100px to recenter it):
point.y += (bottomViewHeight / 2) * curZoom / neededZoom;
Update:
This is a more general approach taht takes into account the map bounds and calculates a new map bounds according to the height of your bottomView
. This is zoom independent.
public void recenter() {
LatLngBounds mapBounds = mMap.getProjection().getVisibleRegion().latLngBounds;
Point nothEastPoint = mMap.getProjection().toScreenLocation(mapBounds.northeast);
Point souhWestPoint = mMap.getProjection().toScreenLocation(mapBounds.southwest);
Point newNorthEast = new Point(nothEastPoint.x, nothEastPoint.y + bottomView.getHeight() / 2);
Point newSouhWestPoint = new Point(souhWestPoint.x, souhWestPoint.y + bottomView.getHeight() / 2);
LatLngBounds newBounds = LatLngBounds.builder()
.include(mMap.getProjection().fromScreenLocation(newNorthEast))
.include(mMap.getProjection().fromScreenLocation(newSouhWestPoint))
.build();
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(newBounds, 0));
}
Note that each time you call recenter()
the map will move.
Upvotes: 2