¿Cómo dibujar una línea de degradado(atenuación de entrada/salida) con Core Graphics/iPhone?
core-graphics draw (5)
Sé cómo dibujar una línea simple:
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextMoveToPoint(context, x, y);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);
Y sé cómo hacer un rectángulo degradado, ig:
CGColorSpaceRef myColorspace=CGColorSpaceCreateDeviceRGB();
size_t num_locations = 2;
CGFloat locations[2] = { 1.0, 0.0 };
CGFloat components[8] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, num_locations);
CGPoint myStartPoint, myEndPoint;
myStartPoint.x = 0.0;
myStartPoint.y = 0.0;
myEndPoint.x = 0.0;
myEndPoint.y = 10.0;
CGContextDrawLinearGradient (context, myGradient, myStartPoint, myEndPoint, 0);
Pero, ¿cómo podría dibujar una línea con un degradado, ig desvaneciéndose de negro a blanco (y tal vez desvaneciéndose a negro en el otro lado también)?
Después de dibujar la línea, puede llamar
CGContextClip(context);
para recortar más dibujo a su área de línea. Si dibuja el degradado, ahora debería estar contenido dentro del área de la línea. Tenga en cuenta que necesitará usar un color claro para su línea si solo desea que se muestre el degradado, y no la línea debajo de ella.
Existe la posibilidad de que una línea sea demasiado delgada para que aparezca su degradado, en cuyo caso puede usar CGContextAddRect()
para definir un área más gruesa.
Presento un ejemplo más elaborado del uso de este recorte de contexto en mi respuesta here .
Después de varios intentos, ahora estoy seguro de que los gradientes no afectan los trazos, por lo que creo que es imposible dibujar líneas de gradiente con CGContextStrokePath()
. Para líneas horizontales y verticales, la solución es usar CGContextAddRect()
lugar, que afortunadamente es lo que necesito. Reemplacé
CGContextMoveToPoint(context, x, y);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);
con
CGContextSaveGState(context);
CGContextAddRect(context, CGRectMake(x, y, width, height));
CGContextClip(context);
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
y todo funciona bien. Gracias a Brad Larson por la pista crucial.
Puede utilizar capas de animación Core. Puede usar un CAShaperLayer para su línea configurando su propiedad de ruta y luego puede usar un CAGradientLayer como una máscara de capa para su capa de forma que hará que la línea se desvanezca.
Reemplace sus llamadas de CGContext ... por llamadas a CGPath ... para crear la ruta de la línea. Establezca el campo de ruta en la capa usando esa ruta. Luego, en la capa de degradado, especifique los colores que desea usar (probablemente de negro a blanco) y luego configure la máscara para que sea la capa de línea como esta:
[gradientLayer setMask:lineLayer];
Lo bueno de la capa de degradado es que le permite especificar una lista de ubicaciones donde se detendrá el degradado, para que pueda aparecer y desaparecer. Solo admite gradientes lineales, pero suena como que puede adaptarse a sus necesidades.
Déjame saber si necesitas una aclaración.
EDIT: Ahora que lo pienso, solo cree un CAGradientLayer que sea el ancho / alto de la línea que desea. Especifique los colores degradados (negro a blanco o negro a color claro) y los puntos startPoint y endtPoints y le dará lo que necesita.
Es posible trazar trazados arbitrarios con un degradado, o cualquier otro efecto de relleno, como un patrón.
Como ha encontrado, los trazos trazados no se representan con el gradiente actual. Solo los caminos rellenos usan el degradado (cuando los convierte en un clip y luego dibuja el degradado).
Sin embargo , Core Graphics tiene un procedimiento asombrosamente genial, CGContextReplacePathWithStrokedPath
que transformará la ruta que pretende CGContextReplacePathWithStrokedPath
en una ruta que es equivalente cuando se llena .
Detrás de las escenas, CGContextReplacePathWithStrokedPath
crea un polígono de borde alrededor de su trayectoria de trazo y cambia eso para la ruta que ha definido. Yo especulaba que el motor de renderizado de Core Graphics probablemente haga esto de todos modos en las llamadas a CGContextStrokePath
.
Aquí está la documentación de Apple sobre esto:
Quartz crea una ruta trazada utilizando los parámetros del contexto de gráficos actual. La nueva ruta se crea para que al rellenarla dibuje los mismos píxeles que al trazar la ruta original. Puedes usar esta ruta de la misma manera que usas la ruta de cualquier contexto. Por ejemplo, puede recortar a la versión trazada de una ruta llamando a esta función seguida de una llamada a la función CGContextClip.
Por lo tanto, convierta su ruta en algo que pueda rellenar, conviértala en un clip y luego dibuje su gradiente. El efecto será como si hubieras trazado el camino con el degradado.
Código
Se verá algo como esto ...
// Get the current graphics context.
//
const CGContextRef context = UIGraphicsGetCurrentContext();
// Define your stroked path.
//
// You can set up **anything** you like here.
//
CGContextAddRect(context, yourRectToStrokeWithAGradient);
// Set up any stroking parameters like line.
//
// I''m setting width. You could also set up a dashed stroke
// pattern, or whatever you like.
//
CGContextSetLineWidth(context, 1);
// Use the magical call.
//
// It turns your _stroked_ path in to a **fillable** one.
//
CGContextReplacePathWithStrokedPath(context);
// Use the current _fillable_ path in to define a clipping region.
//
CGContextClip(context);
// Draw the gradient.
//
// The gradient will be clipped to your original path.
// You could use other fill effects like patterns here.
//
CGContextDrawLinearGradient(
context,
yourGradient,
gradientTop,
gradientBottom,
0
);
Notas adicionales
Vale la pena destacar parte de la documentación anterior:
Quartz crea una ruta trazada utilizando los parámetros del contexto de gráficos actual .
El parámetro obvio es el ancho de línea. Sin embargo, se utiliza todo el estado de dibujo de líneas, como el patrón de trazo, el límite de inglete, las uniones de líneas, los topes, los patrones de guiones, etc. Esto hace que el enfoque sea extremadamente poderoso.
Para detalles adicionales vea esta respuesta de esta pregunta SO .
CGContextMoveToPoint(context, frame.size.width-200, frame.origin.y+10);
CGContextAddLineToPoint(context, frame.size.width-200, 100-10);
CGFloat colors[16] = { 0,0, 0, 0,
0, 0, 0, .8,
0, 0, 0, .8,
0, 0,0 ,0 };
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 4);
CGContextSaveGState(context);
CGContextAddRect(context, CGRectMake(frame.size.width-200,10, 1, 80));
CGContextClip(context);
CGContextDrawLinearGradient (context, gradient, CGPointMake(frame.size.width-200, 10), CGPointMake(frame.size.width-200,80), 0);
CGContextRestoreGState(context);
su trabajo para mi