I have to remove all the annotations added to my MKMapView but when I execute :
NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray: mapView.annotations];
[mapView removeAnnotations: annotationsToRemove];
The array annotationsToRemove contains a MKUserLocation annotation and it doesn't delete it.
Is there a way to reset the map? I need to delete all the annotations from it!
You can just set the showsUserLocation property of your mapView to NO.
mapView.showsUserLocation = NO;
Actually you can not edit MKUserLocation annotation. I mean you can not remove it from map annotation's array as it is a read-only property of MKMapView.
If you visit MKMapView.h class. You will find below line
#property (nonatomic, readonly) MKUserLocation *userLocation;
Here we can see that this property is a read only. So we can not delete it from MKMapView annotations array. How ever you face difficulties in calculation with other annotations then you can runtime hide it.
What I am trying to explain is when user location is not required any more you can set NO for user location property.
For example with your code:
NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray: mapView.annotations];
[mapView removeAnnotations: annotationsToRemove];
[self.mapView setShowsUserLocation:NO];
NSLog(#"MapView annotations :%#", mapView.annotations);
Check NSLog output, you will see that MKUserLocation annotation is removed from mapView.annotations array.
It is the simple way I did follow. How ever I am not sure about there is other way to do this. Please leave a comment if you found any other solution.
In the h insert
#property (weak) MKAnnotationView *ulv;
In the m insert
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
MKZoomScale currentZoomScale = mapView.bounds.size.width / mapView.visibleMapRect.size.width;
NSLog(#"current zoom scale is %f",currentZoomScale);
ulv = [mapView viewForAnnotation:mapView.userLocation];
if( currentZoomScale > 0.049 ){
ulv.hidden = YES;
}else{
ulv.hidden = NO;
}
}
Related
I am trying to make a map, where I can see my current location, and see what the street is called.
so far, I am able to put a pin on my map, but for some reason, I am not getting the callout.
and I have put a NSLog in my viewForAnnotation method, but it is not being called, so i wasn't able to test it.
can someone help me?
-(void)lat:(float)lat lon:(float)lon
{
CLLocationCoordinate2D location;
location.latitude = lat;
location.longitude = lon;
NSLog(#"Latitude: %f, Longitude: %f",location.latitude, location.longitude);
//One location is obtained.. just zoom to that location
MKCoordinateRegion region;
region.center=location;
//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta=.005f;
span.longitudeDelta=.005f;
region.span=span;
[map setRegion:region animated:TRUE];
//MKReverseGeocoder *geocoder=[[MKReverseGeocoder alloc] initWithCoordinate:location];
//geocoder.delegate=self;
//[geocoder start];
if (cPlacemark != nil) {
[map removeAnnotation:cPlacemark];
}
cPlacemark=[[CustomPlacemark alloc] initWithCoordinate:location];
cPlacemark.title = mPlacemark.thoroughfare;
cPlacemark.subtitle = mPlacemark.locality;
[map addAnnotation:cPlacemark];
[cPlacemark release];
[mLocationManager stopUpdatingLocation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// try to dequeue an existing pin view first
if ([annotation isKindOfClass:[CustomPlacemark class]]){
MKPinAnnotationView *pinView=(MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:#"customIdentifier"];
if (!pinView)
{
// if an existing pin view was not available, create one
MKPinAnnotationView* cPinAnnoView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"customIdentifier"] autorelease];
cPinAnnoView.pinColor = MKPinAnnotationColorPurple;
cPinAnnoView.animatesDrop = YES;
cPinAnnoView.canShowCallout = YES;
// Add button
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[leftButton addTarget:self action:#selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
cPinAnnoView.leftCalloutAccessoryView = leftButton;
} else
{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Right now I have customized my viewForAnnotation to be like this.
But I still can't get a callout from my pin and the pin remains red.
But it should be purple of nothing at all
I had the same problem which was not setting the MapView delegate to the File Owner.
Open your nib
Right click on the MapView
Drag the delegate to the File's Owner
I had the same problem, as you mentioned. The delegate had been set to ViewController, but the viewForAnnotation selector was not being called. After some checks, I realized if you do not call addAnotation in the main thread, mapView would not call viewForAnnotation, so following update resolved my problem:
Before:
[_mMapView addAnnotation:marker];
After:
dispatch_async(dispatch_get_main_queue(), ^{
[_mMapView addAnnotation:marker];
});
In order to get the viewForAnnotation to be called, add mapView.delegate=self; to e.g. the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
mapView.delegate=self;
}
Could it be that your annotation has been added outside the current view area of the MKMapView?
For storyboard, Ctl drag the MKMapView to the orange circle on the bottom bar of ViewController, and select delegate.
This will solve the problem.
As vatrif mentioned in the comments, you must set your delegate BEFORE adding annotations to your MKMapView object.
Others have already explained, odds are high you have not connected your mapview delegate to your controller. Its the first thing to check
i have been working in ios 9 Mapview related app and I experienced the same problem.
somehow I solved my problem, in my case im resizing the mapview.
I added delegate after i resize the mapview. it works now perfectly.!
After having set the delegate for the mapview if still the viewforannotation not getting called then this is something which you have missed - set the self.mapView.showsUserLocation to YES, in interface builder you can tick the shows userLocation option in attributes inspector.
Trying to learn how to have a pin drop at a users location when they push a button on screen. Do I need to use Mkannotation, also I want this pin to disappear when they drop a new pin in the future. This is the code I have in controller.h. Also the longitude and latitude are just for example.
thanks
#implementation ViewController
- (void)viewWillAppear:(BOOL)animated {
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 39.281516;
zoomLocation.longitude = -76.580806;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation,
0.1*METERS_PER_MILE, 0.1*METERS_PER_MILE);
[_mapView setRegion:viewRegion animated:YES];
}
While I think this is discussed in some detail in the Adding Annotations to a Map section of the Location Awareness Programming Guide, I have a few observations:
You ask "do I need to use MKAnnotation?" Yes and no.
Yes, all annotations should conform to the MKAnnotation protocol. As that guide describes, if you can create your own annotation subclass, you'd want it explicitly declare it to conform to the MKAnnotation protocol.
But, no, you don't have to always create your own annotation class that conforms to the MKAnnotation protocol. You can also use a predefined annotation class, MKPointAnnotation (which, itself, already conforms to the MKAnnotation protocol), such as:
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(39.281516, -76.580806);
annotation.title = #"Lens Crafters";
annotation.subtitle = #"2400 Boston St.";
[self.mapView addAnnotation:annotation];
If you want the old annotation to disappear when you drop a new one on your map, you just (a) keep a reference to the old annotation; (b) when adding a new annotation, remove the old one (if you have an old one); and then (c) add your new annotation.
Thus you might have defined some class property for your annotation:
#property (weak, nonatomic) id<MKAnnotation> annotation;
(Two side observations: First, whether you use weak or strong is up to you and your app design. By saying weak, I'm saying that when the annotation is removed from the map, I'm happy to have the annotation released. Maybe you want it retained until you explicitly nil this property, in which case you'd make this property strong. That's entirely up to you and the goals of your app. Second, I use the type id<MKAnnotation> (i.e. "an object that conforms to MKAnnotation") which makes this more flexible. If you later replace MKPointAnnotation with your own custom annotation class, this property will still work. But if you want to explicitly define this annotation property to be a MKPointAnnotation to match your annotation adding routine, that's fine, too.)
Anyway, now that you have this property, you can now write a method to add an annotation to your map (which removes the old one):
- (void)addAnnotationAtCoordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)title
subtitle:(NSString *)subtitle
{
if (self.annotation)
[self.mapView removeAnnotation:self.annotation];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = title;
annotation.subtitle = subtitle;
[self.mapView addAnnotation:annotation];
self.annotation = annotation;
}
iPhone newbie is here coming from Java. So my objective at this stage is to allow the user to 'drop a pin' on the map. My initialization of the map looks like this:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"your view did load, I'm going to initizlie the map by your location");
CLLocationCoordinate2D location = theMap.userLocation.coordinate;
NSLog(#"Location found from Map: %f %f",location.latitude,location.longitude);
MKCoordinateRegion region;
MKCoordinateSpan span;
NSLog(#"coordinates: %f %f",location.latitude,location.longitude);
if (TARGET_IPHONE_SIMULATOR) {
NSLog(#"You're using the simulator:");
location.latitude = 40.8761620;
location.longitude = -73.782596;
} else {
location.latitude = theMap.userLocation.location.coordinate.latitude;
location.longitude = theMap.userLocation.location.coordinate.longitude;
}
span.latitudeDelta = 0.001;
span.longitudeDelta = 0.002;
region.span = span;
region.center = location;
[theMap setRegion:region animated:YES];
[theMap regionThatFits:region];
[theMap setMapType:MKMapTypeSatellite];
[theMap setZoomEnabled:YES];
[theMap setScrollEnabled:YES];
[theMap setShowsUserLocation:YES];
}
For the requested pin drop I have
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if (annotation != theMap.userLocation) {
static NSString *defaultPinID = #"aPin";
pinView = (MKPinAnnotationView *)[theMap dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (pinView == nil)
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
} else {
}
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
return pinView;
}
I'm not sure I fully understand how this map (theMap) works for pins in viewForAnnotation? I mean, what action the user does will activate the viewForAnnotation method? This code doesn't work and I'm not sure why.
I'm using the simulator so I'm not sure if there's a button I should press or Alt click it?
I'm not sure I fully understand how this map (theMap) works for pins in viewForAnnotation?
MKPinAnnotationView is just another kind of annotation view -- that is, you add an annotation (an object conforming to the MKAnnotation protocol) to the map. When the map wants to display the annotation (maybe because the user scrolled the map so that the annotation is in view), it asks you for a view to use to represent the annotation. At that point, your mapView:viewForAnnotation: method can fetch or create a pin annotation view and return that. The user doesn't do anything directly to trigger mapView:viewForAnnotation:, except for scrolling or zooming.
If you want to the user to be able to drop a pin, that's a different thing. You'll need to provide a view (possibly even a MKPinAnnotationView) that they can drag around. When they indicate that they want to drop the pin (perhaps by lifting their finger), you remove the view and add an appropriate annotation at that point. Then the map view will ask you for a view to represent the annotation by calling its delegate's mapView:viewForAnnotation: method.
This code doesn't work and I'm not sure why.
Have you added any annotations to the map? If so, are you looking at the part of the map where they should be displayed?
I'm guessing that you're looking at the animatesDrop property and expecting it to do the entire user pin-dropping interaction. It doesn't do that. Setting that property to YES merely animates the pin as it appears on the map.
ok, after a while, I understood what went wrong:
theMap.delegate = (id) self;
in the constructor was missing. Once I did that any action by end user will activate other methods (protocols) of the map.
I am trying to learn MAP for iPhone.
What I have right now is below.
Created new project
Added framework for MAP
Brought map object on storyboard (UIViewController)
Run the project.
What I see is, its not showing any location. When I change location in xcode, it shows me the dot at location.
What I wanted is, by default it should show me the PIN to the location that I will set by using latitude and longitude. Also the map should be zoomed. What I meant by zoom is, I should see the location with lets say 13 zoom effect. Right now, I see world map on screen.
Any idea how to get this done?
You can center your map around a location by doing something like this:
MKCoordinateRegion mapRegion;
mapRegion.center.latitude = aLatitude;
mapRegion.center.longitude = aLongitude;
mapRegion.span.latitudeDelta = 0.005;
mapRegion.span.longitudeDelta = 0.005;
self.mapView.region = mapRegion;
Use the span values to determine the zoom level you want.
In order to show a pin you need to create an annotation with the coordinates of your location and then add it to the map.
Also, check out this tutorial.. http://www.raywenderlich.com/2847/introduction-to-mapkit-on-ios-tutorial
Dot is showing your current location.
If you want to add a pin with coordinate you should call addAnnotation method with object which conforms to MKAnnotation protocol. Such object has a property coordinate (you should add it to your class):
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
Also you should add MKMapViewDelegate protocol to your controller and implement -mapView:viewForAnnotation: method. It works as -tableView:viewForRowAtIndexPath:.
- (MKAnnotationView *)mapView:(MKMapView *)_mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *annotationIdentifier = #"annotation";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier]; // Reusing
if (!annotationView) {
MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
pinView.animatesDrop = YES;
annotationView = pinView;
}
else {
annotationView.annotation = annotation; // Reusing already created pin as UITableViewCell does
}
return annotationView;
}
Then when you call
MKMapView *mapView = ...;
id<MKAnnotation> obj = ...;
[mapView addAnnotation:obj];
The pin would be placed on map.
For zoom look there. There is a handy category for those purposes.
If you want to remove current location dot you should find an object with class MKUserLocation in mapView.annotations and then call [mapView removeAnnotation:userLocationDot].
For creating an application with Map you need to implement the MKAnnotation, MKMapViewDelegate delgates.
This is a good tutorial for you.
I have a lot of annotations on the mapView and user location dot. Then, if user tap for 2 sec. on the map, I add an extra annotation with options. I need to remove that last added annotation from map by pressing the button. How can I remove it without to remove any other annotation?
- (void)addPin:(UILongPressGestureRecognizer*)recognizer {
if(UIGestureRecognizerStateBegan == recognizer.state) {
CGPoint tappedPoint = [recognizer locationInView:mapView];
CLLocationCoordinate2D locCoord= [mapView convertPoint:tappedPoint toCoordinateFromView:mapView];
MKPointAnnotation *annot = [[MKPointAnnotation alloc] init];
annot.coordinate = locCoord;
[self.mapView addAnnotation:annot];
}
if(UIGestureRecognizerStateChanged == recognizer.state) {
// Do repeated work here (repeats continuously) while finger is down
}
if(UIGestureRecognizerStateEnded == recognizer.state) {
// Do end work here when finger is lifted
}
}
To remove all the annotations from map view:
[vwMap removeAnnotations:vwMap.annotations];
PS: vwMap is the MKMap view object
Do the following,
If you have the annotation object
[self.mapView removeAnnotation:annot];
If you have the index of the object
[self.mapView removeAnnotation:self.mapView.annotations.lastObject];
Do this to remove your last added annotation in your delete Action:
[self.mapView removeAnnotation:[self.mapView.annotations lastObject]];
Hope helpful
I managed to remove the annotation object that is touched by doing the following, I know this wasn't the question but it may help someone out
set the mapView as delegate
- (void)mapView:(MKMapView *)thisMapView didSelectAnnotationView:(MKAnnotationView *)view {
MKPointAnnotation *thisTouchedAnnotation = view.annotation;
uint8_t annotationCount = thisMapView.annotations.count;
for(int i =0; i<annotationCount; i++)
{
if ([thisMapView.annotations objectAtIndex:i]==thisTouchedAnnotation){
[thisMapView removeAnnotation:[mapView.annotations objectAtIndex:i]];
break;
}
}
}
not flawless code but it may guide you :-)
Use this code!
NSArray *array=self.mapview.annotations;
for (MKPointAnnotation *anno in array)
{
if(anno==[array lastObject])
{
[self.mapview removeAnnotation:anno];
}
}