Dears,
I have a map view that covers the whole screen. On the top of it, there is a view pager.
The view pager consist of two parts, top 40% and bottom 60%, the top one is just a transparent view.
While swiping the view pager, marker displayed on map should be located to middle of transparent top view 40%.
This image describe the story:
How to achieve this?
I tried this, but with no luck:
public void FollowVehicle(clsFollowMode vehicle){
final LatLng vehiclePosition = new LatLng(vehicle.getLatitude(), vehicle.getLongtitude());
Marker vehicleMarker = myGMap.addMarker(new MarkerOptions()
.position(vehiclePosition)
.title(vehicle.getDeviceName())
.snippet(String.valueOf(vehicle.getSpeed()))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_vehicle_follow)));
float zoom_lvl = myGMap.getCameraPosition().zoom;
double dpPerdegree = 256.0*Math.pow(2, zoom_lvl)/170.0;
double screen_height = (double) mapContainer.getHeight();
double screen_height_30p = -20.0*screen_height/100.0;
double degree_30p = screen_height_30p/dpPerdegree;
LatLng centerlatlng = new LatLng( vehiclePosition.latitude + degree_30p, vehiclePosition.longitude );
myGMap.animateCamera( CameraUpdateFactory.newLatLngZoom( centerlatlng, 15 ), 1000, null);
}
Any help? the above solution found here.
Regards,
If I understood you correctly, then your problem is the fact that you placed the map as full screen fragmnet, and on top of this you placed the ViewPager. as a result when you center on the marker the map does that but the marker is under the ViewPager.
You can trick the map into thinking that it has a smaller size then it really is, by using the GoogleMap.setPadding method, you can read more about it here:
https://developers.google.com/maps/documentation/android/map#map_padding
Related
I have a google maps app that I need to be able to upload different floorplans to. So far I am adding the floorplan image to the map using a ground overlay object like this:
LatLngBounds bounds = new LatLngBounds(new LatLng(floorplan.get_swlat(), floorplan.get_swlng()),
new LatLng(floorplan.get_nelat(), floorplan.get_nelng()));
GroundOverlayOptions overlayOptions = new GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromBitmap(floorplan.get_floorplanimage())).positionFromBounds(bounds);
mMap.addGroundOverlay(overlayOptions);
This adds the floorplan to the map, but the problem is that it is only north-south facing, so it won't work for buildings that don't perfectly sit like that. So I was wondering if there was a way to go in and manually place it (and use fingers to rotate and scale the image) where I need it to be. Anyone know where to even begin?
Took some time but I finally figured something out. Instead of adding the overlay using the two corners I use the center lat/lon and the width and height. I add the overlay as follows.
mOverlayOptions = new GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromBitmap(floorplan.get_floorplanimage()))
.position(new LatLng(floorplan.get_clat(), floorplan.get_clng()), (float) floorplan.get_width(), (float) floorplan.get_height())
.bearing((float) floorplan.get_bearing())
.transparency(mOpacity);
mOverlay = mMap.addGroundOverlay(mOverlayOptions);
So you have to give the floorplan initial values to begin.Then I added two markers, one located at the center of the overlay (same lat/lon) and another one located along the center of the right edge of the overlay (mSizeMarker). Make sure they're draggable. I had to do some math to figure out where to place the one on the right edge.
mCenterMarker = mMap.addMarker(new MarkerOptions().position(new LatLng(floorplan.get_clat(), floorplan.get_clng())));
Double new_longitude = floorplan.get_clng() + (floorplan.get_width() / 2 / (6371000)) * (180 / 3.14159265) / Math.cos(floorplan.get_clat() * 3.14159265/180);
mSizeMarker = mMap.addMarker(new MarkerOptions().position(new LatLng(floorplan.get_clat(), new_longitude)));
mCenterMarker.setDraggable(true);
mSizeMarker.setDraggable(true);
All that's left is to add an OnMarkerDragListener:
mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
#Override
public void onMarkerDragStart(Marker marker) {
}
}
#Override
public void onMarkerDrag(Marker marker) {
if (marker.equals(mCenterMarker)) {
mOverlay.remove();
mOverlayOptions.position(marker.getPosition(), mOverlay.getWidth(), mOverlay.getHeight());
mOverlay = mMap.addGroundOverlay(mOverlayOptions);
mSizeMarker.setPosition(new LatLng(marker.getPosition().latitude, marker.getPosition().longitude + (mOverlay.getWidth() / 2 / (6371000)) * (180 / 3.14159265) / Math.cos(marker.getPosition().latitude * 3.14159265/180)));
}
if (marker.equals(mSizeMarker)) {
marker.setPosition(new LatLng(mCenterMarker.getPosition().latitude, marker.getPosition().longitude));
double newWidth = ((marker.getPosition().longitude - mCenterMarker.getPosition().longitude) / ((180 / 3.14159265) / Math.cos(mCenterMarker.getPosition().latitude * 3.14159265/180))) * 6371000 * 2;
mOverlay.remove();
mOverlayOptions.position(mCenterMarker.getPosition(), (float) newWidth);
mOverlay = mMap.addGroundOverlay(mOverlayOptions);
}
}
#Override
public void onMarkerDragEnd(Marker marker) {
if (marker.equals(mSizeMarker)) {
marker.setPosition(new LatLng(mCenterMarker.getPosition().latitude, marker.getPosition().longitude));
}
}
});
Use the middle marker to drag where you want the floorplan to be located, and the one on the right to change the width (the height will automatically update correspondingly).
Then when the image is positioned correctly, just have a save button somewhere that updates where the floorplan is stored with the position, width, and height of mOverlay. It would be possible to add another marker to manually adjust the bearing, but that's more math than I need to do right now. I'll just keep adjusting it when I set it originally. Hope this helps anyone else who comes along this problem, I know this solution is working great for me so far.
I am working on an Android app and I have two markers i want to place on a google map. The idea is that the user can see the two locations at a glance without having to interact with the map.
LatLngBounds.Builder b = new LatLngBounds.Builder();
b.include(userPos);
b.include(cardPos);
LatLngBounds bounds = b.build();
int width = (int) (0.7 * infoView.getWidth());
int height = (int) (0.7 * mapView.getHeight());
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, 5);
googleMap.animateCamera(cu);
The code works fine when the two locations are not very far apart. But when the locations are, for example, Singapore and USA, the two markers cannot be seen together.
I have tried to manually set the zoom level to 0 with the same result.
Is there any way that I can show the entire world map on the android device at once (i.e without the need for scrolling on the user's part)?
Update:
I have tried setting the map to zoom level 0 explicitly. The map does not fit the View I have created. Is it not possible to have the full world view of the map on the screen?
You should use the CameraUpdate class to do (probably) all programmatic map movements.
To do this, first calculate the bounds of all the markers like so:
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker marker : markers) {
builder.include(marker.getPosition());
}
LatLngBounds bounds = builder.build();
Then obtain a movement description object by using the factory: CameraUpdateFactory:
int padding = 0; // offset from edges of the map in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
Finally move the map:
googleMap.moveCamera(cu);
Or if you want an animation:
googleMap.animateCamera(cu);
That's all :)
Background
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.
The problem
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).
What I've tried
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.
The question
What's wrong with what I wrote? What can I do to fix it?
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.
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.
I have 2 LatLng, usually a few kilometers apart, and I want to zoom map such that both points are visible. My code below sometimes works, sometimes not (map is zoomed to level 3 then). I think the reason is that the loop is too fast for the map to make the necessary adjustments in time.
Is there a way to wait for the map to update before making the test again? To note that process runs on UI thread
double x1=from.latitude;
double x2= to.latitude;
double x1half=(x1+x2)/2;
x1=from.longitude;
x2= to.longitude;
double x2half=(x1+x2)/2;
LatLng pp=new LatLng(x1half, x2half);
map.moveCamera(CameraUpdateFactory.newLatLng(pp));//3.0
//now zoom map so that both points are in
double zoom=21;//V3.3
while(zoom>2){//
map.animateCamera( CameraUpdateFactory.zoomTo( (float) zoom ) );
if(isCurrentLocationVisible(from,map)&&isCurrentLocationVisible(to,map)) return;
/now we know map is still not visible. give it a bit more room
zoom--;
}
I'd advice you to use the newLatLngBounds() instead..You can create your bounds from your two geo points with the LatLngBounds.builder().
To the second part of your question..You could do somethink like map.post(new Runnable..) which could solve the concurrency issue.
You can use LatLngBounds like the following:
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(locationOne);
builder.include(locationTwo);
LatLngBounds bounds = builder.build();
int padding = 0; // offset from edges of the map in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds,screen width, screen height, padding);
map.moveCamera(cu);
I have a screen with google map, on top of screen there is one AutotextView for search place, and make a custom info window to show more details, problem is when user click on any mark custom window popup as their default behaviour (center on screen), so it mixed up autotextview, Can I change info-window position on screen, i.e bottom or anything like that.
If you want to adjust Marker location perfect center on google map screen with popup then please use below code in that i have get popup height and based on that update y axis.i hope it will help you.
public boolean onMarkerClick(Marker marker) {
//Please use fix height popup
float container_height = getResources().getDimension(R.dimen.DIP_300);
Projection projection = mGoogleMap.getProjection();
Point markerScreenPosition = projection.toScreenLocation(marker.getPosition());
Point pointHalfScreenAbove = new Point(markerScreenPosition.x,(int) (markerScreenPosition.y - (container_height / 2)));
LatLng aboveMarkerLatLng = projection.fromScreenLocation(pointHalfScreenAbove);
marker.showInfoWindow();
CameraUpdate center = CameraUpdateFactory.newLatLng(aboveMarkerLatLng);
mGoogleMap.moveCamera(center);
mGoogleMap.animateCamera(center);
marker.showInfoWindow();
return true;
}
Currently you cannot change the info window to be below marker. This is already requested and discussed on gmaps-api-issues.
I can only suggest you to animate marker after being clicked to a different position. Add OnMarkerClickListener and return true (handled) there. After that you can call:
marker.showInfoWindow();
map.animateCamera(...);
to create an effect similar to default but with a different position.
Google Map Info Window Position always on top middle of marker now. If marker is rotated.
double angle = MARKER_ROTATION_ANGLE;
double x = Math.sin(-angle * Math.PI / 180) * 0.5 + 0.5;
double y = -(Math.cos(-angle * Math.PI / 180) * 0.5 - 0.5);
marker.setInfoWindowAnchor((float)x, (float)y);
Explanation:
instead of MARKER_ROTATION_ANGLE you have to give the exact rotation of your marker. Then it will be work fine. :)