When adding some markers on a map using Google Maps Android API v2, the markers are no set to the right positions and move when zooming.
When zooming in they get closer to the right positions, as if they were translated by a factor related to the zoom.
What's wrong?
Example zooming in:
fragment
public class CenterMapFragment extends Fragment {
private GoogleMap mMap;
private List<Center> mCenterList;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.center_map_fragment, container, false);
}
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
mMap = ((SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
if (mMap != null) {
mCenterList = MyApplication.dbHelper.getAllCenter();
for(Center center : mCenterList){
mMap.addMarker(new MarkerOptions().position(new LatLng(center.lat, center.lng)).icon(BitmapDescriptorFactory
.fromResource(R.drawable.myicon)));
}
}
}
}
layout
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
For custom markers you need also use
MarkerOptions.anchor(float u, float v)
which describes where is the pointer point on the marker. By default this point is located at middle-bottom of the image.
To show an window info, you have to use setInfoWindowAdapter on your "mMap" or have a title set for your marker.
About the icon, it seems to be moving when you zoom out, but the anchor always point to the same place on the map. You can set an anchor if the image you're using don't follow Google's icon pattern (anchor on the middle of the botton of the image). For that you have to do use MarkerOptions' method anchor(u,v)
Related
In my app I use GoogleMap (play-services-maps:10.2.1). I've fixed the position of the map on a specific location and I don't want my user to be able move the map. I only want him to be able to zoom on it.
Here's what I tried :
// Set position
LatLng requestedPosition = new LatLng(lat, lon);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(requestedPosition, zoom));
// Disable all Ui interaction except for zoom
map.getUiSettings().setAllGesturesEnabled(false);
map.getUiSettings().setZoomGesturesEnabled(true);
It looks like it work at first sight but in fact while zooming and dezooming the camera position change a little on every zoom movement.
I have no idea what to do.
Thanks for your help
If I understand correctly, you would like to preserve a centre position after the zoom gestures. Zooming with the gesture doesn't maintain the same centre, you should correct position of camera once the gesture zoom is over. You can listen the idle event after zooming and animate the camera to the initial centre position.
Code snippet
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
GoogleMap.OnCameraIdleListener {
private GoogleMap map;
private LatLng requestedPosition;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
// Add a marker in Sydney and move the camera
requestedPosition = new LatLng(41.385692,2.163953);
float zoom = 16.0f;
map.addMarker(new MarkerOptions().position(requestedPosition).title("Marker in Barcelona"));
map.moveCamera(CameraUpdateFactory.newLatLngZoom(requestedPosition, zoom));
//map.moveCamera(CameraUpdateFactory.newLatLngZoom(requestedPosition, zoom));
// Disable all Ui interaction except for zoom
map.getUiSettings().setAllGesturesEnabled(false);
map.getUiSettings().setZoomGesturesEnabled(true);
map.setOnCameraIdleListener(this);
}
#Override
public void onCameraIdle() {
float zoom = map.getCameraPosition().zoom;
map.animateCamera(CameraUpdateFactory.newLatLngZoom(requestedPosition, zoom));
}
}
I placed this sample at Github https://github.com/xomena-so/so43733628
Hope this helps!
I've faced strange behaviour of Google Map v2 on my Nexus7 when trying to place camera in specified position.
Code:
public class PlacesFragment extends MapFragment {
GoogleMap mapView;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mapView = getMap();
mapView.moveCamera(
CameraUpdateFactory.newLatLng(new LatLng(50.4293817, 30.5316606)));
mapView.moveCamera(CameraUpdateFactory.zoomTo(11));
}
This piece of code moves camera to specified position on Nexus4, but on Nexus7 2013 it moves camera to (19.1599396,30.5316606) position, which has right longitude, but not latitude.
I've found a workaround, but I'm still interested why this happens.
For those who have this problem this is the solution:
mapView.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(50.4293817, 30.5316606), 11));
My activity contains a MapFragment in a LinearLayout. I do the following
in onCreate:
I inflate this layout using setContentView in the onCreate method of
my activity.
Get a handle to the GoogleMap using getMap().
in onStart:
I get some place coordinates from an SQLite Database
add corresponding markers to the map
add these points to a LatLngBounds.Builder
animate the camera using newLatLngBounds(Builder.build(), 10)
According to maps api reference, I shouldn't call newLatLngBounds(LatLngBounds bounds, int padding) before making sure that the map has a size. I indeed get an IllegalStateException at this point. But what is the right method for waiting until the map has a size?
The solution by rusmus didn't work for me. I used this one instead:
map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
map.animateCamera(cameraUpdate);
}
});
If you know the map size, you can avoid waiting and move the camera before the map is displayed. We finally used the display size as an approximation of the map size (but you could find out the exact size if you want to be more precise):
final DisplayMetrics display = getResources().getDisplayMetrics();
final int padding = display.widthPixels / 20;
final CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(
boundsBuilder.build(), display.widthPixels, display.heightPixels, padding);
map.moveCamera(cameraUpdate);
I have succesfully used the following code in the past:
final LatLngBounds.Builder builder = new LatLngBounds.Builder();
final View mapView = fragment.getView();
final GoogleMap map = fragment.getMap():
//Add points to builder. And get bounds...
final LatLngBounds bounds = builder.build();
// Pan to see all markers in view.
// Cannot zoom to bounds until the map has a size.
if (mapView.getViewTreeObserver().isAlive()) {
mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50), 1500, null);
}
});
}
With the latest GoogleServices you can use MapFragment.getMapAsync.
Directly from the docs
Sets a callback object which will be triggered when the GoogleMap instance is ready to be used.
This question already has answers here:
Polygon Touch detection Google Map API V2
(7 answers)
Closed 7 years ago.
I am working on a map application on Android and i am using Google Maps Android API V2. I get the polygon data from a web service, convert it by XML parse and can show it on the map without a problem. But isn't there any way to open like pop-up when user touches on any polygon? Or maybe if user wants to change coordinates of selected polygon. I saw many examples, but they are done with javascript or some using different third party. Do someone has any advice? Thanks in advance.
I had the same problem. onMapClickListener is not called when user taps a polygon, it's only called when other overlays (such as Polygons) do not process the tap event. Polygon does process it, as you can see - GM moves the polygon to center of screen. And the event is not passed to onMapClickListener, that's it.
To workaround it, I intercept tap events before GM handles them, in a View wrapping MapFragment, as described here, project clicked point from screen coordinates to map, and then check if it is inside a polygon on the map as described here (other answer tells about it too)
Relevant code:
public class MySupportMapFragment extends SupportMapFragment {
private View mOriginalContentView;
private TouchableWrapper mTouchView;
private BasicMapActivity mActivity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = (BasicMapActivity) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
mOriginalContentView = super.onCreateView(inflater, parent,
savedInstanceState);
mTouchView = new TouchableWrapper();
mTouchView.addView(mOriginalContentView);
return mTouchView;
}
#Override
public View getView() {
return mOriginalContentView;
}
class TouchableWrapper extends FrameLayout {
public TouchableWrapper() {
super(mActivity);
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP: {
int x = (int) event.getX();
int y = (int) event.getY();
mActivity.tapEvent(x,y);
break;
}
}
return super.dispatchTouchEvent(event);
}
}
}
BasicMapActivity:
public void tapEvent(int x, int y) {
Log.d(TAG,String.format("tap event x=%d y=%d",x,y));
if(!isEditMode()) {
Projection pp = mMap.getProjection();
LatLng point = pp.fromScreenLocation(new Point(x, y));
for (Shape ss : mPolygons) {
if(ss.isPointInPolygon(point)) {
ss.mMarkers.get(0).marker.showInfoWindow();
}
}
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="au.com.datalink.plugins.MySupportMapFragment" />
</RelativeLayout>
All you have to work with is onMapClickListener which returns the latlng of the press
public abstract void onMapClick (LatLng point)
Called when the user makes a tap gesture on the map, but only if none of the overlays of the map handled the gesture. Implementations of this method are always invoked on the main thread.
Parameters
point The point on the ground (projected from the screen point) that was tapped.
Then check if the latlng is inside the polygon.
How to determine if a point is inside a 2D convex polygon?
I kinda pieced this together but the good news is lat and lng are already doubles.
Good Luck
I'am using maps api v2 in my app. I have to show my current location and target location on the map such that both the locations are visible (at the greatest possible zoom level) on the screen. Here is what i have tried so far...
googleMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.mapFragment)).getMap();
if(googleMap != null){
googleMap.setMyLocationEnabled(true);
LatLng targetLocationLatLng = new LatLng(modelObject.getLattitude(), modelObject.getLongitude());
LatLng currentLocationLatLng = new LatLng(this.currentLocationLattitude, this.currentLocationLongitude);
googleMap.addMarker(new MarkerOptions().position(targetLocationLatLng).title(modelObject.getLocationName()).icon(BitmapDescriptorFactory.fromResource(R.drawable.location_icon)));
LatLngBounds bounds = new LatLngBounds(currentLocationLatLng, targetLocationLatLng);
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 3));
}
App is force closing due to the following :
java.lang.IllegalStateException: Map size should not be 0. Most likely, layout has not yet occured for the map view.
How can i get max possible zoom level? Please help me.
In my project I use the com.google.android.gms.maps.model.LatLngBounds.Builder
Adapted to your source code it should look something like this:
Builder boundsBuilder = new LatLngBounds.Builder();
boundsBuilder.include(currentLocationLatLng);
boundsBuilder.include(targetLocationLatLng);
// pan to see all markers on map:
LatLngBounds bounds = boundsBuilder.build();
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 3));
A good method to avoid this problem is to use a ViewTreeObserver to the layout containing the map fragment and a listener, to ensure that the layout has first been initialised (and hasn't a width=0) using addOnGlobalLayoutListener, as below:
private void zoomMapToLatLngBounds(final LinearLayout layout,final GoogleMap mMap, final LatLngBounds bounds){
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds,OVERVIEW_MAP_PADDING));
}
});
}