Posted at

facebook/pop を使ってみた

More than 5 years have passed since last update.

最近 FacebookがOSSとして公開した pop

Paperで使われているアニメーションライブラリです

https://github.com/facebook/pop

少し触ってみたので基本的な使い方などをまとめてみます

この記事はブログでも公開しています


pop とは

公式ブログに記事があるのでそちらがとても参考になります

Introducing Pop, the animation engine behind Paper

iOS や OS X でアニメーションを実装しようとするとCoreAnimationを使うと思うのですが実はCoreAnimationはなかなか使いにくいライブラリだったりします。確かにCABasicAnimationは簡単ですが、Timing Functionをlinear, ease-in, ease-out, ease-in ease-outの四種類と3次ベジェ曲線のいずれかからしか指定することができません。これだとバネだとかバウンドだとかの表現が出来ませんよね。一方CAKeyframeAnimationは万能ですが、パスを逐一作らなければならず手間がかかりコードも煩雑になります。

pop はCABasicAnimationの簡単さを保ちつつCAKeyframeAnimation並みの表現力を持ったアニメーションを作れるAPIを提供しています。またそのAPIもCoreAnimationに似せていて学習コストを下げる工夫がされています。

pop の目標として

* よく使われるアニメーションを簡単に書けるようにすること

* 拡張可能なフレームワークであること

* 開発者にとって使いやすく強力なプログラミングモデルを構築すること

の3つが掲げてあり、今後もFacebookが中心となってメンテされていくことを考えると安心して使って行けます。


基本的な使い方


導入

Cocoapods経由でインストールします(もちろん直接プロジェクトに追加することも可能です)。適当なXcodeプロジェクトのルートフォルダにPodfileを作成して

pod 'pop', '~> 1.0'

の行を追加しpod installします。これで準備完了です☆

あとは使いたいファイルの先頭に

#import "pop/pop.h"

を追加しましょう。


POPSpringAnimation



POPSpringAnimationはpopの威力を知るのに一番簡単でとても強力な例になるでしょう。

まずはアニメーションさせる対象を作ります

_view = [[UIView alloc] initWithFrame:CGRectMake(200,200,80,80)];

[_view setBackgroundColor:[UIColor cyanColor]];

これに対し適当なタイミングでアニメーションオブジェクトを作成して登録してやることでアニメーションを発生させます。

例えば以下のようにします

POPSpringAnimation *animation = [POPSpringAnimation animation];

animation.property = [POPAnimatableProperty propertyWithName:kPOPLayerSize];
animation.toValue = [NSValue valueWithCGSize:CGSizeMake(100, 100)];

animation.springBounciness = 24.0f;
animation.springSpeed = 6.0f;

[_view pop_addAnimation:animation forKey:@"bound"];

これで対象の大きさをバネのような弾性を持ったアニメーションで変化させることが出来ます。

例としてサイズの変更を挙げましたがPOPAnimatableProperty propertyWithName:の引数の定数を変えることで色々なプロパティを変化させることが出来ます。用意されている定数の一覧はPOPAnimatableProperty.hで見ることが出来ます。

以上の断片的なコードをまとめて以下の様なViewControllerの実装を作ればすぐにでも試すことが出来ます。

ビルドしたら画面をタップしてみてください!

#import "pop/pop.h"

#import "ViewController.h"

@implementation ViewController
{
UIView *_view;
}

- (void)viewDidLoad
{
[super viewDidLoad];

_view = [[UIView alloc] initWithFrame:CGRectMake(120, 120, 80, 80)];
[_view setBackgroundColor:[UIColor cyanColor]];

[self.view addSubview:_view];

[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(startAnimation)]];
}

-(void) startAnimation
{
POPSpringAnimation *animation = [POPSpringAnimation animation];
animation.property = [POPAnimatableProperty propertyWithName:kPOPLayerSize];
animation.toValue = [NSValue valueWithCGSize:CGSizeMake(100, 100)];

animation.springBounciness = 24.0f;
animation.springSpeed = 6.0f;

[_view pop_addAnimation:animation forKey:@"spring"];
}

@end

パラメータを調節すればもっと激しい動きをさせることも出来ますよ!

参考: Playing with Pop (ii)


POPDecayAnimation



POPDecayAnimationease-outよりももっとゆっくり変化がとまるようなアニメーションです。

先ほどのstartAnimationを例えば以下のように変更してみてください

-(void) startAnimation

{
POPDecayAnimation *animation = [POPDecayAnimation animation];
animation.property = [POPAnimatableProperty propertyWithName:kPOPLayerSize];

animation.velocity = [NSValue valueWithCGSize:CGSizeMake(100, 100)];

[_view pop_addAnimation:animation forKey:@"decay"];
}

POPDecayAnimationは少し癖があって例えばtoValueのプロパティを設定するとエラーを吐きます。

これはこのオブジェクトがfromValuevelocitydecelerationの3つのプロパティからdurationtoValueを自動的に決定するからです。なので使う時は前の3つを設定してやれば使うことが出来ます(実際にはfromValuedecelerationはデフォルト値が存在するので省略可能です)。


POPCustomAnimation



POPCustomAnimationは以上3つのクラスとは違って自分でオリジナルのアニメーションを作るためのクラスです。

実際にどうやって作るのが正しいのかわかりませんが、実装をみながら簡単なアニメーションを作ってみたいと思います。

アニメーションといえばバウンドの表現もよく使うと思うのですがこれは標準では用意されていないようです。今回はPOPCustomAnimationを使ってバウンドのアニメーションを実装してみたいと思います。

-(void) startAnimation

{
float duration = 0.6;
CGPoint fromValue = _view.frame.origin;
CGPoint toValue = CGPointMake(120,240);

float dx = toValue.x - fromValue.x;
float dy = toValue.y - fromValue.y;

POPCustomAnimation *animation = [POPCustomAnimation animationWithBlock:^BOOL(id target, POPCustomAnimation *animation) {
float t = (animation.currentTime-animation.beginTime)/duration;

float d = 8/pow(2, floor(log2(1 + 11*(1-t))));
float timing = pow(t*11/4-3*(1-1/d), 2) + (1-1/d)*(1+1/d);

UIView *view = (UIView *)target;
CGSize size = view.frame.size;

CGRect after = CGRectMake(fromValue.x + timing * dx, fromValue.y + timing * dy, size.width, size.height);

[view setFrame:after];

return t < 1.0;
}];

[_view pop_addAnimation:animation forKey:@"bounce"];
}

POPCustomAnimation animationWithBlock:のブロックはアニメーションの各フレームで呼び出されるのでその中でtargetがどのように変化するのかを記述しています。

ブロックの引数のanimationからは


  • beginTime - 開始時間

  • currentTime - 現在の時間

  • elapsedTime - 1ステップにかかった時間

が取得できるのでこれらの値を使ってtargetのプロパティを更新して行きます。

今の場合targetには_viewが入っています。

ブロックの返り値はアニメーションを続けるかどうかの真偽値を返します。

今の場合はtが1.0より小さい時はYESが返ってアニメーションが継続され、tが1.0より大きくなるとNOが返ってその時点でアニメーションが停止します。


POPBasicAnimation



POPBasicAnimationCABasicAnimationと同等のアニメーションを置き換えたクラスになっています。

-(void) startAnimation

{
POPBasicAnimation *animation = [POPBasicAnimation animation];
//POPBasicAnimation *animation = [POPBasicAnimation easeInEaseOutAnimation];
animation.property = [POPAnimatableProperty propertyWithName:kPOPLayerSize];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.toValue = [NSValue valueWithCGSize:CGSizeMake(100, 100)];

[_view pop_addAnimation:animation forKey:@"basic"];
}

コメントアウトしている

POPBasicAnimation *animation = [POPBasicAnimation easeInEaseOutAnimation];

POPBasicAnimation *animation = [POPBasicAnimation animation];

animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

全く同等の処理になっています。


まとめ

以上ざっと pop の基本的な使い方を見てきました。

紹介したのは


  • POPSpringAnimation

  • POPDecayAnimation

  • POPCustomAnimation

  • POPBasicAnimation

の四つだけでしたがどれもとても簡単に使えたと思います。

pop には他にも


  • POPPropertyAnimation

  • POPAnimatableProperty

などのクラスがありまだまだ出来ることは多そうです。


pop はBSDライセンスで公開されています。

https://github.com/facebook/pop