その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

パスに沿ってアニメーションさせる

Core Animationを用いると、UIViewのアニメーションと比較してより自由度の高いアニメーションを実現できます。たとえば、CAKeyframeAnimation に Core Graphics で描画したパスを渡すことで、円に沿ってアニメーションさせたり、放物線状にアニメーションさせたり、ハート形などの図形や、手書きの軌跡に沿ってアニメーションさせたりといったことが可能になります。

放物線状にアニメーションさせる

パスに沿ってアニメーションさせる方法のシンプルな事例として、サイドビューの2Dゲームのキャラ(例:マリオ)のジャンプのように、放物線状にアニメーションさせる場合の実装例を紹介します。



準備として、QuartzCore.framework をプロジェクトに追加し、ヘッダをインポートしておきます。

#import <QuartzCore/QuartzCore.h>


アニメーションの処理を下記のように実装します。

// CAKeyframeAnimationオブジェクトを生成
CAKeyframeAnimation *animation;
animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.duration = 1.0;

// 放物線のパスを生成
CGFloat jumpHeight = 80.0;
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, kStartPos.x, kStartPos.y);
CGPathAddCurveToPoint(curvedPath, NULL,
                      kStartPos.x + jumpHeight/2, kStartPos.y - jumpHeight,
                      kEndPos.x - jumpHeight/2, kStartPos.y - jumpHeight,
                      kEndPos.x, kEndPos.y);

// パスをCAKeyframeAnimationオブジェクトにセット
animation.path = curvedPath;

// パスを解放
CGPathRelease(curvedPath);

// レイヤーにアニメーションを追加
[self.imageView.layer addAnimation:animation forKey:nil];


この実装のポイントは以下の2点です。

  • CAKeyFrameAnimation で position プロパティをアニメーションさせるよう指定する
  • Core Graphics で描画した放物線のパスを CAKeyframeAnimation の path プロパティにセットする

アニメーション完了時に処理を行う

アニメーション完了後に処理をさせたい場合は、CAAnimation のプロパティにある delegate を指定しておけば、

animation.delegate = self;


animationDidStop:finished: メソッドがアニメーション完了後に呼ばれるようになります。

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    NSLog(@"完了");
}

UIBezierPath オブジェクトをパスとして使用する

CAKeyframeAnimation の path プロパティの型は CGPathRef なので、UIBezierPath オブジェクトをパスとして使用したい場合は、UIBezierPath の CGPath プロパティから CGPathRef を取り出して使用します。

// CAKeyframeAnimationオブジェクトを生成
CAKeyframeAnimation *animation;
animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.duration = 1.0;

// UIBezierPathで放物線のパスを生成
UIBezierPath *path = [UIBezierPath bezierPath];

CGFloat jumpHeight = 80.0;
[path moveToPoint:kStartPos];
[path addCurveToPoint:kEndPos
        controlPoint1:CGPointMake(kStartPos.x + jumpHeight/2,
                                  kStartPos.y - jumpHeight)
        controlPoint2:CGPointMake(kEndPos.x - jumpHeight/2,
                                  kEndPos.y - jumpHeight)];

// パスをCAKeyframeAnimationオブジェクトにセット
animation.path = path.CGPath;
    
// レイヤーにアニメーションを追加
[self.imageView.layer addAnimation:animation forKey:nil];