1

I need to derive a new class from the MKAnnotationView just like in the WeatherMap project from Apple but with the graphic part defined through a NIB file: is there a way of doing this? Do I have to create a new controller?

stack-o-frankie
  • 457
  • 5
  • 15

2 Answers2

13

One way to do it is to load a view from a nib, then add the view as a subview to your MKAnnotationView. You do not need to create any new controllers.

First, create your MKAnnotationView subclass, with a property into which you'll load the NIB's custom view:

@interface MapAnnotationView : MKAnnotationView 

@property (nonatomic, retain) IBOutlet UIView* loadedView;

Then, in the init method for this class, load the nib and add as a subview:

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString*)reuseIdentifier
{
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self != nil)
    {
        [[NSBundle mainBundle] loadNibNamed:@"MyCustomView" owner:self options:nil];
        if (loadedView){
            [self addSubview:loadedView];
        }
    }
    return self;
}

Finally, create your MyCustomView NIB (as a UIView). Make the file's owner the above MapAnnotationView class, and attach the view to the IBOutlet defined above.

That's about it.

Aidan O
  • 549
  • 4
  • 10
  • Hi, Aidan! I try your code and what I get was the pin Annotation like the _loadedView_. Is it possible to have an annotation view (the one that comes up when touches on pin) loaded from a nib file?? Thanks – Frade Jan 20 '12 at 15:53
  • Yes, my example supports that. I suspect you have something mis-wired that's causing the default pin to show up rather than what's defined in the NIB's UIView. – Aidan O Jan 21 '12 at 00:46
  • Sorry my mistake. I didn't explain it properly. What i'm trying to do is to load a custom callout from Nib. If you don't mind please check [this question](http://stackoverflow.com/questions/8945376/how-to-add-a-custom-calloutview-loaded-from-nib-file), its well explained. Thanks – Frade Jan 23 '12 at 10:33
  • How can you set the reuseIdentifier on the annotation view, seeing as how that property is read-only? – elsurudo Mar 23 '13 at 21:28
  • @AidanO Thanks, it worked. Still I have a problem, when the map view loaded and the annotation added, the callout are all showed. I only want to show it when I click on the pin. What's wrong? – yong ho Nov 05 '14 at 02:44
  • Could you translate this to Swift please ? – Jack Berstrem Feb 16 '16 at 16:07
4

One problem with the Aidan's solution is that it load the view from nib and then add it as a subview of the custom AnnotationView. This will result in an extra view sitting in the memory for every visible annotation that you created on the map view. If you have only one annotation, then maybe it doesn't matter. But if you have dozens of annotations on the map at the same time, then that solution is a bit waste of memory and GPU rendering resources.

A simpler and more efficient solution is to override the reuseIdentifier getter method in your custom MapAnnotationView, like so:

class MapAnnotationView: MKAnnotationView {
    override var reuseIdentifier: String? {
        get { return "MapAnnotationView" }
    }
}

And that is it, the view will get reused properly. No need to do the trick of add view as subview and etc.

Yuchen
  • 30,852
  • 26
  • 164
  • 234
  • Can you elaborate on this @Yuchen? How do you avoid loading the view from the xib? I'm looking to have an MKAnnotationView use a view created from a xib. – KMLong Jan 26 '17 at 14:50
  • Hey @KMLong, sorry for the delay. To answer your question: I did not avoid loading the annotation view from xib. What I suggests is avoid loading a separate subview from xib as Adian's answer does: `[[NSBundle mainBundle] loadNibNamed:@"MyCustomView" owner:self options:nil]`. – Yuchen Feb 02 '17 at 04:38
  • 1
    great answer, this is the solution for swift..just add this to grab the xib -> class func loadFromXib() -> WWMapItemAnnotationView { let xib = Bundle.main.loadNibNamed("WWMapItemAnnotationView", owner: self, options: nil) return xib?[0] as! WWMapItemAnnotationView } – shokaveli Jun 13 '18 at 21:09