[iOS 7] [UIKit Dynamics] UIDynamicAnimatorとビヘイビアの使い方〜UISnapBehavior〜

[iOS 7] [UIKit Dynamics] UIDynamicAnimatorとビヘイビアの使い方〜UISnapBehavior〜

前回はUICollisionBehaviorについて解説しました。今回解説するのはUISnapBehaviorです。

UISnapBehaviorとは?

UISnapBehaviorはその名の通り、指定したアイテム(ビュー)を指定した座標に移動する際に、まるでスナップするようにアニメーションさせるためのクラスです。それでは早速ソースコードを見てみましょう。

これから示すサンプルは、画面の任意の場所をタップすると、予め配置しておいたビュー(赤い正方形)がその座標にスナップするといったものです。画面全体がアニメーションの領域です。
ちなみに、UISnapBehaviorは他のビヘイビアと比較するとあまり覚えることは多くありませんので、肩の力を抜いてやってみてください!
Xcodeプロジェクトを作成していない方は、Xcode5を起動して、Single View Applicationプロジェクトを作成しておきましょう。

ViewController.m
#import "ViewController.h"

@interface ViewController ()

@property (nonatomic) UIView *myView;

@property (nonatomic) UIDynamicAnimator *animator;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // アニメーションさせるビュー(赤い四角)
    self.myView = [[UIView alloc] initWithFrame:CGRectMake(110.0, 0.0, 100.0, 100.0)];
    self.myView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.myView];
 
    // self.view、すなわち画面をタップしたときの動作を追加する
    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
    [self.view addGestureRecognizer:gesture];
}

// 画面をタップしたときに実行されるメソッド
- (void)handleTapGesture:(UITapGestureRecognizer *)gesture
{
    // タップした座標を取得する
    CGPoint point = [gesture locationInView:self.view];

    // self.viewを基準としてUIDynamicAnimatorインスタンスを生成する
    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    
    // UISnapBehaviorインスタンスを生成してアニメーターに追加する
    UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:self.myView snapToPoint:point];
    snapBehavior.damping = 0.5;
    [self.animator addBehavior:snapBehavior];
}

@end

それでは、実際に実行してみましょう。シミュレータが起動して画面が表示されたら、画面の適当な場所をタップしてみましょう。すると、タップした座標に赤い正方形のビューがスナップするはずです。

ios7-uidynamic-4-1

コードの解説

今回はメインのスナップよりむしろ関係ないところが多いですね(笑)
ざっくり説明すると、- viewDidLoadメソッドで、アニメーション対象となるビューを生成して配置し(18〜20行目)、タップジェスチャーを追加(23,24行目)しています。
画面の適当な場所をタップすると、独自に定義した- handleTapGesture:メソッドが呼び出されます(28 〜40行目)。このメソッドの中身が今回のメインとなるところですね。

やることは非常に簡単で、

  1. UIDynamicAnimatorを生成する
  2. 移動先の座標を指定してUISnapBehaviorを生成する
  3. UIDynamicAnimatorインスタンスにUISnapBehaviorインスタンスを追加する

たったこれだけです!たったこれだけで、スナップさせることができちゃいます。

UISnapBehaviorクラス

UISnapBehaviorに定義されているメソッド・プロパティですが、

  1. - initWithItem:snapToPoint:
  2. dampingプロパティ

の2つと非常にシンプルです。以下に使い方を説明するので、是非覚えておきましょう!

UISnapBehaviorインスタンスの生成

UISnapBehaviorインスタンスを生成するには、- initWithItem:snapToPoint:メソッドを使用します。

UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:self.myView snapToPoint:point];

引数として指定するのは、第1引数にはアニメーション対象のビュー(今回は赤い正方形のやつ)、第2引数にはスナップする座標を指定します。このとき、指定する座標はUIDynamicAnimatorに指定した基準となるビューの座標系上であることに注意してください。

damping

dampingプロパティは直訳すると「damping=減衰」となります。対象のビューが目的地の座標に到達したときの振動の減衰量を指定するために使用します。基本的には0.0から1.0の間で指定します。デフォルトは0.5です。
試しに0.0にして実行してみてください。ものすごく落ち着きのない動きになります(笑)
逆に1.0を指定すると、振動がなくなり品のある動きをします。

snapBehavior.damping = 0.2;

まとめ

UIGravityBehavior、UICollisionBehaviorに続き、今回はUISnapBehaviorについて解説しました。いずれも、ウソみたいに少ないソースコードで複雑なアニメーションが実現できていることがわかります。
注意しなければならない点としては、Androidアプリと工数の差が出てしまった場合にお客様にどう説明するかぐらいでしょうか。
いずれにしても非常に強力な機能ですので、是非マスターしましょう。