2011-12-30 92 views
10

iOS 5中改變了內置的谷歌地圖應用程序繪製路線的方式:繪製的MKMapView疊加像谷歌地圖路線

Apple's line

我現在想複製路線覆蓋的設計自己的應用程序但我目前只能畫一條純藍線。我想添加漸變,邊框和發光的3D效果。任何想法如何實現這一目標?

目前我使用下面的代碼:

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

在一個相當難看的線得到的:

my line

謝謝!

更新:解決方案應該可以在iOS 4.0及更高版本上運行。

+0

您是否可以發佈您正在使用繪製線條的代碼? – 2012-05-18 22:50:26

+0

@sudo rm -rf:我已經添加了繪圖代碼。 – myell0w 2012-05-19 13:08:39

回答

7

我認爲@ChrisMiles是正確的,因爲這些段可能是單獨繪製的。 (我最初認爲這可能是可行的,使用CGPatternRef,但您無法訪問模式繪圖回調中的CTM或路徑端點。)

考慮到這一點,這裏是一個極其粗糙的,你可能會開始這樣的努力(單獨填充分段)。需要注意的是:

  • 漸變顏色猜
  • 端蓋是不存在的,需要單獨實施
  • 一些鋸齒假象保持
  • 沒有的極大關注支付給業績

希望這可以讓你至少開始(並通過一些解析幾何工作)。

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

我會說他們正在繪製原始線條周圍的CGPath,撫摸邊緣和漸變填充它。通過向CGPath添加一個半圓圈來限制末端。

比簡單地繪製一條線並撫摸它要多一點工作,但讓它們完全控制渲染路徑的樣式。

+0

這聽起來很對Chris,謝謝。我的問題是如何沿着CGPath繪製漸變。任何想法或代碼片段,你可以分享? – myell0w 2012-05-19 13:09:12

+0

我不知道結果會是什麼樣子,但是您可以使用'CGContextReplacePathWithStrokedPath()'檢索輪廓,然後可以使用漸變填充輪廓。這個前面的問題可能是有用的:http://stackoverflow.com/questions/2737973/on-osx-how-do-i-gradient-fill-a-path-stroke – lxt 2012-05-19 20:48:20

+0

經過一些實驗後,我找不到方式很容易得到漸變填充以遵循路徑,就像他們正在做的那樣。他們可能會分解路徑並分別爲每個段繪製漸變填充。 – 2012-05-21 09:33:05