MKMapView Off Screen Annotation Image Incorrect - iphone

I have a map to which I add several annotations, like so:
for (Users *user in mapUsers){
double userlat = [user.llat doubleValue];
double userLong = [user.llong doubleValue];
CLLocationCoordinate2D userCoord = {.latitude = userlat, .longitude = userLong};
MapAnnotationViewController *addAnnotation = [[MapAnnotationViewController alloc] initWithCoordinate:userCoord];
NSString *userName = user.username;
NSString *relationship = user.relationship;
[addAnnotation setTitle:userName];
[addAnnotation setRelationshipParam:relationship];
[self.mainMapView addAnnotation:addAnnotation];
}
Using this delegate method code:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *identifier = #"AnnotationIdentifier";
if ([annotation isKindOfClass:[MapAnnotationViewController class]]) {
MKAnnotationView *annView = (MKAnnotationView *)[self.mainMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annView) {
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}
MapAnnotationViewController *sac = (MapAnnotationViewController *)annView.annotation;
if ([sac.relationshipParam isEqualToString:#"paramA"])
{
annView.image = [UIImage imageNamed:#"image1.png"];
}
else if ([sac.relationshipParam isEqualToString:#"paramB"])
{
annView.image = [UIImage imageNamed:#"image2.png"];
}
else if ([sac.relationshipParam isEqualToString:#"paramC"])
{
annView.image = [UIImage imageNamed:#"image3.png"];
}
return annView;
}
else {
return nil;
}
This all works fine on the original loading of the map. However, when I select the annotation (which has custom code that is too long to post but includes a zoom in) the annotation images that were previously drawn have changed icons. The map is not redrawn and the annotations are not re-added in that process. When I pinch back out on the map, the images are different (they have match the incorrect relationship params with the wrong image1-3.png's.
Can anyone think of why this is happening, or what to look for?

The dequeueReusableAnnotationViewWithIdentifier may return an annotation view that was used for an annotation different from the current annotation parameter.
If the dequeueReusableAnnotationViewWithIdentifier is succesful (ie. you're using a previously-used annotation view), you must update its annotation property to be sure the view matches the current annotation's properties.
So try changing this part:
MKAnnotationView *annView = (MKAnnotationView *)[self.mainMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annView) {
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}
MapAnnotationViewController *sac = (MapAnnotationViewController *)annView.annotation;
to:
MKAnnotationView *annView = (MKAnnotationView *)[self.mainMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annView) {
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}
else {
annView.annotation = annotation; // <-- add this
}
MapAnnotationViewController *sac = (MapAnnotationViewController *)annView.annotation;
Another potential issue (not causing the problem in the question) is that the view's image property is only set if relationshipParam is one of three values.
If somehow relationshipParam is not one of those three coded values and the view was dequeued, the image will be based on some other annotation's relationshipParam.
So you should add an else part to the section that sets image and set it to some default image just in case:
...
else if ([sac.relationshipParam isEqualToString:#"paramC"])
{
annView.image = [UIImage imageNamed:#"image3.png"];
}
else
{
annView.image = [UIImage imageNamed:#"UnknownRelationship.png"];
}

Related

multiple annotation in map messing

I have dot as a pin annotation in map and showing custom annotation view.My problem is that when I click on dot sometimes dot behinds custom annotation view comes in fron of custom annotation view instead of showing behind it.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKAnnotationView *annotationView;
PinAnnotationView *pinView = nil;
NSString *identifier;
if ([annotation isKindOfClass:[DisplayMap class]])
{
identifier = #"Pin";
NSInteger myid = ((DisplayMap *)annotation).takeid;
MKAnnotationView *pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
DisplayMap *a = (DisplayMap *)annotation;
pinView.annotation=a;
if (myid == 1)
{
UIImage *test = [UIImage imageNamed:#"red_dot.png"];
pinView.image = test;
pinView.opaque = NO;
}
else if (myid == 2)
{
UIImage *test = [UIImage imageNamed:#"blue_dot.png"];
pinView.image = test;
pinView.opaque = NO;
}
else {
UIImage *test = [UIImage imageNamed:#"green_dot.png"];
pinView.image = test;
pinView.opaque = NO;
}
return pinView;
}
else if ([annotation isKindOfClass:[CalloutAnnotation class]])
{
identifier = [NSString stringWithFormat:#"Callout%d",pinView.tag];
annotationView = [[CalloutAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
CalloutAnnotation *calloutAnnotation = (CalloutAnnotation *)annotation;
((CalloutAnnotationView *)annotationView).title = calloutAnnotation.title;
((CalloutAnnotationView *)annotationView).iTag = calloutAnnotation.iTag;
[annotationView setNeedsDisplay];
[UIView animateWithDuration:0.5f
animations:^(void) {
mapView.centerCoordinate = calloutAnnotation.coordinate;
}];
annotationView.annotation = annotation;
return annotationView;
}
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view1
{
if ([view1.annotation isKindOfClass:[DisplayMap class]])
{
DisplayMap *pinAnnotation = ((DisplayMap *)view1.annotation);
LoginDetail *obj = [[appDelegate mapArray] objectAtIndex:pinAnnotation.iTag];
[mapView removeAnnotations:annotationRemoveArray];
CalloutAnnotation *calloutAnnotation = [[CalloutAnnotation alloc] init];
calloutAnnotation.title = pinAnnotation.title;
pinAnnotation.calloutAnnotation = calloutAnnotation;
[mapView addAnnotation:calloutAnnotation];
[annotationRemoveArray addObject:calloutAnnotation];
[self setzoomonselectannotation:pinAnnotation.coordinate];
}
}
The callout window is an annotation view as well. That is wrong ;)
follow one the hints:
How to customize the callout bubble for MKAnnotationView?
Basically what they say: make the callout a subview of the pin itself

MKAnnotationView doesn't show custom pin

I'm implementing a custom pin for a map, the image is in te project's folder but didn't show.
Perhaps (and very likely) I'm doing something wrong.
The map displays and shows the pins (default red pins) but not the custom image nor the UIButtonTypeDetailDisclosure
This is the code I'm using:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// in case it's the user location, we already have an annotation, so just return nil
if ([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
static NSString *TheAnnotationIdentifier = #"theAnnotationIdentifier";
MKAnnotationView *shoppeAnnotationView =
[self.mapView dequeueReusableAnnotationViewWithIdentifier:TheAnnotationIdentifier];
if (shoppeAnnotationView == nil)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:TheAnnotationIdentifier];
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"pin.png"];
annotationView.rightCalloutAccessoryView = [ UIButton buttonWithType:UIButtonTypeDetailDisclosure ];
annotationView.opaque = NO;
return annotationView;
}
return nil;
}
Any hints?
Thank you!

MKMapView custom pins change when I zoom in and out

I'm making an app that uses MKMapView. I add custom pins (with image). And now when I zoom in and then zoom out, pins change back to default (red color).
Here is my code:
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
static NSString* SFAnnotationIdentifier = #"Kamera";
MKPinAnnotationView* pinView =
(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];
if (!pinView)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:SFAnnotationIdentifier];
annotationView.canShowCallout = NO;
UIImage *flagImage = [UIImage imageNamed:#"pinModer.png"];
CGRect resizeRect;
resizeRect.size = flagImage.size;
resizeRect.size = CGSizeMake(40, 60);
resizeRect.origin = (CGPoint){0.0f, 0.0f};
UIGraphicsBeginImageContext(resizeRect.size);
[flagImage drawInRect:resizeRect];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
annotationView.image = resizedImage;
annotationView.opaque = NO;
UIImageView *sfIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"kameraNaprejModra.png"]];
annotationView.leftCalloutAccessoryView = sfIconView;
return annotationView;
}
return nil;
}
The code is not handling the case where the dequeue returns a non-nil pinView (meaning it is re-using a previous annotation view).
If pinView is not nil, the method ends up at the last line which returns nil for the annotation view.
When you return nil, the map view draws the default annotation view which is a red pin.
Adjust the code like this:
if (!pinView)
{
//no changes to code inside this if
//...
return annotationView;
}
//add an else part and return pinView instead of nil...
else
{
pinView.annotation = annotation;
}
return pinView;

Multiple annotation color

i have a map with multiple annotation on it. i was able to show the first and the last annotations. i want to give each annotation a different color.
here is my code of how to insert my annotations
if(i<1 || i >object.count-2)
{
MyAnnotation* myAnnotation1=[[MyAnnotation alloc] init];
myAnnotation1.coordinate=theCoordinate1;
myAnnotation1.title=DEVNAME;
myAnnotation1.subtitle=it.address;
[mapView addAnnotation:myAnnotation1];
[annotations addObject:myAnnotation1];
}
the if condition is reading the index of the array to only drop the first and last annotation.
and here is how do i drop the pins on the map...
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString* MyAnnotationIdentifier = #"MyAnnotationIdentifier";
MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:MyAnnotationIdentifier] autorelease];
customPinView.pinColor = MKPinAnnotationColorRed;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
how to different annotations color?
It is of course not going to work as except for the first and last pin, for rest of the pins, the else part of the code will execute.
So there the MKPinAnnotationView *pinView will be nil. So the annotation with no memory allocated, can not change color!!! :-)
You must alloc, init the MKPinAnnotationView *pinView for else part somewhere according to your requirement.
Use MKAnnotationView class and set a custom image for each pin:
MKAnnotationView *customPinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
customPinView.image = [UIImage imageNamed:#"pin1.png"];
.
.
.
instead of using images from your app bundle, you might need to programmatically build your UIImage so you can achieve unique colors, this is up to you.
Furthermore, you can set a value on your annotation to help identify which annotation gets which image. You'll subclass MKAnnotation to add this integer property called pinNumber.
myAnnotation.pinNumber = 2;
customPinView.image = [UIImage imageNamed:[NSString stringWithFormat:#"pin%d.png",annotation.pinNumber]];

setting up Image in MKAnnotationPinView

I have the following code inside the delegate:
- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id <MKAnnotation>)anAnnotation
{
MKPinAnnotationView *pin = (MKPinAnnotationView *) [map dequeueReusableAnnotationViewWithIdentifier: #"RoutePin"];
if (pin == nil)
{
if ([anAnnotation isKindOfClass:[RouteMapAnnotation class]])
{
RouteMapAnnotation *theAnnotation = (RouteMapAnnotation *)anAnnotation;
if (theAnnotation.identifier == #"routePin")
{
//NSLog(#"TESTING PART III");
MKPinAnnotationView *startAnnotationPin = [[MKPinAnnotationView alloc] initWithAnnotation:anAnnotation reuseIdentifier:#"RoutePin"];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
startAnnotationPin.canShowCallout = YES;
startAnnotationPin.animatesDrop = YES;
startAnnotationPin.rightCalloutAccessoryView = rightButton;
startAnnotationPin.pinColor = MKPinAnnotationColorRed;
return startAnnotationPin;
}
else if (theAnnotation.identifier == #"finishPin")
{
NSLog(#"CREATING FINISH FLAG PRIOR");
MKPinAnnotationView *finishAnnotationPin = [[MKPinAnnotationView alloc] initWithAnnotation:anAnnotation reuseIdentifier:#"FinishPin"];
finishAnnotationPin.canShowCallout = NO;
finishAnnotationPin.animatesDrop = YES;
//finishAnnotationPin.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://cdn4.iconfinder.com/data/icons/formula1/f1_png/128/checkered_flag.png"]]];
finishAnnotationPin.image = [UIImage imageNamed:#"flag_finish"];
return finishAnnotationPin;
}
}
}
return nil;
}
However it's not showing the image for the pin on the map. What am I missing??
You should use MKAnnotationView instead of MKPinAnnotationView.
pin annotation is for pins.
Also note that MKPinAnnotationView does offer some additional functionality to a regular MKAnnotationView, such as animating while dragging and the 3d shadow effect. You won't get these if you use MKAnnotationView.
If you want these built-in features, you can create a UIImageView and add it as a subview to your MKPinAnnotationView. This will give you an annotation that looks like whatever you want; but behaves like a pin. I use it to replace the head of the pin with my own images.