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;
Related
This question already has answers here:
MKMapView: Instead of Annotation Pin, a custom view
(3 answers)
Closed 9 years ago.
I want to show two flags on Map but these are not pins. I search a lot for this but could not find solutions but to add as pin.
please help
You are looking for Map Overlay MKOverlayView.
Check these tutorials:
Overlay View
Image Overlay
Creating overlay
Creating a MKOverlayView
Create a subclass of MKOverlayView like:
.h
#import
#import
#interface MapOverlayView : MKOverlayView
{
}
#end
.m
#import "MapOverlayView.h"
#implementation MapOverlayView
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)ctx
{
UIImage *image = [UIImage imageNamed:#"yourImage.png"];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextDrawImage(ctx, theRect, imageReference);
}
#end
Adding Overlay
Implement the viewForOverlay: ,inside that create the overlay and add to map.
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MapOverlay *mapOverlay = (MapOverlay *)overlay;
MapOverlayView *mapOverlayView = [[[MapOverlayView alloc] initWithOverlay:mapOverlay] autorelease];
return mapOverlayView;
}
you can do it with MKAnnotationView with image property like bellow in viewForAnnotation: method..
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"Current";
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier] autorelease];
}
if (annotation == mapView.userLocation)
return nil;
annotationView.image = [UIImage imageNamed:#"yourImageName.png"];
annotationView.annotation = annotation;
annotationView.canShowCallout = YES;
return annotationView;
}
try this one
annotation = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"try"];
annotation.canShowCallout = YES;
annotation.image = [UIImage imageNamed:#"image.png"];
return annotation;
and do not use annotation.animatesDrop property.
If you are talkin about MKMapView:
To show an image instead of Pin annotation , you need to override MKMapView's method
- (MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation
Like this:
- (MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation{
static NSString* annotationIdentifier = #"Identifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
annotationView.canShowCallout = YES;
// here you need to give the image you want instead of pin
annotationView.image = [UIImage imageNamed:[NSString stringWithFormat:#"balloon.png"]];
return annotationView;
}
return nil;
}
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!
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"];
}
I would like to know how to change the pin color of an annotation in map kit. Currently Im using the following code.
//King Solomon's Lodge No. 194
CLLocationCoordinate2D kingsolomons;
kingsolomons.latitude = 38.052041;
kingsolomons.longitude = -78.683218;
Annotation *kingsolomonslodge = [[Annotation alloc] init];
kingsolomonslodge.coordinate = kingsolomons;
kingsolomonslodge.title = #"King Solomon's Lodge No. 194";
kingsolomonslodge.subtitle = #"Charlottesville, VA";
[self.myMapView addAnnotation:kingsolomonslodge];
I have googled this question a few times but Im unsure on how to implement this into the current code that I have.
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapview.userLocation)
return nil;
MKPinAnnotationView *pin = (MKPinAnnotationView *) [mapview dequeueReusableAnnotationViewWithIdentifier: #"asdf"];
if (pin == nil)
pin = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: #"asdf"] autorelease];
else
pin.annotation = annotation;
// NSLog(#"%#",annotation.title);
NSString *titlename=#"xyz";
if ([annotation.title isEqualToString:titlename]) {
pin.pinColor = MKPinAnnotationColorGreen;
// pin.image=[UIImage imageNamed:#"arrest.png"] ;
}
else{
pin.pinColor= MKPinAnnotationColorPurple;
}
pin.userInteractionEnabled = YES;
UIButton *disclosureButton = [UIButton buttonWithType:UIButtonTypeCustom];
// //pin.image=[UIImage imageNamed:#"arrest.png"] ;
pin.rightCalloutAccessoryView = disclosureButton;
//pin.pinColor = MKPinAnnotationColorRed;
pin.animatesDrop = YES;
[pin setEnabled:YES];
[pin setCanShowCallout:YES];
return pin;
}
You can use pinColor property if MKAnnotation class.
kingsolomonslodge.pinColor = MKPinAnnotationColorGreen;
Another way is you can use image instead of the default pin using viewForAnnotation: delegate:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[yourAnnotationLocation class]])
{
MKAnnotationView *annotationView = (MKAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"yourImage.png"];//here we use a nice image instead of the default pins
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
try this man...
kingsolomonslodge.pinColor = AnnotationColorRed;
let me know whether it is workihg or not
happy coding!!!!
If you want to apply custom color you can add image also.
MKAnnotationView *pinView = nil;
pinView.image = [UIImage imageNamed:#"pinks.jpg"];
Since iOS 9:
kingsolomonslodge.pinTintColor = UIColor.greenColor;
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.