Edited at

実はObjective-Cではアニメーションが動かない事がある

More than 5 years have passed since last update.


アニメーションが動かない


animateWithDuration

Objective-Cでアニメーションを実装する場合、次のようなコードを書く場合があります。(有名な「逆引きObjective-C」のものをつかっています。)

自分の環境の場合、このコードは動くのですが、拡大・縮小だけでなく移動を入れようとするととたんに動かなくなりました。

- (void)viewDidLoad

{
[super viewDidLoad];

// 画像を表示する
UIImage *image = [UIImage imageNamed:@"image01.png"];
UIImageView *imageView = [[UIImageView alloc]initWithImage:image];
imageView.center = CGPointMake(160, 240);
[self.view addSubview:imageView];

// アニメーション
[UIView animateWithDuration:2.5f // アニメーション速度2.5秒
delay:1.0f // 1秒後にアニメーション
options:UIViewAnimationOptionCurveEaseIn
animations:^{
// 画像を2倍に拡大
imageView.transform = CGAffineTransformMakeScale(2.0, 2.0);

} completion:^(BOOL finished) {
// アニメーション終了時
NSLog(@"アニメーション終了");
}];
}

コードは完璧なのに・・・。なぜでしょうか?


原因

AutoLayoutを使用した場合、viewDidLoad,viewWillAppearではframeが決定していないようです(参考: [iOS6] AutoLayoutを使用すると、viewWillAppear: でframeが決定しないので注意)そのため、このタイミングでanimationを開始した場合挙動が環境によっては不安定になります。(Xcodeのバージョンによっても変わる模様)

以下のライフサイクルが分かっている人にとってはある当然のことかもしれません。(viewDidLoadのタイミングでは画面はまだ表示されていないから)

イベント
iOS

クラスが生成されたとき
init

画面がロードされる前
loadView

画面がロードされた時
viewDidLoad

UIの配置が行われる前
viewWillLayoutSubviews

UIの配置が行われた後
viewDidLayoutSubviews

画面が表示される直前
viewWillAppear

画面が表示された直後
viewDidAppear


解決策


解決策1:viewDidAppear後にアニメーションを開始する

以下のように書きます

-(void)viewDidAppear:(BOOL)animated{

// 画像を表示する
UIImage *image = [UIImage imageNamed:@"image01.png"];
UIImageView *imageView = [[UIImageView alloc]initWithImage:image];
imageView.center = CGPointMake(160, 240);
[self.view addSubview:imageView];

// アニメーション
[UIView animateWithDuration:2.5f // アニメーション速度2.5秒
delay:1.0f // 1秒後にアニメーション
options:UIViewAnimationOptionCurveEaseIn
animations:^{
// 画像を2倍に拡大
imageView.transform = CGAffineTransformMakeScale(2.0, 2.0);

} completion:^(BOOL finished) {
// アニメーション終了時
NSLog(@"アニメーション終了");
}];
}


解決策2:autolayoutのチェックを外す

autolayoutが悪いならautolayoutしなければよい、ということでautolayoutのチェックを外してやっても解決します

スクリーンショット 2014-06-10 16.02.21.png