2012-01-29 20 views
8

Añadir superposición círculo invertida a la vista del mapa

He seguido las instrucciones aquí (usando iOS 5 y Xcode 4.2.): http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/AnnotatingMaps/AnnotatingMaps.html#//apple_ref/doc/uid/TP40009497-CH6-SW15 y utilizado los MKCircle y MKCircleView clases para agregar una superposición de círculo en mi MKMapView.

Sin embargo lo que realmente quiero es una superposición círculo invertida, como el mapa de la izquierda en el siguiente esquema (actualmente tengo una superposición de círculo como el de la derecha):

Inverted and not-inverted circle overlay sketches

Para la invertida círculo, la superposición debe cubrir todo el mapa, además del círculo visible.

¿Hay una manera fácil de lograr esto utilizando las clases MKCircle/MKCircleView? ¿O tendré que profundizar más y definir un objeto/vista de superposición personalizada?

Gracias por su ayuda :)

Respuesta

5

La mejor manera de hacerlo, sería una subclase MKMapView y anular la llamada súper drawRect método, luego pintar sobre el mapa con el color que desee. Luego, cada vez que el usuario se mueve, drawRect debe responder dibujando apropiadamente.

+0

¿Puede usted por favor, sugiera cómo o por qué ha escrito usted en el método drawRect? – HarshIT

+0

Pintar en un mapa completo también hará que el área entre pintada, pero él no la quiere. ¿Cómo se acepta la respuesta? –

6

que tenían la misma tarea y aquí es cómo lo resuelvo:

NOTA: este código sólo funcionará a partir de iOS7

Añadir una superposición al mapa, en algún lugar de su controlador de vista:

MyMapOverlay *overlay = [[MyMapOverlay alloc] initWithCoordinate:coordinate]; 
[self.mapView addOverlay:overlay level:MKOverlayLevelAboveLabels]; 

En los métodos MKMapViewDelegate escribir a continuación:

- (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; 
} 

El MyMapOverlay sí mismo debería ser algo como sigue:

@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 

Y el MyMapOverlayRenderer:

@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); 
} 

Como resultado, usted tendrá exactamente la misma vista como la de la imagen de la izquierda que se ha escrito en la pregunta .

Cuestiones relacionadas