我正在尝试在PieChart视图中为绘图部分设置动画。因此,每个行业都有自己的颜色,行业从头到尾逐渐增长。
为此,我使用了
-(id<CAAction>)actionForKey:(NSString *)event {
if ([event isEqualToString:@"startAngle"] ||
[event isEqualToString:@"endAngle"]) {
return [self makeAnimationForKey:event];
}
return [super actionForKey:event];
}
-(CABasicAnimation *)makeAnimationForKey:(NSString *)key {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
// set up animation
return animation;
}
因此,这些方法运行良好,但问题在于使用CGContextDrawLinearGradient
代替CGContextSetStrokeColorWithColor
进行色段。随着CGContextSetStrokeColorWithColor
段逐步绘制,虽然我正在增加结束,但是CGContextDrawLinearGradient
它会丢失所有中间值并仅绘制最终段大小。因此,对于用户来说,没有任何动画小子只能一次绘制段,没有任何动态。
-(void)drawInContext:(CGContextRef)ctx {
CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
CGFloat radius = MIN(center.x, center.y);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, center.x, center.y);
CGPoint p1 = CGPointMake(center.x + radius * cosf(self.startAngle), center.y + radius * sinf(self.startAngle));
CGPoint p2 = CGPointMake(center.x + radius * cosf(self.endAngle), center.y + radius * sinf(self.endAngle));
CGContextAddLineToPoint(ctx, p1.x, p1.y);
int clockwise = self.startAngle > self.endAngle;
CGContextAddArc(ctx, center.x, center.y, radius, self.startAngle, self.endAngle, clockwise);
CGContextSaveGState(ctx);
CGContextClip(ctx);
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(space, (CFArrayRef)self.gradients, NULL);
CGContextDrawLinearGradient(ctx, gradient, p1, p2, kCGGradientDrawsBeforeStartLocation);
// CGContextSetFillColorWithColor working properly
// CGContextSetFillColorWithColor(ctx, self.fillColor.CGColor);
CGContextSetStrokeColorWithColor(ctx, self.strokeColor.CGColor);
CGContextSetLineWidth(ctx, self.strokeWidth);
CGContextDrawPath(ctx, kCGPathFillStroke);
}
任何评论都会受到赞赏,因为我是CoreGraphics的新手。
谢谢!
答案 0 :(得分:1)
我使用合成的核心动画层对此进行了尝试。它继承自CAGradientLayer
,然后使用CAShapeLayer
来利用strokeStart
和strokeEnd
属性。形状图层用于遮盖梯度图层,该图层仅允许显示形状图层alpha - 在这种情况下,无论strokeStart
和strokeEnd
属性设置为什么。这允许您动态设置饼图大小。以下是我提出的视觉输出:
我使用渐变图层作为基类的原因是因为您在drawInContext:
代码中显示了渐变。如果您愿意,可以使用常规CALayer
。
以下是我如何定义继承的图层类的init方法:
- (instancetype)initWithRect:(CGRect)rect
{
self = [super init];
if (self) {
// Give it some default gradient colors
self.colors = @[(id)[[UIColor darkGrayColor] CGColor],
(id)[[UIColor lightGrayColor] CGColor]];
// Linear gradient from left side to right side
self.startPoint = CGPointMake(0.0f, 0.5f);
self.endPoint = CGPointMake(1.0f, 0.5f);
// Set our bounds based on what was passed in
self.bounds = rect;
// Initialize our shape layer and set its bounds and position
_shapeLayer = [CAShapeLayer layer];
_shapeLayer.bounds = rect;
_shapeLayer.position = CGPointMake(self.bounds.size.width/2.0f,
self.bounds.size.height/2.0f);
// Create an inner rect we'll use for the bezier path rectangle
CGRect innerRect = CGRectInset(rect, self.bounds.size.width/4.0f,
self.bounds.size.height/4.0f);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:innerRect
cornerRadius:self.bounds.size.width/2.0f];
// Set the path
_shapeLayer.path = [bezierPath CGPath];
// No fill color
_shapeLayer.fillColor = [[UIColor clearColor] CGColor];
// This color doesn't matter since we only care about whether or
// not there is alpha when masking.
_shapeLayer.strokeColor = [[UIColor redColor] CGColor];
// Set the line with to half of the size since the stroke
// is centered
_shapeLayer.lineWidth = self.bounds.size.width/2.0f;
// Set the mask
self.mask = _shapeLayer;
}
return self;
}
现在你可以声明你的每一个馅饼:
MLGradientPieLayer *pie = [[MLGradientPieLayer alloc] initWithRect:kRect];
pie.colors = @[(id)[[UIColor orangeColor] CGColor], (id)[[UIColor yellowColor] CGColor]];
pie.position = kPosition;
[pie setStart:0.0f];
[pie setEnd:0.15f];
[self.view.layer addSublayer:pie];
您可以在此处查看Github上的完整项目:https://github.com/perlmunger/GradientPieLayer.git
我没有添加动画,但是,您可以设置内部strokeStart
的{{1}}和strokeEnd
属性的动画,这些属性被称为(非想象的)CAShapeLayer
。
答案 1 :(得分:0)
如果您需要自定义动画,请查看:
他们一起教你很多自定义动画的好方法。