andrei
andrei

Reputation: 2083

How do I change the frame position for a custom MKAnnotationView?

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];
}

Upvotes: 7

Views: 14038

Answers (4)

VICTORGS3
VICTORGS3

Reputation: 203

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

Upvotes: 3

BadPirate
BadPirate

Reputation: 26177

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.

Upvotes: 19

NBALA
NBALA

Reputation: 17

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;
}

Upvotes: -3

Tom
Tom

Reputation: 3861

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

Upvotes: 16

Related Questions