How to animate fill color of path drawn with CGCon

2019-04-15 01:46发布

问题:

I wonder if is possible to animate the fill color of a path I have drawn using CoreGraphics? I am drawing this: Simple drawing with Quartz - Core Graphics

and I want to change its fill color from white to let's say gray. Is this possible?

I know the existence of view.layer.content property but Is this useful here? Though, I am not sure how can I use it in this case.

Thanks in advance.

Update

I am trying this approach (its buggy, hence I can tell if its going to work) basically I am creating a CGImageRef and pass it to self.layer.contents which is animatable using UIView animations but .... I am getting strange results, besides is not animating.

int bitsPerComponent = 8;
int channels = 4;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *data = malloc(self.bounds.size.width*self.bounds.size.height*channels);

CGContextRef context = CGBitmapContextCreate(data,                      //pointer to data
                                             self.bounds.size.width,    //width
                                             self.bounds.size.height,   //height
                                             bitsPerComponent,          //bitsPerComponent
                                             self.bounds.size.width*channels,//bytesPerRow
                                             colorSpace,                    //colorSpace
                                             kCGImageAlphaPremultipliedFirst);  //bitmapInfo

//method that uses below link's code
[self _drawBackgroundInContext:context color:UIColorFromMandalaBoxType(type)];

CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL,         //info, NULL
                                                              data,         //pointer to data
                                                              self.bounds.size.width*self.bounds.size.height*channels, //number of bytes
                                                              NULL);        //release callback


CGImageRef image = CGImageCreate(self.bounds.size.width,            //width
                                 self.bounds.size.height,         //height
                                 bitsPerComponent,                //bitsPerComponent
                                 bitsPerComponent*channels,       //bitsPerPixel
                                 self.bounds.size.width*channels, //bytesPerRow
                                 colorSpace,                        //colorSpace
                                 kCGImageAlphaPremultipliedFirst,   //bitmapInfo
                                 dataProvider, NULL, false, kCGRenderingIntentDefault);

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.5f];
self.layer.contents = (id)image;
[UIView commitAnimations];

CGImageRelease(image);
CGDataProviderRelease(dataProvider);
CGContextRelease(context);
free(data);
CGColorSpaceRelease(colorSpace);

Is logic OK?, and where is the mistake here? ;(

回答1:

Edited answer:
You can't animate stuff in -drawRect:. If you're trying to animate the color of a shape, you may want to look at CAShapeLayer. It allows you to specify a CGPathRef that it should draw, as well as stroke/fill colors, and all these properties are animatable. One thing to bear in mind, though, is that this isn't terribly efficient at its job. If your shape is not animating all the time, you may want to set shouldRasterize to YES. This will significantly speed up the rendering as long as the layer is not animating. If you do this, be careful as there are bugs relating to shouldRasterize. One that springs to mind is if you set the opacity to 0, and later make it non-0, shouldRasterize has a tendency to draw nothing at all because it cached the drawing at the 0 opacity.

Original answer:
If you're living in CoreGraphics entirely, you can use CGContextSetFillColorWithColor(), giving it the context and a CGColorRef (e.g. CGContextSetFillColorWithColor(ctx, [UIColor grayColor].CGColor). If you're trying to adjust the fill color of the "current" graphics context, you can also just use the slightly simpler [[UIColor grayColor] setFill].

Edit: After looking at your link, you just need to change the line that says

CGContextSetFillColorWithColor(context, [UIColor white].CGColor);

to use whatever color you want. In this case it would be

CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);


回答2:

I don't think you can. Quartz is meant for drawing static things like buttons, it's not good at real-time drawing.



回答3:

You might look at CALayer and Core Animation. You might be able to do something like this (untested):

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.8];
self.view.layer.backgroundColor = [UIColor grayColor];
[UIView commitAnimations];

CALayer's backgroundColor is "animatable". This might require some changes to your drawRect: method - like doing a fill with [UIColor clearColor] and/or setting view's opaque property to NO, etc.

Just an idea - but it should be doable.

I had to do something similar but a bit more involved. For that I ended up using a second thread and a kind of Producer/Consumer pattern. I think that that would overkill for your needs, but it is another option.