在动画期间将图像剪切为CALayers内容

时间:2015-03-28 14:33:09

标签: ios objective-c animation calayer cgpath

我创建了一个CALayer的子类来绘制一个饼图,其中包含一个自定义颜色(color),一个startAngle(actualStartAngle),一个endAngle(actualEndAngle)和图像(image)[此图像应始终位于切片的中间],因为使用普通的CAShapeLayer无法进行动画处理。该图层目前的绘制方式如下:

- (void)drawInContext:(CGContextRef)ctx{
    CGContextBeginPath(ctx);

    CGContextMoveToPoint(ctx, self.center.x, self.center.y);
    CGContextAddArc(ctx, self.center.x, self.center.y, self.radius, self.actualEndAngle, self.actualStartAngle, YES);

    CGContextClosePath(ctx);

    CGContextSetFillColorWithColor(ctx, self.color);
    CGContextSetLineWidth(ctx, 0);

    CGContextDrawPath(ctx, kCGPathFillStroke);

    if (self.image) {
        CGContextDrawImage(ctx, [self getFrameForImgLayerWithStartAngle:self.actualStartAngle andEndAngle:self.actualEndAngle], self.image);
    }
}

这些单独的切片通过以下方式设置动画:

[CATransaction begin];

CABasicAnimation *colorAnimation = [CABasicAnimation animationWithKeyPath:@"color"];
colorAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
colorAnimation.duration = duration;
colorAnimation.fromValue = (id)self.color;
colorAnimation.toValue = (id)colorTU.CGColor;

CABasicAnimation *startAngleAnimation = [CABasicAnimation animationWithKeyPath:@"actualStartAngle"];
startAngleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
startAngleAnimation.duration = duration;
startAngleAnimation.fromValue = [self valueForKey:@"actualStartAngle"];
startAngleAnimation.toValue = [[NSNumber alloc] initWithFloat:newStartAngle];

CABasicAnimation *endAngleAnimation = [CABasicAnimation animationWithKeyPath:@"actualEndAngle"];
endAngleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
endAngleAnimation.duration = duration;
endAngleAnimation.fromValue = [self valueForKey:@"actualEndAngle"];
endAngleAnimation.toValue = [[NSNumber alloc] initWithFloat:newEndAngle];

if (completionBlock) {
    [CATransaction setCompletionBlock:completionBlock];
}

if (colorTU && colorTU.CGColor != self.color) {
    [self addAnimation:colorAnimation forKey:@"color"];
}
if (newStartAngle != self.actualStartAngle) {
    [self addAnimation:startAngleAnimation forKey:@"actualStartAngle"];
}
if (newEndAngle != self.actualEndAngle) {
    [self addAnimation:endAngleAnimation forKey:@"actualEndAngle"];
}

[CATransaction commit];

问题在于我希望图像只占用单个图层占用的空间(相应的形状)。这通常通过以下方法解决:

- (BOOL)imageFitsIntoSliceWithStartAngle:(float)sA andEndAngle:(float)eA{
    BOOL fits = YES;
    CGRect rectToUse = [self getFrameForImgLayerWithStartAngle:sA andEndAngle:eA];

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:self.center];
    [path addArcWithCenter:self.center radius:self.deg startAngle:sA endAngle:eA clockwise:YES];
    for (int w = 0; w <= 1; w++) {
        if (fits) {
            for (int h = 0; h <= 1; h++) {
                if (![path containsPoint:CGPointMake(rectToUse.origin.x + rectToUse.size.width * w, rectToUse.origin.y + rectToUse.size.height * h)]) {
                    fits = NO;
                    break;
                }
            }
        }
    }
    return fits;
}

现在的问题是它可能适合最终而不是动画的开头,所以当发生这种情况时,我必须将图像剪切为与切片一样大。

我尝试了以下内容:

  • 为切片设置遮罩而不是直接绘制 - >这首先是错误的编码,我发现它非常节能,也为我造成了错误(expecting model layer not copy)。

有关如何解决此问题的任何想法? (不是我试过的,但一般来说这个问题,我认为你不应该像我上面尝试的那样做)

由于

1 个答案:

答案 0 :(得分:0)

不知道它是否有用,但这里是饼图部分的绘图代码:

- (void)drawChartWithFrame:(CGRect)frame startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle fillColor:(UIColor *)fillColor strokeColor:(UIColor *)strokeColor
{

    //// Oval Drawing
    CGRect ovalRect = CGRectMake(CGRectGetMinX(frame),CGRectGetMinY(frame), CGRectGetWidth(frame), CGRectGetHeight(frame));
    UIBezierPath* ovalPath = UIBezierPath.bezierPath;
    [ovalPath addArcWithCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)) radius: CGRectGetWidth(ovalRect) / 2 startAngle: -(startAngle - 25) * M_PI/180 endAngle: -(endAngle - 93) * M_PI/180 clockwise: YES];
    [ovalPath addLineToPoint: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))];
    [ovalPath closePath];ansform ovalTransform = CGAffineTransformMakeTranslation(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect));
    ovalTransform = CGAffineTransformScale(ovalTransform, 1, CGRectGetHeight(ovalRect) / CGRectGetWidth(ovalRect));
    [ovalPath applyTransform: ovalTransform];

    [fillColor setFill];
    [ovalPath fill];
    [strokeColor setStroke];
    ovalPath.lineWidth = 1;
    [ovalPath stroke];
}

为真实图像制作动画要轻得多。