Objective-Cでアニメーションまとめ


アニメーションさせるにはいくつか方法があるみたい。

* `beginAnimations:context:`メソッドを使う
* `animateWithDuration:animations:`メソッドを使う
* `CATransaction`を利用する方法
* `CABasicAnimation`を利用する方法

--------------------------

##`animateWithDuration:animations:`を使う方法

`animateWithDuration:animations:`メソッドはクラスメソッドとして実行する。
（細かく指定する場合は`animateWithDuration:delay:options:animations:`メソッドを使う）
blockでコールバックが実行できるので、こちらのほうが簡単。

ちなみにイメージとしては

1. `animateWithDuration:animations:`クラスメソッドの`animations:`に変更したい値をblock経由で渡す
2. 渡された情報を元に、最終的なアニメーション終了後の値が設定される
3. アニメーション実行
4. `completion:`で受け取ったblockを実行して終了

という流れ。

###サンプルコード

```objc
//UIViewを生成
UIView *animView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[animView setBackgroundColor:[UIColor redColor]];

[UIView animateWithDuration:1.0f delay:0.5f options:UIViewAnimationOptionCurveEaseInOut animations:^ {
	//アニメーションで変化させたい値を設定する（最終的に変更したい値）
	animView.frame = CGRectMake(0, 0, 320, 100);
} completion:^ {
	//完了時のコールバック
}];
```

####optionsに指定できるオプション
* UIViewAnimationOptionCurveEaseInOut
* UIViewAnimationOptionCurveEaseIn
* UIViewAnimationOptionCurveEaseOut
* UIViewAnimationOptionCurveLinear

--------------------------

##`beginAnimations:context:`を使う方法

※コメントで指摘いただきました。
`beginAnimations:context:`メソッドの`context`は主にユーザデータとして利用するもののようです。
最初は`CGContextRef`を渡していましたが、これは必要ありません。

こちらもUIViewのクラス・メソッドで実行する。
手順としては

<del>1. `CGContextRef`型のコンテキストを取得</del>

1. UIViewの`beginAnimations:context:`メソッドでアニメーション実行の開始を宣言
2. `setAnimationDuration:`メソッドでアニメーション時間を設定
3. `setAnimationDelegate:`メソッドでアニメーションイベントのデリゲート先を設定
4. `setAnimationDidStopSelector:`メソッドで終了時のデリゲートメソッドを指定
5. <del>コンテキストに登録したい</del> viewの変更をそれぞれ設定
6. `commitAnimations`メソッドでアニメーションを実行

要はコンテキスト作って、その間に設定されたviewの変更はアニメーションされるようになる、ってことですね。

###サンプルコード

```objc
UIView *animView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];

//アニメーション開始のコンテキストを設定
[UIView beginAnimations:nil context:nil];

//アニメーションの実行時間を設定（例では2秒）
[UIView setAnimationDuration:2.0];

//アニメーションイベントを受け取るデリゲート先
[UIView setAnimationDelegate:self];

//アニメーション終了後に実行されるコールバック
[UIView setAnimationDidStopSelector:@selector(endAnimation)];

//アニメーションの詳細
animView.frame = CGRectMake(0, 0, 320, 100);
//...以下、アニメーションしたいものを列挙していく。


//アニメーション開始
[UIView commitAnimations];

```

--------------------------

##`CATransaction`を使う

上記ふたつはそれぞれUIViewに実装されたメソッドでした。
`CATransaction`は、CALayerに実装されたメソッドです。
ただ、基本的な概念は上記で説明したように、アニメーションの開始を宣言する部分と実際にどういう値に変化させたいかを指定することになります。
サンプルコードを見比べてもらえれば、UIViewに対する操作とCALayerに対する操作という違いがあるだけで、基本的な部分が一緒だということが分かるかと思います。

```objc
//CALayerを取得
CALayer *layer = animView.layer;

//CoreAnimationのアニメーション開始宣言
[CATransaction begin];
[CATransaction setAnimationDuration:5.0];

//どう変化させたいのかの変化を指定
layer.frame = CGRectMake(0, 0, 200, 300);

//CATransactionを入れ子にすることによって複数のアニメーションを実行可能
[CATransaction begin];
[CATransaction setAnimationDuration:1.0];

layer.opacity = 0.5;

//CALayerのアニメーションを開始
[CATransaction commit];
[CATransaction commit];
```

###アニメーションを中止する

上記のアニメーションを実行中に、それを中止するには以下のメソッドを呼べば中止されます。

```objc
[layer removeAllAnimations];
```

--------------------------

##`CABasicAnimation`を使う

CABasicAnimationクラスを使うことで、キーフレームアニメーションを実装できます。
CABasicAnimationを使う手順は、アニメーションさせたいプロパティ名をNSStringで与え、それに対してどうアニメーションさせるか、というのを指定します。

###サンプルコード

```objc
//なにがしかのUIViewからlayerを取得
CALayer *layer = sampleView.layer;

//CABasicAnimationオブジェクトを生成
//サンプルでは"position"をアニメーションさせる例。
//他に、transformを変更したい場合は@"transform.translate.x"などと指定する
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];

//アニメーション時間
animation.duration = 2.5;

//アニメーションの繰り返し回数
animation.repeatCount = 1;

//アニメーションの開始時間
animation.beginTime = CACurrentMediaTime() + 2; //2秒後から開始

//アニメーション終了時に、逆方向にもアニメーションさせるか
animation.autoreverses = NO; //YESにした場合はアニメーションが往復する

//アニメーションのイージングを制御
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

//アニメーションの開始と終了の値を設定
animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(320, 480)];

//アニメーション終了時、元の状態に戻すか否かの設定（サンプルではアニメーション後はそのまま）
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;

//アニメーションキーを設定（任意の名前）
[layer addAnimation:animation forKey:@"sample-animation"];
```

###複数アニメーションを組み合わせる

アニメーションを組み合わせるには`CAAnimationGroup`クラスを利用します。

####サンプルコード

```objc
//ひとつめのアニメーション
CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"position.x"];

//終点を設定
animation1.toValue = @50.0f;

//ふたつめのアニメーション
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"position.y"];

animation2.fromValue = @0.0f;
animation2.toValue = @55.0f;

//アニメーショングループを作成
CAAnimationGroup *group = [CAAnimationGroup animation];

//アニメーショングループの設定
group.duration = 3.0;
group.repeatCount = 1;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;

//グループにアニメーションを追加
group.animations = @[animation1, animation2];
[layer addAnimation:group forKey:@"group-animation-test"];
```

HTMLを使っている人には、CSSによるアニメーションをベースに考えるとイメージしやすいかもしれません。

--------------------------

##UIImageViewを使ってスプライトアニメーション

UIImageViewにはスプライトアニメーションを簡単に行える方法があります。
まず簡単にフローを書くと、

1. UIImageインスタンスをスプライトアニメーションで使用する分だけ生成（10コマなら10個）
2. 生成したUIImageをNSMutableArrayインスタンスの配列として格納
3. NSMutableArrayを、UIImageViewの`animationImages`プロパティにセット
4. UIImageViewの`animationDuration`、`animationRepeatCount`を設定する
5. UIImageViewの`startAnimating`メソッドでアニメーション開始

そもそもプロパティでスプライトアニメーション用のものが存在していて、それに設定していく、という流れです。

###サンプルコード

```objc
//スプライトアニメーションを表示するUIImageViewを生成
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];

//スプライトアニメーション用画像配列
NSMutableArray *imageList = [NSMutableArray array];

//コマ数分UIImageを生成
for (NSInteger i = 1; i < 10; i++) {
	NSString *imagePath = [NSString stringWithFormat:@"hoge_%d.png", i];
	UIImage *img = [UIImage imageNamed:imagePath];
	[imageList addObject:img];
}

[self.view addSubview:imageView];

//スプライトアニメーション用画像をセット
imageView.animationImages = imageList;

//アニメーションする時間
imageView.animationDuration = 2.0;

//アニメーションのリピート回数
imageView.animationRepeatCount = 5;

//アニメーション開始
[imageView startAnimating];
```


##参考記事

* [CoreAnimation CATransaction](http://mm-workmode.blogspot.jp/2011/11/coreanimation-catransaction.html)
* [CABasicAnimationの基本的な使い方（移動・回転・拡大・縮小）](http://www.objectivec-iphone.com/animation/CoreAnimation/CABasicAnimation.html)