I’m trying to animate a radar image on an MKMapView. I have separate images for different times, and I have successfully set an image as an overlay on top of the MKMapView. My problem is when I try to show these different images in a sequence one after each other. I tried a method of adding and removing overlays, but the system does not handle it well at all, with flickering of overlays, and some overlays not being removed, and overall, its not worth it.
Could anyone help me find a way to show multiple images (like an animated gif) on top of a MapView in a way that is smooth and fast?
Here’s my code to overlay the image:
- (id)initWithImageData:(NSData*)imageData withLowerLeftCoordinate:(CLLocationCoordinate2D)lowerLeftCoordinate withUpperRightCoordinate:(CLLocationCoordinate2D)upperRightCoordinate {
self.radarData = imageData;
MKMapPoint lowerLeft = MKMapPointForCoordinate(lowerLeftCoordinate);
MKMapPoint upperRight = MKMapPointForCoordinate(upperRightCoordinate);
mapRect = MKMapRectMake(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);
return self;
}
- (CLLocationCoordinate2D)coordinate
{
return MKCoordinateForMapPoint(MKMapPointMake(MKMapRectGetMidX(mapRect), MKMapRectGetMidY(mapRect)));
}
- (MKMapRect)boundingMapRect
{
return mapRect;
}
and here’s how I’m setting it up on the MapView:
- (void)drawMapRect:(MKMapRect)mapRect
zoomScale:(MKZoomScale)zoomScale
inContext:(CGContextRef)ctx
{
MapOverlay *mapOverlay = (MapOverlay *)self.overlay;
image = [[UIImage alloc] initWithData:mapOverlay.radarData];
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
@try {
UIGraphicsBeginImageContext(image.size);
UIGraphicsPushContext(ctx);
[image drawInRect:theRect blendMode:kCGBlendModeNormal alpha:0.5];
UIGraphicsPopContext();
UIGraphicsEndImageContext();
}
@catch (NSException *exception) {
NSLog(@"Caught an exception while drawing radar on map - %@",[exception description]);
}
@finally {
}
}
and here’s where I’m adding the overlay:
- (void)mapRadar {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.mapOverlay = [[MapOverlay alloc] initWithImageData:appDelegate.image withLowerLeftCoordinate:CLLocationCoordinate2DMake(appDelegate.south, appDelegate.west) withUpperRightCoordinate:CLLocationCoordinate2DMake(appDelegate.north, appDelegate.east)];
[self.mapView addOverlay:self.mapOverlay];
[self.mapView setNeedsDisplay];
self.mapView.showsUserLocation = YES;
MKMapPoint lowerLeft2 = MKMapPointForCoordinate(CLLocationCoordinate2DMake(appDelegate.south2, appDelegate.west2) );
MKMapPoint upperRight2 = MKMapPointForCoordinate(CLLocationCoordinate2DMake(appDelegate.north2, appDelegate.east2));
MKMapRect localMapRect = MKMapRectMake(lowerLeft2.x, upperRight2.y, upperRight2.x - lowerLeft2.x, lowerLeft2.y - upperRight2.y);
[self.mapView setVisibleMapRect:localMapRect animated:YES];
}
#pragma Mark - MKOverlayDelgateMethods
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay{
if([overlay isKindOfClass:[MapOverlay class]]) {
MapOverlay *mapOverlay = overlay;
self.mapOverlayView = [[MapOverlayView alloc] initWithOverlay:mapOverlay];
}
return self.mapOverlayView;
}
Does anyone have an idea or a solution where I can show a sequence of images on an MKMapView smoothly? At this point, I’m desperate for solutions and can’t find it anywhere else, so anything would help me, thanks!
Using Lefteris’ suggestion, you can just use UIImageView with animationImages. The animation should be smooth provided your overlay images are properly sized for the screen.
To pass touches through to the map view below, you can create a new UIView subclass with a (weak) reference to the map view. Override the touch event methods (touchesBegan:withEvent:, touchesMoved:withEvent:, etc) to forward to the map view, like so:
This way the user can still interact with the view below.
You may run into problems when the user tries to zoom, as it will be difficult if not impossible to scale all your animation frames in real-time. You should look into using CATiledLayer instead.