プログラミングノート

一からものを作ることが好きなエンジニアの開発ブログです。

UIViewで手軽にアニメーションを実行する方法

UIViewにはアニメーション関連メソッドが用意されているので、お手軽にアニメーションを実行することができます。ボタン、ラベル、画像などは全てUIViewを継承しているので基本的に全て同じ方法で実行可能です。


まずはUIViewの初期化メソッドでUIButtonを生成してViewに追加しておきます。このボタンが押されると@selector()で指定してあるメソッドが呼ばれるので、そこでアニメーションを実行します。

- (id)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    self.backgroundColor = [UIColor whiteColor];
    // button
    UIButton *btn= [UIButton  buttonWithType:UIButtonTypeRoundedRect];
    [btn setFrame:CGRectMake(0.0, 0.0, 100.0, 50.0)];
    [btn setCenter:CGPointMake(160.0, 200.0)];
    [btn setTitle:@"TEST" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(startAnimation:) forControlEvents:UIControlEventTouchUpInside];			
    [self addSubview:btn];
  }
  return self;
}


UIViewのアニメーションの設定はbeginAnimationsで始まり、commitAnimationsで終わります。基本的には下記コードをそのまま記述し、//TODO: と記載している箇所でアニメーション終了後のUI部品の状態を指定しておくだけでOKです。あとはフレームワークがその間の座標を補完してアニメーションにしてくれます。

-(void)startAnimation:(id)sender{
  UIButton *btn = (UIButton *)sender;
	
  //アニメーションの対象となるコンテキスト
  CGContextRef context = UIGraphicsGetCurrentContext();
  [UIView beginAnimations:nil context:context];
  //アニメーションを実行する時間
  [UIView setAnimationDuration:0.5];
  //アニメーションイベントを受け取るview
  [UIView setAnimationDelegate:self];
  //アニメーション終了後に実行される
  [UIView setAnimationDidStopSelector:@selector(endAnimation)];

  //TODO: 

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


TODOの箇所には色々かけますが、例えば座標変更や、透明度の変更は下記のように指定します。

//中心座標を変更する
[btn setCenter:CGPointMake(0,0)];
		
//座標を変更する1
CGRect rect = [btn frame];
rect.origin.y = 200;
[btn setFrame:rect];
	
//座標を変更する2
[btn setFrame:CGRectMake(0,100,100,50)];

//透明にする
[btn setAlpha:0.0];	


回転させる場合にはおなじみのアフィン変換も、メソッドが用意されているので手軽に実行することができます。

//90度回転
CGAffineTransform rotate = CGAffineTransformMakeRotation(90.0f * (M_PI / 180.0f));
[btn setTransform:rotate];

//縦横2倍に拡大
CGAffineTransform scale = CGAffineTransformMakeScale(2.0, 2.0);
[btn setTransform:scale];
	
//XY方向に100px平行移動
CGAffineTransform translate = CGAffineTransformMakeTranslation(100.0, 100.0);
[btn setTransform:translate];


上記はそれぞれ下記のようにも記述できます。

//平行移動 (下記行列のx, yを指定する)
// 1 0 0 
// 0 1 0
// x y 1
CGAffineTransform translate2 = CGAffineTransformMake(1.0, 0.0, 0.0, 1.0, 100.0, 100.0);
[btn setTransform:translate2];
	
//スケール (下記行列のx, yを指定する)
// x 0 0
// 0 y 0
// 0 0 1
CGAffineTransform scale2 = CGAffineTransformMake(2.0, 0.0, 0.0, 2.0, 0.0, 0.0);
[btn setTransform:scale2];
	
//回転 (下記行列のsin, cosを指定する)
// cosA sinA 0
//-sinA cosA 0
// 0    0    1		
float rd = 90.0f * (M_PI / 180.0f);
CGAffineTransform rotate2 = CGAffineTransformMake(cos(rd), sin(rd), -sin(rd), cos(rd), 0.0, 0.0);
[btn setTransform:rotate2];


複数の変換を同時に指定したい場合は自分で演算してCGAffineTransformMakeで一括指定してもよいですが、CGAffineTransformConcatというメソッドを利用すれば楽そうです。

//すべての変換を統合
CGAffineTransform concat = CGAffineTransformConcat(CGAffineTransformConcat(rotate, scale), translate);
[btn setTransform:concat];


アニメーションが終了した後には、setAnimationDidStopSelectorで指定したメソッドが実行されます。2段階でアニメーションを実行したい場合などはこの中で再度別のアニメーションを定義して実行するとよいです。次のコードを実行すると、rollオブジェクトが2回転して止まります。

CGFloat affinea = 0.0f;

-(void) startAnimation{
  CGContextRef context = UIGraphicsGetCurrentContext();
  [UIView beginAnimations:nil context:context];
  [UIView setAnimationDuration:0.02f];
  [UIView setAnimationDelegate:self];
  [UIView setAnimationDidStopSelector:@selector(endAnimation)];
  roll.transform = CGAffineTransformMakeRotation(affinea * (M_PI / 180.0f));
  [UIView commitAnimations];
}

-(void)endAnimation{
  affinea += 10.0f;
  if(affinea < 360.0f*2){
    [self startAnimation];
  }else{
    affinea = 0.0f;
    roll.transform = CGAffineTransformMakeRotation(0);		
  }
}

これだけお手軽に実行できると作ってて楽しいですね。