14

I am trying to learn MapKit and am now trying to add an image as an overlay to the map view. I can't seem to find any sample code to help explain how to do this.

Can you guys please help me how to create MKOverlays and add them to MKMapKit.

Thanks in advance..

Marc W
  • 19,083
  • 4
  • 59
  • 71
Jr Ntr Achanta
  • 201
  • 1
  • 3
  • 4
  • I don't know if I have understood exactly your questione. Shortly, I'd need to use MKPointAnnotation not upon a map but upon a picture captured from the smartphone camera. So I should work with annotations on a picture. is this what you wanted to to doo when you asked about MKOverlay? – SagittariusA Nov 17 '15 at 14:45
  • @Jr Ntr Achanta : Go through below tutorials. https://www.raywenderlich.com/30001/overlay-images-and-overlay-views-with-mapkit-tutorial https://www.raywenderlich.com/87008/overlay-views-mapkit-swift-tutorial – Vijay Jun 08 '16 at 11:57

4 Answers4

25

Here is an example to how to sets a UIImage to a MKMapView overlay. Some parameter (coordinates and image path) are fixed, but the code can be easily changed, I guess.

Create an class that conforms to MKOverlay:

MapOverlay.h

@interface MapOverlay : NSObject <MKOverlay> {

}

- (MKMapRect)boundingMapRect;
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

@end

MapOverlay.m

@implementation MapOverlay

- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate {
    self = [super init];
    if (self != nil) {


    }
    return self;
}

- (CLLocationCoordinate2D)coordinate
{
    CLLocationCoordinate2D coord1 = {
        37.434999,-122.16121
    };

    return coord1;
}

- (MKMapRect)boundingMapRect
{

    MKMapPoint upperLeft = MKMapPointForCoordinate(self.coordinate);

    MKMapRect bounds = MKMapRectMake(upperLeft.x, upperLeft.y, 2000, 2000);
    return bounds;
}


@end

Create an class that conforms to MKOverlayView:

MapOverlayView.h

@interface MapOverlayView : MKOverlayView {

}

@end

MapOverlayView.m

@implementation MapOverlayView

- (void)drawMapRect:(MKMapRect)mapRect
          zoomScale:(MKZoomScale)zoomScale
          inContext:(CGContextRef)ctx
{

    UIImage *image          = [[UIImage imageNamed:@"image.png"] retain];

    CGImageRef imageReference = image.CGImage;

    MKMapRect theMapRect    = [self.overlay boundingMapRect];
    CGRect theRect           = [self rectForMapRect:theMapRect];
    CGRect clipRect     = [self rectForMapRect:mapRect];

    CGContextAddRect(ctx, clipRect);
    CGContextClip(ctx);

    CGContextDrawImage(ctx, theRect, imageReference);

    [image release]; 

}


@end

Add the overlay to the MKMapView:

MapOverlay * mapOverlay = [[MapOverlay alloc] init];
[mapView addOverlay:mapOverlay];
[mapOverlay release];

On the mapView delegate, implement the viewForOverlay:

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {

    MapOverlay *mapOverlay = overlay;
    MapOverlayView *mapOverlayView = [[[MapOverlayView alloc] initWithOverlay:mapOverlay] autorelease];

    return mapOverlayView;

}

Hope it helps!

Raphael Petegrosso
  • 3,870
  • 2
  • 24
  • 27
  • worked quite well! What would be great is if this image is always drawn to the mapView.bounds. Right now it is drawn into the extents of the boundingMapRect, which can be much bigger than the current viewableRect of the mapView – horseshoe7 Jul 20 '11 at 16:48
  • What are the lines above the implementation supposed to look like? Does the OverlayView need to be created as a subclass of UIView, or NSObject? – Alex Zavatone Apr 14 '12 at 01:29
  • Your code works like a charm, though I am still unclear on just what type of subclass I was creating on New File. In any case, I fit your code into Apple's MapCallouts sample and didn't know that my image was being drawn too small. Changing it to an all black image of 2000x2000 pixels actually displayed it at a tiny size. I'm on the right track thanks to you. Cheers. – Alex Zavatone Apr 14 '12 at 01:51
  • 1
    i found that the image was appearing upsidedown. found that this worked better. - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context { MKMapRect theMapRect = [self.overlay boundingMapRect]; CGRect theRect = [self rectForMapRect:theMapRect]; UIGraphicsPushContext(context); [_image drawInRect:theRect blendMode:kCGBlendModeNormal alpha:1.0]; UIGraphicsPopContext(); } – roocell Jan 27 '14 at 03:37
  • 1
    Actually, MKMapPoint upperLeft = MKMapPointForCoordinate(self.coordinate); does not do what you seem to think it does: self.coordinate, being an implementation of the MKOverlay protocol, returns "The approximate center point of the overlay area" according to the documentation, not the upper left point. – Elise van Looij Mar 04 '14 at 10:46
  • somehow fails to present the image on my mapView – genaks Oct 29 '15 at 08:25
2

Documentation:

Sample code:

Anomie
  • 92,546
  • 13
  • 126
  • 145
  • @Marc W: Because it's just a big list of links to documentation, I didn't really contribute anything. – Anomie Mar 12 '11 at 16:54
0

In the search for a solution for my problem, I keep coming back to this question, and here and also here

They were all answering the question I needed answered but in reverse.

I needed to determine if a UIView, i.e. a draw square on my MapView contains a map pin, if it does let me know so I can remove it or select it etc.

Finally after trying to convert my UIView into some MKCoordinateRegion or alike, I thought work backwards. Instead of turning my UIView or square into map madness, I turned the pins into simple CGPoints and did a simple Rect contains point. Which ended up being my solution.. after about 2 hrs!

Hope this help someone down the line

 func findMapPinsWithinBox() {

    guard let myBox = myBox else { return } // some UIView you have drawn or placed on map

    let visibleMapRect = mapView.visibleMapRect
    let visibleAnnotations =  mapView.annotationsInMapRect(visibleMapRect)

    for pin in visibleAnnotations {

        // depending on design you may need to do some casting here
        // ie let pin = pin as! MyMapAnnotation

        let pinsCGPoint = mapView.convertCoordinate(pin.coordinate, toPointToView: self.view)

        if myBox.frame.contains(pinsCGPoint) {
            print("Pin Found within the Box")
            // select pin or delete etc
        }
    }
}
Community
  • 1
  • 1
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
-2

From just looking at Apple's documentation for the MKOverlay protocol, it doesn't look very complex. Just make a class to do whatever you need to compute the overlay and make sure it conforms to that protocol. That means you must have the coordinate and boundingMapRect properties as well as an implementation for intersectsMapRect:. The Apple docs explain it all.

Take a look at the HazardMap sample code from Apple. It uses a custom overlay view like you want to do to display an image in the overlay. You simply need to implement mapView:viewForOverlay: in your MKMapViewDelegate class and return a new instance of your subclass of MKOverlayView to get the custom overlay drawn on the screen.

Marc W
  • 19,083
  • 4
  • 59
  • 71