2011-12-30 2 views
10

IOS 5 изменил способ встроенных в Google Maps App рисует маршруты:Drawing MKMapView Overlay, как Google Maps Directions

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

Можете ли вы опубликовать код, который вы используете, нарисовать линии, в настоящее время? –

+0

@sudo rm -rf: Я добавил код чертежа. – myell0w

ответ

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

Это звучит о правильном Крисе, спасибо. Моя проблема заключается в том, как рисовать градиент вдоль CGPath. Любые идеи или фрагменты кода, которые вы могли бы поделиться? – myell0w

+0

Я не знаю, как будут выглядеть результаты, но вы можете использовать 'CGContextReplacePathWithStrokedPath()' для получения контура, который вы можете заполнить градиентом. Этот предыдущий вопрос может быть полезен: http://stackoverflow.com/questions/2737973/on-osx-how-do-i-gradient-fill-a-path-stroke – lxt

+0

После нескольких экспериментов я не могу найти чтобы легко получить градиентную заливку, чтобы следовать по пути, как они это делают. Они могут разрушать путь и рисовать градиентную заливку для каждого сегмента отдельно. –

Смежные вопросы