7

I am trying to make a custom annotation view by subclassing MKAnnotationView and overriding the drawRect method. I want the view to be drawn offset from the annotation's position, somewhat like MKPinAnnotationView does it, so that the point of the pin is at the specified coordinates, rather than the middle of the pin. So I set the frame position and size as shown below. However, it doesn't look like I can affect the position of the frame at all, only the size. The image ends up being drawn centered over the annotation position. Any tips on how to achieve what I want?

MyAnnotationView.h:

@interface MyAnnotationView : MKAnnotationView {

}

MyAnnotationView.m:

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
        self.canShowCallout = YES;
        self.backgroundColor = [UIColor clearColor];
        // Position the frame so that the bottom of it touches the annotation position 
        self.frame = CGRectMake(0, -16, 32, 32);
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    [[UIImage imageNamed:@"blue-dot.png"] drawInRect:rect];
}
Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
andrei
  • 2,053
  • 3
  • 17
  • 16

4 Answers4

19

I tried using centerOffset and for some reason the image was in the right position when zoomed in, but as you zoomed the map out the image would move away from where it was supposed to be. The fix to this was setting the image frame with the offset. Here's the code I used (You can leave out the callout stuff if you don't have a callout), I used the pins from here)

#pragma mark MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    if(![annotation isKindOfClass:[MyAnnotation class]]) // Don't mess user location
        return nil;

    MKAnnotationView *annotationView = [aMapView dequeueReusableAnnotationViewWithIdentifier:@"spot"];
    if(!annotationView)
    {
        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"spot"];
        annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [(UIButton *)annotationView.rightCalloutAccessoryView addTarget:self action:@selector(openSpot:) forControlEvents:UIControlEventTouchUpInside];
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
        annotationView.centerOffset = CGPointMake(7,-15);
        annotationView.calloutOffset = CGPointMake(-8,0);
    }

    // Setup annotation view
    annotationView.image = [UIImage imageNamed:@"pinYellow.png"]; // Or whatever

    return annotationView;
}

Adjust centerOffset and calloutOffset as needed to suit your image, and desired center point, and callout point.

Community
  • 1
  • 1
BadPirate
  • 25,802
  • 10
  • 92
  • 123
  • 1
    You said "The fix to this was setting the image frame with the offset", but the code provided does not solve the issue. Can you elaborate? centerOffset does not seem to be doing anything on iOS7 (on iOS6 it was fine) – Zoltán Matók Nov 05 '13 at 15:04
  • 1
    I'm using a totally different shape for my annotation view and this doesn't seem to fix the problem. Also, I don't think this solution has anything to do with adjusting the annotation's position as per zoom level. – huong Jan 20 '14 at 08:52
  • I experienced this as well. I had to set the CenterOffset to 0,0 or else it translated the image along with the map moving at some function of the offset x/y ratio. Not sure why. – Timothy Lee Russell May 31 '15 at 01:21
16

Rather than subclass MKAnnotationView, have you tried using a generic MKAnnotationView and setting the image and centerOffset properties?

Tom
  • 3,831
  • 1
  • 22
  • 24
  • Yes, that works for an image-based annotation view (which is actually enough for my purposes). But I'm still curious about the general case. – andrei Mar 21 '10 at 05:56
3

Your UIAnnotationView is always drawn at the same scale, the map's zoom level doesn't matter. That's why centerOffset isn't bound with the zoom level.

annView.centerOffset is what you need. If you see that your pin is not at the good location (for example, the bottom center move a little when you change the zoom level), it's because you didn't set the right centerOffset.

By the way, if you want to set the point of the coordinate at the bottom center of the image, the x coordinate of your centerOffset should be 0.0f, as annotationView center the image by default. So try :

annView.centerOffset = CGPointMake(0, -imageHeight / 2);

Answer from [MKAnnotation image offset with custom pin image

Community
  • 1
  • 1
VICTORGS3
  • 203
  • 3
  • 13
-3

Thanks for the example BadPirate.

I tried using UIImageview, but I dont think it is necessary.

My class looked like this

@interface ImageAnnotationView : MKAnnotationView {
    UIImageView *_imageView;
    id m_parent;
    BusinessMapAnnotation *m_annotation;

    NSString *stitle;
}

And the implementation

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    self.frame = CGRectMake(0, 0, kWidth, kHeight);
    self.backgroundColor = [UIColor clearColor];

    self.m_annotation = (BusinessMapAnnotation*)annotation;

    NSString* categoryTitle = m_annotation.sCTitle;

    NSString* l_titleString =  @"NearPin.png";

    if (categoryTitle!= nil ) {
        if ([categoryTitle length] > 0) {
            //NSLog(@"%@", categoryTitle);
            l_titleString = [NSString stringWithFormat:@"Map%@.png", categoryTitle];
            //NSLog(@"%@", l_titleString);
        }
    }

    self.stitle = m_annotation.sTitle;

    _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:([stitle isEqualToString:@"You are here"]) ? @"Pushpin_large.png":l_titleString]];
    _imageView.contentMode = UIViewContentModeCenter;

    _imageView.frame = CGRectMake(kBorder, kBorder, kWidth, kHeight);

    [self addSubview:_imageView];
    _imageView.center = ([stitle isEqualToString:@"You are here"]) ? CGPointMake(15.0, -10.0):CGPointMake(kWidth/2, 0.0);

    return self;
}
NBALA
  • 17
  • 4