2011-10-14 16 views
9

Chcę dostosować linie rysowane na MKMapView, aby pokazać trasę, tak aby linie miały kolor obramowania i kolor wypełnienia. Podobny do tego, gdzie ma czarne obramowanie i wypełniona jest innym kolorem:jak dostosować MKPolyLineView do rysowania linii o różnych stylach?

blue line with black border

Obecnie jestem po prostu powrocie MKPolyLineView obiektów z mapView:viewForOverlay: która działa dobrze dla prostych liniach. Dokumenty mówią, że MKPolyLineView nie ma podlegać subklasie, więc czy powinienem podklasować MKOverlayView i zaimplementować własny drawMapRect? A może powinienem podklasować MKOverlayPathView? Lub utworzyć zamiennik dla MKPolylineView?

EDIT - o co pytam: gdzie jest miejsce na umieszczenie własnego kodu do rysowania kwarcu w celu narysowania własnych adnotacji/nakładek? Obecnie stworzyłem podklasę MKOverlayView i zaimplementuję własny drawMapRect: zoomScale: inContext: Łatwo jest narysować nakładkę w ten sposób, ale czy to najlepsze rozwiązanie?

Odpowiedz

12

Możesz to zrobić przez zaimplementowanie własnej podklasy MKOverlayPathView, która rysuje ścieżkę dwa razy na mapie rect. Raz grubszy z czarnym i raz cieńszy na wierzchu z innym kolorem.

Stworzyłem prosty zamiennik MKPolylineView, który pozwala to zrobić: ASPolylineView.

Jeśli chcesz zrobić to sam, dwie główne metody, które trzeba realizować mógłby wyglądać następująco:

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

Wiem, że to może nie pasować do czystego podejścia, które chcesz, ale dlaczego nie używać MKPolygon zamiast MKPolyLine?
Tworzenie MKPolygon instancję, która stanowi rodzaj korytarza wokół trasy, a następnie, podczas tworzenia MKPolygonView odpowiadającą utworzonej w MKPolygon/korytarz, ustaw właściwości MKPolygonView dostać inny kolor wypełnienia i skokColor

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

Sam nie próbowałem, ale to powinno zadziałać. Jedyną wadą jest to, że podczas powiększania/pomniejszania "szerokość" "trasy" zmieni się ....:/

+0

ładny pomysł, ale obliczania granic wielokąta z arbitralny zestaw współrzędnych trasy jest dość skomplikowany – progrmr

+0

podstawowym podejściem może być dodanie 0.000001 do szerokości górnej części korytarza, a następnie -0,000001 dla dolnej części, a następnie zbudowanie korytarza z wielokąta złożonego z górnej i dolnej części części ... po prostu pomysł ... – yonel

+0

To działałoby tylko wtedy, gdy trasa przebiegała w kierunku wschód/zachód. Mogą one przebiegać w dowolnym kierunku, więc wielobok musiałby być oparty na nagłówku każdego odcinka linii. Strona musi być prostopadła do kierunku trasy i obliczać kurs z pary lat/lon za pomocą [sferycznego prawa cosinusów] (http://stackoverflow.com/questions/6924742/valid-way-to- obliczyć-kąt-między-2-cllocations/7352235 # 7352235) jest kosztowną operacją. – progrmr

4

Możesz po prostu dodać dwa obiekty MKPolyLineView o tych samych współrzędnych, ale o różnych grubościach.

Dodaj jeden z liniowĘ ... 10 (lub cokolwiek innego) z ustawieniem colorColor na czarny.

Następnie dodaj kolejny element o szerokości wiersza równej 6 z ustawieniem colorColor do innego żądanego koloru.

Możesz używać tej samej MKPolyLine dla obu obiektów MKPolyLineView.

+0

Hmmm, dobry pomysł, po prostu upewnij się, że szersza polilinia znajduje się pod cieńszą polilinią. – progrmr

+0

fajny pomysł, może można dodać cieńszą polilinię jako podzbiór szerszego? ponieważ MKPolyLineView rozciąga się od UIView, jest to możliwe w teorii ... – yonel

+0

Można to zrobić, ale wtedy trzeba przesunąć współrzędne dla subview, co oznacza, nie dzieląc MKPolyLine. Lepiej uczynić je oboje dzieci nadrzędnego obiektu UIView, jeśli chcesz, aby się razem przekształcili. – MindJuice

2

MKPolylineView może być używany tylko do gładzenia wyznaczoną ścieżką. Możesz użyć niektórych właściwości w MKOverlayPathView, aby zmienić ich wygląd, ale tylko niektóre z nich będą miały zastosowanie, np. fillColor, strokeColor.

Jeśli chcesz narysować coś bardziej złożonego, możesz użyć MKOverlayPathView. Jest bardziej ogólny i dlatego nadaje się do czegoś więcej niż tylko gładkich ścieżek. W przypadku rysowania prostych linii wynik byłby identyczny z MKPolylineView (przynajmniej według dokumentów).

Jeśli chcesz wykonać bardziej złożony rysunek, podklasę MKOverlayPathView. To, co próbujesz zrobić, nie jest banalne.

2

używam NamedOverlay podklasy, która posiada nakładkę o nazwę:

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 

iw sterowniku Mapa I instancji dwie nakładki z inną nazwą, a następnie w MKMapViewDelegate mogę zidentyfikować które nakładka Chcę wyciągnąć i zrobić coś takiego:

- (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; 
    } 
} 
Powiązane problemy