ios - example - Dibujar un gradiente a lo largo de una curva UIBezierPath
uibezierpath ovalin (2)
En una aplicación, dibujo un UIBezierPath curvo y una clase MKOverlayPathView para mostrar las rutas de vuelo. Este es el código que estoy usando:
- (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);
}
Esto está funcionando bien, pero me gustaría dibujar un degradado a lo largo de ese camino en lugar de solo un color de relleno. Y aquí es donde empieza a ser muy complicado.
He experimentado con CGContextDrawLinearGradient () pero todavía no me ha servido de nada.
El truco es usar la ruta de trazo de la línea ( CGContextReplacePathWithStrokedPath
) y recortarla ( CGContextClip
) para restringir el gradiente a la ruta:
// 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;
En Swift 3, esto se puede lograr usando el siguiente código. Este ejemplo es para una línea recta, pero deben aplicarse los mismos principios.
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()