2012年9月29日土曜日

iOSのレイヤアニメーションメモ

キー値コーディングの知識は、iOSアプリではほとんど無駄だと思っていたけど、Coreフレームワーク群はプロパティの生まれるObjective-C 2.0以前の、つまりキー値コーディングの時代の知識を必要とするドキュメントが多いので、目を通しておくだけでも理解できなかったドキュメントが頭に入るようになると思うのでオススメ。

---

レイヤアニメーション(Core Animation)関連で調べていて躓いた点のまとめなど。

---

レイヤって何?

UIKitではViewが最小の粒度だったが、さらに下位のフレームワークでは最適化のためにViewは描画部分と、ユーザーインタラクションの部分を別の仕組みで扱っている。

このうち描画を担当しているのがレイヤ。

このため、UIViewアニメーションでは当たり判定も同時に移動していたが、レイヤアニメーションでは当たり判定は追従しないという違いがある。

その分レイヤアニメーションの方が性能が高く、出来ることも多い。

---

CAAnimationとかCABasicAnimationとかいろいろあってワケ分からない。

CAのプレフィクスはCoreAnimationフレームワークに属することを意味する。

全てのアニメーションクラスの抽象クラスがCAAnimation、その他はサブクラス。クラスの関係はリファレンスに載っている。

transformやalphaなどのプロパティ値の変化を数学的に補完するCAPropertyAnimationがあり、そのサブクラスとして開始状態と終了状態を指定するCABasicAnimation、配列で値を渡すことで複雑な動きを表現するCAKeyframeAnimationとがある。

それとは別に異なるレイヤへの切り替え処理を行う、トランザクションアニメーションを扱うCATransitionがある。

---

イージングを使いたい

iOSのアニメーションは確か何もしなくてもEaseInEaseOutのイージングが機能していると思うけど、組み込みで使えるイージングはLinear、EaseIn、EaseOut、EaseInEaseOutの4種類しかない。

カスタムなイージング関数を使う場合、レイヤアニメーションのtimingFunctionプロパティを自作のCAMediaTimingFunctionクラスのオブジェクトに置き換える。

「ベジェ曲線の制御点を2点指定する」方法で簡単に作れるが、それ以上の制御点が必要な複雑なアニメーション(例えば振動して収縮する系統など)はサブクラスを作ってgetControlPointAtIndex:values:をオーバーライドすればよさげ。

嘘でした。複雑なアニメーションはKeyFrameAnimationとしてしか作れないみたいです。

---

アニメーション終了時に処理を書きたい

普通にやるならアニメーションオブジェクトのdelegateプロパティを指定して、デリゲートメソッドを実装する。

その辺の処理をラップして、ブロック構文で済ませられるようにすると良さげ。

---

アニメーション終了後処理でアニメーションの識別をしたい

普通にデリゲートメソッドとして書く場合、デリゲートオブジェクトは大抵呼び出し元一つになるので、「どのアニメーションの終了処理なのか?」を知る必要がある。

そういうデリゲートの残念さを回避するのにブロック構文を使うといいんだけど、使わない場合は落とし穴が二つあるので注意。

まず、アニメーションは終了時点で識別するには、引数で渡したアニメーションと、レイヤに与えたアニメーションが同じオブジェクトかを比較するしかない。

しかし、デフォルトではアニメーションが終了した時点で解放されるので、removedOnCompletionプロパティにNOを渡して、解放されないようにしなければならない。

ただしこのままだと与えたアニメーションが保持し続けられてしまうため、同じレイヤに複数のアニメーションを実行させたときに、終了後にレイヤが不可視になるなどの振る舞いが発生してしまう。なので、終了処理でremoveAllAnimationsメソッドなどでアニメーションを手動解放する必要がある。

---

レイヤアニメーションを使うメリットって?

UIViewアニメーションで処理がもたつく場合は、レイヤアニメーションに切り替えることで改善される可能性はある。

カスタマイズしたイージング関数が使える。これはデフォルトで選べる選択肢が少なすぎるのが悪い気がするけど。

また3Dトランスフォームが可能。MacOSXやiPhoneにカバーフロー表示があるのは、偏にCore Animationが3Dトランスフォームアニメーションをサポートしているから。

---

実はUIViewAnimationでもレイヤを操作できる

CAAnimationの低レベルAPIを使用しなくても、レイヤを操作したアニメーション自体はできる。

UIViewのbeginAnimationでも、iOS4以降のanimateWithDuration:animations:でもOK。layerの値を操作するとちゃんと補完され、レイヤアニメーションが実行され、終了後にはViewの判定も移動している。CATransform3Dを使用してもまったく問題なし。

不可能だと書いてある本やサイトも存在するので、iOS5前後で可能になったのでしょうかこれ…。

0 件のコメント:

コメントを投稿