Entries

iOS用のアニメーションエンジンを作ろうと思う その2 〜 APIを設計する

GLDTweenを作るにあたって、まずパブリックAPIの仕様を決める。

自分はライブラリを作るときは、まず内部仕様より先に、パブリックAPIを定めるべきだと考えている。

まずユーザーが実際にさわるAPIを策定し、先にサンプルコードを書いて「ユーザーが使いやすいことを確信」する。その後ライブラリの中身を設計する。この工程を省略すると、パワフルかつ難解なオナニーライブラリが生まれてしまうからだ。設計にパブリックなAPIが従事するのではなく、パブリックなAPIに設計が従事すべきだと考える。

アニメーションエンジンの定番API
というわけで既存のAPIを調査し、パブリックAPIの設計を下記3つの方式から選択することとした。
すなわちUIAnimation型、CATransition型、Tweener型だ。


1: UIAnimation型
UIAanimationやOpenGLのように、betinとendの間にアニメーションステートメントを書く方式。

[GLDTween beginAnimation];
    [GLDTween setDuration:1.0];
    [GLDTween setEasing:@"easeInOutExpo"];
    myView.frame = CGRectMake(100,100);
[GLDTween endAnimation];

この設計の長所は、記述がシンプルで明解なこと。短所としてはステートメント終了時にアニメーション処理が開始されるため、複数のアニメーションを同時に実行する場合の競合や上書きに疑問が残る点。ステートメント内のプロパティの変化をウォッチしなければならない為、対応できるアニメや機能の柔軟性に限界がある点・・・などが考えられる。またUIAnimationの場合は内部がブラックボックス化されており、機能拡張ができない。


2: CATransition型
パターン2は、アニメーション毎にインスタンスを作成する手法。

GLDTween* tween = [GLDTween tweenWithTarget:myView];
tween.duration = 2.0;
tween.easing = @"easeInOutExpo";
[tween setValue:10 forKeyPath: @"frame.origin.x"];
[tween setValue:0.2 forKeyPath: @"alpha"];
[tween play];

個人的には、この方式には疑問が大きい。アニメーション毎のインスタンス生成は、たしかに柔軟性と機能性を担保できる。しかし同時に記述や管理が冗長になってしまう。基本的にアニメーションのコーディングは、スクラッチ&ビルドであり最初に設計をするのが難しい。このため冗長な記述は書き直し、つまりアニメーションの高コスト化をもたらしてしまう。

あわせてインスタンス方式では、1つのオブジェクトに2つ以上のアニメーションを生成した場合の管理問題がある。アニメーションの上書きや競合によって、インスタンスの分割などが発生すると、過去に作成したアニメーションインスタンスの整合性が保てなくなる。またパラメータのセットが、メソッドかプロパティ経由になるため、拡張性に難がある(アニメ毎にサブクラスを作る必要がある)。


3: Tweener型
第3の候補は、Flashの伝統を引き継いだTweener型。この設計スタイルではAPIへのアクセスを1つの静的クラスに集約し(内部的にはシングルトン)、またすべてのパラメーターを辞書で渡す。

[GLDTween addTween:myView params:@{
    @"duration": @2.0,
    @"easing": @"easeInOutExpo",
    @"x": @100.0,
    @"y": @100,0
}];

このアプローチの長所は記述のシンプルさと柔軟性である。あらゆるアニメーションが1つのAPIから指定できるため、拡張の柔軟性が非常に高い。短所は、あらゆる手続きを辞書に集約するため、型指定の堅牢性が崩れる点、またパラメータを同一視して処理する必要があるため、かなりメンド臭いな実装を行う必要がある。TweenerそのものはFlashのダイナミック変数が前提となっている為、iOSへそのままポーティングすることはできない。あくあまで思想を継承しつつ、独自実装をしていく形になる。おそらくは内部的には1あるいは2の実装をベースに、手続きのためのラッパーを設けることとなる。


結論
3つの特性を比較した場合、基本的にTweener型は既存のUIAnimationの上位互換になる。

内部実装の前に、上記3種類のAPIでサンプルコードをいくつか書いた結果、アプローチ3がもっとも楽に記述できた為である。前述したように、アニメーションのプログラミングでは、スクラッチビルドが大量に発生するため、最優先させるべきはシンプルさと柔軟性の両立であり、処理速度は第二プライオリティになる。

というわけで候補3版のTweener型、すべてのAPIを1つの静的クラスに集約する方向で設計する。

続く