I am using the code below to detect zoom by user but its in loop even if I dont touch anything .How do I detect human touch on device and check if he zoomed ? I really appreciate any help.Thanks in Advance.
googleMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition position) {
// TODO Auto-generated method stub
if (position.zoom < 12 ) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(13));
}
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
});
}
The endless loop is obvious.
Either you have a zoom level of 20, then you will always end up in the second if condition.
Or you have a zoom level less than 20, then you will always end up in the third if condition.
I would try something like this:
boolean changeTriggeredByProgram = false;
googleMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition position) {
if (changeTriggerByProgram) {
changeTriggeredByProgram = false;
return;
}
/* Check, whether you want to adapt the position by program,
* and if so, do the following: */
changeTriggeredByProgram = true;
googleMap.animateCamera(newPosition, new CancelableCallback() {
#Override
public void onFinish() {
}
#Override
public void onCancel() {
changeTriggeredByProgram = false;
}
};
}
}
No guarantee that this works. I am using a slightly different solution, as my problem is slightly different.
Related
i have read in the premium user guide that we can download a small amount of map with MapDataPrefetcher. i use a Mapfragment to show the map in my app, and it says that the MapEngine is automatically initialized by using MapFragment.
the problem is that i can't understand how to apply the methods and where i need to initialize the request for downloading the bounding box itself. its not so clear in the user guide.
if someone here can help me with that problem or send an example of the implementation i will be very grateful!
this is my init method for the map and the map fragment
private void initialize() {
setContentView(R.layout.activity_main);
// Search for the map fragment to finish setup by calling init().
// mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.mapfragment);
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.mapfragment);
mLocationInfo = (TextView) findViewById(R.id.textViewLocationInfo);
mapFragment.setRetainInstance(false);
// Set up disk cache path for the map service for this application
// It is recommended to use a path under your application folder for storing the disk cache
boolean success = com.here.android.mpa.common.MapSettings.setIsolatedDiskCacheRootPath(
getApplicationContext().getExternalFilesDir(null)+File.separator + ".here-maps",
"com.example.andrey88.MapService"); /* ATTENTION! Do not forget to update {YOUR_INTENT_NAME} */
if (!success) {
Toast.makeText(getApplicationContext(), "Unable to set isolated disk cache path.", Toast.LENGTH_LONG);
} else {
mapFragment.init(new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
if (error == OnEngineInitListener.Error.NONE) {
// retrieve a reference of the map from the map fragment
map = mapFragment.getMap();
// Set the map center to the Ruppin region (no animation)
map.setCenter(new GeoCoordinate(32.343099, 34.911272, 0.0), Map.Animation.NONE);
// Set the zoom level
map.setZoomLevel(17.8);
map.setMapScheme(Map.Scheme.PEDESTRIAN_DAY);
map.setLandmarksVisible(false);
map.setProjectionMode(Map.Projection.MERCATOR);
map.getPedestrianFeaturesVisible();
// position of user
map.addTransformListener(MainActivity.this);
mPositioningManager = PositioningManager.getInstance();
// check source of getting geo location
mHereLocation = LocationDataSourceHERE.getInstance(
new StatusListener() {
#Override
public void onOfflineModeChanged(boolean offline) {
// called when offline mode changes
}
#Override
public void onAirplaneModeEnabled() {
// called when airplane mode is enabled
}
#Override
public void onWifiScansDisabled() {
// called when Wi-Fi scans are disabled
}
#Override
public void onBluetoothDisabled() {
// called when Bluetooth is disabled
}
#Override
public void onCellDisabled() {
// called when Cell radios are switch off
}
#Override
public void onGnssLocationDisabled() {
// called when GPS positioning is disabled
}
#Override
public void onNetworkLocationDisabled() {
// called when network positioning is disabled
}
#Override
public void onServiceError(StatusListener.ServiceError serviceError) {
// called on HERE service error
}
#Override
public void onPositioningError(PositioningError positioningError) {
// called when positioning fails
}
#Override
public void onWifiIndoorPositioningNotAvailable() {
// called when running on Android 9.0 (Pie) or newer
}
});
if (mHereLocation == null) {
Toast.makeText(MainActivity.this, "LocationDataSourceHERE.getInstance(): failed, exiting", Toast.LENGTH_LONG).show();
finish();
}
mPositioningManager.setDataSource(mHereLocation);
mPositioningManager.addListener(new WeakReference<PositioningManager.OnPositionChangedListener>(MainActivity.this));
// Create a custom marker image
com.here.android.mpa.common.Image myImage = new com.here.android.mpa.common.Image();
try {myImage.setImageResource(R.drawable.marker_round);
} catch (IOException e) {
finish();
}
initMarkers(myImage);
createPolygon();
mapFragment.getMapGesture().addOnGestureListener(new MapGesture.OnGestureListener() {
#Override
public void onPanStart() {
}
#Override
public void onPanEnd() {
}
#Override
public void onMultiFingerManipulationStart() {
}
#Override
public void onMultiFingerManipulationEnd() {
}
#Override
public boolean onMapObjectsSelected(List<ViewObject> list) {
return false;
}
#Override
public boolean onTapEvent(PointF pointF) {
return false;
}
#Override
public boolean onDoubleTapEvent(PointF pointF) {
return false;
}
#Override
public void onPinchLocked() {
}
#Override
public boolean onPinchZoomEvent(float v, PointF pointF) {
return false;
}
#Override
public void onRotateLocked() {
}
#Override
public boolean onRotateEvent(float v) {
return false;
}
#Override
public boolean onTiltEvent(float v) {
return false;
}
#Override
public boolean onLongPressEvent(PointF pointF) {
return false;
}
#Override
public void onLongPressRelease() {
}
#Override
public boolean onTwoFingerTapEvent(PointF pointF) {
return false;
}
}, 0, false);
if (mPositioningManager.start(PositioningManager.LocationMethod.GPS_NETWORK_INDOOR)) {
mapFragment.getPositionIndicator().setVisible(true);
} else {
Toast.makeText(MainActivity.this, "PositioningManager.start: failed, exiting", Toast.LENGTH_LONG).show();
finish();
}
}
else {
Log.d("errorTag",error.name());
onDestroy();
}
}
});
}
}
MapEngine must be initialized before it can be used. It should be done in the main thread. MapEngine is automatically initialized for your application by using AndroidXMapFragment. AndroidXMapFragment is a fragment class applications can use as a UI module in an activity for map display. However, if your application does not use AndroidXMapFragment classes, then the application should initialize the MapEngine directly before using any HERE APIs. You can do this by calling MapEngine.init(ApplicationContext, OnEngineInitListener) as shown below:
MapEngine mapEngine = MapEngine.getInstance(); ApplicationContext appContext = new ApplicationContext(context); mapEngine.init(appContext, new OnEngineInitListener() { #Override public void onEngineInitializationCompleted(Error error) {
if (error == OnEngineInitListener.Error.NONE) {
// Post initialization code goes here
} else {
// handle factory initialization failure
} } });
I have a very simple app which has a single activity. Everytime I start the app, the camera is moved to my position. I have used a LocationCallback so everytime I change my position, the camera follows me:
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
currentLocation = location;
LatLng latLng = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
if (isFollowing) {
moveCamera(latLng, DEFAULT_ZOOM);
}
}
}
};
As you can see, I have a Boolean isFollowing which is set by default to true. The problem is when the user tries moves the map to another point, the camera starts following again.
I also have added on click listener to the LocationButton, to be sure that in the moment in which the user clicks it, to be followed by the camera.
mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener(){
#Override
public boolean onMyLocationButtonClick()
isFollowing = true;
return false;
}
});
The question is, how can I set isFollowing to flase, so the camera stops following the user when he moved the map?
I found some posts here on SOF but only with OnMyLocationChangeListener, which I see is deprecated.
You can use the GoogleMap.OnCameraMoveStartedListener and GoogleMap.OnCameraIdleListener. See some examples here.
In your case:
mMap.setOnCameraMoveStartedListener(this);
mMap.setOnCameraIdleListener(this);
...
#Override
public void onCameraMoveStarted(int reason) {
if (reason == OnCameraMoveStartedListener.REASON_GESTURE) {
isFollowing = false;
}
}
#Override
public void onCameraIdle() {
// You may want to set isFollowing = true here
}
For future visitors, I have solved this problem by creating an invisible overlay in my layout file. I have added a simple TextView like this:
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/invisible_text_view"/>
And then in my activity is have used setOnTouchListener and managed to change the value of the isFollowing variable to false, like this:
View invisibleTextView = findViewById(R.id.invisible_text_view);
invisibleTextView.bringToFront();
invisibleTextView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
isFollowing = false;
return false;
}
});
I have an activity that holds a fragment with Google Map view in it. App adds several dozens of markers to the MapView, using MarkerManager and ClusterRenderer to form clusters.
The problem is that when I have marker's InfoWindow opened and I press hardware Back button, it closes the app. Instead of that, I would like to have the InfoWindow closed.
Is there any straightforward way to achieve this?
I managed to solve the problem.
I modified MarkerManager to send notification via EventBus when InfoWindow is about to be opened:
#Override
public View getInfoContents(Marker marker) {
View content = fillContent();
EventBus.getDefault().post(new MapInfoWindowShownEvent(marker));
return content;
}
and I added event handling in the activity:
private Marker mLastShownInfoWindowMarker = null;
#Override
public void onBackPressed() {
if(mLastShownInfoWindowMarker != null && mLastShownInfoWindowMarker.isInfoWindowShown()) {
mLastShownInfoWindowMarker.hideInfoWindow();
} else {
super.onBackPressed();
}
}
public void onEvent(MapInfoWindowShownEvent event) {
mLastShownInfoWindowMarker = event.getMarker();
}
Using this information I decided to make it a bit simpler for myself:
private Marker mLastShownInfoWindowMarker = null;
public void setMLastShownInfoWindowMarker(Marker marker)
{this.mActiveMapMarker=marker;}
#Override
public void onBackPressed() {
if(mLastShownInfoWindowMarker != null && mLastShownInfoWindowMarker.isInfoWindowShown()) {
mLastShownInfoWindowMarker.hideInfoWindow();
} else {
super.onBackPressed();
}
}
Then the following where you have your mapfragment:
private MainActivity activity; // swap this to your activity
public MainActivityMapController(MainActivity activity) {
this.activity = activity;
}
// override markerclicklistener to store lastShownInfoWindowMarker in
// the activity where back button will be used
map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
activity.setMLastShownInfoWindowMarker(marker);
return false; // false keeps the standard behavior
}
});
I'm using Google Maps Android API Utility Library and I'm downloading certain images from internet that I want to use as markers.
The way I'm doing it is like in the following snippet:
class MarkerItemClusterRenderer extends DefaultClusterRenderer<MarkerItem> {
...
#Override
protected void onBeforeClusterItemRendered(MarkerItem item,
final MarkerOptions markerOptions) {
super.onBeforeClusterItemRendered(item, markerOptions);
mImageLoader.get(item.getImageUrl(), new ImageListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("XXX", error.toString());
}
#Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response != null && response.getBitmap() != null) {
mImageIcon.setImageBitmap(response.getBitmap());
Bitmap icon = mIconGenerator.makeIcon();
Bitmap bhalfsize = Bitmap.createScaledBitmap(icon, 150,
150, false);
markerOptions.icon(BitmapDescriptorFactory
.fromBitmap(bhalfsize));
}
}
});
}
The problem is, that when the image is downloaded, the map (and thus the marker) doesn't refresh, so most of the times (but not always) I still see the red default markers.
I tried to do mImageIcon.invalidate(); mImageIcon.requestLayout(); but there's still no luck.
Is there anyway to achieve this?
Thanks a lot in advance.
You just need to make all this stuff in
protected void onClusterItemRendered(T clusterItem, Marker marker) {
...
}
In onBeforeClusterItemRendered you set icon on MarkerOptions in async callback. At this time it could be added to map and become real Marker. So you icon will be set to already useless object.
That's why you need to do it in onClusterItemRendered
Let's say you have GoogleMap object declared as:
private GoogleMap mMap;
In onResponse() method before applying any change to marker, try writing following statement to clear previous markers:
mMap.clear();
Now set your new marker.
I might be a bit late but i write it down so it can be useful for somebody looking for a solution like i was.
Basically what you have to do is refresh the marker and not the ClusterItem, but i used my own ClusterItem implementation to store some important data.
So your code inside onBeforeClusterItemRendered becomes like this:
LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds; //take visible region on map
if(bounds.contains(item.getPosition()) && !item.hasImage()) { //if item is not inside that region or it has an image already don't load his image
mImageLoader.get(item.getImageUrl(), new ImageListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("XXX", error.toString());
}
#Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response != null && response.getBitmap() != null) {
mImageIcon.setImageBitmap(response.getBitmap());
Bitmap icon = mIconGenerator.makeIcon();
Bitmap bhalfsize = Bitmap.createScaledBitmap(icon, 150,
150, false);
//Set has image flag
item.setHasImage(true);
//Find the right marker
MarkerManager.Collection markerCollection = mClusterManager.getMarkerCollection();
Collection<Marker> markers = markerCollection.getMarkers();
for (Marker m : markers) {
if (id.equals(m.getTitle())) {
//set the icon
m.setIcon(BitmapDescriptorFactory.fromBitmap(image));
break;
}
}
}
}
});
}
And your MyItem class must have some parameters which are useful for remember our stuff:
public class MyItem implements ClusterItem {
private String itemId;
private LatLng mPosition;
private WMWall wall;
private boolean hasImage = false;
public MyItem(double latitude, double longitude) {
mPosition = new LatLng(latitude, longitude);
}
#Override
public LatLng getPosition() {
return mPosition;
}
public WMWall getWall() {
return wall;
}
public void setWall(WMWall wall) {
this.wall = wall;
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public boolean hasImage() {
return hasImage;
}
public void setHasImage(boolean hasImage) {
this.hasImage = hasImage;
}
}
It is really important to load only the images of markers contained into bounds, otherwise you'll run into OOM.
And if the hasImage() method returns true we don't need to load the image again since it is already stored into the marker object.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iphone like annotation on android map
I am implementing an application that uses google maps.To the moment I was successfully able to mark locations on google map. But what I exactly need is to set a title on top of the google map position. Just like image below.
Can anybody help me out?
Thanks.
Its basically called Mapview Ballons. Here is the sample project developed on github for your reference. It will help me a lot in my project.
Mapview Ballons
Hope it helps you.
Take a look at the new Google Maps Android API v2 that was just released. It makes adding markers with info windows (with title and snippet) much easier - see the documentation for an example.
You can use Alertbox/Dialog box in ItemizedOverlay by using onTap method..
You can mark as many places you like and you can set a title on top of of the google map position.
For Example
public void onCreate(Bundle b)
{
super.onCreate(b);
try{
setContentView(R.layout.main);
System.out.println(""+lati+place+longi+position.get(0)+position.size());
mapView=(MapView)findViewById(R.id.map_view);
mapView.setBuiltInZoomControls(true);
mc = mapView.getController();
mc.setZoom(12);
drae=this.getResources().getDrawable(R.drawable.ic_launcher);
test tt=new test(drae,this);
tt.addit(latitude,longitude, place_name);
tt.addit(latitude1,longitude1, place_name1);
mapView.getOverlays().add(tt);
System.out.println(ii);
break;
}
default:
System.out.println(position.size());
}
}
}
}catch (Exception e) {
System.out.println(e.getMessage());
}
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
class test extends ItemizedOverlay
{
List<OverlayItem>overLayItem=new ArrayList<OverlayItem>();
Context con;
public test(Drawable drae,Context con) {
super(boundCenterBottom(drae));
testt(con);
}
void testt(Context con)
{
this.con=con;
}
#Override
protected OverlayItem createItem(int i) {
return overLayItem.get(i);
}
#Override
public int size() {
return overLayItem.size();
}
protected boolean onTap(int index) {
// TODO Auto-generated method stub
OverlayItem ir=overLayItem.get(index);
AlertDialog.Builder dia=new AlertDialog.Builder(con);
dia.setTitle(ir.getTitle());
dia.setMessage(ir.getSnippet());
dia.setPositiveButton("close",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
dia.show();
return true;
}
public void additem(OverlayItem item)
{
overLayItem.add(item);
populate();
}
public void addit(int l,int g,String s)
{
GeoPoint po=new GeoPoint(l, g);
OverlayItem it=new OverlayItem(po,s,null);
additem(it);
}
}
}