Search code examples
iphoneobjective-cmkmapviewmkoverlay

How to draw a MKCircle whose fill color is not solid but an image


I found out how to draw a cricle around map annotation. I do it like this:

     MKCircle *circle = [MKCircle circleWithCenterCoordinate:theCoordinate radius:15000];
     [myMap addOverlay:circle];

 -(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay
 {
    MKCircleView *circleView = [[MKCircleView alloc] initWithOverlay:overlay];
    circleView.fillColor =[UIColor redColor];

   return circleView;
}

It works ok but i would like to draw a circle whose fill color is not solid like this:

enter image description here


Solution

  • To draw a circle with a gradient, you have to provide an own annotation view class, as none of the existing ones support that. What you can do is you can override the method - (void)fillPath:(CGPathRef)path inContext:(CGContextRef)context in a subclass of MKCircleView. Here is some code (non-optimized, with hardcoded fill parameters) to get you started:

    @interface TWOGradientCircleView : MKCircleView
    @end
    
    @implementation TWOGradientCircleView
    
    - (void)fillPath:(CGPathRef)path inContext:(CGContextRef)context
    {
        CGRect rect = CGPathGetBoundingBox(path);
    
        CGContextAddPath(context, path);
        CGContextClip(context);
    
        CGFloat gradientLocations[2] = {0.6f, 1.0f};
        // Start color white with 0.25 alpha,
        // End color green with 0.25 alpha
        CGFloat gradientColors[8] = {1.0f, 1.0f, 1.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.25f};
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocations, 2);
        CGColorSpaceRelease(colorSpace);
    
        CGPoint gradientCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
        CGFloat gradientRadius = MIN(rect.size.width, rect.size.height) / 2;
    
        CGContextDrawRadialGradient(context, gradient, gradientCenter, 0, gradientCenter, gradientRadius, kCGGradientDrawsAfterEndLocation);
    
        CGGradientRelease(gradient);
    }
    

    To use it, just replace MKCircleView with TWOGradientCircleView:

    - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay
    {
        MKCircleView *circleView = [[TWOGradientCircleView alloc] initWithOverlay:overlay];
    
        return circleView;
    }
    

    If you would like to use an image instead of drawing the gradient, you can replace the gradient drawing above with image drawing. As zooming in would then blur the image, you should either disable zoom, or tile the image as Apple demonstrated in a session at WWDC10 (see here for a repository with their sample code). Setting a UIColor with a pattern image does not work for a radius of 15000 (unless you use a really, really huge image ;)).