2011-12-30 15 views
10

iOS 5 cambió la forma de las rutas integradas Mapas de Google App dibuja:Dibujo MKMapView superposición como Google Maps llegar

Apple's line

ahora me gustaría replicar el diseño de la superposición de rutas en mi propia aplicación pero actualmente solo puedo dibujar una línea azul simple. Me gustaría agregar el efecto 3D con el degradado, los bordes y el resplandor. ¿Alguna idea sobre cómo lograr esto?

Actualmente estoy usando el siguiente código:

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

Resultando en una línea bastante feo:

my line

Gracias!

Actualización: la solución debería funcionar en iOS 4.0 y posteriores.

+0

¿Puede publicar el código que está utilizando para dibujar las líneas, actualmente? –

+0

@sudo rm -rf: He agregado el código de dibujo. – myell0w

Respuesta

7

Creo que @ChrisMiles tiene razón en que los segmentos probablemente se dibujan individualmente. (Inicialmente pensé que esto podría haber sido posible usando CGPatternRef pero no tiene acceso a la CTM o puntos finales de ruta dentro de la devolución de llamada del dibujo del patrón)

Teniendo esto en cuenta, aquí hay una respuesta extremadamente cruda, ejemplo de cómo podría comenzar ese esfuerzo (llenar los segmentos individualmente). Tenga en cuenta que:

  • colores de la pendiente se adivinan
  • tapas de los extremos son inexistentes, y tendrán que ser implementado por separado
  • algunos artefactos de solapamiento permanecen
  • no una gran cantidad de atención se prestó a un rendimiento

Afortunadamente, esto puede comenzar por lo menos (y funciona a través de la geometría analítica).

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

Yo diría que están dibujando un CGPath alrededor de la línea original, acariciando los bordes y rellenando el degradado. Los extremos están cerrados agregando un semicírculo al CGPath.

Sería un trabajo un poco más que simplemente dibujar una sola línea y acariciarlo, pero les da un control total sobre el estilo de la ruta representada.

+0

Eso suena correcto Chris, gracias. Mi problema es cómo dibujar un degradado a lo largo de un CGPath. ¿Alguna idea o fragmento de código que puedas compartir? – myell0w

+0

No sé cómo se verán los resultados, pero puede usar 'CGContextReplacePathWithStrokedPath()' para recuperar un esquema que luego puede rellenar con un degradado. Esta pregunta anterior podría ser útil: http://stackoverflow.com/questions/2737973/on-osx-how-do-i-gradient-fill-a-path-stroke – lxt

+0

Después de un poco de experimentación no puedo encontrar un forma de obtener fácilmente un relleno de degradado para seguir un camino, en la forma en que lo están haciendo. Podrían estar rompiendo el camino y dibujando un relleno de degradado para cada segmento por separado. –

Cuestiones relacionadas