2011-12-30 16 views
10

iOS 5 zmienił sposób wbudowanej Aplikacja Mapy Google czerpie trasach:Drawing MKMapView Nakładka jak Google Maps Directions

Apple's line

Chciałbym teraz powtórzyć projekt nakładki trasy w moim app ale obecnie jestem w stanie narysować zwykłą niebieską linię. Chciałbym dodać efekt 3D z gradientem, granicami i blaskiem. Wszelkie pomysły, jak to osiągnąć?

Obecnie używam następujący kod:

CGContextSetFillColorWithColor(context, fillColor.CGColor); 
CGContextSetLineJoin(context, kCGLineJoinRound); 
CGContextSetLineCap(context, kCGLineCapRound); 
CGContextSetLineWidth(context, lineWidth); 
CGContextAddPath(context, path); 
CGContextReplacePathWithStrokedPath(context); 
CGContextFillPath(context); 

Powstałe w dość brzydkiej linii:

my line

Dzięki!

Aktualizacja: rozwiązanie powinno działać w systemie iOS 4.0 i nowszym.

+0

Czy jesteś w stanie opublikować kod, którego używasz do rysowania linii? –

+0

@sudo rm -rf: Dodałem kod rysunkowy. – myell0w

Odpowiedz

7

Myślę, że @ChrisMiles ma rację, ponieważ segmenty są prawdopodobnie rysowane indywidualnie. (Początkowo sądziłem, że mogło to być możliwe przy użyciu CGPatternRef, ale nie masz żadnego dostępu do punktów końcowych CTM lub ścieżek we wzorcu wywołania rysunku.)

Mając to na uwadze, tutaj jest niezmiernie prymitywny, przykładowy sposób, w jaki możesz rozpocząć taki wysiłek (wypełnianie poszczególnych segmentów). Należy pamiętać, że:

  • gradient kolorów są domyślić
  • zaślepki nie istnieją i trzeba będzie oddzielnie realizowane
  • niektóre artefakty aliasingu pozostają
  • nie wiele uwagi poświęcono wydajności

Mam nadzieję, że to pomoże Ci zacząć przynajmniej (i działa przez niektóre z geometrii analitycznej).

- (CGGradientRef)lineGradient 
{ 
    static CGGradientRef gradient = NULL; 
    if (gradient == NULL) { 
     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
     CGColorRef white = [[UIColor colorWithWhite:1.f 
               alpha:0.7f] CGColor]; 
     CGColorRef blue = [[UIColor colorWithRed:0.1f 
              green:0.2f 
              blue:1.f 
              alpha:0.7f] CGColor]; 
     CGColorRef lightBlue = [[UIColor colorWithRed:0.4f 
               green:0.6f 
               blue:1.f 
               alpha:0.7f] CGColor]; 
     CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, 
                 8, 
                 NULL); 
     CFArrayAppendValue(colors, blue); 
     CFArrayAppendValue(colors, blue); 
     CFArrayAppendValue(colors, white); 
     CFArrayAppendValue(colors, white); 
     CFArrayAppendValue(colors, lightBlue); 
     CFArrayAppendValue(colors, lightBlue); 
     CFArrayAppendValue(colors, blue); 
     CFArrayAppendValue(colors, blue); 
     CGFloat locations[8] = {0.f, 0.08f, 0.14f, 0.21f, 0.29f, 0.86f, 0.93f, 1.f}; 
     gradient = CGGradientCreateWithColors(colorSpace, 
               colors, 
               locations); 
     CFRelease(colors); 
     CGColorSpaceRelease(colorSpace); 
    } 
    return gradient; 
} 

- (void)drawRect:(CGRect)rect 
{ 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextSaveGState(context); 

    CGContextSetAllowsAntialiasing(context, YES); 
    CGContextSetShouldAntialias(context, YES); 

    // Fill background color 
    [[UIColor whiteColor] setFill]; 
    UIRectFill(rect); 

    // Build a path 
    CGFloat strokeWidth = 10.f; 
    CGContextSetLineWidth(context, strokeWidth); 

    CGGradientRef gradient = [self lineGradient]; 

    CGPoint points[9] = { 
     CGPointMake(10.f, 25.f), 
     CGPointMake(100.f, 100.f), 
     CGPointMake(100.f, 150.f), 
     CGPointMake(22.f, 300.f), 
     CGPointMake(230.f, 400.f), 
     CGPointMake(230.f, 200.f), 
     CGPointMake(300.f, 200.f), 
     CGPointMake(310.f, 160.f), 
     CGPointMake(280.f, 100.f) 
    }; 


    for (NSUInteger i = 1; i < 9; i++) { 
     CGPoint start = points[i - 1]; 
     CGPoint end = points[i]; 
     CGFloat dy = end.y - start.y; 
     CGFloat dx = end.x - start.x; 
     CGFloat xOffset, yOffset; 
     // Remember that, unlike Cartesian geometry, origin is in *upper* left! 
     if (dx == 0) { 
      // Vertical to start, gradient is horizontal 
      xOffset = 0.5 * strokeWidth; 
      yOffset = 0.f; 
      if (dy < 0) { 
       xOffset *= -1; 
      } 
     } 
     else if (dy == 0) { 
      // Horizontal to start, gradient is vertical 
      xOffset = 0.f; 
      yOffset = 0.5 * strokeWidth; 
     } 
     else { 
      // Sloped 
      CGFloat gradientSlope = - dx/dy; 
      xOffset = 0.5 * strokeWidth/sqrt(1 + gradientSlope * gradientSlope); 
      yOffset = 0.5 * strokeWidth/sqrt(1 + 1/(gradientSlope * gradientSlope)); 
      if (dx < 0 && dy > 0) { 
       yOffset *= -1; 
      } 
      else if (dx > 0 && dy < 0) { 
       xOffset *= -1; 
      } 
      else if (dx < 0 && dy < 0) { 
       yOffset *= -1; 
       xOffset *= -1; 
      } 
      else { 
      } 
     } 
     CGAffineTransform startTransform = CGAffineTransformMakeTranslation(-xOffset, yOffset); 
     CGAffineTransform endTransform = CGAffineTransformMakeTranslation(xOffset, -yOffset); 
     CGPoint gradientStart = CGPointApplyAffineTransform(start, startTransform); 
     CGPoint gradientEnd = CGPointApplyAffineTransform(start, endTransform); 

     CGContextSaveGState(context); 
     CGContextMoveToPoint(context, start.x, start.y); 
     CGContextAddLineToPoint(context, end.x, end.y); 
     CGContextReplacePathWithStrokedPath(context); 
     CGContextClip(context); 
     CGContextDrawLinearGradient(context, 
            gradient, 
            gradientStart, 
            gradientEnd, 
            kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation); 
     CGContextRestoreGState(context); 
    } 

    CGContextRestoreGState(context); 
} 
1

Powiedziałbym, że rysują CGPath wokół oryginalnej linii, głaszcząc krawędzie i wypełniając ją gradientem. Końce są ograniczone przez dodanie półkola do CGPath.

Może to być nieco więcej pracy niż tylko rysowanie pojedynczej linii i głaskanie jej, ale daje im pełną kontrolę nad stylem renderowanej ścieżki.

+0

To brzmi dobrze Chris, dzięki. Mój problem polega na narysowaniu gradientu wzdłuż CGPath. Wszelkie pomysły lub fragmenty kodu, które możesz udostępniać? – myell0w

+0

Nie wiem, jak będą wyglądały wyniki, ale można użyć 'CGContextReplacePathWithStrokedPath()', aby pobrać kontur, który można następnie wypełnić gradientem. To pytanie może być przydatne: http://stackoverflow.com/questions/2737973/on-osx-how-do-i-gradient-fill-a-path-stroke – lxt

+0

Po odrobinie eksperymentów nie mogę znaleźć sposób, aby łatwo uzyskać wypełnienie gradientowe, aby podążać ścieżką, w taki sposób, w jaki to robią. Mogą one rozkładać ścieżkę i rysować gradientowe wypełnienie dla każdego segmentu osobno. –

Powiązane problemy