动画饼图与弧形渐变

时间:2013-12-07 10:26:00

标签: ios objective-c core-graphics core-animation calayer

我正在尝试在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);
}

My result:

任何评论都会受到赞赏,因为我是CoreGraphics的新手。

谢谢!

2 个答案:

答案 0 :(得分:1)

我使用合成的核心动画层对此进行了尝试。它继承自CAGradientLayer,然后使用CAShapeLayer来利用strokeStartstrokeEnd属性。形状图层用于遮盖梯度图层,该图层仅允许显示形状图层alpha - 在这种情况下,无论strokeStartstrokeEnd属性设置为什么。这允许您动态设置饼图大小。以下是我提出的视觉输出:

Pieces of Pie

我使用渐变图层作为基类的原因是因为您在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)

如果您需要自定义动画,请查看:

他们一起教你很多自定义动画的好方法。