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:
Answer for iOS 7 using MKCircleRenderer...
You should subclass MKCircleRenderer, and override the fillPath:inContext
method, similarly to the accepted answer to this question. e.g.
@implementation MKGradientCircleRenderer
- (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);
}
And then in your MKMapView delegate, implement the following method...
-(MKOverlayRenderer *)mapView:(MKMapView*)mapView rendererForOverlay:(id<MKOverlay>)overlay {
MKCircle * circle = (MKCircle *)overlay;
MKGradientCircleRenderer * renderer = [[MKGradientCircleRenderer alloc] initWithCircle:circle];
return renderer;
}
This will allow you to achieve the same effect, but using the new methods available in iOS 7.
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 ;)).
To implement the solution in Swift 2.0 (iOS7+) I used the following solution
import Foundation
import MapKit
class TWOGradientCircleRenderer: MKCircleRenderer {
override func fillPath(path: CGPath, inContext context: CGContext) {
let rect:CGRect = CGPathGetBoundingBox(path)
CGContextAddPath(context, path);
CGContextClip(context);
let gradientLocations: [CGFloat] = [0.6, 1.0];
let gradientColors: [CGFloat] = [1.0, 1.0, 1.0, 0.25, 0.0, 1.0, 0.0, 0.25];
let colorSpace = CGColorSpaceCreateDeviceRGB();
let gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocations, 2);
let gradientCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
let gradientRadius = min(rect.size.width, rect.size.height) / 2;
CGContextDrawRadialGradient(context, gradient, gradientCenter, 0, gradientCenter, gradientRadius, .DrawsAfterEndLocation);
}
}
And in your MKMapViewDelegate you will need to add
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKCircle {
let circleRenderer = TWOGradientCircleRenderer(overlay: overlay)
return circleRenderer
} else {
return MKOverlayRenderer()
}
}
Have you tried setting the fill colour to a colour created with [UIColor colorWithPatternImage:]
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With