动画CAShapeLayer大小更改

时间:2012-11-14 01:35:09

标签: objective-c ios cabasicanimation cashapelayer

我正在绘制一个圆,初始半径为200

self.circle = [CAShapeLayer layer];
self.circle.fillColor = nil;
self.circle.strokeColor = [UIColor blackColor].CGColor;
self.circle.lineWidth = 7;
self.circle.bounds = CGRectMake(0, 0, 2 * radius, 2 * radius);
self.circle.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.radius, self.radius)

任何人都可以告诉我如何将更改设置为半径100的动画吗?

4 个答案:

答案 0 :(得分:23)

这就是我最终做到的方式:

UIBezierPath *newPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(newRadius, newRadius) radius:newRadius startAngle:(-M_PI/2) endAngle:(3*M_PI/2) clockwise:YES];
CGRect newBounds = CGRectMake(0, 0, 2 * newRadius, 2 * newRadius);

CABasicAnimation* pathAnim = [CABasicAnimation animationWithKeyPath: @"path"];
pathAnim.toValue = (id)newPath.CGPath;

CABasicAnimation* boundsAnim = [CABasicAnimation animationWithKeyPath: @"bounds"];
boundsAnim.toValue = [NSValue valueWithCGRect:newBounds];

CAAnimationGroup *anims = [CAAnimationGroup animation];
anims.animations = [NSArray arrayWithObjects:pathAnim, boundsAnim, nil];
anims.removedOnCompletion = NO;
anims.duration = 2.0f;
anims.fillMode  = kCAFillModeForwards;

[self.circle addAnimation:anims forKey:nil];

感谢雅各布指出我正确的方向。

答案 1 :(得分:11)

我认为,这是一种更简单,更首选的方式:

UIBezierPath *newPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(newRadius, newRadius) radius:newRadius startAngle:(-M_PI/2) endAngle:(3*M_PI/2) clockwise:YES];
CABasicAnimation* pathAnim = [CABasicAnimation animationWithKeyPath:@"path"];
pathAnim.fromValue = (id)self.circle.path;
pathAnim.toValue = (id)newPath.CGPath;
pathAnim.duration = 2.0f;
[self.circle addAnimation:pathAnim forKey:@"animateRadius"];

self.circle.path = newPath.CGPath;

我从Apple Documentation here得到了这种方法(参见清单3-2)。这里重要的是您设置fromValue并在设置动画后立即将self.circle的{​​{1}}的最终值设置为path。动画不会更改模型的基础值,因此在另一种方法中,您实际上并未对形状图层的newPath.CGPath变量进行永久性更改。

我过去使用了一个类似于所选答案的解决方案(使用pathremovedOnCompletion等),但我发现在某些版本的iOS上它们会导致内存泄漏,有时也会出现这种情况因某种原因无法正常工作。

使用这种方法,您可以显式创建动画(无论是从哪里开始,也可以在结束的位置),您在末尾指定路径的最终永久值(使用那个最后一行),所以没有必要在完成时不要删除动画(我相信如果你很多时候这个动画会导致内存泄漏......那些未被删除的动画会在内存中建立)

此外,我删除了fillMode的动画,因为您不需要它来为圆圈设置动画。即使路径被绘制到图层的边界之外,它仍然会完全显示(请参阅bounds的文档)。如果您确实需要为某些其他原因设置边界的动画,可以使用相同的方法(确保指定CAShapeLayer和边界的最终值)。

答案 2 :(得分:2)

您可以使用CAAnimationGroupbounds的{​​{1}}和path制作动画:

CAShapeLayer

答案 3 :(得分:2)

如果有人需要,可以直接快速转换Jonathan的代码。

func scaleShape(shape : CAShapeLayer){

    let newRadius : CGFloat = 50;

    let newPath: UIBezierPath = UIBezierPath(arcCenter: CGPointMake(newRadius, newRadius), radius: newRadius, startAngle: (CGFloat(-M_PI) / 2.0), endAngle: (3 * CGFloat(M_PI) / 2), clockwise: true);


    let newBounds : CGRect = CGRect(x: 0, y: 0, width: 2 * newRadius, height: 2 * newRadius);
    let pathAnim : CABasicAnimation = CABasicAnimation(keyPath: "path");

    pathAnim.toValue = newPath.CGPath;

    let boundsAnim : CABasicAnimation = CABasicAnimation(keyPath: "bounds");
    boundsAnim.toValue = NSValue(CGRect: newBounds);

    let anims: CAAnimationGroup = CAAnimationGroup();
    anims.animations = [pathAnim, boundsAnim];
    anims.removedOnCompletion = false;
    anims.duration = 2.0;
    anims.fillMode = kCAFillModeForwards;

    shape.addAnimation(anims, forKey: nil);
}