我创建了一个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
)。有关如何解决此问题的任何想法? (不是我试过的,但一般来说这个问题,我认为你不应该像我上面尝试的那样做)
由于
答案 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];
}
为真实图像制作动画要轻得多。