2011-10-14 13 views
9

Desidero personalizzare le linee disegnate su MKMapView per mostrare un percorso in modo che le linee abbiano un colore del bordo e un colore di riempimento. Simile a questo, dove si ha un bordo nero ed è riempito con un altro colore:come personalizzare MKPolyLineView per disegnare linee di stile diverse

blue line with black border

Attualmente sto appena tornando MKPolyLineView oggetti da mapView:viewForOverlay: che funziona bene per le linee semplici. I documenti dicono che MKPolyLineView non deve essere sottoclasse, quindi dovrei sottoclasse MKOverlayView e implementare il mio drawMapRect? O dovrei sottoclasse MKOverlayPathView? O creare un sostituto per MKPolylineView?

EDIT - Quello che sto chiedendo è: dove è il posto dove inserire il proprio codice di disegno Quartz per disegnare le proprie annotazioni/sovrapposizioni? Attualmente ho creato una sottoclasse di MKOverlayView e implementato il mio drawMapRect: zoomScale: inContext: È piuttosto facile disegnare la sovrapposizione in questo modo ma è quella la soluzione migliore?

risposta

12

È possibile eseguire questa operazione implementando la propria sottoclasse MKOverlayPathView, che disegna il percorso due volte nella mappa rect. Una volta più spesso con il nero e una volta più sottile sopra con un altro colore.

Ho creato una semplice sostituzione drop-in di MKPolylineView che ti consente di farlo: ASPolylineView.

Se volete farlo da soli, i due metodi principali che è necessario per implementare potrebbe essere la seguente:

- (void)drawMapRect:(MKMapRect)mapRect 
      zoomScale:(MKZoomScale)zoomScale 
      inContext:(CGContextRef)context 
{ 
    UIColor *darker = [UIColor blackColor]; 
    CGFloat baseWidth = self.lineWidth/zoomScale; 

    // draw the dark colour thicker 
    CGContextAddPath(context, self.path); 
    CGContextSetStrokeColorWithColor(context, darker.CGColor); 
    CGContextSetLineWidth(context, baseWidth * 1.5); 
    CGContextSetLineCap(context, self.lineCap); 
    CGContextStrokePath(context); 

    // now draw the stroke color with the regular width 
    CGContextAddPath(context, self.path); 
    CGContextSetStrokeColorWithColor(context, self.strokeColor.CGColor); 
    CGContextSetLineWidth(context, baseWidth); 
    CGContextSetLineCap(context, self.lineCap); 
    CGContextStrokePath(context); 

    [super drawMapRect:mapRect zoomScale:zoomScale inContext:context]; 
} 

- (void)createPath 
{ 
    // turn the polyline into a path 

    CGMutablePathRef path = CGPathCreateMutable(); 
    BOOL pathIsEmpty = YES; 

    for (int i = 0; i < self.polyline.pointCount; i++) { 
     CGPoint point = [self pointForMapPoint:self.polyline.points[i]]; 

     if (pathIsEmpty) { 
      CGPathMoveToPoint(path, nil, point.x, point.y); 
      pathIsEmpty = NO; 
     } else { 
      CGPathAddLineToPoint(path, nil, point.x, point.y); 
     } 
    } 

    self.path = path; 
} 
1

So che questo potrebbe non corrispondere all'approccio puro desiderato, ma perché non utilizzare MKPolygon anziché MKPolyLine?
creare un'istanza MKPolygon che rappresenta una sorta di corridoio intorno il percorso, e poi, quando si crea il MKPolygonView che corrisponde al MKPolygon/corridoio che hai creato, impostare le proprietà del MKPolygonView per ottenere un diverso colore di riempimento e ictusColor

myPolygonView.lineWidth=3; 
    myPolygonView.fillColor=[UIColor blueColor]; 
    myPolygonView.strokeColor=[UIColor darkGrayColor]; 

Non l'ho provato ma questo dovrebbe funzionare. Lo svantaggio è che quando si esegue lo zoom in avanti o indietro, la "larghezza" del "percorso" cambia ....:/

+0

bella idea, ma il calcolo dei limiti del poligono da un insieme arbitrario di coordinate di percorso è piuttosto complesso – progrmr

+0

un approccio di base potrebbe essere quello di aggiungere 0,000001 alla latitudine per la parte superiore del corridoio, quindi -0,000001 per la parte inferiore, e quindi costruire un corridoio con un poligono composto da superiore e inferiore parti ... solo un'idea ... – yonel

+0

Ciò funzionerebbe solo se il percorso si svolgesse in direzione est/ovest. Questi possono essere eseguiti in qualsiasi direzione, quindi il poligono dovrebbe essere basato sull'intestazione di ciascun segmento di linea. La parte dovrebbe essere ad angolo retto rispetto alla rotta e calcolare l'intestazione dalla coppia lat/lon usando la [Spherical Law of Cosines] (http://stackoverflow.com/questions/6924742/valid-way-to-to calculate-angle-between-2-cllocations/7352235 # 7352235) è un'operazione costosa. – progrmr

4

È possibile aggiungere solo due oggetti MKPolyLineView con le stesse coordinate, ma diversi spessori.

Aggiungi uno con una lineaWidth di 10 (o qualsiasi altra cosa) con strokeColor impostato su nero.

Quindi aggiungere un altro con una linea Larghezza di 6 con strokeColor impostato sull'altro colore desiderato.

È possibile utilizzare la stessa MKPolyLine per entrambi gli oggetti MKPolyLineView.

+0

Hmmm, buona idea, devi solo assicurarti che la polilinea più larga si trovi sotto la polilinea più sottile. – progrmr

+0

bella idea, forse puoi aggiungere la polilinea più sottile come sottoview di quella più ampia? come MKPolyLineView si estende da UIView, questo è possibile in teoria .... – yonel

+0

Si potrebbe fare ciò, ma allora avresti bisogno di compensare le coordinate per la sottoview, il che significa non condividere la MKPolyLine. Meglio renderli entrambi figli di un oggetto UIView genitore se vuoi che si trasformino insieme. – MindJuice

2

MKPolylineView può essere utilizzato solo per accarezzare un percorso designato. Puoi utilizzare alcune proprietà in MKOverlayPathView per modificarne l'aspetto, ma solo alcune si applicano, ad es. fillColor, strokeColor.

Se si desidera disegnare qualcosa di più complesso, è possibile utilizzare MKOverlayPathView. È più generico e quindi adatto per più di semplici carezze. Per disegnare linee semplici, il risultato sarebbe identico a MKPolylineView (almeno, secondo i documenti).

Se si desidera eseguire un disegno più complesso, sottoclasse MKOverlayPathView. Quello che stai cercando di fare è non banale.

2

io uso un NamedOverlay sottoclasse che contiene una sovrapposizione di un nome:

NamedOverlay.h

#import <Foundation/Foundation.h> 
#import <MapKit/MapKit.h> 

@interface NamedOverlay : NSObject <MKOverlay> 

@property (strong, readonly, nonatomic) NSString *name; 
@property (strong, readonly, nonatomic) id<MKOverlay> overlay; 

-(id)initWithOverlay:(id<MKOverlay>)overlay andName:(NSString *)name; 

@end 

NamedOverlay.m

#import "NamedOverlay.h" 

@implementation NamedOverlay 

- (id)initWithOverlay:(id<MKOverlay>)overlay andName:(NSString *)name 
{ 
    _name = name; 
    _overlay = overlay; 
    return self; 
} 

- (MKMapRect)boundingMapRect 
{ 
    return [_overlay boundingMapRect]; 
} 

- (CLLocationCoordinate2D)coordinate 
{ 
    return [_overlay coordinate]; 
} 

-(BOOL)intersectsMapRect:(MKMapRect)mapRect 
{ 
    return [_overlay intersectsMapRect:mapRect]; 
} 

@end 

e nel controller mappa che ho un'istanza di due sovrapposizioni con nome diverso, poi nel MKMapViewDelegate posso identificare quali overlay voglio disegnare e fare qualcosa di simile:

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay 
{ 
    NamedOverlay *namedOverlay = (NamedOverlay *) overlay; 
    MKPolyline *polyline = namedOverlay.overlay; 
    if ([namedOverlay.name isEqualToString:@"top"]) { 
     MKPolylineView *view1 = [[MKPolylineView alloc] initWithOverlay:polyline]; 
     view1.strokeColor = [UIColor whiteColor]; 
     view1.lineWidth = 25.0; 
     return view1; 
    } else { 
     MKPolylineView *view1 = [[MKPolylineView alloc] initWithOverlay:polyline]; 
     view1.strokeColor = [UIColor blueColor]; 
     view1.lineWidth = 15.0; 
     return view1; 
    } 
} 
Problemi correlati