18

初期半径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

4 に答える 4

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];
于 2012-11-14T13:32:18.823 に答える
13

これは、それを行うためのより簡単で好ましい方法だと思います。

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 ドキュメントのこちらから入手しました(リスト 3-2 を参照)。ここで重要なことは、アニメーションを設定した直後に を設定し、のfromValue最終値も に設定することです。アニメーションはモデルの基になる値を変更しないため、他のアプローチでは、シェイプ レイヤーの変数を実際に永続的に変更することはありません。self.circlepathnewPath.CGPathpath

過去に選択した回答のようなソリューションを使用しましたが (removedOnCompletionなどを使用fillMode)、iOS の特定のバージョンではメモリリークが発生し、そのアプローチが何らかの理由で機能しないこともあります。

このアプローチでは、アニメーションを明示的に (開始場所と終了場所の両方で) 作成し、最後に (最後の行で) パスの最終的な永続値を指定ているため、必要はありません。終了時にアニメーションを削除しないことを台無しにします(このアニメーションを何度も実行するとメモリリークが発生すると思います...削除されていないアニメーションがメモリに蓄積されます)。

boundsまた、円をアニメーション化する必要がないため、 のアニメーションを削除しました。パスがレイヤーの境界外に描画されていても、完全に表示されます (それについてはドキュメントを参照してくださいCAShapeLayer)。他の理由で境界をアニメーション化する必要がある場合は、同じアプローチを使用できます (fromValue境界の と最終値を必ず指定してください)。

于 2016-04-21T13:13:22.373 に答える
2

を使用して、のとCAAnimationGroupをアニメーション化できます。boundspathCAShapeLayer

- (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];
}
于 2012-11-14T01:47:28.260 に答える