2009-08-20 7 views
22

sé cómo dibujar una línea sencilla:Cómo dibujar una línea de degradado (fundido de entrada/salida) con Core Graphics/iPhone?

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 de gradiente, i.g .:

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 trazar una línea con un gradiente, i.g. desvanecimiento de negro a blanco (y tal vez desvanecimiento a negro en el otro lado también)?

+1

Una nota rápida: la respuesta seleccionada aquí es incorrecta. ** Es posible trazar caminos arbitrarios con un degradado ** como se muestra [esta respuesta] (http://stackoverflow.com/a/25034854/2547229). – Benjohn

Respuesta

20

Después de varios intentos, estoy seguro de que los degradados no afectan a los trazos, por lo que creo que es imposible dibujar líneas de degradado con CGContextStrokePath(). Para líneas horizontales y verticales, la solución es usar CGContextAddRect(), que afortunadamente es lo que necesito. He sustituido

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.

+0

He encontrado exactamente lo mismo. Parece que los degradados requieren una ruta de clip (o rectángulo) para aplicarse primero al contexto de gráficos. Quizás esto se deba a que los degradados se representan en el área circundante y no en el borde de la ruta (o rectángulo). – Dalmazio

+0

Esto no puede representar una línea de decantación? – AntiMoron

8

Puede usar capas de animación principal. 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 en su capa de forma que hará que la línea se desvanezca.

Reemplace su CGContext ... llamadas con llamadas a CGPath ... llamadas para crear la ruta de línea. Establezca el campo de ruta en la capa usando esa ruta. Luego en su capa de gradiente, especificar los colores que desea utilizar (probablemente negro a blanco) y luego ponga la mascarilla para la capa de línea como la siguiente:

[gradientLayer setMask:lineLayer]; 

Lo bueno de la capa de gradiente es que se le permite para especificar una lista de ubicaciones donde se detendrá el degradado, por lo que puede desvanecerse y desaparecer. Solo admite gradientes lineales, pero parece que puede ajustarse a tus necesidades.

Avísame si necesitas alguna aclaración.

EDIT: Ahora que lo pienso, simplemente crea un CAGradientLayer único que tenga el ancho/alto de la línea que deseas. Especifique los colores de degradado (negro a blanco o negro para borrar el color) y los puntos de inicio y final y debe darle lo que necesita.

+0

Tiene razón, esto se ajustaría perfectamente a mis necesidades, pero desafortunadamente esto solo está disponible con la versión 3 del SO iPhone y quiero usar al menos 2.2. Gracias de cualquier manera... – Walchy

+1

Supongo que querías decir [gradientLayer setMask: LineLayer]; - ¿derecho? Enmascara CAGradientLayer con CAShapeLayer. – Palimondo

+0

Brillante. Aprendí mucho haciendo esto. – Ian1971

8

Después de dibujar la línea, puede llamar

CGContextClip(context); 

al clip de dibujo a su área de la línea más. Si dibuja el degradado, ahora debería estar contenido dentro del área de 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 él.

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.

+1

He intentado con su sugerencia: \t CGContextSetLineWidth (context, 10.0); // debería ser lo suficientemente grueso \t CGContextSetRGBStrokeColor (contexto, 0.0, 0.0, 0.0, 0.0); \t CGContextMoveToPoint (context, 50,50); \t CGContextAddLineToPoint (contexto, 100,100); \t CGContextStrokePath (contexto); \t CGContextClip (context); \t CGContextDrawLinearGradient (contexto, myGradient, myStartPoint, myEndPoint, 0); pero esto arroja : doClip: ruta vacía. La documentación dice que CGContextStrokePath (context); borra la ruta - sin este método no se produce ningún error, pero no se dibuja nada. ¿Alguna idea? – Walchy

0
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 mí.

25

Es posible trazar rutas arbitrarias con un degradado, o cualquier otro efecto de relleno, como un patrón.

Como ha encontrado, las rutas contorneadas no se representan con el degradado actual. Solo las rutas llenas usan el degradado (cuando las conviertes en un clip y luego dibujas el degradado).

Sin embargo, núcleo de gráficos tiene un procedimiento increíblemente fresco CGContextReplacePathWithStrokedPath que transformará el camino que va a accidente cerebrovascular en a un camino que es equivalente cuando se llena.

Detrás de escena, CGContextReplacePathWithStrokedPath construye un polígono de borde alrededor de la trayectoria de su trazo y lo cambia para la ruta que ha definido. Especulo que el motor de renderizado Core Graphics probablemente lo haga de todos modos en llamadas al CGContextStrokePath.

Aquí está la documentación de Apple en esto:

cuarzo crea un camino acariciado utilizando los parámetros del contexto gráfico actual. La nueva ruta se crea de modo que al llenarla se dibujen los mismos píxeles que cuando se acaricia la ruta original. Puede usar esta ruta de la misma manera que usa la ruta de cualquier contexto. Por ejemplo, puede hacer un clip a la versión acariciada de una ruta llamando a esta función seguida de una llamada a la función CGContextClip.

Por lo tanto, convertir su camino a algo que se puede llenar, a su vez que en un clip, y luego llamar su gradiente. El efecto será como si hubieras acariciado 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 enfatizar parte de la documentación anterior:

cuarzo crea un camino acariciado usando los parámetros del contexto gráfico actual.

El parámetro obvio es el ancho de línea. Sin embargo, se utiliza el estado de dibujo de línea, como patrón de trazo, límite de inglete, uniones de línea, límites, patrones de guiones, etc. Esto hace que el enfoque sea extremadamente poderoso.

Para obtener más información, consulte this answer de this S.O. question.

Cuestiones relacionadas