I have the annotation ready to go, but trying to figure out on how to make it draggable with my code:
-(IBAction) updateLocation:(id)sender{
MKCoordinateRegion newRegion;
newRegion.center.latitude = mapView.userLocation.location.coordinate.latitude;
newRegion.center.longitude = mapView.userLocation.location.coordinate.longitude;
newRegion.span.latitudeDelta = 0.0004f;
newRegion.span.longitudeDelta = 0.0004f;
[mapView setRegion: newRegion animated: YES];
CLLocationCoordinate2D coordinate;
coordinate.latitude = mapView.userLocation.location.coordinate.latitude;
coordinate.longitude = mapView.userLocation.location.coordinate.longitude;
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate: coordinate];
[annotation setTitle: #"Your Car is parked here"];
[annotation setSubtitle: #"Come here for pepsi"];
[mapView addAnnotation: annotation];
[mapView setZoomEnabled: YES];
[mapView setScrollEnabled: YES];
}
Thanks in advance!
To make an annotation draggable, set the annotation view's draggable property to YES.
This is normally done in the viewForAnnotation delegate method.
For example:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *reuseId = #"pin";
MKPinAnnotationView *pav = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (pav == nil)
{
pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
pav.draggable = YES;
pav.canShowCallout = YES;
}
else
{
pav.annotation = annotation;
}
return pav;
}
If you need to handle when the user stops dragging and drops the annotation, see:
how to manage drag and drop for MKAnnotationView on IOS?
In addition, your annotation object (the one that implements MKAnnotation) should have a settable coordinate property. You are using the MKPointAnnotation class which does implement setCoordinate so that part's already taken care of.
Related
I am trying to add annotations on MKMapView. The annotations can show up when the coordinates are not (0, 0), but when I set the annotation's coordinate as (0, 0), the annotation view can NOT show up.
On the iPhone XS simulator and device, only one annotation showing(location (10, 0)), the location(0, 0) not show up.
It seem that the (0, 0) annotation is add at the bottom of the map, not at the west side of Africa.
Any suggestion is appreciated.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Add Annotation
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(0, 0);
[self.mapView addAnnotation:annotation];
MKPointAnnotation *annotationZero = [[MKPointAnnotation alloc] init];
annotationZero.coordinate = CLLocationCoordinate2DMake(10, 0);
[self.mapView addAnnotation:annotationZero];
}
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
static NSString *reuseIdentifier = #"map_annotation";
MKAnnotationView *annotationView = [_mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
}
annotationView.image = [UIImage imageNamed:#"annotation_icon"];
return annotationView;
}
return nil;
}
I started with a test using Swift and CLLocationCoordinate2DMake(0,0) worked fine, so the problem isn't related to a device but it is language specific issue.
You cannot use (0,0) in objective-c, instead use DBL_MIN, which is the smallest number possible, like so:
CLLocationCoordinate2DMake(DBL_MIN, DBL_MIN)
Am trying to add custom annotations on MKMapView and implement custom callOut view on tap of annotation.
Am following this link for the same. The issue is when I add the custom annotation didSelectAnnotationView is called on its own and the popOver callout is shown, even when the user has not clicked the annotation
Here is my code:
-(void)callAddAnnotationsLocal{
[_mapView removeAnnotations:[_mapView annotations]];
CLLocationCoordinate2D coord = {.latitude = 43.3998170679, .longitude = -95.1288472486};
[_mapView addAnnotations:[self annotationsLocal]];
}
-(NSArray *)annotationsLocal{
self.annotArrayLocal = nil;
self.annotArrayLocal = [[NSMutableArray alloc] init];
for (int i=0; i<[arrAmmenities count];i++)
{
MKAnnotationView *propertyAnnotation = [[MKAnnotationView alloc] init];
UIFont *font = [UIFont fontWithName:#"Arial" size:18];
NSDictionary *userAttributes = #{NSFontAttributeName: font,
NSForegroundColorAttributeName: [UIColor blackColor]};
NSString *latStr = [NSString stringWithFormat:#"%#",[[arrAmmenities objectAtIndex:i]objectForKey:#"latitude"]];
float latitude = [latStr floatValue];
NSString *longStr = [NSString stringWithFormat:#"%#",[[arrAmmenities objectAtIndex:i]objectForKey:#"longitude"]];
float longitude = [longStr floatValue];
CLLocationCoordinate2D coord = {.latitude = latitude, .longitude = longitude};
PinAnnotation * annotation = [[PinAnnotation alloc] init];
[annotation setCoordinate:coord];
[annotation setType:[[arrAmmenities objectAtIndex:i] objectForKey:#"category"]];
[annotation setTag:i];
[self.mapView addAnnotation:annotation];
[self.annotArrayLocal addObject:propertyAnnotation];
}
return _annotArrayLocal;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation {
MKAnnotationView *annotationView;
NSString *identifier;
if ([annotation isKindOfClass:[PinAnnotation class]]) {
// Pin annotation.
identifier = #"Pin";
annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
if([[(PinAnnotation *)annotation type] isEqualToString:#"Gas Stations"])
annotationView.image = [UIImage imageNamed:#"marker_gas"];
else if([[(PinAnnotation *)annotation type] isEqualToString:#"Golf Courses"])
annotationView.image = [UIImage imageNamed:#"marker_golf"];
else if([[(PinAnnotation *)annotation type] isEqualToString:#"Restaurants"])
annotationView.image = [UIImage imageNamed:#"marker_restaurant"];
else
annotationView.image = [UIImage imageNamed:#"marker_hospital"];
annotationView.canShowCallout = NO;
}
return annotationView;
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
// [mapView deselectAnnotation:view.annotation animated:YES];
MapAnnotViewController *controller = [[UIStoryboard storyboardWithName:#"MapStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"sidMapAnnotVC"];
// controller.annotation = view.annotation; // it's useful to have property in your view controller for whatever data it needs to present the annotation's details
wyPopController = [[WYPopoverController alloc] initWithContentViewController:controller];
wyPopController.delegate = self;
[wyPopController setPopoverContentSize:CGSizeMake(200.0, 100.0)];
[wyPopController presentPopoverFromRect:view.frame
inView:view.superview
permittedArrowDirections:WYPopoverArrowDirectionAny
animated:YES];
}
Where am I getting wrong? How do I solve this?
A couple of thoughts:
In annotationsLocal, you are not only instantiating PinAnnotation objects and adding them to a map, but you are also instantiating MKAnnotationView objects, building an array of them, and then returning that array, which is then added as annotations to the map view.
That second array of MKAnnotationView should not be built at all, and certainly shouldn't be added as annotations of the map view. Don't conflate annotation objects (which represent the coordinates of points on a map) and annotation view objects (which represent visual representation of those annotations as they are rendered on the map).
As an aside, and unrelated to your problem, you are instantiating unnecessary annotation views in viewForAnnotation, too. You should dequeue an annotation view, and only instantiate a new one if you didn't successfully retrieve one that was to be reused:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation {
MKAnnotationView *annotationView;
if ([annotation isKindOfClass:[PinAnnotation class]]) {
// Pin annotation.
NSString *identifier = #"Pin";
annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView) {
annotationView.annotation = annotation
} else {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.canShowCallout = NO;
}
if ([[(PinAnnotation *)annotation type] isEqualToString:#"Gas Stations"])
annotationView.image = [UIImage imageNamed:#"marker_gas"];
else if([[(PinAnnotation *)annotation type] isEqualToString:#"Golf Courses"])
annotationView.image = [UIImage imageNamed:#"marker_golf"];
else if([[(PinAnnotation *)annotation type] isEqualToString:#"Restaurants"])
annotationView.image = [UIImage imageNamed:#"marker_restaurant"];
else
annotationView.image = [UIImage imageNamed:#"marker_hospital"];
}
return annotationView;
}
But I'm not seeing anything here that would cause didSelectAnnotationView to be called, unless that incorrect process of adding annotation views as annotations had some weird side effect that caused this. If you're still seeing didSelectAnnotationView called, I might suggest adding a breakpoint there and looking at the call stack and seeing if you can see where that was being invoked. But hopefully the fixing of annotationsLocal will fix it.
I am trying to change colour of annotation pin on MKMapView by overriding this below:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.pinColor = MKPinAnnotationColorGreen;
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Here below are relevant methods:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
// display map ????
PFGeoPoint *geoPoint = self.detailItem[#"location"];
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(geoPoint.latitude,geoPoint.longitude);
MKPointAnnotation *annotation =[[MKPointAnnotation alloc] init];
annotation.coordinate = coordinate;
// remove previous annotation pin
if([self.mapView.annotations count] == 1) {
[self.mapView removeAnnotation:[self.mapView.annotations objectAtIndex:0]];
}
[self.mapView addAnnotation:annotation];
annotation.title = self.detailItem[#"text"];
MKCoordinateSpan span = {.latitudeDelta = 0.05, .longitudeDelta = 0.05};
MKCoordinateRegion region = {coordinate, span};
[self.mapView setRegion:region];
[self.mapView setCenterCoordinate:self.mapView.region.center animated:NO];
}
}
My problem is pin annotation colour is still shown Red as default not Green as I want. What am I missing here?
Credit to #Anna, add the line below to - (void)configureView
self.mapView.delegate = self;
I am trying to annotate my map with MKPointAnnotation, like this:
- (void)viewDidLoad
{
NSLog(#"RootViewController viewDidLoad");
[super viewDidLoad];
CLLocationCoordinate2D coord =
CLLocationCoordinate2DMake(54.903683,23.895435);
MKPointAnnotation *toyAnnotation = [[MKPointAnnotation alloc] init];
toyAnnotation.coordinate = coord;
toyAnnotation.title = #"Title";
toyAnnotation.subtitle = #"Subtitle";
[mapView addAnnotation:toyAnnotation];
[toyAnnotation release];
}
- (MKAnnotationView *)mapView:(MKMapView *)m
viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"RootViewController mapView: viewForAnnotation:");
NSLog(#"%#",annotation);
MKAnnotationView *pin = [[MKAnnotationView alloc]
initWithAnnotation:annotation
reuseIdentifier:nil];
pin.enabled = YES;
pin.canShowCallout = YES;
return [pin autorelease];
}
Pin fails to appear on the map. RootViewController is a delegate for mapView and thus mapView:viewForAnnotation: method gets called:
2011-11-24 15:04:03.808 App[2532:707] RootViewController mapView: viewForAnnotation:
2011-11-24 15:04:03.810 App[2532:707] <MKPointAnnotation: 0x1885c0>
What am I doing wrong and how to fix this issue?
In viewForAnnotation, create an MKPinAnnotationView instead of an MKAnnotationView (for which you have to set the image).
Although for a default pin annotation view, you don't need to implement the delegate method at all.
please i have recently made a Map which suppose to show the user location (green pin color) and others annotations for service stations (red pins color), for the moment, i am able to show all annotations with the same color and i still unable to tell the MKMapView delegate how to make difference between two pin types and so assign to each type the right title to show.
this is my MKAnnotationView method :
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
[annotationView setAnimatesDrop:YES];
annotationView.canShowCallout = YES;
return annotationView;
}
return nil;
}
and for my class which implement the MKAnnotation delegate i have this method :
-(id)initWithName:(NSString *)enseigneDeLaStation distanceVersLaStation:(NSString *) distanceVersLaStation coordinate:(CLLocationCoordinate2D)coordinate
{
if ((self = [super init])) {
_enseigneDeLaStation = [enseigneDeLaStation copy];
_distanceVersLaStation = [distanceVersLaStation copy];
_coordinate = coordinate;
}
return self;
}
thx in advance for your help :)
EDIT
i try to make the user location annotation like this, please if i am wrong correct me :
location2D = (CLLocationCoordinate2D){ .latitude = latitudeOfUserLocation, .longitude = longitudeOfUserLocation };
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
[mapView addAnnotation:annotation];
EDIT 2
Hi again, i try to make one annotation to make sure it even call the annotation method so imake this simple example :
latitudeOfUserLocation=43.2923;
longitudeOfUserLocation=5.45427;
location2D = (CLLocationCoordinate2D){ .latitude = latitudeOfUserLocation, .longitude = longitudeOfUserLocation };
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"coucou" coordinate:location2D]autorelease];
[mapView addAnnotation:annotation];
MKCoordinateSpan span={latitudeDelta:1,longitudeDelta:0.5};
MKCoordinateRegion region={location2D,span};
[mapView setRegion:region];
when i run the app, i see the region zoomed well which go with the 43.2923/5.45427 but i don't see the annotation, why it's not calling the annotation method,i can't move on since it's not showing the user annotation, please help, thx in advance :)
EDIT 3
Hi, i assumed that this has always relation with making difference between user and station pins, so i have declared a var codeColor, set it to 1 (the type of the user) when invoking the annotations and set it to 2(station type) when calling the annotations for the stations :
-(void)viewWillAppear:(BOOL)animated
{
codeColor=1;//it's the first type, the user one
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are right here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorGreen;
[mapView addAnnotation:annotation];
}
and :
-(void)requestFinished:(ASIHTTPRequest *)request
{ codeColor=2;
[MBProgressHUD hideHUDForView:self.view animated:YES];
MyLocation *annotation=[[[MyLocation alloc]initWithName:ensStation distanceVersLaStation:distance coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorPurple;
[mapView addAnnotation:annotation];
}
and for the annotations method :
if (codeColor==2) {
annotationView.rightCalloutAccessoryView=[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
now when testing for the first time, all is ok, the user annotation without button and the station one is with the button, but when i move from the view and i came back, all annotations are with buttons, even the user one. could you please help me there, thx in advance :)
One simple way is to add a pinColor property to your MyLocation class:
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
When creating the annotation, set the pinColor:
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorGreen; //or red or whatever
[mapView addAnnotation:annotation];
and in the viewForAnnotation method:
//...
annotationView.canShowCallout = YES;
annotationView.pinColor = ((MyLocation *)annotation).pinColor;