Ios 将倒圆覆盖添加到地图视图

Ios 将倒圆覆盖添加到地图视图,ios,ios5,mapkit,mkoverlay,Ios,Ios5,Mapkit,Mkoverlay,(使用iOS 5和Xcode 4.2。) 我按照这里的说明进行了操作:并使用和类在我的 然而,我真正想要的是一个倒圆覆盖,如下图中的左侧地图(目前我有一个像右侧一样的圆覆盖): 对于倒圆,覆盖应覆盖整个地图-除了可见圆 使用MKCircle/MKCircleView类是否有一种简单的方法来实现这一点?或者我需要更深入地定义自定义覆盖对象/视图吗 感谢您的帮助:)最好的方法是子类化MKMapView并重写drawRect方法调用super,然后用您想要的颜色在地图上绘制。 然后,每次用户移动时,

(使用iOS 5和Xcode 4.2。)

我按照这里的说明进行了操作:并使用和类在我的

然而,我真正想要的是一个倒圆覆盖,如下图中的左侧地图(目前我有一个像右侧一样的圆覆盖):

对于倒圆,覆盖应覆盖整个地图-除了可见圆

使用MKCircle/MKCircleView类是否有一种简单的方法来实现这一点?或者我需要更深入地定义自定义覆盖对象/视图吗


感谢您的帮助:)

最好的方法是子类化
MKMapView
并重写
drawRect
方法调用super,然后用您想要的颜色在地图上绘制。
然后,每次用户移动时,
drawRect
都应该通过适当地绘制来响应。

我有同样的任务,下面是我如何解决它的:

注意:此代码仅从iOS7开始工作

在视图控制器中的某个位置向地图添加覆盖:

MyMapOverlay *overlay = [[MyMapOverlay alloc] initWithCoordinate:coordinate];
[self.mapView addOverlay:overlay level:MKOverlayLevelAboveLabels];
在MKMapViewDelegate方法中,编写下一步:

- (MKOverlayRenderer *)mapView:(MKMapView *)map rendererForOverlay:(id<MKOverlay>)overlay {
    /// we need to draw overlay on the map in a way when everything except the area in radius of 500 should be grayed
    /// to do that there is special renderer implemented - NearbyMapOverlay
    if ([overlay isKindOfClass:[NearbyMapOverlay class]]) {
        MyMapOverlayRenderer *renderer = [[MyMapOverlayRenderer alloc] initWithOverlay:overlay];
        renderer.fillColor = [UIColor whateverColor];/// specify color which you want to use for gray out everything out of radius
        renderer.diameterInMeters = 1000;/// choose whatever diameter you need

        return renderer;
    }
    return nil;
}

因此,您将获得与问题中发布的左图完全相同的视图。

这里是Swift版本。谢谢你,瓦莱丽


我尝试使用这个swift版本,但没有成功,所以我发布了我的实现(在iOS 12上测试)


你能建议一下你用drawRect方法写了什么吗?在整个地图上画画也会使中间区域被画出来,但他不想要。答案如何被接受?
@interface MyMapOverlay : NSObject<MKOverlay>
- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate;
@end

@implementation MyMapOverlay

@synthesize coordinate = _coordinate;

- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate {
    self = [super init];
    if (self) {
        _coordinate = coordinate;
    }
    return self;
}

- (MKMapRect)boundingMapRect {
    return MKMapRectWorld;
}

@end
@interface MyMapOverlayRenderer : MKOverlayRenderer
@property (nonatomic, assign) double diameterInMeters;
@property (nonatomic, copy) UIColor *fillColor;
@end

@implementation MyMapOverlayRenderer

/// this method is called as a part of rendering the map, and it draws the overlay polygon by polygon
/// which means that it renders overlay by square pieces
- (void)drawMapRect:(MKMapRect)mapRect
      zoomScale:(MKZoomScale)zoomScale
      inContext:(CGContextRef)context {

    /// main path - whole area
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(mapRect.origin.x, mapRect.origin.y, mapRect.size.width, mapRect.size.height)];

    /// converting to the 'world' coordinates
    double radiusInMapPoints = self.diameterInMeters * MKMapPointsPerMeterAtLatitude(self.overlay.coordinate.latitude);
    MKMapSize radiusSquared = {radiusInMapPoints, radiusInMapPoints};
    MKMapPoint regionOrigin = MKMapPointForCoordinate(self.overlay.coordinate);
    MKMapRect regionRect = (MKMapRect){regionOrigin, radiusSquared}; //origin is the top-left corner
    regionRect = MKMapRectOffset(regionRect, -radiusInMapPoints/2, -radiusInMapPoints/2);
    // clamp the rect to be within the world
    regionRect = MKMapRectIntersection(regionRect, MKMapRectWorld);

    /// next path is used for excluding the area within the specific radius from current user location, so it will not be filled by overlay fill color
    UIBezierPath *excludePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(regionRect.origin.x, regionRect.origin.y, regionRect.size.width, regionRect.size.height) cornerRadius:regionRect.size.width / 2];
    [path appendPath:excludePath];

    /// setting overlay fill color
    CGContextSetFillColorWithColor(context, self.fillColor.CGColor);
    /// adding main path. NOTE that exclusionPath was appended to main path, so we should only add 'path'
    CGContextAddPath(context, path.CGPath);
    /// tells the context to fill the path but with regards to even odd rule
    CGContextEOFillPath(context);
}
import Foundation
import UIKit
import MapKit

class MKInvertedCircleOverlayRenderer: MKOverlayRenderer {

var fillColor: UIColor = UIColor.red
var strokeColor: UIColor = UIColor.blue
var lineWidth: CGFloat = 3
var circle: MKCircle

init(circle: MKCircle) {
    self.circle = circle
    super.init(overlay: circle)
}

override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
    let path = UIBezierPath(rect: rect(for: MKMapRectWorld))

    let excludePath: UIBezierPath = UIBezierPath(roundedRect: CGRect(x: circle.coordinate.latitude,
                                                                     y: circle.coordinate.longitude,
                                                                     width: circle.boundingMapRect.size.width,
                                                                     height: circle.boundingMapRect.size.height),
                                                 cornerRadius: CGFloat(circle.boundingMapRect.size.width))

    context.setFillColor(fillColor.cgColor)

    path.append(excludePath)
    context.addPath(path.cgPath)
    context.fillPath(using: .evenOdd)

    context.addPath(excludePath.cgPath)
    context.setLineWidth(9 / zoomScale)
    context.setStrokeColor(strokeColor.cgColor)
    context.strokePath()

    //line showing circle radius
    let lineBeginPoint = CGPoint(x: excludePath.bounds.midX, y: excludePath.bounds.midY)
    let lineEndPoint = CGPoint(x: excludePath.bounds.maxX, y: excludePath.bounds.midY)
    let linePath: UIBezierPath = UIBezierPath()
    linePath.move(to: lineBeginPoint)
    linePath.addLine(to: lineEndPoint)

    context.addPath(linePath.cgPath)
    context.setLineWidth(6/zoomScale)
    context.setStrokeColor(UIColor.black.cgColor)
    context.setLineDash(phase: 1, lengths: [20 / zoomScale, 10 / zoomScale])
    context.strokePath()

    // circle at the end of the line above
    let circleSize: CGFloat = 30/zoomScale
    let circleRect = CGRect(origin: CGPoint(x: lineEndPoint.x - (circleSize/2), y: lineEndPoint.y - (circleSize/2)),
                            size: CGSize(width: circleSize, height: circleSize))

    let circlePath: UIBezierPath =
        UIBezierPath(roundedRect: circleRect, cornerRadius: circleSize)

    context.addPath(circlePath.cgPath)
    context.setFillColor(UIColor.black.cgColor)
    context.fillPath()
}