我画一个圆圈,用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为半径?
这是我最后只是:
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];
由于雅各布指着我在正确的方向。
这一点,我相信,简单的和最佳的方式做到这一点:
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;
我从这个方法苹果文档这里 (参见清单3-2)。 这里最重要的事情是,你设置fromValue
并设置终值self.circle
的path
来newPath.CGPath
右侧设置了动画后。 动画不会改变模型的潜在价值,所以在另一种方法,你没有真正做的形状层的永久改变path
变量。
我使用(使用像过去所选择的答案的解决方案removedOnCompletion
并fillMode
等),但我发现,iOS上的某些版本中他们造成内存泄露,也有时这种做法只是没有出于某种原因。
通过这种方法,你明确地创建动画(包括它的开始,在哪里结束), 并且你在最后指定的路径最终永久值(与上线),以便有没有必要与不删除当它完成动画一塌糊涂(我相信是如果你这样做动画了很多次什么导致内存泄漏...未去除的动画建立在内存中)。
另外,我删除了动画bounds
,因为你不需要它动画圆。 即使路径绘制层的边界之外,它仍然尽显(请参阅文档CAShapeLayer
有关)。 如果你确实需要动画一些其他原因的界限,你可以使用相同的方法(确保指定fromValue
和边界的最终值)。
您可以使用CAAnimationGroup
动画的bounds
和path
您的CAShapeLayer
:
- (void)animateToRadius:(CGFloat)newRadius {
CAShapeLayer *shapeLayer = ...;
UIBezierPath *newBezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(newRadius, newRadius)];
NSValue *newBounds = [NSValue valueWithCGRect:CGRectMake(0,0,2*newRadius,2*newRadius);
CAAnimationGroup *group = [CAAnimationGroup animation];
NSMutableArray *animations = [@[] mutableCopy];
NSDictionary *animationData = @{@"path":newBezierPath.CGPath, @"bounds":newBounds};
for(NSString *keyPath in animationData) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
animation.toValue = animationData[keyPath];
[animations addObject:animation];
}
group.animations = [animations copy];
group.duration = 2;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[shapeLayer addAnimation:group forKey:nil];
}
下面是乔纳森的代码直接转换迅速如若有人需要它。
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);
}