Adding Custom Map Overlays

Oftentimes you'll want to display your custom data on the map managed by AWFWeatherMap, such as custom annotations and/or overlays. However, since your AWFWeatherMap instance must remain the map view's delegate to retain the built-in weather layer functionality, you cannot change the map view's delegate.

Fortunately, all delegate methods associated with your chosen mapping strategy (e.g. Apple Maps/MapKit, Google Maps or Mapbox) will get forwarded to the delegate you assign on AWFWeatherMap's mapViewDelegate property. This allows you to use the map view managed by your AWFWeatherMap instance as you typically would when interacting with the native map view instance directly outside of our SDK.

To add custom overlays to your AWFWeatherMap instance, just set the mapViewDelegate property and add your overlays by accessing the map strategy and implementing the necessary map delegate methods as required by your chosen mapping library (e.g. MKMapViewDelegate when using the default of Apple Maps):

ObjectiveC
Swift
import UIKit
import AerisWeatherKit
import AerisMapKit

class CustomOverlay: NSObject, MKOverlay {
    var coordinate: CLLocationCoordinate2D
    var boundingMapRect: MKMapRect
    
    init(bounds: MKMapRect) {
        boundingMapRect = bounds
        
        let region = MKCoordinateRegionForMapRect(bounds)
        coordinate = region.center
    }
}

class CustomMapViewController: AWFWeatherMapViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // our controller will receive MKMapViewDelegate events
        weatherMap.mapViewDelegate = self

        // add custom overlay
        let origin = MKMapPoint(x: 43521794.381855115, y: 93767182.83934316)
        let size = MKMapSize(width: 197934.4362897724, height: 198543.5568140447)
        let overlay = CustomOverlay(bounds: MKMapRect(origin: origin, size: size))
        weatherMap.strategy.addOverlay(overlay)
    }
}

extension CustomMapViewController: MKMapViewDelegate {
    
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if let overlay = overlay as? CustomOverlay {
            // return a custom overlay renderer or MKOverlayRenderer subclass
            return MKOverlayRenderer(overlay: overlay)
        } else if let strategy = weatherMap.strategy as? AWFAppleMapStrategy {
            // fall back to the built-in AWFWeatherMap functionality for the overlay
            return strategy.defaultRenderer(forOverlay: overlay)
        }
        return MKOverlayRenderer(overlay: overlay)
    }
}
#pragma mark - CustomOverlay

@interface CustomOverlay : NSObject<MKOverlay>
@end

@implementation CustomOverlay

@synthesize boundingMapRect;
@synthesize coordinate;

- (instancetype)initWithBoundingRect:(MKMapRect)boundingMapRect {
    self = [super init];
    if (self) {
        self.boundingMapRect = boundingMapRect;
    }
    return self;
}

@end

#pragma mark - CustomMapViewController

@interface CustomMapViewController : AWFWeatherMapViewController <MKMapViewDelegate>
@end

@implementation CustomMapViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // our controller will receive MKMapViewDelegate events
    self.weatherMap.mapViewDelegate = self;
    
    // add custom overlay
    CustomOverlay *overlay = [[CustomOverlay alloc] initWithBoundingRect:MKMapRectMake(43521794.381855115, 93767182.83934316, 197934.4362897724, 198543.5568140447)];
    [self.weatherMap.strategy addOverlay:overlay];
}

#pragma mark - MKMapViewDelegate

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
    MKOverlayRenderer *renderer = nil;
    
    if ([overlay isKindOfClass:[CustomOverlay class]]) {
        // return a custom overlay renderer or MKOverlayRenderer subclass
        renderer = [[MKOverlayRenderer alloc] initWithOverlay:overlay];
    } else {
        // fall back to the built-in AWFWeatherMap functionality for the overlay
        renderer = [self.weatherMap.strategy defaultRendererForOverlay:overlay];
    }
    
    return renderer;
}

@end

Last modified: May 21, 2020