2013-12-17 16 views
16

In einer App zeichne ich einen gekrümmten UIBezierPath und eine MKOverlayPathView-Klasse, um Flugrouten anzuzeigen. Dies ist der Code ich verwende:Gefälle entlang eines gekrümmten UIBezierPfads zeichnen

- (UIBezierPath *)pathForOverlayForMapRect:(MKMapRect)mapRect { 

    ... bla bla bla ... 

    UIBezierPath *path = [UIBezierPath bezierPath]; 
    [path moveToPoint:s]; 
    [path addQuadCurveToPoint:e controlPoint:cp1]; 
    [path addLineToPoint:e2]; 
    [path addQuadCurveToPoint:s2 controlPoint:cp2]; 
    [path closePath]; 

    return path; 
    } 
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context{ 

    self.mapRect = mapRect; 

    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); 
    CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0); 
    CGContextSetLineWidth(context, mapRect.size.height/700); 
    CGContextSetLineJoin(context, kCGLineJoinRound); 
    CGContextSetLineCap(context, kCGLineCapRound); 

    CGContextAddPath(context, [self pathForOverlayForMapRect:mapRect].CGPath); 

    [self updateTouchablePathForMapRect:mapRect]; 

    CGContextDrawPath(context, kCGPathFillStroke); 

} 

Das funktioniert ganz gut, aber ich möchte einen Gradienten auf diesem Weg ziehen, anstatt nur eine Füllfarbe. Und hier beginnt es sehr schwierig zu werden.

Ich habe mit CGContextDrawLinearGradient() experimentiert, aber es hat mich noch nirgendwo nützlich nützlich.

Antwort

23

Der Trick besteht darin, den Hubweg der Leitung zu verwenden (CGContextReplacePathWithStrokedPath) und Clip it (CGContextClip) den Gradienten auf den Pfad zu beschränken:

// Create a gradient from white to red 
CGFloat colors [] = { 
    1.0, 1.0, 1.0, 1.0, 
    1.0, 0.0, 0.0, 1.0 
}; 

CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); 
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2); 
CGColorSpaceRelease(baseSpace), baseSpace = NULL; 

CGContextSetLineWidth(context, mapRect.size.height/700); 
CGContextSetLineJoin(context, kCGLineJoinRound); 
CGContextSetLineCap(context, kCGLineCapRound); 

CGContextAddPath(context, [self pathForOverlayForMapRect:mapRect].CGPath); 
CGContextReplacePathWithStrokedPath(context); 
CGContextClip(context); 

[self updateTouchablePathForMapRect:mapRect]; 

// Define the start and end points for the gradient 
// This determines the direction in which the gradient is drawn 
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); 
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); 

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 
CGGradientRelease(gradient), gradient = NULL; 
+0

Diese Antwort ist perfekt! Vielen Dank. Ich habe 'CGContextReplacePathWithStrokedPath()' entfernt, so dass mein Pfad mit dem Farbverlauf gefüllt und nicht nur davon umrissen würde. – freshking

+0

'CGContextReplacePathWithStrokedPath' ist nützlich, wenn Sie einen Gradienten _along_ den Pfad (nach der Frage) und nicht _inside_ den Pfad wünschen. – neilco

+0

Das Problem, das ich mit 'CGContextReplacePathWithStrokedPath' bekam, war, dass der Farbverlauf nur auf den Pfad selbst angewendet wurde, ihn aber nicht füllte. Strich statt Füllung. Oder habe ich etwas falsch gemacht? – freshking

0

In Swift 3 dies erreicht werden kann, den Code unter Verwendung von . Dieses Beispiel gilt für eine gerade Linie, aber die gleichen Prinzipien sollten gelten.

let startPoint = CGPoint(x:100, y:100) 
    let endPoint = CGPoint(x: 300, y:400) 

    let context = UIGraphicsGetCurrentContext()! 
    context.setStrokeColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0); 
    // create a line 
    context.move(to: startPoint) 
    context.addLine(to: endPoint) 
    context.setLineWidth(4) 
    // use the line created above as a clipping mask 
    context.replacePathWithStrokedPath() 
    context.clip() 

    // create a gradient 
    let locations: [CGFloat] = [ 0.0, 0.5 ] 

    let colors = [UIColor.green.cgColor, 
        UIColor.white.cgColor] 

    let colorspace = CGColorSpaceCreateDeviceRGB() 

    let gradient = CGGradient(colorsSpace: colorspace, 
           colors: colors as CFArray, locations: locations) 

    let gradientStartPoint = CGPoint(x: rect.midX, y: rect.minY) 
    let gradientEndPoint = CGPoint(x: rect.midX, y: rect.maxY) 

    context.drawLinearGradient(gradient!, 
           start: gradientStartPoint, end: gradientEndPoint, 
           options: .drawsBeforeStartLocation) 
    UIGraphicsEndImageContext()