Reputation: 12670
I am trying to build an animated pie chart that can animate the pie in both directions depending on whether the value of its progress
increases or decreases. I've started with sample code provided here and made some adjustments as suggested here.
The trouble is that the back-animation is not yet quite working. It only partially clears the pie. I am not quite sure whether this is due to me using animations incorrectly or calculating coordinates incorrectly, for if I insert CGContextSetFillColorWithColor(context, UIColor.redColor.CGColor);
into the first if
branch and change blend mode to kCGBlendModeNormal
also there the result is similarly off.
So here is my current code (excerpt from PieLayer.m
) -- who can suggest improvements?
- (void)drawInContext:(CGContextRef)context {
PieView *pieView = self.delegate;
NSAssert(pieView != nil, nil);
CGRect rect = CGRectInset(self.bounds, 1, 1);
CGFloat radius = MIN(CGRectGetMidX(rect), CGRectGetMidY(rect));
CGPoint center = CGPointMake(radius, CGRectGetMidY(rect));
CGContextSetFillColorWithColor(context, UIColor.clearColor.CGColor);
CGContextSetStrokeColorWithColor(context, pieView.circumferenceTintColor.CGColor);
CGContextSetLineWidth(context, 2.0f);
CGContextFillEllipseInRect(context, rect);
CGContextStrokeEllipseInRect(context, rect);
CGFloat startAngle = -M_PI / 2;
CGFloat endAngle = self.progress * 2 * M_PI + startAngle;
CGFloat lastEndAngle = self.lastProgress * 2 * M_PI + startAngle;
if (self.lastProgress > self.progress) {
NSLog(@"clear sector between progress=%f and lastProgress=%f", self.progress, self.lastProgress);
CGContextMoveToPoint(context, center.x, center.y);
CGContextAddArc(context, center.x, center.y, radius, endAngle, lastEndAngle, 0);
CGContextClosePath(context);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillPath(context);
}
if (self.progress > 0) {
NSLog(@"draw sector to progress=%f (lastProgress=%f)", self.progress, self.lastProgress);
CGContextSetFillColorWithColor(context, pieView.sectorTintColor.CGColor);
CGContextMoveToPoint(context, center.x, center.y);
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
CGContextClosePath(context);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextFillPath(context);
}
((PieLayer *)self.modelLayer).lastProgress = self.progress;
[super drawInContext:context];
}
Upvotes: 0
Views: 203
Reputation: 2622
The code in the answer you posted (animated CAShapeLayer pie) works fine in both directions for me, even using clearColor
: see this video.
The only situation in which clearColor
does not produce a correct behavior is when the background color is solid and the foreground is clear: in that case a change in the blending mode is required, as you pointed out in your code.
I tried with these three configuration, and in all the cases the layer was responding correctly to -setProgress:
.
DZRoundProgressView
as subview of the main UIView
;DZRoundProgressView
;DZRoundProgressView
as sublayer of the main UIView
;Moreover, it is unlikely that the content of a layer in the previous frame is still visible at the next draw call: apparently, the default behavior of -drawInContext:
is to clear the context before execution, as this question says.
If you are not working with the contents
property of the layer, and you are not hacking the drawing pipe, then there could be something wrong with the value of self.progress
; perhaps some issue with presentation layer and model layer, or in the implementation of the property.
Indeed this doesn't solve your problem, since I couldn't reproduce it or isolate it, but should allow you to work around it.
Upvotes: 1